From 30f0e7d71cb81e7eda7fcfa7c4cac3db7e864e2a Mon Sep 17 00:00:00 2001 From: Kareena Hirani Date: Thu, 18 Nov 2021 10:45:40 -0800 Subject: [PATCH 001/175] fix: Wait for all canary pods to come up in TrafficRouting canary before switching traffic (#1663) Signed-off-by: khhirani --- rollout/trafficrouting.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rollout/trafficrouting.go b/rollout/trafficrouting.go index db6e53a432..62d698074e 100644 --- a/rollout/trafficrouting.go +++ b/rollout/trafficrouting.go @@ -131,7 +131,7 @@ func (c *rolloutContext) reconcileTrafficRouting() error { weightDestinations = append(weightDestinations, c.calculateWeightDestinationsFromExperiment()...) } else if index != nil { atDesiredReplicaCount := replicasetutil.AtDesiredReplicaCountsForCanary(c.rollout, c.newRS, c.stableRS, c.otherRSs, nil) - if !atDesiredReplicaCount { + if !atDesiredReplicaCount && !c.rollout.Status.PromoteFull { // Use the previous weight since the new RS is not ready for a new weight for i := *index - 1; i >= 0; i-- { step := c.rollout.Spec.Strategy.Canary.Steps[i] From 74e4be494d6088c1bf8605454fb0ed98b8b7597f Mon Sep 17 00:00:00 2001 From: Kareena Hirani Date: Thu, 18 Nov 2021 10:45:57 -0800 Subject: [PATCH 002/175] fix: Modify Experiment collision naming from dot-notation to dash (#1646) Signed-off-by: khhirani --- rollout/experiment.go | 2 +- rollout/experiment_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rollout/experiment.go b/rollout/experiment.go index 807d44ddb7..a000fe014e 100644 --- a/rollout/experiment.go +++ b/rollout/experiment.go @@ -230,7 +230,7 @@ func (c *rolloutContext) createExperimentWithCollisionHandling(newEx *v1alpha1.E // we likely reconciled the rollout with a stale cache (quite common). return existingEx, nil } - newEx.Name = fmt.Sprintf("%s.%d", baseName, collisionCount) + newEx.Name = fmt.Sprintf("%s-%d", baseName, collisionCount) collisionCount++ } } diff --git a/rollout/experiment_test.go b/rollout/experiment_test.go index 48c05e4233..6ba0ca43b0 100644 --- a/rollout/experiment_test.go +++ b/rollout/experiment_test.go @@ -165,7 +165,7 @@ func TestCreateExperimentWithCollision(t *testing.T) { f.run(getKey(r2, t)) createdEx := f.getCreatedExperiment(createExIndex) - assert.Equal(t, ex.Name+".1", createdEx.Name) + assert.Equal(t, ex.Name+"-1", createdEx.Name) patch := f.getPatchedRollout(patchIndex) expectedPatch := `{ "status": { From 7fcea513d2ff062cb67ffe2f19d9d6a5d16fbd5f Mon Sep 17 00:00:00 2001 From: Kareena Hirani Date: Thu, 18 Nov 2021 10:46:17 -0800 Subject: [PATCH 003/175] fix: add service delete to argo-rollouts role (#1632) Signed-off-by: khhirani --- manifests/install.yaml | 1 + manifests/namespace-install.yaml | 1 + manifests/role/argo-rollouts-clusterrole.yaml | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/manifests/install.yaml b/manifests/install.yaml index b957a4f992..dfd4c2602f 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -13578,6 +13578,7 @@ rules: - watch - patch - create + - delete - apiGroups: - coordination.k8s.io resources: diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index a5c88a7efc..449bbddd86 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -13578,6 +13578,7 @@ rules: - watch - patch - create + - delete - apiGroups: - coordination.k8s.io resources: diff --git a/manifests/role/argo-rollouts-clusterrole.yaml b/manifests/role/argo-rollouts-clusterrole.yaml index 207e50ad17..9b90538a1a 100644 --- a/manifests/role/argo-rollouts-clusterrole.yaml +++ b/manifests/role/argo-rollouts-clusterrole.yaml @@ -68,7 +68,7 @@ rules: - list - watch # services patch needed to update selector of canary/stable/active/preview services -# services create needed to create services for experiments +# services create needed to create and delete services for experiments - apiGroups: - "" resources: @@ -79,6 +79,7 @@ rules: - watch - patch - create + - delete # leases create/get/update needed for leader election - apiGroups: - coordination.k8s.io From 55c70a140d5e0dd738f013860025faa718e616c0 Mon Sep 17 00:00:00 2001 From: Rohit Agrawal Date: Thu, 18 Nov 2021 13:54:13 -0500 Subject: [PATCH 004/175] fix: Fixed NPE while getting the ReplicaSet labels (#1664) Signed-off-by: Rohit Agrawal --- utils/replicaset/replicaset.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/replicaset/replicaset.go b/utils/replicaset/replicaset.go index deb1af1da0..04134b2450 100644 --- a/utils/replicaset/replicaset.go +++ b/utils/replicaset/replicaset.go @@ -523,7 +523,7 @@ func PodTemplateEqualIgnoreHash(live, desired *corev1.PodTemplateSpec) bool { // GetPodTemplateHash returns the rollouts-pod-template-hash value from a ReplicaSet's labels func GetPodTemplateHash(rs *appsv1.ReplicaSet) string { - if rs.Labels == nil { + if rs == nil || rs.Labels == nil { return "" } return rs.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] From 615bce39475c74a44bf253000037e58cadf84a9e Mon Sep 17 00:00:00 2001 From: cskh Date: Fri, 19 Nov 2021 14:07:38 -0500 Subject: [PATCH 005/175] fix: reset the progress condition when a pod is restarted (#1649) fix: reset the progress condition when a pod is restarted (#1649) Signed-off-by: Hui Kang Co-authored-by: Hui Kang Co-authored-by: Rohit Agrawal --- rollout/bluegreen_test.go | 54 ++++++++++++++++++++++++++++++++++ rollout/controller_test.go | 3 ++ rollout/sync.go | 19 ++++++++++-- test/e2e/functional_test.go | 37 +++++++++++++++++++++++ utils/conditions/conditions.go | 6 ++++ 5 files changed, 116 insertions(+), 3 deletions(-) diff --git a/rollout/bluegreen_test.go b/rollout/bluegreen_test.go index a83b9071c2..ea81faa88a 100644 --- a/rollout/bluegreen_test.go +++ b/rollout/bluegreen_test.go @@ -37,6 +37,60 @@ func newBlueGreenRollout(name string, replicas int, revisionHistoryLimit *int32, return rollout } +func TestBlueGreenComplateRolloutRestart(t *testing.T) { + f := newFixture(t) + defer f.Close() + + r := newBlueGreenRollout("foo", 1, nil, "active", "preview") + r.Status.Conditions = []v1alpha1.RolloutCondition{} + + completedCond := conditions.NewRolloutCondition(v1alpha1.RolloutCompleted, corev1.ConditionTrue, conditions.RolloutCompletedReason, conditions.RolloutCompletedReason) + conditions.SetRolloutCondition(&r.Status, *completedCond) + + f.rolloutLister = append(f.rolloutLister, r) + f.objects = append(f.objects, r) + previewSvc := newService("preview", 80, nil, r) + activeSvc := newService("active", 80, nil, r) + f.kubeobjects = append(f.kubeobjects, previewSvc, activeSvc) + f.serviceLister = append(f.serviceLister, activeSvc, previewSvc) + + rs := newReplicaSet(r, 1) + rsPodHash := rs.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] + generatedConditions := generateConditionsPatchWithComplete(false, conditions.ReplicaSetNotAvailableReason, rs, false, "", false) + + f.expectCreateReplicaSetAction(rs) + servicePatchIndex := f.expectPatchServiceAction(previewSvc, rsPodHash) + f.expectUpdateReplicaSetAction(rs) // scale up RS + updatedRolloutIndex := f.expectUpdateRolloutStatusAction(r) + expectedPatchWithoutSubs := `{ + "status":{ + "blueGreen" : { + "previewSelector": "%s" + }, + "conditions": %s, + "selector": "foo=bar", + "stableRS": "%s", + "phase": "Progressing", + "message": "more replicas need to be updated" + } + }` + expectedPatch := calculatePatch(r, fmt.Sprintf(expectedPatchWithoutSubs, rsPodHash, generatedConditions, rsPodHash)) + patchRolloutIndex := f.expectPatchRolloutActionWithPatch(r, expectedPatch) + f.run(getKey(r, t)) + + f.verifyPatchedService(servicePatchIndex, rsPodHash, "") + + updatedRollout := f.getUpdatedRollout(updatedRolloutIndex) + updatedProgressingCondition := conditions.GetRolloutCondition(updatedRollout.Status, v1alpha1.RolloutProgressing) + assert.NotNil(t, updatedProgressingCondition) + assert.Equal(t, conditions.NewReplicaSetReason, updatedProgressingCondition.Reason) + assert.Equal(t, corev1.ConditionTrue, updatedProgressingCondition.Status) + assert.Equal(t, fmt.Sprintf(conditions.NewReplicaSetMessage, rs.Name), updatedProgressingCondition.Message) + + patch := f.getPatchedRollout(patchRolloutIndex) + assert.Equal(t, expectedPatch, patch) +} + func TestBlueGreenCreatesReplicaSet(t *testing.T) { f := newFixture(t) defer f.Close() diff --git a/rollout/controller_test.go b/rollout/controller_test.go index d58904e779..7d545d4e79 100644 --- a/rollout/controller_test.go +++ b/rollout/controller_test.go @@ -229,6 +229,9 @@ func newProgressingCondition(reason string, resourceObj runtime.Object, optional if reason == conditions.NewRSAvailableReason { msg = fmt.Sprintf(conditions.ReplicaSetCompletedMessage, resource.Name) } + if reason == conditions.ReplicaSetNotAvailableReason { + msg = conditions.NotAvailableMessage + } case *v1alpha1.Rollout: if reason == conditions.ReplicaSetUpdatedReason { msg = fmt.Sprintf(conditions.RolloutProgressingMessage, resource.Name) diff --git a/rollout/sync.go b/rollout/sync.go index e54f3375e6..ee1da25ef4 100644 --- a/rollout/sync.go +++ b/rollout/sync.go @@ -577,6 +577,7 @@ func (c *rolloutContext) calculateRolloutConditions(newStatus v1alpha1.RolloutSt isPaused := len(c.rollout.Status.PauseConditions) > 0 || c.rollout.Spec.Paused isAborted := c.pauseContext.IsAborted() + var becameIncomplete bool // remember if we transitioned from completed completeCond := conditions.GetRolloutCondition(c.rollout.Status, v1alpha1.RolloutCompleted) if !isPaused && conditions.RolloutComplete(c.rollout, &newStatus) { updateCompletedCond := conditions.NewRolloutCondition(v1alpha1.RolloutCompleted, corev1.ConditionTrue, conditions.RolloutCompletedReason, conditions.RolloutCompletedReason) @@ -584,7 +585,7 @@ func (c *rolloutContext) calculateRolloutConditions(newStatus v1alpha1.RolloutSt } else { if completeCond != nil { updateCompletedCond := conditions.NewRolloutCondition(v1alpha1.RolloutCompleted, corev1.ConditionFalse, conditions.RolloutCompletedReason, conditions.RolloutCompletedReason) - conditions.SetRolloutCondition(&newStatus, *updateCompletedCond) + becameIncomplete = conditions.SetRolloutCondition(&newStatus, *updateCompletedCond) } } @@ -619,14 +620,26 @@ func (c *rolloutContext) calculateRolloutConditions(newStatus v1alpha1.RolloutSt msg := fmt.Sprintf(conditions.ReplicaSetCompletedMessage, rsName) progressingCondition := conditions.NewRolloutCondition(v1alpha1.RolloutProgressing, corev1.ConditionTrue, conditions.NewRSAvailableReason, msg) conditions.SetRolloutCondition(&newStatus, *progressingCondition) - case conditions.RolloutProgressing(c.rollout, &newStatus): + case conditions.RolloutProgressing(c.rollout, &newStatus) || becameIncomplete: // If there is any progress made, continue by not checking if the rollout failed. This // behavior emulates the rolling updater progressDeadline check. msg := fmt.Sprintf(conditions.RolloutProgressingMessage, c.rollout.Name) if c.newRS != nil { msg = fmt.Sprintf(conditions.ReplicaSetProgressingMessage, c.newRS.Name) } - condition := conditions.NewRolloutCondition(v1alpha1.RolloutProgressing, corev1.ConditionTrue, conditions.ReplicaSetUpdatedReason, msg) + + var reason string + if newStatus.StableRS == newStatus.CurrentPodHash && becameIncomplete { + // When a fully promoted rollout becomes Incomplete, e.g., due to the ReplicaSet status changes like + // pod restarts, evicted -> recreated, we'll need to reset the rollout's condition to `PROGRESSING` to + // avoid any timeouts. + reason = conditions.ReplicaSetNotAvailableReason + msg = conditions.NotAvailableMessage + } else { + reason = conditions.ReplicaSetUpdatedReason + } + condition := conditions.NewRolloutCondition(v1alpha1.RolloutProgressing, corev1.ConditionTrue, reason, msg) + // Update the current Progressing condition or add a new one if it doesn't exist. // If a Progressing condition with status=true already exists, we should update // everything but lastTransitionTime. SetRolloutCondition already does that but diff --git a/test/e2e/functional_test.go b/test/e2e/functional_test.go index d5e44f49f3..977335ba29 100644 --- a/test/e2e/functional_test.go +++ b/test/e2e/functional_test.go @@ -1074,6 +1074,43 @@ spec: ExpectActiveRevision("2") } +func (s *FunctionalSuite) TestCompleteRolloutRestart() { + s.Given(). + HealthyRollout(` +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollout-restart +spec: + progressDeadlineAbort: true + progressDeadlineSeconds: 15 + replicas: 2 + selector: + matchLabels: + app: ollout-restart + template: + metadata: + labels: + app: ollout-restart + spec: + containers: + - name: ollout-restart + image: nginx:1.19-alpine + imagePullPolicy: Always + strategy: + canary: + steps: + - setWeight: 20 +`). + When(). + WatchRolloutStatus("Healthy"). + Sleep(16 * time.Second). // give it enough time to pass the progressDeadlineSeconds + Then(). + When(). + RestartRollout(). + WatchRolloutStatus("Healthy") +} + func (s *FunctionalSuite) TestKubectlWaitForCompleted() { s.Given(). HealthyRollout(` diff --git a/utils/conditions/conditions.go b/utils/conditions/conditions.go index 8ebaf5412c..4f4cf04004 100644 --- a/utils/conditions/conditions.go +++ b/utils/conditions/conditions.go @@ -86,6 +86,12 @@ const ( // estimated once a rollout is paused. RolloutPausedMessage = "Rollout is paused" + // ReplicaSetNotAvailableReason is added when the replicaset of an rollout is not available. + // This could happen when a fully promoted rollout becomes incomplete, e.g., + // due to pod restarts, evicted -> recreated. In this case, we'll need to reset the rollout's + // condition to `PROGRESSING` to avoid any timeouts. + ReplicaSetNotAvailableReason = "ReplicaSetNotAvailable" + // RolloutResumedReason is added in a rollout when it is resumed. Useful for not failing accidentally // rollout that paused amidst a rollout and are bounded by a deadline. RolloutResumedReason = "RolloutResumed" From ca3ccd01c13bf21732c484c03c6086c416e98633 Mon Sep 17 00:00:00 2001 From: Yuan Tang Date: Fri, 19 Nov 2021 15:50:36 -0500 Subject: [PATCH 006/175] docs: Add link to awesome-argo for more resources (#1622) * docs: Add link to awesome-argo for more resources Signed-off-by: Yuan Tang * Retrigger CI pipeline Signed-off-by: Yuan Tang --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4e08ea0499..cccd5c3f8c 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ To learn more about Argo Rollouts go to the [complete documentation](https://arg ## Community Blogs and Presentations +* [Awesome-Argo: A Curated List of Awesome Projects and Resources Related to Argo](https://github.com/terrytangyuan/awesome-argo) * [Automation of Everything - How To Combine Argo Events, Workflows & Pipelines, CD, and Rollouts](https://youtu.be/XNXJtxkUKeY) * [Argo Rollouts - Canary Deployments Made Easy In Kubernetes](https://youtu.be/84Ky0aPbHvY) * [How Intuit Does Canary and Blue Green Deployments](https://www.youtube.com/watch?v=yeVkTTO9nOA) From 47d59fa9855ab737e40e21ef5938b2b6723cb899 Mon Sep 17 00:00:00 2001 From: Siddharth Maloo <92331248+smaloo-salesforce@users.noreply.github.com> Date: Sat, 20 Nov 2021 04:12:57 +0530 Subject: [PATCH 007/175] feat: added Argo version info in /metrics endpoint (#1662) Signed-off-by: Siddharth Maloo --- controller/metrics/metrics.go | 1 + controller/metrics/metrics_test.go | 7 +++++++ controller/metrics/prommetrics.go | 19 ++++++++++++++++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/controller/metrics/metrics.go b/controller/metrics/metrics.go index 75e73063e8..b502ff32e6 100644 --- a/controller/metrics/metrics.go +++ b/controller/metrics/metrics.go @@ -75,6 +75,7 @@ func NewMetricsServer(cfg ServerConfig, isPrimary bool) *MetricsServer { reg.MustRegister(MetricExperimentReconcileError) reg.MustRegister(MetricAnalysisRunReconcile) reg.MustRegister(MetricAnalysisRunReconcileError) + reg.MustRegister(MetricVersionGauge) mux.Handle(MetricsPath, promhttp.HandlerFor(prometheus.Gatherers{ // contains app controller specific metrics diff --git a/controller/metrics/metrics_test.go b/controller/metrics/metrics_test.go index de4619bd17..098d576702 100644 --- a/controller/metrics/metrics_test.go +++ b/controller/metrics/metrics_test.go @@ -89,6 +89,13 @@ rollout_reconcile_error{name="name",namespace="ns"} 1` testHttpResponse(t, metricsServ.Handler, expectedResponse) } +func TestVersionInfo(t *testing.T) { + expectedResponse := `# HELP argo_rollouts_controller_info Running Argo-rollouts version +# TYPE argo_rollouts_controller_info gauge` + metricsServ := NewMetricsServer(newFakeServerConfig(), true) + testHttpResponse(t, metricsServ.Handler, expectedResponse) +} + func TestSecondaryMetricsServer(t *testing.T) { expectedResponse := `` diff --git a/controller/metrics/prommetrics.go b/controller/metrics/prommetrics.go index ff2017765e..564f1b46f3 100644 --- a/controller/metrics/prommetrics.go +++ b/controller/metrics/prommetrics.go @@ -1,6 +1,9 @@ package metrics -import "github.com/prometheus/client_golang/prometheus" +import ( + "github.com/argoproj/argo-rollouts/utils/version" + "github.com/prometheus/client_golang/prometheus" +) // Follow Prometheus naming practices // https://prometheus.io/docs/practices/naming/ @@ -184,3 +187,17 @@ var ( []string{"kind", "namespace", "name", "verb", "status_code"}, ) ) + +// MetricVersionGauge version info +var ( + MetricVersionGauge = prometheus.NewGaugeFunc( + prometheus.GaugeOpts{ + Name: "argo_rollouts_controller_info", + Help: "Running Argo-rollouts version", + ConstLabels: prometheus.Labels{"version": version.GetVersion().Version}, + }, + func() float64 { + return float64(1) + }, + ) +) From 104df9aaaacedaa7ee7f0926ca483ddabd1ff1eb Mon Sep 17 00:00:00 2001 From: Shlomo Sanders Date: Tue, 30 Nov 2021 15:30:59 +0200 Subject: [PATCH 008/175] add rollout.Spec.Strategy.Canary.MinPodsPerRS --- pkg/apis/rollouts/v1alpha1/types.go | 3 +++ utils/replicaset/canary.go | 18 ++++++++++++++++-- utils/replicaset/canary_test.go | 18 ++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/pkg/apis/rollouts/v1alpha1/types.go b/pkg/apis/rollouts/v1alpha1/types.go index 4cb87b334b..722879303f 100644 --- a/pkg/apis/rollouts/v1alpha1/types.go +++ b/pkg/apis/rollouts/v1alpha1/types.go @@ -305,6 +305,9 @@ type CanaryStrategy struct { // scaling down the stable as traffic is increased to canary. When disabled (the default behavior) // the stable ReplicaSet remains fully scaled to support instantaneous aborts. DynamicStableScale bool `json:"dynamicStableScale,omitempty" protobuf:"varint,14,opt,name=dynamicStableScale"` + // Assuming the desired number of pods in a stable or canary ReplicaSet is not zero, then make sure it is at least + // MinPodsPerRS for High Availability. Only applicable for TrafficRoutedCanary + MinPodsPerRS *int32 `json:"minPodsPerRS,omitempty" protobuf:"varint,15,opt,name=minPodsPerRS"` } // AnalysisRunStrategy configuration for the analysis runs and experiments to retain diff --git a/utils/replicaset/canary.go b/utils/replicaset/canary.go index 01055d1931..9116c0839c 100644 --- a/utils/replicaset/canary.go +++ b/utils/replicaset/canary.go @@ -91,8 +91,21 @@ func DesiredReplicaCountsForCanary(rollout *v1alpha1.Rollout, newRS, stableRS *a return desiredNewRSReplicaCount, desiredStableRSReplicaCount } + */ +// CheckMinPodsPerRS ensures that if the desired number of pods in a stable or canary ReplicaSet is not zero, +// then it is at least MinPodsPerRS for High Availability. Only applicable if using TrafficRouting +func CheckMinPodsPerRS (rollout *v1alpha1.Rollout, count int32) (int32) { + if count == 0 { + return count + } + if rollout.Spec.Strategy.Canary == nil || rollout.Spec.Strategy.Canary.MinPodsPerRS == nil || rollout.Spec.Strategy.Canary.TrafficRouting == nil { + return count + } + return max (count, *rollout.Spec.Strategy.Canary.MinPodsPerRS) +} + // CalculateReplicaCountsForBasicCanary calculates the number of replicas for the newRS and the stableRS // when using the basic canary strategy. The function calculates the desired number of replicas for // the new and stable RS using the following equations: @@ -290,6 +303,7 @@ func maxValue(countA int32, countB int32) int32 { // CalculateReplicaCountsForTrafficRoutedCanary calculates the canary and stable replica counts // when using canary with traffic routing. If current traffic weights are supplied, we factor the // those weights into the and return the higher of current traffic scale vs. desired traffic scale +// If MinPodsPerRS is defined and the number of replicas in either RS is not 0, then return at least MinPodsPerRS func CalculateReplicaCountsForTrafficRoutedCanary(rollout *v1alpha1.Rollout, weights *v1alpha1.TrafficWeights) (int32, int32) { var canaryCount, stableCount int32 rolloutSpecReplica := defaults.GetReplicasOrDefault(rollout.Spec.Replicas) @@ -298,7 +312,7 @@ func CalculateReplicaCountsForTrafficRoutedCanary(rollout *v1alpha1.Rollout, wei // a canary count was explicitly set canaryCount = *setCanaryScaleReplicas } else { - canaryCount = trafficWeightToReplicas(rolloutSpecReplica, desiredWeight) + canaryCount = CheckMinPodsPerRS(rollout, trafficWeightToReplicas(rolloutSpecReplica, desiredWeight)) } if !rollout.Spec.Strategy.Canary.DynamicStableScale { @@ -329,7 +343,7 @@ func CalculateReplicaCountsForTrafficRoutedCanary(rollout *v1alpha1.Rollout, wei canaryCount = max(trafficWeightReplicaCount, canaryCount) } } - return canaryCount, stableCount + return CheckMinPodsPerRS(rollout, canaryCount), CheckMinPodsPerRS(rollout, stableCount) } // trafficWeightToReplicas returns the appropriate replicas given the full spec.replicas and a weight diff --git a/utils/replicaset/canary_test.go b/utils/replicaset/canary_test.go index 3b817ad96b..c1e4ed0c44 100644 --- a/utils/replicaset/canary_test.go +++ b/utils/replicaset/canary_test.go @@ -96,6 +96,7 @@ func TestCalculateReplicaCountsForCanary(t *testing.T) { abortScaleDownDelaySeconds *int32 statusAbort bool + minPodsPerRS *int32 }{ { name: "Do not add extra RSs in scaleDownCount when .Spec.Replica < AvailableReplicas", @@ -626,6 +627,23 @@ func TestCalculateReplicaCountsForCanary(t *testing.T) { expectedStableReplicaCount: 1, expectedCanaryReplicaCount: 0, }, + { + name: "Honor MinPodsPerRS when using trafficRouting and starting canary", + rolloutSpecReplicas: 10, + setWeight: 5, + + stableSpecReplica: 10, + stableAvailableReplica: 10, + + canarySpecReplica: 0, + canaryAvailableReplica: 0, + + trafficRouting: &v1alpha1.RolloutTrafficRouting{}, + minPodsPerRS: intPnt(2), + + expectedStableReplicaCount: 10, + expectedCanaryReplicaCount: 2, + }, } for i := range tests { test := tests[i] From 9d32c13c4eb469a138bc9673c08c42d73e1c01fb Mon Sep 17 00:00:00 2001 From: Andrii Perenesenko Date: Tue, 30 Nov 2021 13:02:13 -0800 Subject: [PATCH 009/175] fix: sending updates to dashboard when a pod terminates (#1642) * fix: sending updates to dashboard when a pod terminates Signed-off-by: Andrii Perenesenko * Fix imports Signed-off-by: Andrii Perenesenko --- server/server.go | 99 ++++++++++++++++++++++++++++-------------------- 1 file changed, 58 insertions(+), 41 deletions(-) diff --git a/server/server.go b/server/server.go index e0dca4bbbd..6e4033accb 100644 --- a/server/server.go +++ b/server/server.go @@ -24,12 +24,14 @@ import ( "k8s.io/client-go/dynamic" kubeinformers "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes" + appslisters "k8s.io/client-go/listers/apps/v1" "k8s.io/client-go/tools/cache" "github.com/argoproj/argo-rollouts/pkg/apiclient/rollout" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" rolloutclientset "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned" rolloutinformers "github.com/argoproj/argo-rollouts/pkg/client/informers/externalversions" + listers "github.com/argoproj/argo-rollouts/pkg/client/listers/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/cmd/abort" "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/cmd/get" "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/cmd/promote" @@ -293,65 +295,61 @@ func (s *ArgoRolloutsServer) WatchRolloutInfos(q *rollout.RolloutInfoListQuery, } } ctx := ws.Context() - rolloutIf := s.Options.RolloutsClientset.ArgoprojV1alpha1().Rollouts(q.GetNamespace()) + + rolloutsInformerFactory := rolloutinformers.NewSharedInformerFactoryWithOptions(s.Options.RolloutsClientset, 0, rolloutinformers.WithNamespace(q.Namespace)) + rolloutsLister := rolloutsInformerFactory.Argoproj().V1alpha1().Rollouts().Lister().Rollouts(q.Namespace) + rolloutInformer := rolloutsInformerFactory.Argoproj().V1alpha1().Rollouts().Informer() kubeInformerFactory := kubeinformers.NewSharedInformerFactoryWithOptions(s.Options.KubeClientset, 0, kubeinformers.WithNamespace(q.Namespace)) podsLister := kubeInformerFactory.Core().V1().Pods().Lister().Pods(q.GetNamespace()) rsLister := kubeInformerFactory.Apps().V1().ReplicaSets().Lister().ReplicaSets(q.GetNamespace()) kubeInformerFactory.Start(ws.Context().Done()) + podsInformer := kubeInformerFactory.Core().V1().Pods().Informer() + + rolloutUpdateChan := make(chan *v1alpha1.Rollout) + + rolloutInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + rolloutUpdateChan <- obj.(*v1alpha1.Rollout) + }, + UpdateFunc: func(oldObj, newObj interface{}) { + rolloutUpdateChan <- newObj.(*v1alpha1.Rollout) + }, + }) + podsInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ + DeleteFunc: func(obj interface{}) { + podUpdated(obj.(*corev1.Pod), rsLister, rolloutsLister, rolloutUpdateChan) + }, + }) + + go rolloutInformer.Run(ctx.Done()) cache.WaitForCacheSync( ws.Context().Done(), - kubeInformerFactory.Core().V1().Pods().Informer().HasSynced, + podsInformer.HasSynced, kubeInformerFactory.Apps().V1().ReplicaSets().Informer().HasSynced, + rolloutInformer.HasSynced, ) - watchIf, err := rolloutIf.Watch(ctx, v1.ListOptions{}) - if err != nil { - return err - } - - var ro *v1alpha1.Rollout - retries := 0 -L: for { select { - case next := <-watchIf.ResultChan(): - ro, _ = next.Object.(*v1alpha1.Rollout) case <-ctx.Done(): - break L - } - if ro == nil { - watchIf.Stop() - newWatchIf, err := rolloutIf.Watch(ctx, v1.ListOptions{}) + return nil + case ro := <-rolloutUpdateChan: + allPods, err := podsLister.List(labels.Everything()) if err != nil { - if retries > 5 { - return err - } - log.Warn(err) - time.Sleep(time.Second) - retries++ - } else { - watchIf = newWatchIf - retries = 0 + return err + } + allReplicaSets, err := rsLister.List(labels.Everything()) + if err != nil { + return err } - continue - } - allPods, err := podsLister.List(labels.Everything()) - if err != nil { - return err - } - allReplicaSets, err := rsLister.List(labels.Everything()) - if err != nil { - return err - } - // get shallow rollout info - ri := info.NewRolloutInfo(ro, allReplicaSets, allPods, nil, nil) - send(ri) + // get shallow rollout info + ri := info.NewRolloutInfo(ro, allReplicaSets, allPods, nil, nil) + send(ri) + } } - watchIf.Stop() - return nil } func (s *ArgoRolloutsServer) RolloutToRolloutInfo(ro *v1alpha1.Rollout) (*rollout.RolloutInfo, error) { @@ -428,3 +426,22 @@ func (s *ArgoRolloutsServer) Version(ctx context.Context, _ *empty.Empty) (*roll RolloutsVersion: version.String(), }, nil } + +func podUpdated(pod *corev1.Pod, rsLister appslisters.ReplicaSetNamespaceLister, + rolloutLister listers.RolloutNamespaceLister, rolloutUpdated chan *v1alpha1.Rollout) { + for _, podOwner := range pod.GetOwnerReferences() { + if podOwner.Kind == "ReplicaSet" { + rs, err := rsLister.Get(podOwner.Name) + if err == nil { + for _, rsOwner := range rs.GetOwnerReferences() { + if rsOwner.APIVersion == v1alpha1.SchemeGroupVersion.String() && rsOwner.Kind == "Rollout" { + ro, err := rolloutLister.Get(rsOwner.Name) + if err == nil { + rolloutUpdated <- ro + } + } + } + } + } + } +} From ec3d3834ffe9a3762554a706ad2f595d747504dc Mon Sep 17 00:00:00 2001 From: Rohit Agrawal Date: Thu, 2 Dec 2021 12:59:25 -0500 Subject: [PATCH 010/175] feat(analysis): Add Dry-Run Mode (#1627) dryRun can be used on a metric to control whether or not to evaluate that metric in a dry-run mode. A metric running in the dry-run mode won't impact the final state of the rollout or experiment even if it fails or the evaluation comes out as inconclusive. Signed-off-by: Rohit Agrawal --- analysis/analysis.go | 221 ++++++++++---- analysis/analysis_test.go | 283 ++++++++++++++---- controller/metrics/analysis.go | 19 +- controller/metrics/analysis_test.go | 43 ++- controller/metrics/prommetrics.go | 2 +- docs/features/analysis.md | 108 +++++++ manifests/crds/analysis-run-crd.yaml | 47 +++ manifests/crds/analysis-template-crd.yaml | 9 + .../crds/cluster-analysis-template-crd.yaml | 9 + manifests/crds/rollout-crd.yaml | 36 +++ manifests/install.yaml | 101 +++++++ manifests/namespace-install.yaml | 101 +++++++ pkg/apiclient/rollout/rollout.swagger.json | 17 ++ pkg/apis/api-rules/violation_exceptions.list | 3 + pkg/apis/rollouts/v1alpha1/analysis_types.go | 35 +++ pkg/apis/rollouts/v1alpha1/generated.pb.go | 1 + pkg/apis/rollouts/v1alpha1/generated.proto | 2 - pkg/apis/rollouts/v1alpha1/types.go | 4 + .../v1alpha1/zz_generated.deepcopy.go | 53 ++++ .../validation/validation_references.go | 2 +- rollout/analysis.go | 2 +- utils/analysis/factory.go | 2 +- utils/analysis/factory_test.go | 2 +- utils/analysis/helpers.go | 81 ++++- utils/analysis/helpers_test.go | 136 ++++++++- 25 files changed, 1164 insertions(+), 155 deletions(-) diff --git a/analysis/analysis.go b/analysis/analysis.go index 046e3899b8..952994146d 100644 --- a/analysis/analysis.go +++ b/analysis/analysis.go @@ -26,7 +26,10 @@ const ( DefaultMeasurementHistoryLimit = 10 // DefaultErrorRetryInterval is the default interval to retry a measurement upon error, in the // event an interval was not specified - DefaultErrorRetryInterval time.Duration = 10 * time.Second + DefaultErrorRetryInterval = 10 * time.Second + // SuccessfulAssessmentRunTerminatedResult is used for logging purposes when the metrics evaluation + // is successful and the run is terminated. + SuccessfulAssessmentRunTerminatedResult = "Metric Assessment Result - Successful: Run Terminated" ) // metricTask holds the metric which need to be measured during this reconciliation along with @@ -40,7 +43,7 @@ func (c *Controller) reconcileAnalysisRun(origRun *v1alpha1.AnalysisRun) *v1alph if origRun.Status.Phase.Completed() { return origRun } - log := logutil.WithAnalysisRun(origRun) + logger := logutil.WithAnalysisRun(origRun) run := origRun.DeepCopy() if run.Status.MetricResults == nil { @@ -49,8 +52,8 @@ func (c *Controller) reconcileAnalysisRun(origRun *v1alpha1.AnalysisRun) *v1alph resolvedMetrics, err := getResolvedMetricsWithoutSecrets(run.Spec.Metrics, run.Spec.Args) if err != nil { - message := fmt.Sprintf("unable to resolve metric arguments: %v", err) - log.Warn(message) + message := fmt.Sprintf("Unable to resolve metric arguments: %v", err) + logger.Warn(message) run.Status.Phase = v1alpha1.AnalysisPhaseError run.Status.Message = message c.recordAnalysisRunCompletionEvent(run) @@ -59,8 +62,18 @@ func (c *Controller) reconcileAnalysisRun(origRun *v1alpha1.AnalysisRun) *v1alph err = analysisutil.ValidateMetrics(resolvedMetrics) if err != nil { - message := fmt.Sprintf("analysis spec invalid: %v", err) - log.Warn(message) + message := fmt.Sprintf("Analysis spec invalid: %v", err) + logger.Warn(message) + run.Status.Phase = v1alpha1.AnalysisPhaseError + run.Status.Message = message + c.recordAnalysisRunCompletionEvent(run) + return run + } + + dryRunMetricsMap, err := analysisutil.GetDryRunMetrics(run.Spec.DryRun, resolvedMetrics) + if err != nil { + message := fmt.Sprintf("Analysis spec invalid: %v", err) + logger.Warn(message) run.Status.Phase = v1alpha1.AnalysisPhaseError run.Status.Message = message c.recordAnalysisRunCompletionEvent(run) @@ -68,18 +81,18 @@ func (c *Controller) reconcileAnalysisRun(origRun *v1alpha1.AnalysisRun) *v1alph } tasks := generateMetricTasks(run, resolvedMetrics) - log.Infof("taking %d measurements", len(tasks)) - err = c.runMeasurements(run, tasks) + logger.Infof("Taking %d Measurement(s)...", len(tasks)) + err = c.runMeasurements(run, tasks, dryRunMetricsMap) if err != nil { - message := fmt.Sprintf("unable to resolve metric arguments: %v", err) - log.Warn(message) + message := fmt.Sprintf("Unable to resolve metric arguments: %v", err) + logger.Warn(message) run.Status.Phase = v1alpha1.AnalysisPhaseError run.Status.Message = message c.recordAnalysisRunCompletionEvent(run) return run } - newStatus, newMessage := c.assessRunStatus(run, resolvedMetrics) + newStatus, newMessage := c.assessRunStatus(run, resolvedMetrics, dryRunMetricsMap) if newStatus != run.Status.Phase { run.Status.Phase = newStatus run.Status.Message = newMessage @@ -91,7 +104,7 @@ func (c *Controller) reconcileAnalysisRun(origRun *v1alpha1.AnalysisRun) *v1alph err = c.garbageCollectMeasurements(run, DefaultMeasurementHistoryLimit) if err != nil { // TODO(jessesuen): surface errors to controller so they can be retried - log.Warnf("Failed to garbage collect measurements: %v", err) + logger.Warnf("Failed to garbage collect measurements: %v", err) } nextReconcileTime := calculateNextReconcileTime(run, resolvedMetrics) @@ -100,7 +113,7 @@ func (c *Controller) reconcileAnalysisRun(origRun *v1alpha1.AnalysisRun) *v1alph if enqueueSeconds < 0 { enqueueSeconds = 0 } - log.Infof("enqueueing analysis after %v", enqueueSeconds) + logger.Infof("Enqueueing analysis after %v", enqueueSeconds) c.enqueueAnalysisAfter(run, enqueueSeconds) } return run @@ -133,7 +146,7 @@ func (c *Controller) recordAnalysisRunCompletionEvent(run *v1alpha1.AnalysisRun) case v1alpha1.AnalysisPhaseError, v1alpha1.AnalysisPhaseFailed: eventType = corev1.EventTypeWarning } - c.recorder.Eventf(run, record.EventOptions{EventType: eventType, EventReason: "AnalysisRun" + string(run.Status.Phase)}, "analysis completed %s", run.Status.Phase) + c.recorder.Eventf(run, record.EventOptions{EventType: eventType, EventReason: "AnalysisRun" + string(run.Status.Phase)}, "Analysis Completed. Result: %s", run.Status.Phase) } // generateMetricTasks generates a list of metrics tasks needed to be measured as part of this @@ -141,7 +154,7 @@ func (c *Controller) recordAnalysisRunCompletionEvent(run *v1alpha1.AnalysisRun) // terminating (e.g. due to manual termination or failing metric), will not schedule further // measurements other than to resume any in-flight measurements. func generateMetricTasks(run *v1alpha1.AnalysisRun, metrics []v1alpha1.Metric) []metricTask { - log := logutil.WithAnalysisRun(run) + logger := logutil.WithAnalysisRun(run) var tasks []metricTask terminating := analysisutil.IsTerminating(run) @@ -149,7 +162,7 @@ func generateMetricTasks(run *v1alpha1.AnalysisRun, metrics []v1alpha1.Metric) [ if analysisutil.MetricCompleted(run, metric.Name) { continue } - logCtx := log.WithField("metric", metric.Name) + logCtx := logger.WithField("metric", metric.Name) lastMeasurement := analysisutil.LastMeasurement(run, metric.Name) if lastMeasurement != nil && lastMeasurement.FinishedAt == nil { now := metav1.Now() @@ -157,7 +170,7 @@ func generateMetricTasks(run *v1alpha1.AnalysisRun, metrics []v1alpha1.Metric) [ continue } // last measurement is still in-progress. need to complete it - logCtx.Infof("resuming in-progress measurement") + logCtx.Infof("Resuming in-progress measurement") tasks = append(tasks, metricTask{ metric: run.Spec.Metrics[i], incompleteMeasurement: lastMeasurement, @@ -165,7 +178,7 @@ func generateMetricTasks(run *v1alpha1.AnalysisRun, metrics []v1alpha1.Metric) [ continue } if terminating { - logCtx.Infof("skipping measurement: run is terminating") + logCtx.Infof("Skipping measurement: run is terminating") continue } if lastMeasurement == nil { @@ -179,13 +192,13 @@ func generateMetricTasks(run *v1alpha1.AnalysisRun, metrics []v1alpha1.Metric) [ continue } if run.Status.StartedAt.Add(duration).After(time.Now()) { - logCtx.Infof("waiting until start delay duration passes") + logCtx.Infof("Waiting until start delay duration passes") continue } } // measurement never taken tasks = append(tasks, metricTask{metric: run.Spec.Metrics[i]}) - logCtx.Infof("running initial measurement") + logCtx.Infof("Running initial measurement") continue } metricResult := analysisutil.GetResult(run, metric.Name) @@ -201,22 +214,32 @@ func generateMetricTasks(run *v1alpha1.AnalysisRun, metrics []v1alpha1.Metric) [ if lastMeasurement.Phase == v1alpha1.AnalysisPhaseError { interval = DefaultErrorRetryInterval } else if metric.Interval != "" { - metricInterval, err := metric.Interval.Duration() + parsedInterval, err := parseMetricInterval(*logCtx, metric.Interval) if err != nil { - logCtx.Warnf("failed to parse interval: %v", err) continue } - interval = metricInterval + interval = parsedInterval } if time.Now().After(lastMeasurement.FinishedAt.Add(interval)) { tasks = append(tasks, metricTask{metric: run.Spec.Metrics[i]}) - logCtx.Infof("running overdue measurement") + logCtx.Infof("Running overdue measurement") continue } } return tasks } +// parseMetricInterval is a helper method to parse the given metric interval and return the +// parsed duration or error (if any) +func parseMetricInterval(logCtx log.Entry, metricDurationString v1alpha1.DurationString) (time.Duration, error) { + metricInterval, err := metricDurationString.Duration() + if err != nil { + logCtx.Warnf("Failed to parse interval: %v", err) + return -1, err + } + return metricInterval, nil +} + // resolveArgs resolves args for metricTasks, including secret references // returns resolved metricTasks and secrets for log redaction func (c *Controller) resolveArgs(tasks []metricTask, args []v1alpha1.Argument, namespace string) ([]metricTask, []string, error) { @@ -266,7 +289,7 @@ func (c *Controller) resolveArgs(tasks []metricTask, args []v1alpha1.Argument, n } // runMeasurements iterates a list of metric tasks, and runs, resumes, or terminates measurements -func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTask) error { +func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTask, dryRunMetricsMap map[string]bool) error { var wg sync.WaitGroup // resultsLock should be held whenever we are accessing or setting status.metricResults since // we are performing queries in parallel @@ -286,7 +309,7 @@ func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTa go func(t metricTask) { defer wg.Done() //redact secret values from logs - log := logutil.WithRedactor(*logutil.WithAnalysisRun(run).WithField("metric", t.metric.Name), secrets) + logger := logutil.WithRedactor(*logutil.WithAnalysisRun(run).WithField("metric", t.metric.Name), secrets) resultsLock.Lock() metricResult := analysisutil.GetResult(run, t.metric.Name) @@ -294,13 +317,14 @@ func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTa if metricResult == nil { metricResult = &v1alpha1.MetricResult{ - Name: t.metric.Name, - Phase: v1alpha1.AnalysisPhaseRunning, + Name: t.metric.Name, + Phase: v1alpha1.AnalysisPhaseRunning, + DryRun: dryRunMetricsMap[t.metric.Name], } } var newMeasurement v1alpha1.Measurement - provider, err := c.newProvider(*log, t.metric) + provider, err := c.newProvider(*logger, t.metric) if err != nil { if t.incompleteMeasurement != nil { newMeasurement = *t.incompleteMeasurement @@ -316,10 +340,10 @@ func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTa } else { // metric is incomplete. either terminate or resume it if terminating { - log.Infof("terminating in-progress measurement") + logger.Infof("Terminating in-progress measurement") newMeasurement = provider.Terminate(run, t.metric, *t.incompleteMeasurement) if newMeasurement.Phase == v1alpha1.AnalysisPhaseSuccessful { - newMeasurement.Message = "metric terminated" + newMeasurement.Message = "Metric Terminated" } } else { newMeasurement = provider.Resume(run, t.metric, *t.incompleteMeasurement) @@ -328,7 +352,7 @@ func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTa } if newMeasurement.Phase.Completed() { - log.Infof("measurement completed %s", newMeasurement.Phase) + logger.Infof("Measurement Completed. Result: %s", newMeasurement.Phase) if newMeasurement.FinishedAt == nil { finishedAt := metav1.Now() newMeasurement.FinishedAt = &finishedAt @@ -349,7 +373,7 @@ func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTa case v1alpha1.AnalysisPhaseError: metricResult.Error++ metricResult.ConsecutiveError++ - log.Warnf("measurement had error: %s", newMeasurement.Message) + logger.Warnf("Measurement had error: %s", newMeasurement.Message) } } @@ -380,7 +404,7 @@ func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTa // assessRunStatus assesses the overall status of this AnalysisRun // If any metric is not yet completed, the AnalysisRun is still considered Running // Once all metrics are complete, the worst status is used as the overall AnalysisRun status -func (c *Controller) assessRunStatus(run *v1alpha1.AnalysisRun, metrics []v1alpha1.Metric) (v1alpha1.AnalysisPhase, string) { +func (c *Controller) assessRunStatus(run *v1alpha1.AnalysisRun, metrics []v1alpha1.Metric, dryRunMetricsMap map[string]bool) (v1alpha1.AnalysisPhase, string) { var worstStatus v1alpha1.AnalysisPhase var worstMessage string terminating := analysisutil.IsTerminating(run) @@ -391,23 +415,45 @@ func (c *Controller) assessRunStatus(run *v1alpha1.AnalysisRun, metrics []v1alph run.Status.StartedAt = &now } if run.Spec.Terminate { - worstMessage = "run terminated" + worstMessage = "Run Terminated" } - // Iterate all metrics and update MetricResult.Phase fields based on latest measurement(s) + // Initialize Run & Dry-Run summary object + runSummary := v1alpha1.RunSummary{ + Count: 0, + Successful: 0, + Failed: 0, + Inconclusive: 0, + Error: 0, + } + dryRunSummary := v1alpha1.RunSummary{ + Count: 0, + Successful: 0, + Failed: 0, + Inconclusive: 0, + Error: 0, + } + + // Iterate all metrics and update `MetricResult.Phase` fields based on latest measurement(s) for _, metric := range metrics { + if dryRunMetricsMap[metric.Name] { + log.Infof("Metric '%s' is running in the Dry-Run mode.", metric.Name) + dryRunSummary.Count++ + } else { + runSummary.Count++ + } if result := analysisutil.GetResult(run, metric.Name); result != nil { - log := logutil.WithAnalysisRun(run).WithField("metric", metric.Name) + logger := logutil.WithAnalysisRun(run).WithField("metric", metric.Name) metricStatus := assessMetricStatus(metric, *result, terminating) if result.Phase != metricStatus { - log.Infof("metric transitioned from %s -> %s", result.Phase, metricStatus) + logger.Infof("Metric '%s' transitioned from %s -> %s", metric.Name, result.Phase, metricStatus) if metricStatus.Completed() { eventType := corev1.EventTypeNormal switch metricStatus { case v1alpha1.AnalysisPhaseError, v1alpha1.AnalysisPhaseFailed: eventType = corev1.EventTypeWarning } - c.recorder.Eventf(run, record.EventOptions{EventType: eventType, EventReason: "Metric" + string(metricStatus)}, "metric '%s' completed %s", metric.Name, metricStatus) + c.recorder.Eventf(run, record.EventOptions{EventType: eventType, EventReason: "Metric" + string(metricStatus)}, "Metric '%s' Completed. Result: %s", metric.Name, metricStatus) } if lastMeasurement := analysisutil.LastMeasurement(run, metric.Name); lastMeasurement != nil { result.Message = lastMeasurement.Message @@ -419,31 +465,76 @@ func (c *Controller) assessRunStatus(run *v1alpha1.AnalysisRun, metrics []v1alph // if any metric is in-progress, then entire analysis run will be considered running everythingCompleted = false } else { + phase, message := assessMetricFailureInconclusiveOrError(metric, *result) + // NOTE: We don't care about the status if the metric is marked as a Dry-Run // otherwise, remember the worst status of all completed metric results - if worstStatus == "" || analysisutil.IsWorse(worstStatus, metricStatus) { - worstStatus = metricStatus - _, message := assessMetricFailureInconclusiveOrError(metric, *result) + if !dryRunMetricsMap[metric.Name] { + if worstStatus == "" || analysisutil.IsWorse(worstStatus, metricStatus) { + worstStatus = metricStatus + if message != "" { + worstMessage = fmt.Sprintf("Metric \"%s\" assessed %s due to %s", metric.Name, metricStatus, message) + if result.Message != "" { + worstMessage += fmt.Sprintf(": \"Error Message: %s\"", result.Message) + } + } + } + // Update Run Summary + switch phase { + case v1alpha1.AnalysisPhaseError: + runSummary.Error++ + case v1alpha1.AnalysisPhaseFailed: + runSummary.Failed++ + case v1alpha1.AnalysisPhaseInconclusive: + runSummary.Inconclusive++ + case v1alpha1.AnalysisPhaseSuccessful: + runSummary.Successful++ + default: + // We'll mark the status as success by default if it doesn't match anything. + runSummary.Successful++ + } + } else { + // Update metric result message if message != "" { - worstMessage = fmt.Sprintf("metric \"%s\" assessed %s due to %s", metric.Name, metricStatus, message) + failureMessage := fmt.Sprintf("Metric assessed %s due to %s", metricStatus, message) if result.Message != "" { - worstMessage += fmt.Sprintf(": \"Error Message: %s\"", result.Message) + result.Message = fmt.Sprintf("%s: \"Error Message: %s\"", failureMessage, result.Message) + } else { + result.Message = failureMessage } + analysisutil.SetResult(run, *result) + } + // Update DryRun Summary + switch phase { + case v1alpha1.AnalysisPhaseError: + dryRunSummary.Error++ + case v1alpha1.AnalysisPhaseFailed: + dryRunSummary.Failed++ + case v1alpha1.AnalysisPhaseInconclusive: + dryRunSummary.Inconclusive++ + case v1alpha1.AnalysisPhaseSuccessful: + dryRunSummary.Successful++ + default: + // We'll mark the status as success by default if it doesn't match anything. + dryRunSummary.Successful++ } } } } else { - // metric hasn't started running. possible cases where some of the metrics starts with delay + // metric hasn't started running. possible cases where some metrics starts with delay everythingCompleted = false } } - + // Append Dry-Run metrics results if any. + worstMessage = strings.TrimSpace(worstMessage) + run.Status.RunSummary = runSummary + run.Status.DryRunSummary = &dryRunSummary if terminating { if worstStatus == "" { // we have yet to take a single measurement, but have already been instructed to stop - log.Infof("metric assessed %s: run terminated", v1alpha1.AnalysisPhaseSuccessful) + log.Infof(SuccessfulAssessmentRunTerminatedResult) return v1alpha1.AnalysisPhaseSuccessful, worstMessage } - log.Infof("metric assessed %s: run terminated", worstStatus) + log.Infof("Metric Assessment Result - %s: Run Terminated", worstStatus) return worstStatus, worstMessage } if !everythingCompleted || worstStatus == "" { @@ -453,25 +544,25 @@ func (c *Controller) assessRunStatus(run *v1alpha1.AnalysisRun, metrics []v1alph } // assessMetricStatus assesses the status of a single metric based on: -// * current/latest measurement status +// * current or latest measurement status // * parameters given by the metric (failureLimit, count, etc...) -// * whether or not we are terminating (e.g. due to failing run, or termination request) +// * whether we are terminating (e.g. due to failing run, or termination request) func assessMetricStatus(metric v1alpha1.Metric, result v1alpha1.MetricResult, terminating bool) v1alpha1.AnalysisPhase { if result.Phase.Completed() { return result.Phase } - log := log.WithField("metric", metric.Name) + logger := log.WithField("metric", metric.Name) if len(result.Measurements) == 0 { if terminating { // we have yet to take a single measurement, but have already been instructed to stop - log.Infof("metric assessed %s: run terminated", v1alpha1.AnalysisPhaseSuccessful) + logger.Infof(SuccessfulAssessmentRunTerminatedResult) return v1alpha1.AnalysisPhaseSuccessful } return v1alpha1.AnalysisPhasePending } lastMeasurement := result.Measurements[len(result.Measurements)-1] if !lastMeasurement.Phase.Completed() { - // we still have a in-flight measurement + // we still have an in-flight measurement return v1alpha1.AnalysisPhaseRunning } @@ -479,7 +570,7 @@ func assessMetricStatus(metric v1alpha1.Metric, result v1alpha1.MetricResult, te // If true, then return AnalysisRunPhase as Failed, Inconclusive, or Error respectively phaseFailureInconclusiveOrError, message := assessMetricFailureInconclusiveOrError(metric, result) if phaseFailureInconclusiveOrError != "" { - log.Infof("metric assessed %s: %s", phaseFailureInconclusiveOrError, message) + logger.Infof("Metric Assessment Result - %s: %s", phaseFailureInconclusiveOrError, message) return phaseFailureInconclusiveOrError } @@ -488,12 +579,12 @@ func assessMetricStatus(metric v1alpha1.Metric, result v1alpha1.MetricResult, te // taken into consideration above, and we do not want to fail if failures < failureLimit. effectiveCount := metric.EffectiveCount() if effectiveCount != nil && result.Count >= int32(effectiveCount.IntValue()) { - log.Infof("metric assessed %s: count (%s) reached", v1alpha1.AnalysisPhaseSuccessful, effectiveCount.String()) + logger.Infof("Metric Assessment Result - %s: Count (%s) Reached", v1alpha1.AnalysisPhaseSuccessful, effectiveCount.String()) return v1alpha1.AnalysisPhaseSuccessful } // if we get here, this metric runs indefinitely if terminating { - log.Infof("metric assessed %s: run terminated", v1alpha1.AnalysisPhaseSuccessful) + logger.Infof(SuccessfulAssessmentRunTerminatedResult) return v1alpha1.AnalysisPhaseSuccessful } return v1alpha1.AnalysisPhaseRunning @@ -546,19 +637,18 @@ func calculateNextReconcileTime(run *v1alpha1.AnalysisRun, metrics []v1alpha1.Me if run.Status.StartedAt != nil { startTime = *run.Status.StartedAt } - duration, err := metric.InitialDelay.Duration() + parsedInterval, err := parseMetricInterval(*logCtx, metric.InitialDelay) if err != nil { - logCtx.Warnf("failed to parse interval: %v", err) continue } - endInitialDelay := startTime.Add(duration) + endInitialDelay := startTime.Add(parsedInterval) if reconcileTime == nil || reconcileTime.After(endInitialDelay) { reconcileTime = &endInitialDelay } continue } // no measurement was started . we should never get here - logCtx.Warnf("metric never started. not factored into enqueue time") + logCtx.Warnf("Metric never started. Not factored into enqueue time.") continue } if lastMeasurement.FinishedAt == nil { @@ -580,18 +670,17 @@ func calculateNextReconcileTime(run *v1alpha1.AnalysisRun, metrics []v1alpha1.Me if lastMeasurement.Phase == v1alpha1.AnalysisPhaseError { interval = DefaultErrorRetryInterval } else if metric.Interval != "" { - metricInterval, err := metric.Interval.Duration() + parsedInterval, err := parseMetricInterval(*logCtx, metric.Interval) if err != nil { - logCtx.Warnf("failed to parse interval: %v", err) continue } - interval = metricInterval + interval = parsedInterval } else { // if we get here, an interval was not set (meaning reoccurrence was not desired), and // there was no error (meaning we don't need to retry). no need to requeue this metric. // NOTE: we shouldn't ever get here since it means we are not doing proper bookkeeping // of count. - logCtx.Warnf("skipping requeue. no interval or error (count: %d, effectiveCount: %s)", metricResult.Count, metric.EffectiveCount().String()) + logCtx.Warnf("Skipping requeue. No interval or error (count: %d, effectiveCount: %s)", metricResult.Count, metric.EffectiveCount().String()) continue } // Take the earliest time of all metrics @@ -619,8 +708,8 @@ func (c *Controller) garbageCollectMeasurements(run *v1alpha1.AnalysisRun, limit if !ok { continue } - log := logutil.WithAnalysisRun(run).WithField("metric", metric.Name) - provider, err := c.newProvider(*log, metric) + logger := logutil.WithAnalysisRun(run).WithField("metric", metric.Name) + provider, err := c.newProvider(*logger, metric) if err != nil { errors = append(errors, err) continue diff --git a/analysis/analysis_test.go b/analysis/analysis_test.go index 5b1fa56062..4273fe3b68 100644 --- a/analysis/analysis_test.go +++ b/analysis/analysis_test.go @@ -91,7 +91,12 @@ func newRun() *v1alpha1.AnalysisRun { } // newTerminatingRun returns a run which is terminating because of the given status -func newTerminatingRun(status v1alpha1.AnalysisPhase) *v1alpha1.AnalysisRun { +func newTerminatingRun(status v1alpha1.AnalysisPhase, isDryRun bool) *v1alpha1.AnalysisRun { + var dryRunArray []v1alpha1.DryRun + if isDryRun { + dryRunArray = append(dryRunArray, v1alpha1.DryRun{MetricName: "run-forever"}) + dryRunArray = append(dryRunArray, v1alpha1.DryRun{MetricName: "failed-metric"}) + } run := v1alpha1.AnalysisRun{ Spec: v1alpha1.AnalysisRunSpec{ Metrics: []v1alpha1.Metric{ @@ -108,21 +113,24 @@ func newTerminatingRun(status v1alpha1.AnalysisPhase) *v1alpha1.AnalysisRun { }, }, }, + DryRun: dryRunArray, }, Status: v1alpha1.AnalysisRunStatus{ Phase: v1alpha1.AnalysisPhaseRunning, MetricResults: []v1alpha1.MetricResult{ { - Name: "run-forever", - Phase: v1alpha1.AnalysisPhaseRunning, + Name: "run-forever", + DryRun: isDryRun, + Phase: v1alpha1.AnalysisPhaseRunning, Measurements: []v1alpha1.Measurement{{ Phase: v1alpha1.AnalysisPhaseRunning, StartedAt: timePtr(metav1.NewTime(time.Now().Add(-60 * time.Second))), }}, }, { - Name: "failed-metric", - Count: 1, + Name: "failed-metric", + Count: 1, + DryRun: isDryRun, Measurements: []v1alpha1.Measurement{{ Phase: status, StartedAt: timePtr(metav1.NewTime(time.Now().Add(-60 * time.Second))), @@ -439,7 +447,7 @@ func TestAssessRunStatus(t *testing.T) { }, }, } - status, message := c.assessRunStatus(run, run.Spec.Metrics) + status, message := c.assessRunStatus(run, run.Spec.Metrics, map[string]bool{}) assert.Equal(t, v1alpha1.AnalysisPhaseRunning, status) assert.Equal(t, "", message) } @@ -458,7 +466,7 @@ func TestAssessRunStatus(t *testing.T) { }, }, } - status, message := c.assessRunStatus(run, run.Spec.Metrics) + status, message := c.assessRunStatus(run, run.Spec.Metrics, map[string]bool{}) assert.Equal(t, v1alpha1.AnalysisPhaseFailed, status) assert.Equal(t, "", message) } @@ -512,7 +520,7 @@ func TestAssessRunStatusUpdateResult(t *testing.T) { }, }, } - status, message := c.assessRunStatus(run, run.Spec.Metrics) + status, message := c.assessRunStatus(run, run.Spec.Metrics, map[string]bool{}) assert.Equal(t, v1alpha1.AnalysisPhaseRunning, status) assert.Equal(t, "", message) assert.Equal(t, v1alpha1.AnalysisPhaseFailed, run.Status.MetricResults[1].Phase) @@ -941,7 +949,7 @@ func TestReconcileAnalysisRunTerminateSiblingAfterFail(t *testing.T) { f.provider.On("Terminate", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(newMeasurement(v1alpha1.AnalysisPhaseSuccessful), nil) for _, status := range []v1alpha1.AnalysisPhase{v1alpha1.AnalysisPhaseFailed, v1alpha1.AnalysisPhaseInconclusive, v1alpha1.AnalysisPhaseError} { - run := newTerminatingRun(status) + run := newTerminatingRun(status, false) newRun := c.reconcileAnalysisRun(run) assert.Equal(t, status, newRun.Status.Phase) @@ -950,8 +958,8 @@ func TestReconcileAnalysisRunTerminateSiblingAfterFail(t *testing.T) { // ensure the in-progress measurement is now terminated assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, newRun.Status.MetricResults[0].Measurements[0].Phase) assert.NotNil(t, newRun.Status.MetricResults[0].Measurements[0].FinishedAt) - assert.Equal(t, "metric terminated", newRun.Status.MetricResults[0].Message) - assert.Equal(t, "metric terminated", newRun.Status.MetricResults[0].Measurements[0].Message) + assert.Equal(t, "Metric Terminated", newRun.Status.MetricResults[0].Message) + assert.Equal(t, "Metric Terminated", newRun.Status.MetricResults[0].Measurements[0].Message) } } @@ -1069,22 +1077,30 @@ func TestResolveMetricArgsUnableToSubstitute(t *testing.T) { f := newFixture(t) defer f.Close() c, _, _ := f.newController(noResyncPeriodFunc) - run := &v1alpha1.AnalysisRun{ - Spec: v1alpha1.AnalysisRunSpec{ - Metrics: []v1alpha1.Metric{{ - Name: "rate", - SuccessCondition: "{{args.does-not-exist}}", - Provider: v1alpha1.MetricProvider{ - Prometheus: &v1alpha1.PrometheusMetric{ - Query: "{{args.metric-name}}", + // Dry-Run or not if the args resolution fails then we should fail the analysis + for _, isDryRun := range [3]bool{false, true, false} { + var dryRunArray []v1alpha1.DryRun + if isDryRun { + dryRunArray = append(dryRunArray, v1alpha1.DryRun{MetricName: "*"}) + } + run := &v1alpha1.AnalysisRun{ + Spec: v1alpha1.AnalysisRunSpec{ + Metrics: []v1alpha1.Metric{{ + Name: "rate", + SuccessCondition: "{{args.does-not-exist}}", + Provider: v1alpha1.MetricProvider{ + Prometheus: &v1alpha1.PrometheusMetric{ + Query: "{{args.metric-name}}", + }, }, - }, - }}, - }, + }}, + DryRun: dryRunArray, + }, + } + newRun := c.reconcileAnalysisRun(run) + assert.Equal(t, v1alpha1.AnalysisPhaseError, newRun.Status.Phase) + assert.Equal(t, "Unable to resolve metric arguments: failed to resolve {{args.metric-name}}", newRun.Status.Message) } - newRun := c.reconcileAnalysisRun(run) - assert.Equal(t, v1alpha1.AnalysisPhaseError, newRun.Status.Phase) - assert.Equal(t, "unable to resolve metric arguments: failed to resolve {{args.metric-name}}", newRun.Status.Message) } // TestSecretContentReferenceSuccess verifies that secret arguments are properly resolved @@ -1396,72 +1412,171 @@ func TestAssessMetricFailureInconclusiveOrError(t *testing.T) { assert.Equal(t, phase, assessMetricStatus(metric, result, true)) } -func TestAssessRunStatusErrorMessageAnalysisPhaseFail(t *testing.T) { +func StartAssessRunStatusErrorMessageAnalysisPhaseFail(t *testing.T, isDryRun bool) (v1alpha1.AnalysisPhase, string, *v1alpha1.RunSummary) { f := newFixture(t) defer f.Close() c, _, _ := f.newController(noResyncPeriodFunc) - run := newTerminatingRun(v1alpha1.AnalysisPhaseFailed) + run := newTerminatingRun(v1alpha1.AnalysisPhaseFailed, isDryRun) run.Status.MetricResults[0].Phase = v1alpha1.AnalysisPhaseSuccessful - status, message := c.assessRunStatus(run, run.Spec.Metrics) + status, message := c.assessRunStatus(run, run.Spec.Metrics, map[string]bool{"run-forever": isDryRun, "failed-metric": isDryRun}) + return status, message, run.Status.DryRunSummary +} + +func TestAssessRunStatusErrorMessageAnalysisPhaseFail(t *testing.T) { + status, message, dryRunSummary := StartAssessRunStatusErrorMessageAnalysisPhaseFail(t, false) assert.Equal(t, v1alpha1.AnalysisPhaseFailed, status) - assert.Equal(t, "metric \"failed-metric\" assessed Failed due to failed (1) > failureLimit (0)", message) + assert.Equal(t, "Metric \"failed-metric\" assessed Failed due to failed (1) > failureLimit (0)", message) + expectedDryRunSummary := v1alpha1.RunSummary{ + Count: 0, + Successful: 0, + Failed: 0, + Inconclusive: 0, + Error: 0, + } + assert.Equal(t, &expectedDryRunSummary, dryRunSummary) } -// TestAssessRunStatusErrorMessageFromProvider verifies that the message returned by assessRunStatus -// includes the error message from the provider -func TestAssessRunStatusErrorMessageFromProvider(t *testing.T) { +func TestAssessRunStatusErrorMessageAnalysisPhaseFailInDryRunMode(t *testing.T) { + status, message, dryRunSummary := StartAssessRunStatusErrorMessageAnalysisPhaseFail(t, true) + assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, status) + assert.Equal(t, "", message) + expectedDryRunSummary := v1alpha1.RunSummary{ + Count: 2, + Successful: 1, + Failed: 1, + Inconclusive: 0, + Error: 0, + } + assert.Equal(t, &expectedDryRunSummary, dryRunSummary) +} + +func StartAssessRunStatusErrorMessageFromProvider(t *testing.T, providerMessage string, isDryRun bool) (v1alpha1.AnalysisPhase, string, *v1alpha1.RunSummary) { f := newFixture(t) defer f.Close() c, _, _ := f.newController(noResyncPeriodFunc) - run := newTerminatingRun(v1alpha1.AnalysisPhaseFailed) + run := newTerminatingRun(v1alpha1.AnalysisPhaseFailed, isDryRun) run.Status.MetricResults[0].Phase = v1alpha1.AnalysisPhaseSuccessful // All metrics must complete, or assessRunStatus will not return message - - providerMessage := "Provider error" run.Status.MetricResults[1].Message = providerMessage + status, message := c.assessRunStatus(run, run.Spec.Metrics, map[string]bool{"run-forever": isDryRun, "failed-metric": isDryRun}) + return status, message, run.Status.DryRunSummary +} - status, message := c.assessRunStatus(run, run.Spec.Metrics) - expectedMessage := fmt.Sprintf("metric \"failed-metric\" assessed Failed due to failed (1) > failureLimit (0): \"Error Message: %s\"", providerMessage) +// TestAssessRunStatusErrorMessageFromProvider verifies that the message returned by assessRunStatus +// includes the error message from the provider +func TestAssessRunStatusErrorMessageFromProvider(t *testing.T) { + providerMessage := "Provider Error" + status, message, dryRunSummary := StartAssessRunStatusErrorMessageFromProvider(t, providerMessage, false) + expectedMessage := fmt.Sprintf("Metric \"failed-metric\" assessed Failed due to failed (1) > failureLimit (0): \"Error Message: %s\"", providerMessage) assert.Equal(t, v1alpha1.AnalysisPhaseFailed, status) assert.Equal(t, expectedMessage, message) + expectedDryRunSummary := v1alpha1.RunSummary{ + Count: 0, + Successful: 0, + Failed: 0, + Inconclusive: 0, + Error: 0, + } + assert.Equal(t, &expectedDryRunSummary, dryRunSummary) } -// TestAssessRunStatusMultipleFailures verifies that if there are multiple failed metrics, assessRunStatus returns the message -// from the first failed metric -func TestAssessRunStatusMultipleFailures(t *testing.T) { +func TestAssessRunStatusErrorMessageFromProviderInDryRunMode(t *testing.T) { + providerMessage := "Provider Error" + status, message, dryRunSummary := StartAssessRunStatusErrorMessageFromProvider(t, providerMessage, true) + assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, status) + assert.Equal(t, "", message) + expectedDryRunSummary := v1alpha1.RunSummary{ + Count: 2, + Successful: 1, + Failed: 1, + Inconclusive: 0, + Error: 0, + } + assert.Equal(t, &expectedDryRunSummary, dryRunSummary) +} + +func StartAssessRunStatusMultipleFailures(t *testing.T, isDryRun bool) (v1alpha1.AnalysisPhase, string, *v1alpha1.RunSummary) { f := newFixture(t) defer f.Close() c, _, _ := f.newController(noResyncPeriodFunc) - run := newTerminatingRun(v1alpha1.AnalysisPhaseFailed) + run := newTerminatingRun(v1alpha1.AnalysisPhaseFailed, isDryRun) run.Status.MetricResults[0].Phase = v1alpha1.AnalysisPhaseFailed run.Status.MetricResults[0].Failed = 1 + status, message := c.assessRunStatus(run, run.Spec.Metrics, map[string]bool{"run-forever": isDryRun, "failed-metric": isDryRun}) + return status, message, run.Status.DryRunSummary +} - status, message := c.assessRunStatus(run, run.Spec.Metrics) +// TestAssessRunStatusMultipleFailures verifies that if there are multiple failed metrics, assessRunStatus returns the message +// from the first failed metric +func TestAssessRunStatusMultipleFailures(t *testing.T) { + status, message, dryRunSummary := StartAssessRunStatusMultipleFailures(t, false) assert.Equal(t, v1alpha1.AnalysisPhaseFailed, status) - assert.Equal(t, "metric \"run-forever\" assessed Failed due to failed (1) > failureLimit (0)", message) + assert.Equal(t, "Metric \"run-forever\" assessed Failed due to failed (1) > failureLimit (0)", message) + expectedDryRunSummary := v1alpha1.RunSummary{ + Count: 0, + Successful: 0, + Failed: 0, + Inconclusive: 0, + Error: 0, + } + assert.Equal(t, &expectedDryRunSummary, dryRunSummary) } -// TestAssessRunStatusWorstMessageInReconcileAnalysisRun verifies that the worstMessage returned by assessRunStatus is set as the -// status of the AnalysisRun returned by reconcileAnalysisRun -func TestAssessRunStatusWorstMessageInReconcileAnalysisRun(t *testing.T) { +func TestAssessRunStatusMultipleFailuresInDryRunMode(t *testing.T) { + status, message, dryRunSummary := StartAssessRunStatusMultipleFailures(t, true) + assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, status) + assert.Equal(t, "", message) + expectedDryRunSummary := v1alpha1.RunSummary{ + Count: 2, + Successful: 0, + Failed: 2, + Inconclusive: 0, + Error: 0, + } + assert.Equal(t, &expectedDryRunSummary, dryRunSummary) +} + +func StartAssessRunStatusWorstMessageInReconcileAnalysisRun(t *testing.T, isDryRun bool) *v1alpha1.AnalysisRun { f := newFixture(t) defer f.Close() c, _, _ := f.newController(noResyncPeriodFunc) - run := newTerminatingRun(v1alpha1.AnalysisPhaseFailed) + run := newTerminatingRun(v1alpha1.AnalysisPhaseFailed, isDryRun) run.Status.MetricResults[0].Phase = v1alpha1.AnalysisPhaseFailed run.Status.MetricResults[0].Failed = 1 f.provider.On("Run", mock.Anything, mock.Anything, mock.Anything).Return(newMeasurement(v1alpha1.AnalysisPhaseFailed), nil) - newRun := c.reconcileAnalysisRun(run) + return c.reconcileAnalysisRun(run) +} + +// TestAssessRunStatusWorstMessageInReconcileAnalysisRun verifies that the worstMessage returned by assessRunStatus is set as the +// status of the AnalysisRun returned by reconcileAnalysisRun +func TestAssessRunStatusWorstMessageInReconcileAnalysisRun(t *testing.T) { + newRun := StartAssessRunStatusWorstMessageInReconcileAnalysisRun(t, false) assert.Equal(t, v1alpha1.AnalysisPhaseFailed, newRun.Status.Phase) - assert.Equal(t, "metric \"run-forever\" assessed Failed due to failed (1) > failureLimit (0)", newRun.Status.Message) + assert.Equal(t, "Metric \"run-forever\" assessed Failed due to failed (1) > failureLimit (0)", newRun.Status.Message) } -func TestTerminateAnalysisRun(t *testing.T) { +func TestAssessRunStatusWorstMessageInReconcileAnalysisRunInDryRunMode(t *testing.T) { + newRun := StartAssessRunStatusWorstMessageInReconcileAnalysisRun(t, true) + assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, newRun.Status.Phase) + assert.Equal(t, "", newRun.Status.Message) + expectedDryRunSummary := v1alpha1.RunSummary{ + Count: 2, + Successful: 0, + Failed: 2, + Inconclusive: 0, + Error: 0, + } + assert.Equal(t, &expectedDryRunSummary, newRun.Status.DryRunSummary) + assert.Equal(t, "Metric assessed Failed due to failed (1) > failureLimit (0)", newRun.Status.MetricResults[0].Message) + assert.Equal(t, "Metric assessed Failed due to failed (1) > failureLimit (0)", newRun.Status.MetricResults[1].Message) +} + +func StartTerminatingAnalysisRun(t *testing.T, isDryRun bool) *v1alpha1.AnalysisRun { f := newFixture(t) defer f.Close() c, _, _ := f.newController(noResyncPeriodFunc) @@ -1469,6 +1584,10 @@ func TestTerminateAnalysisRun(t *testing.T) { f.provider.On("Run", mock.Anything, mock.Anything, mock.Anything).Return(newMeasurement(v1alpha1.AnalysisPhaseError), nil) now := metav1.Now() + var dryRunArray []v1alpha1.DryRun + if isDryRun { + dryRunArray = append(dryRunArray, v1alpha1.DryRun{MetricName: "success-rate"}) + } run := &v1alpha1.AnalysisRun{ Spec: v1alpha1.AnalysisRunSpec{ Terminate: true, @@ -1487,13 +1606,73 @@ func TestTerminateAnalysisRun(t *testing.T) { Web: &v1alpha1.WebMetric{}, }, }}, + DryRun: dryRunArray, }, Status: v1alpha1.AnalysisRunStatus{ StartedAt: &now, Phase: v1alpha1.AnalysisPhaseRunning, }, } - newRun := c.reconcileAnalysisRun(run) + return c.reconcileAnalysisRun(run) +} + +func TestTerminateAnalysisRun(t *testing.T) { + newRun := StartTerminatingAnalysisRun(t, false) + assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, newRun.Status.Phase) + assert.Equal(t, "Run Terminated", newRun.Status.Message) +} + +func TestTerminateAnalysisRunInDryRunMode(t *testing.T) { + newRun := StartTerminatingAnalysisRun(t, true) assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, newRun.Status.Phase) - assert.Equal(t, "run terminated", newRun.Status.Message) + assert.Equal(t, "Run Terminated", newRun.Status.Message) + expectedDryRunSummary := v1alpha1.RunSummary{ + Count: 1, + Successful: 0, + Failed: 0, + Inconclusive: 0, + Error: 0, + } + assert.Equal(t, &expectedDryRunSummary, newRun.Status.DryRunSummary) +} + +func TestInvalidDryRunConfigThrowsError(t *testing.T) { + f := newFixture(t) + defer f.Close() + c, _, _ := f.newController(noResyncPeriodFunc) + + // Mocks terminate to cancel the in-progress measurement + f.provider.On("Terminate", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(newMeasurement(v1alpha1.AnalysisPhaseSuccessful), nil) + + var dryRunArray []v1alpha1.DryRun + dryRunArray = append(dryRunArray, v1alpha1.DryRun{MetricName: "error-rate"}) + now := metav1.Now() + run := &v1alpha1.AnalysisRun{ + Spec: v1alpha1.AnalysisRunSpec{ + Terminate: true, + Args: []v1alpha1.Argument{ + { + Name: "service", + Value: pointer.StringPtr("rollouts-demo-canary.default.svc.cluster.local"), + }, + }, + Metrics: []v1alpha1.Metric{{ + Name: "success-rate", + InitialDelay: "20s", + Interval: "20s", + SuccessCondition: "result[0] > 0.90", + Provider: v1alpha1.MetricProvider{ + Web: &v1alpha1.WebMetric{}, + }, + }}, + DryRun: dryRunArray, + }, + Status: v1alpha1.AnalysisRunStatus{ + StartedAt: &now, + Phase: v1alpha1.AnalysisPhaseRunning, + }, + } + newRun := c.reconcileAnalysisRun(run) + assert.Equal(t, v1alpha1.AnalysisPhaseError, newRun.Status.Phase) + assert.Equal(t, "Analysis spec invalid: dryRun[0]: Rule didn't match any metric name(s)", newRun.Status.Message) } diff --git a/controller/metrics/analysis.go b/controller/metrics/analysis.go index d8634b92c6..12480b76c8 100644 --- a/controller/metrics/analysis.go +++ b/controller/metrics/analysis.go @@ -1,6 +1,8 @@ package metrics import ( + "fmt" + "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/labels" @@ -8,7 +10,7 @@ import ( "github.com/argoproj/argo-rollouts/metricproviders" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" rolloutlister "github.com/argoproj/argo-rollouts/pkg/client/listers/rollouts/v1alpha1" - "github.com/argoproj/argo-rollouts/utils/analysis" + analysisutil "github.com/argoproj/argo-rollouts/utils/analysis" ) type analysisRunCollector struct { @@ -80,20 +82,21 @@ func collectAnalysisRuns(ch chan<- prometheus.Metric, ar *v1alpha1.AnalysisRun) addGauge(MetricAnalysisRunPhase, boolFloat64(calculatedPhase == v1alpha1.AnalysisPhaseRunning), string(v1alpha1.AnalysisPhaseRunning)) addGauge(MetricAnalysisRunPhase, boolFloat64(calculatedPhase == v1alpha1.AnalysisPhaseInconclusive), string(v1alpha1.AnalysisPhaseInconclusive)) + dryRunMetricsMap, _ := analysisutil.GetDryRunMetrics(ar.Spec.DryRun, ar.Spec.Metrics) for _, metric := range ar.Spec.Metrics { metricType := metricproviders.Type(metric) - metricResult := analysis.GetResult(ar, metric.Name) + metricResult := analysisutil.GetResult(ar, metric.Name) addGauge(MetricAnalysisRunMetricType, 1, metric.Name, metricType) calculatedPhase := v1alpha1.AnalysisPhase("") if metricResult != nil { calculatedPhase = metricResult.Phase } - addGauge(MetricAnalysisRunMetricPhase, boolFloat64(calculatedPhase == v1alpha1.AnalysisPhasePending || calculatedPhase == ""), metric.Name, metricType, string(v1alpha1.AnalysisPhasePending)) - addGauge(MetricAnalysisRunMetricPhase, boolFloat64(calculatedPhase == v1alpha1.AnalysisPhaseError), metric.Name, metricType, string(v1alpha1.AnalysisPhaseError)) - addGauge(MetricAnalysisRunMetricPhase, boolFloat64(calculatedPhase == v1alpha1.AnalysisPhaseFailed), metric.Name, metricType, string(v1alpha1.AnalysisPhaseFailed)) - addGauge(MetricAnalysisRunMetricPhase, boolFloat64(calculatedPhase == v1alpha1.AnalysisPhaseSuccessful), metric.Name, metricType, string(v1alpha1.AnalysisPhaseSuccessful)) - addGauge(MetricAnalysisRunMetricPhase, boolFloat64(calculatedPhase == v1alpha1.AnalysisPhaseRunning), metric.Name, metricType, string(v1alpha1.AnalysisPhaseRunning)) - addGauge(MetricAnalysisRunMetricPhase, boolFloat64(calculatedPhase == v1alpha1.AnalysisPhaseInconclusive), metric.Name, metricType, string(v1alpha1.AnalysisPhaseInconclusive)) + addGauge(MetricAnalysisRunMetricPhase, boolFloat64(calculatedPhase == v1alpha1.AnalysisPhasePending || calculatedPhase == ""), metric.Name, metricType, fmt.Sprint(dryRunMetricsMap[metric.Name]), string(v1alpha1.AnalysisPhasePending)) + addGauge(MetricAnalysisRunMetricPhase, boolFloat64(calculatedPhase == v1alpha1.AnalysisPhaseError), metric.Name, metricType, fmt.Sprint(dryRunMetricsMap[metric.Name]), string(v1alpha1.AnalysisPhaseError)) + addGauge(MetricAnalysisRunMetricPhase, boolFloat64(calculatedPhase == v1alpha1.AnalysisPhaseFailed), metric.Name, metricType, fmt.Sprint(dryRunMetricsMap[metric.Name]), string(v1alpha1.AnalysisPhaseFailed)) + addGauge(MetricAnalysisRunMetricPhase, boolFloat64(calculatedPhase == v1alpha1.AnalysisPhaseSuccessful), metric.Name, metricType, fmt.Sprint(dryRunMetricsMap[metric.Name]), string(v1alpha1.AnalysisPhaseSuccessful)) + addGauge(MetricAnalysisRunMetricPhase, boolFloat64(calculatedPhase == v1alpha1.AnalysisPhaseRunning), metric.Name, metricType, fmt.Sprint(dryRunMetricsMap[metric.Name]), string(v1alpha1.AnalysisPhaseRunning)) + addGauge(MetricAnalysisRunMetricPhase, boolFloat64(calculatedPhase == v1alpha1.AnalysisPhaseInconclusive), metric.Name, metricType, fmt.Sprint(dryRunMetricsMap[metric.Name]), string(v1alpha1.AnalysisPhaseInconclusive)) } } diff --git a/controller/metrics/analysis_test.go b/controller/metrics/analysis_test.go index 4c8a6f70fd..992be05c9f 100644 --- a/controller/metrics/analysis_test.go +++ b/controller/metrics/analysis_test.go @@ -54,12 +54,19 @@ metadata: namespace: jesse-test spec: metrics: - - name: webmetric + - name: web-metric-1 provider: web: jsonPath: . url: https://www.google.com successCondition: "true" + - name: web-metric-2 + dryRun: true + provider: + web: + jsonPath: . + url: https://www.msn.com + successCondition: "false" ` fakeClusterAnalysisTemplate = ` @@ -67,15 +74,22 @@ apiVersion: argoproj.io/v1alpha1 kind: ClusterAnalysisTemplate metadata: creationTimestamp: "2020-03-16T20:01:13Z" - name: http-benchmark-test + name: http-benchmark-cluster-test spec: metrics: - - name: webmetric + - name: web-metric-1 provider: web: jsonPath: . url: https://www.google.com successCondition: "true" + - name: web-metric-2 + dryRun: true + provider: + web: + jsonPath: . + url: https://www.msn.com + successCondition: "false" ` ) const expectedAnalysisRunResponse = `# HELP analysis_run_info Information about analysis run. @@ -83,12 +97,12 @@ const expectedAnalysisRunResponse = `# HELP analysis_run_info Information about analysis_run_info{name="http-benchmark-test-tr8rn",namespace="jesse-test",phase="Error"} 1 # HELP analysis_run_metric_phase Information on the duration of a specific metric in the Analysis Run # TYPE analysis_run_metric_phase gauge -analysis_run_metric_phase{metric="webmetric",name="http-benchmark-test-tr8rn",namespace="jesse-test",phase="Error",type="Web"} 1 -analysis_run_metric_phase{metric="webmetric",name="http-benchmark-test-tr8rn",namespace="jesse-test",phase="Failed",type="Web"} 0 -analysis_run_metric_phase{metric="webmetric",name="http-benchmark-test-tr8rn",namespace="jesse-test",phase="Inconclusive",type="Web"} 0 -analysis_run_metric_phase{metric="webmetric",name="http-benchmark-test-tr8rn",namespace="jesse-test",phase="Pending",type="Web"} 0 -analysis_run_metric_phase{metric="webmetric",name="http-benchmark-test-tr8rn",namespace="jesse-test",phase="Running",type="Web"} 0 -analysis_run_metric_phase{metric="webmetric",name="http-benchmark-test-tr8rn",namespace="jesse-test",phase="Successful",type="Web"} 0 +analysis_run_metric_phase{dry_run="false",metric="webmetric",name="http-benchmark-test-tr8rn",namespace="jesse-test",phase="Error",type="Web"} 1 +analysis_run_metric_phase{dry_run="false",metric="webmetric",name="http-benchmark-test-tr8rn",namespace="jesse-test",phase="Failed",type="Web"} 0 +analysis_run_metric_phase{dry_run="false",metric="webmetric",name="http-benchmark-test-tr8rn",namespace="jesse-test",phase="Inconclusive",type="Web"} 0 +analysis_run_metric_phase{dry_run="false",metric="webmetric",name="http-benchmark-test-tr8rn",namespace="jesse-test",phase="Pending",type="Web"} 0 +analysis_run_metric_phase{dry_run="false",metric="webmetric",name="http-benchmark-test-tr8rn",namespace="jesse-test",phase="Running",type="Web"} 0 +analysis_run_metric_phase{dry_run="false",metric="webmetric",name="http-benchmark-test-tr8rn",namespace="jesse-test",phase="Successful",type="Web"} 0 # HELP analysis_run_metric_type Information on the type of a specific metric in the Analysis Runs # TYPE analysis_run_metric_type gauge analysis_run_metric_type{metric="webmetric",name="http-benchmark-test-tr8rn",namespace="jesse-test",type="Web"} 1 @@ -174,13 +188,16 @@ analysis_run_reconcile_count{name="ar-test",namespace="ar-namespace"} 1` } func TestAnalysisTemplateDescribe(t *testing.T) { - expectedResponse := `# TYPE analysis_template_info gauge -analysis_template_info{name="http-benchmark-test",namespace=""} 1 + expectedResponse := `# HELP analysis_template_info Information about analysis templates. +# TYPE analysis_template_info gauge +analysis_template_info{name="http-benchmark-cluster-test",namespace=""} 1 analysis_template_info{name="http-benchmark-test",namespace="jesse-test"} 1 # HELP analysis_template_metric_info Information on metrics in analysis templates. # TYPE analysis_template_metric_info gauge -analysis_template_metric_info{metric="webmetric",name="http-benchmark-test",namespace="",type="Web"} 1 -analysis_template_metric_info{metric="webmetric",name="http-benchmark-test",namespace="jesse-test",type="Web"} 1 +analysis_template_metric_info{metric="web-metric-1",name="http-benchmark-cluster-test",namespace="",type="Web"} 1 +analysis_template_metric_info{metric="web-metric-1",name="http-benchmark-test",namespace="jesse-test",type="Web"} 1 +analysis_template_metric_info{metric="web-metric-2",name="http-benchmark-cluster-test",namespace="",type="Web"} 1 +analysis_template_metric_info{metric="web-metric-2",name="http-benchmark-test",namespace="jesse-test",type="Web"} 1 ` registry := prometheus.NewRegistry() at := newFakeAnalysisTemplate(fakeAnalysisTemplate) diff --git a/controller/metrics/prommetrics.go b/controller/metrics/prommetrics.go index 564f1b46f3..abf6a77312 100644 --- a/controller/metrics/prommetrics.go +++ b/controller/metrics/prommetrics.go @@ -118,7 +118,7 @@ var ( MetricAnalysisRunMetricPhase = prometheus.NewDesc( "analysis_run_metric_phase", "Information on the duration of a specific metric in the Analysis Run", - append(namespaceNameLabels, "metric", "type", "phase"), + append(namespaceNameLabels, "metric", "type", "dry_run", "phase"), nil, ) ) diff --git a/docs/features/analysis.md b/docs/features/analysis.md index 0c563591ad..f43374b1e6 100644 --- a/docs/features/analysis.md +++ b/docs/features/analysis.md @@ -541,6 +541,114 @@ encountered. )) ``` +## Dry-Run Mode + +!!! important + Available since v1.2 + +`dryRun` can be used on a metric to control whether or not to evaluate that metric in a dry-run mode. A metric running +in the dry-run mode won't impact the final state of the rollout or experiment even if it fails or the evaluation comes +out as inconclusive. + +The following example queries prometheus every 5 minutes to get the total number of 4XX and 5XX errors, and even if the +evaluation of the metric to monitor the 5XX error-rate fail, the analysis run will pass. + +```yaml hl_lines="1 2" + dryRun: + - metricName: total-5xx-errors + metrics: + - name: total-5xx-errors + interval: 5m + failureCondition: result[0] >= 10 + failureLimit: 3 + provider: + prometheus: + address: http://prometheus.example.com:9090 + query: | + sum(irate( + istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code~"5.*"}[5m] + )) + - name: total-4xx-errors + interval: 5m + failureCondition: result[0] >= 10 + failureLimit: 3 + provider: + prometheus: + address: http://prometheus.example.com:9090 + query: | + sum(irate( + istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code~"4.*"}[5m] + )) +``` + +RegEx matches are also supported. `.*` can be used to make all the metrics run in the dry-run mode. In the following +example, even if one or both metrics fail, the analysis run will pass. + +```yaml hl_lines="1 2" + dryRun: + - metricName: .* + metrics: + - name: total-5xx-errors + interval: 5m + failureCondition: result[0] >= 10 + failureLimit: 3 + provider: + prometheus: + address: http://prometheus.example.com:9090 + query: | + sum(irate( + istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code~"5.*"}[5m] + )) + - name: total-4xx-errors + interval: 5m + failureCondition: result[0] >= 10 + failureLimit: 3 + provider: + prometheus: + address: http://prometheus.example.com:9090 + query: | + sum(irate( + istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code~"4.*"}[5m] + )) +``` + +### Dry-Run Summary + +If one or more metrics are running in the dry-run mode, the summary of the dry-run results gets appended to the analysis +run message. Assuming that the `total-4xx-errors` metric fails in the above example but, the `total-5xx-errors` +succeeds, the final dry-run summary will look like this. + +```yaml hl_lines="4 5 6 7" +Message: Run Terminated +Run Summary: + ... +Dry Run Summary: + Count: 2 + Successful: 1 + Failed: 1 +Metric Results: +... +``` + +### Dry-Run Rollouts + +If a rollout wants to dry run its analysis, it simply needs to specify the `dryRun` field to its `analysis` stanza. If a +rollout wants to dry run its analysis, it simply needs to specify the `dryRun` field to its `analysis` stanza. In the +following example, all the metrics from `random-fail` and `always-pass` get merged and executed in the dry-run mode. + +```yaml hl_lines="9 10" +kind: Rollout +spec: +... + steps: + - analysis: + templates: + - templateName: random-fail + - templateName: always-pass + dryRun: + - metricName: .* +``` + ## Inconclusive Runs Analysis runs can also be considered `Inconclusive`, which indicates the run was neither successful, diff --git a/manifests/crds/analysis-run-crd.yaml b/manifests/crds/analysis-run-crd.yaml index 9d612a9206..6d399679a3 100644 --- a/manifests/crds/analysis-run-crd.yaml +++ b/manifests/crds/analysis-run-crd.yaml @@ -68,6 +68,15 @@ spec: - name type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array metrics: items: properties: @@ -2617,6 +2626,24 @@ spec: type: object status: properties: + dryRunSummary: + properties: + count: + format: int32 + type: integer + error: + format: int32 + type: integer + failed: + format: int32 + type: integer + inconclusive: + format: int32 + type: integer + successful: + format: int32 + type: integer + type: object message: type: string metricResults: @@ -2628,6 +2655,8 @@ spec: count: format: int32 type: integer + dryRun: + type: boolean error: format: int32 type: integer @@ -2679,6 +2708,24 @@ spec: type: array phase: type: string + runSummary: + properties: + count: + format: int32 + type: integer + error: + format: int32 + type: integer + failed: + format: int32 + type: integer + inconclusive: + format: int32 + type: integer + successful: + format: int32 + type: integer + type: object startedAt: format: date-time type: string diff --git a/manifests/crds/analysis-template-crd.yaml b/manifests/crds/analysis-template-crd.yaml index 516a5bf5a8..0d61a67203 100644 --- a/manifests/crds/analysis-template-crd.yaml +++ b/manifests/crds/analysis-template-crd.yaml @@ -64,6 +64,15 @@ spec: - name type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array metrics: items: properties: diff --git a/manifests/crds/cluster-analysis-template-crd.yaml b/manifests/crds/cluster-analysis-template-crd.yaml index b10ac4a166..e5cd0d29ba 100644 --- a/manifests/crds/cluster-analysis-template-crd.yaml +++ b/manifests/crds/cluster-analysis-template-crd.yaml @@ -64,6 +64,15 @@ spec: - name type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array metrics: items: properties: diff --git a/manifests/crds/rollout-crd.yaml b/manifests/crds/rollout-crd.yaml index 7881a6b8d5..03d8e70cfe 100644 --- a/manifests/crds/rollout-crd.yaml +++ b/manifests/crds/rollout-crd.yaml @@ -170,6 +170,15 @@ spec: - name type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array templates: items: properties: @@ -205,6 +214,15 @@ spec: - name type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array templates: items: properties: @@ -270,6 +288,15 @@ spec: - name type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array startingStep: format: int32 type: integer @@ -368,6 +395,15 @@ spec: - name type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array templates: items: properties: diff --git a/manifests/install.yaml b/manifests/install.yaml index dfd4c2602f..acdacb2b8f 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -69,6 +69,15 @@ spec: - name type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array metrics: items: properties: @@ -2618,6 +2627,24 @@ spec: type: object status: properties: + dryRunSummary: + properties: + count: + format: int32 + type: integer + error: + format: int32 + type: integer + failed: + format: int32 + type: integer + inconclusive: + format: int32 + type: integer + successful: + format: int32 + type: integer + type: object message: type: string metricResults: @@ -2629,6 +2656,8 @@ spec: count: format: int32 type: integer + dryRun: + type: boolean error: format: int32 type: integer @@ -2680,6 +2709,24 @@ spec: type: array phase: type: string + runSummary: + properties: + count: + format: int32 + type: integer + error: + format: int32 + type: integer + failed: + format: int32 + type: integer + inconclusive: + format: int32 + type: integer + successful: + format: int32 + type: integer + type: object startedAt: format: date-time type: string @@ -2759,6 +2806,15 @@ spec: - name type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array metrics: items: properties: @@ -5377,6 +5433,15 @@ spec: - name type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array metrics: items: properties: @@ -10568,6 +10633,15 @@ spec: - name type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array templates: items: properties: @@ -10603,6 +10677,15 @@ spec: - name type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array templates: items: properties: @@ -10668,6 +10751,15 @@ spec: - name type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array startingStep: format: int32 type: integer @@ -10766,6 +10858,15 @@ spec: - name type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array templates: items: properties: diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 449bbddd86..111a412647 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -69,6 +69,15 @@ spec: - name type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array metrics: items: properties: @@ -2618,6 +2627,24 @@ spec: type: object status: properties: + dryRunSummary: + properties: + count: + format: int32 + type: integer + error: + format: int32 + type: integer + failed: + format: int32 + type: integer + inconclusive: + format: int32 + type: integer + successful: + format: int32 + type: integer + type: object message: type: string metricResults: @@ -2629,6 +2656,8 @@ spec: count: format: int32 type: integer + dryRun: + type: boolean error: format: int32 type: integer @@ -2680,6 +2709,24 @@ spec: type: array phase: type: string + runSummary: + properties: + count: + format: int32 + type: integer + error: + format: int32 + type: integer + failed: + format: int32 + type: integer + inconclusive: + format: int32 + type: integer + successful: + format: int32 + type: integer + type: object startedAt: format: date-time type: string @@ -2759,6 +2806,15 @@ spec: - name type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array metrics: items: properties: @@ -5377,6 +5433,15 @@ spec: - name type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array metrics: items: properties: @@ -10568,6 +10633,15 @@ spec: - name type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array templates: items: properties: @@ -10603,6 +10677,15 @@ spec: - name type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array templates: items: properties: @@ -10668,6 +10751,15 @@ spec: - name type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array startingStep: format: int32 type: integer @@ -10766,6 +10858,15 @@ spec: - name type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array templates: items: properties: diff --git a/pkg/apiclient/rollout/rollout.swagger.json b/pkg/apiclient/rollout/rollout.swagger.json index 000a008fbb..9d20f18ab3 100644 --- a/pkg/apiclient/rollout/rollout.swagger.json +++ b/pkg/apiclient/rollout/rollout.swagger.json @@ -829,6 +829,16 @@ }, "title": "CanaryStrategy defines parameters for a Replica Based Canary" }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.DryRun": { + "type": "object", + "properties": { + "metricName": { + "type": "string", + "description": "Name of the metric which needs to be evaluated in the Dry-Run mode. Wildcard '*' is supported and denotes all\nthe available metrics." + } + }, + "description": "DryRun defines the settings for running the analysis in Dry-Run mode." + }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.FieldRef": { "type": "object", "properties": { @@ -1018,6 +1028,13 @@ "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AnalysisRunArgument" }, "title": "Args the arguments that will be added to the AnalysisRuns\n+patchMergeKey=name\n+patchStrategy=merge" + }, + "dryRun": { + "type": "array", + "items": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.DryRun" + }, + "title": "DryRun object contains the settings for running the analysis in Dry-Run mode\n+patchMergeKey=metricName\n+patchStrategy=merge" } }, "title": "RolloutAnalysis defines a template that is used to create a analysisRun" diff --git a/pkg/apis/api-rules/violation_exceptions.list b/pkg/apis/api-rules/violation_exceptions.list index 2040f4570d..8865c5cf61 100644 --- a/pkg/apis/api-rules/violation_exceptions.list +++ b/pkg/apis/api-rules/violation_exceptions.list @@ -1,8 +1,10 @@ API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AmbassadorTrafficRouting,Mappings API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AnalysisRunSpec,Args +API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AnalysisRunSpec,DryRun API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AnalysisRunSpec,Metrics API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AnalysisRunStatus,MetricResults API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AnalysisTemplateSpec,Args +API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AnalysisTemplateSpec,DryRun API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AnalysisTemplateSpec,Metrics API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,CanaryStrategy,Steps API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,CloudWatchMetric,MetricDataQueries @@ -19,6 +21,7 @@ API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,KayentaMetric,Scopes API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,MetricResult,Measurements API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutAnalysis,Args +API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutAnalysis,DryRun API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutAnalysis,Templates API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutExperimentStep,Analyses API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutExperimentStep,Templates diff --git a/pkg/apis/rollouts/v1alpha1/analysis_types.go b/pkg/apis/rollouts/v1alpha1/analysis_types.go index 65d54789c6..3ecfcbb231 100644 --- a/pkg/apis/rollouts/v1alpha1/analysis_types.go +++ b/pkg/apis/rollouts/v1alpha1/analysis_types.go @@ -61,6 +61,10 @@ type AnalysisTemplateSpec struct { // +patchStrategy=merge // +optional Args []Argument `json:"args,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,2,rep,name=args"` + // DryRun object contains the settings for running the analysis in Dry-Run mode + // +patchMergeKey=metricName + // +patchStrategy=merge + DryRun []DryRun `json:"dryRun,omitempty" patchStrategy:"merge" patchMergeKey:"metricName" protobuf:"bytes,3,rep,name=dryRun"` } // DurationString is a string representing a duration (e.g. 30s, 5m, 1h) @@ -108,6 +112,13 @@ type Metric struct { Provider MetricProvider `json:"provider" protobuf:"bytes,10,opt,name=provider"` } +// DryRun defines the settings for running the analysis in Dry-Run mode. +type DryRun struct { + // Name of the metric which needs to be evaluated in the Dry-Run mode. Wildcard '*' is supported and denotes all + // the available metrics. + MetricName string `json:"metricName" protobuf:"bytes,1,opt,name=metricName"` +} + // EffectiveCount is the effective count based on whether or not count/interval is specified // If neither count or interval is specified, the effective count is 1 // If only interval is specified, metric runs indefinitely and there is no effective count (nil) @@ -275,6 +286,10 @@ type AnalysisRunSpec struct { Args []Argument `json:"args,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,2,rep,name=args"` // Terminate is used to prematurely stop the run (e.g. rollout completed and analysis is no longer desired) Terminate bool `json:"terminate,omitempty" protobuf:"varint,3,opt,name=terminate"` + // DryRun object contains the settings for running the analysis in Dry-Run mode + // +patchMergeKey=metricName + // +patchStrategy=merge + DryRun []DryRun `json:"dryRun,omitempty" patchStrategy:"merge" patchMergeKey:"metricName" protobuf:"bytes,4,rep,name=dryRun"` } // Argument is an argument to an AnalysisRun @@ -316,6 +331,24 @@ type AnalysisRunStatus struct { MetricResults []MetricResult `json:"metricResults,omitempty" protobuf:"bytes,3,rep,name=metricResults"` // StartedAt indicates when the analysisRun first started StartedAt *metav1.Time `json:"startedAt,omitempty" protobuf:"bytes,4,opt,name=startedAt"` + // RunSummary contains the final results from the metric executions + RunSummary RunSummary `json:"runSummary,omitempty" protobuf:"bytes,5,opt,name=runSummary"` + // DryRunSummary contains the final results from the metric executions in the dry-run mode + DryRunSummary *RunSummary `json:"dryRunSummary,omitempty" protobuf:"bytes,6,opt,name=dryRunSummary"` +} + +// RunSummary contains the final results from the metric executions +type RunSummary struct { + // This is equal to the sum of Successful, Failed, Inconclusive + Count int32 `json:"count,omitempty" protobuf:"varint,1,opt,name=count"` + // Successful is the number of times the metric was measured Successful + Successful int32 `json:"successful,omitempty" protobuf:"varint,2,opt,name=successful"` + // Failed is the number of times the metric was measured Failed + Failed int32 `json:"failed,omitempty" protobuf:"varint,3,opt,name=failed"` + // Inconclusive is the number of times the metric was measured Inconclusive + Inconclusive int32 `json:"inconclusive,omitempty" protobuf:"varint,4,opt,name=inconclusive"` + // Error is the number of times an error was encountered during measurement + Error int32 `json:"error,omitempty" protobuf:"varint,5,opt,name=error"` } // MetricResult contain a list of the most recent measurements for a single metric along with @@ -343,6 +376,8 @@ type MetricResult struct { // ConsecutiveError is the number of times an error was encountered during measurement in succession // Resets to zero when non-errors are encountered ConsecutiveError int32 `json:"consecutiveError,omitempty" protobuf:"varint,10,opt,name=consecutiveError"` + // DryRun indicates whether this metric is running in a dry-run mode or not + DryRun bool `json:"dryRun,omitempty" protobuf:"varint,11,opt,name=dryRun"` } // Measurement is a point in time result value of a single metric, and the time it was measured diff --git a/pkg/apis/rollouts/v1alpha1/generated.pb.go b/pkg/apis/rollouts/v1alpha1/generated.pb.go index 4af5129854..53c7c7d425 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.pb.go +++ b/pkg/apis/rollouts/v1alpha1/generated.pb.go @@ -10110,6 +10110,7 @@ func (this *MetricResult) String() string { `Phase:` + fmt.Sprintf("%v", this.Phase) + `,`, `Measurements:` + repeatedStringForMeasurements + `,`, `Message:` + fmt.Sprintf("%v", this.Message) + `,`, + `Dry-Run:` + fmt.Sprintf("%v", this.DryRun) + `,`, `Count:` + fmt.Sprintf("%v", this.Count) + `,`, `Successful:` + fmt.Sprintf("%v", this.Successful) + `,`, `Failed:` + fmt.Sprintf("%v", this.Failed) + `,`, diff --git a/pkg/apis/rollouts/v1alpha1/generated.proto b/pkg/apis/rollouts/v1alpha1/generated.proto index 817372450e..e787c53ea8 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.proto +++ b/pkg/apis/rollouts/v1alpha1/generated.proto @@ -24,8 +24,6 @@ package github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1; import "k8s.io/api/batch/v1/generated.proto"; import "k8s.io/api/core/v1/generated.proto"; import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; -import "k8s.io/apimachinery/pkg/runtime/generated.proto"; -import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; import "k8s.io/apimachinery/pkg/util/intstr/generated.proto"; // Package-wide variables from generator "generated". diff --git a/pkg/apis/rollouts/v1alpha1/types.go b/pkg/apis/rollouts/v1alpha1/types.go index 4cb87b334b..46e5f34082 100644 --- a/pkg/apis/rollouts/v1alpha1/types.go +++ b/pkg/apis/rollouts/v1alpha1/types.go @@ -527,6 +527,10 @@ type RolloutAnalysis struct { // +patchMergeKey=name // +patchStrategy=merge Args []AnalysisRunArgument `json:"args,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,2,rep,name=args"` + // DryRun object contains the settings for running the analysis in Dry-Run mode + // +patchMergeKey=metricName + // +patchStrategy=merge + DryRun []DryRun `json:"dryRun,omitempty" patchStrategy:"merge" patchMergeKey:"metricName" protobuf:"bytes,3,rep,name=dryRun"` } type RolloutAnalysisTemplate struct { diff --git a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go index 3f6ae73cf8..3304117afd 100644 --- a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go @@ -181,6 +181,11 @@ func (in *AnalysisRunSpec) DeepCopyInto(out *AnalysisRunSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.DryRun != nil { + in, out := &in.DryRun, &out.DryRun + *out = make([]DryRun, len(*in)) + copy(*out, *in) + } return } @@ -208,6 +213,12 @@ func (in *AnalysisRunStatus) DeepCopyInto(out *AnalysisRunStatus) { in, out := &in.StartedAt, &out.StartedAt *out = (*in).DeepCopy() } + out.RunSummary = in.RunSummary + if in.DryRunSummary != nil { + in, out := &in.DryRunSummary, &out.DryRunSummary + *out = new(RunSummary) + **out = **in + } return } @@ -324,6 +335,11 @@ func (in *AnalysisTemplateSpec) DeepCopyInto(out *AnalysisTemplateSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.DryRun != nil { + in, out := &in.DryRun, &out.DryRun + *out = make([]DryRun, len(*in)) + copy(*out, *in) + } return } @@ -873,6 +889,22 @@ func (in *DatadogMetric) DeepCopy() *DatadogMetric { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DryRun) DeepCopyInto(out *DryRun) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DryRun. +func (in *DryRun) DeepCopy() *DryRun { + if in == nil { + return nil + } + out := new(DryRun) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Experiment) DeepCopyInto(out *Experiment) { *out = *in @@ -1602,6 +1634,11 @@ func (in *RolloutAnalysis) DeepCopyInto(out *RolloutAnalysis) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.DryRun != nil { + in, out := &in.DryRun, &out.DryRun + *out = make([]DryRun, len(*in)) + copy(*out, *in) + } return } @@ -1996,6 +2033,22 @@ func (in *RolloutTrafficRouting) DeepCopy() *RolloutTrafficRouting { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RunSummary) DeepCopyInto(out *RunSummary) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunSummary. +func (in *RunSummary) DeepCopy() *RunSummary { + if in == nil { + return nil + } + out := new(RunSummary) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SMITrafficRouting) DeepCopyInto(out *SMITrafficRouting) { *out = *in diff --git a/pkg/apis/rollouts/validation/validation_references.go b/pkg/apis/rollouts/validation/validation_references.go index b02add3d97..98efefd9f2 100644 --- a/pkg/apis/rollouts/validation/validation_references.go +++ b/pkg/apis/rollouts/validation/validation_references.go @@ -121,7 +121,7 @@ func ValidateAnalysisTemplatesWithType(rollout *v1alpha1.Rollout, templates Anal templateNames := GetAnalysisTemplateNames(templates) value := fmt.Sprintf("templateNames: %s", templateNames) - _, err := analysisutil.NewAnalysisRunFromTemplates(templates.AnalysisTemplates, templates.ClusterAnalysisTemplates, buildAnalysisArgs(templates.Args, rollout), "", "", "") + _, err := analysisutil.NewAnalysisRunFromTemplates(templates.AnalysisTemplates, templates.ClusterAnalysisTemplates, buildAnalysisArgs(templates.Args, rollout), []v1alpha1.DryRun{}, "", "", "") if err != nil { allErrs = append(allErrs, field.Invalid(fldPath, value, err.Error())) return allErrs diff --git a/rollout/analysis.go b/rollout/analysis.go index e495b07656..ce4bb78719 100644 --- a/rollout/analysis.go +++ b/rollout/analysis.go @@ -448,7 +448,7 @@ func (c *rolloutContext) newAnalysisRunFromRollout(rolloutAnalysis *v1alpha1.Rol } } - run, err = analysisutil.NewAnalysisRunFromTemplates(templates, clusterTemplates, args, name, "", c.rollout.Namespace) + run, err = analysisutil.NewAnalysisRunFromTemplates(templates, clusterTemplates, args, rolloutAnalysis.DryRun, name, "", c.rollout.Namespace) if err != nil { return nil, err } diff --git a/utils/analysis/factory.go b/utils/analysis/factory.go index 90b1a7de1f..e00ddc7e95 100644 --- a/utils/analysis/factory.go +++ b/utils/analysis/factory.go @@ -125,7 +125,7 @@ func ValidateMetrics(metrics []v1alpha1.Metric) error { duplicateNames := make(map[string]bool) for i, metric := range metrics { if _, ok := duplicateNames[metric.Name]; ok { - return fmt.Errorf("metrics[%d]: duplicate name '%s", i, metric.Name) + return fmt.Errorf("metrics[%d]: duplicate name '%s'", i, metric.Name) } duplicateNames[metric.Name] = true if err := ValidateMetric(metric); err != nil { diff --git a/utils/analysis/factory_test.go b/utils/analysis/factory_test.go index 12ec2db117..08ed88359e 100644 --- a/utils/analysis/factory_test.go +++ b/utils/analysis/factory_test.go @@ -303,7 +303,7 @@ func TestValidateMetrics(t *testing.T) { }, } err := ValidateMetrics(spec.Metrics) - assert.EqualError(t, err, "metrics[1]: duplicate name 'success-rate") + assert.EqualError(t, err, "metrics[1]: duplicate name 'success-rate'") }) t.Run("Ensure failureLimit >= 0", func(t *testing.T) { failureLimit := intstr.FromInt(-1) diff --git a/utils/analysis/helpers.go b/utils/analysis/helpers.go index 90d6fcabea..5d1a79a601 100644 --- a/utils/analysis/helpers.go +++ b/utils/analysis/helpers.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "regexp" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" log "github.com/sirupsen/logrus" @@ -92,6 +93,28 @@ func IsTerminating(run *v1alpha1.AnalysisRun) bool { return false } +// GetDryRunMetrics returns an array of metric names matching the RegEx rules from the Dry-Run metrics. +func GetDryRunMetrics(dryRunMetrics []v1alpha1.DryRun, metrics []v1alpha1.Metric) (map[string]bool, error) { + metricsMap := make(map[string]bool) + if len(dryRunMetrics) == 0 { + return metricsMap, nil + } + // Iterate all the rules in `dryRunMetrics` and try to match the `metrics` one by one + for index, dryRunObject := range dryRunMetrics { + matchCount := 0 + for _, metric := range metrics { + if matched, _ := regexp.MatchString(dryRunObject.MetricName, metric.Name); matched { + metricsMap[metric.Name] = true + matchCount++ + } + } + if matchCount < 1 { + return metricsMap, fmt.Errorf("dryRun[%d]: Rule didn't match any metric name(s)", index) + } + } + return metricsMap, nil +} + // GetResult returns the metric result by name func GetResult(run *v1alpha1.AnalysisRun, metricName string) *v1alpha1.MetricResult { for _, result := range run.Status.MetricResults { @@ -142,11 +165,11 @@ func TerminateRun(analysisRunIf argoprojclient.AnalysisRunInterface, name string // IsSemanticallyEqual checks to see if two analysis runs are semantically equal func IsSemanticallyEqual(left, right v1alpha1.AnalysisRunSpec) bool { // NOTE: only consider metrics & args when comparing for semantic equality - leftBytes, err := json.Marshal(v1alpha1.AnalysisRunSpec{Metrics: left.Metrics, Args: left.Args}) + leftBytes, err := json.Marshal(v1alpha1.AnalysisRunSpec{Metrics: left.Metrics, DryRun: left.DryRun, Args: left.Args}) if err != nil { panic(err) } - rightBytes, err := json.Marshal(v1alpha1.AnalysisRunSpec{Metrics: right.Metrics, Args: right.Args}) + rightBytes, err := json.Marshal(v1alpha1.AnalysisRunSpec{Metrics: right.Metrics, DryRun: right.DryRun, Args: right.Args}) if err != nil { panic(err) } @@ -229,7 +252,7 @@ func CreateWithCollisionCounter(logCtx *log.Entry, analysisRunIf argoprojclient. } } -func NewAnalysisRunFromTemplates(templates []*v1alpha1.AnalysisTemplate, clusterTemplates []*v1alpha1.ClusterAnalysisTemplate, args []v1alpha1.Argument, name, generateName, namespace string) (*v1alpha1.AnalysisRun, error) { +func NewAnalysisRunFromTemplates(templates []*v1alpha1.AnalysisTemplate, clusterTemplates []*v1alpha1.ClusterAnalysisTemplate, args []v1alpha1.Argument, dryRunMetrics []v1alpha1.DryRun, name, generateName, namespace string) (*v1alpha1.AnalysisRun, error) { template, err := FlattenTemplates(templates, clusterTemplates) if err != nil { return nil, err @@ -238,6 +261,10 @@ func NewAnalysisRunFromTemplates(templates []*v1alpha1.AnalysisTemplate, cluster if err != nil { return nil, err } + dryRun, err := mergeDryRunMetrics(dryRunMetrics, template.Spec.DryRun) + if err != nil { + return nil, err + } ar := v1alpha1.AnalysisRun{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -246,6 +273,7 @@ func NewAnalysisRunFromTemplates(templates []*v1alpha1.AnalysisTemplate, cluster }, Spec: v1alpha1.AnalysisRunSpec{ Metrics: template.Spec.Metrics, + DryRun: dryRun, Args: newArgs, }, } @@ -257,6 +285,10 @@ func FlattenTemplates(templates []*v1alpha1.AnalysisTemplate, clusterTemplates [ if err != nil { return nil, err } + dryRunMetrics, err := flattenDryRunMetrics(templates, clusterTemplates) + if err != nil { + return nil, err + } args, err := flattenArgs(templates, clusterTemplates) if err != nil { return nil, err @@ -264,6 +296,7 @@ func FlattenTemplates(templates []*v1alpha1.AnalysisTemplate, clusterTemplates [ return &v1alpha1.AnalysisTemplate{ Spec: v1alpha1.AnalysisTemplateSpec{ Metrics: metrics, + DryRun: dryRunMetrics, Args: args, }, }, nil @@ -328,6 +361,46 @@ func flattenMetrics(templates []*v1alpha1.AnalysisTemplate, clusterTemplates []* return combinedMetrics, nil } +func mergeDryRunMetrics(leftDryRunMetrics []v1alpha1.DryRun, rightDryRunMetrics []v1alpha1.DryRun) ([]v1alpha1.DryRun, error) { + var combinedDryRunMetrics []v1alpha1.DryRun + combinedDryRunMetrics = append(combinedDryRunMetrics, leftDryRunMetrics...) + combinedDryRunMetrics = append(combinedDryRunMetrics, rightDryRunMetrics...) + + err := validateDryRunMetrics(combinedDryRunMetrics) + if err != nil { + return nil, err + } + return combinedDryRunMetrics, nil +} + +func flattenDryRunMetrics(templates []*v1alpha1.AnalysisTemplate, clusterTemplates []*v1alpha1.ClusterAnalysisTemplate) ([]v1alpha1.DryRun, error) { + var combinedDryRunMetrics []v1alpha1.DryRun + for _, template := range templates { + combinedDryRunMetrics = append(combinedDryRunMetrics, template.Spec.DryRun...) + } + + for _, template := range clusterTemplates { + combinedDryRunMetrics = append(combinedDryRunMetrics, template.Spec.DryRun...) + } + + err := validateDryRunMetrics(combinedDryRunMetrics) + if err != nil { + return nil, err + } + return combinedDryRunMetrics, nil +} + +func validateDryRunMetrics(dryRunMetrics []v1alpha1.DryRun) error { + metricMap := map[string]bool{} + for _, dryRun := range dryRunMetrics { + if _, ok := metricMap[dryRun.MetricName]; ok { + return fmt.Errorf("two Dry-Run metric rules have the same name '%s'", dryRun.MetricName) + } + metricMap[dryRun.MetricName] = true + } + return nil +} + func NewAnalysisRunFromUnstructured(obj *unstructured.Unstructured, templateArgs []v1alpha1.Argument, name, generateName, namespace string) (*unstructured.Unstructured, error) { var newArgs []v1alpha1.Argument @@ -419,6 +492,7 @@ func NewAnalysisRunFromClusterTemplate(template *v1alpha1.ClusterAnalysisTemplat }, Spec: v1alpha1.AnalysisRunSpec{ Metrics: template.Spec.Metrics, + DryRun: template.Spec.DryRun, Args: newArgs, }, } @@ -439,6 +513,7 @@ func NewAnalysisRunFromTemplate(template *v1alpha1.AnalysisTemplate, args []v1al }, Spec: v1alpha1.AnalysisRunSpec{ Metrics: template.Spec.Metrics, + DryRun: template.Spec.DryRun, Args: newArgs, }, } diff --git a/utils/analysis/helpers_test.go b/utils/analysis/helpers_test.go index 0a5171f23d..1b2ed0df64 100644 --- a/utils/analysis/helpers_test.go +++ b/utils/analysis/helpers_test.go @@ -6,6 +6,8 @@ import ( "fmt" "testing" + "k8s.io/apimachinery/pkg/util/intstr" + log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -369,14 +371,24 @@ func TestFlattenTemplates(t *testing.T) { { Spec: v1alpha1.AnalysisTemplateSpec{ Metrics: []v1alpha1.Metric{fooMetric}, - Args: nil, + DryRun: []v1alpha1.DryRun{ + { + MetricName: "foo", + }, + }, + Args: nil, }, }, }, []*v1alpha1.ClusterAnalysisTemplate{ { Spec: v1alpha1.AnalysisTemplateSpec{ Metrics: []v1alpha1.Metric{barMetric}, - Args: nil, + DryRun: []v1alpha1.DryRun{ + { + MetricName: "bar", + }, + }, + Args: nil, }, }, }) @@ -386,7 +398,7 @@ func TestFlattenTemplates(t *testing.T) { assert.Equal(t, fooMetric, template.Spec.Metrics[0]) assert.Equal(t, barMetric, template.Spec.Metrics[1]) }) - t.Run(" Merge fail with name collision", func(t *testing.T) { + t.Run("Merge fail with name collision", func(t *testing.T) { fooMetric := metric("foo", "true") template, err := FlattenTemplates([]*v1alpha1.AnalysisTemplate{ { @@ -404,6 +416,35 @@ func TestFlattenTemplates(t *testing.T) { assert.Nil(t, template) assert.Equal(t, err, fmt.Errorf("two metrics have the same name 'foo'")) }) + t.Run("Merge fail with dry-run name collision", func(t *testing.T) { + fooMetric := metric("foo", "true") + barMetric := metric("bar", "true") + template, err := FlattenTemplates([]*v1alpha1.AnalysisTemplate{ + { + Spec: v1alpha1.AnalysisTemplateSpec{ + Metrics: []v1alpha1.Metric{fooMetric}, + DryRun: []v1alpha1.DryRun{ + { + MetricName: "foo", + }, + }, + Args: nil, + }, + }, { + Spec: v1alpha1.AnalysisTemplateSpec{ + Metrics: []v1alpha1.Metric{barMetric}, + DryRun: []v1alpha1.DryRun{ + { + MetricName: "foo", + }, + }, + Args: nil, + }, + }, + }, []*v1alpha1.ClusterAnalysisTemplate{}) + assert.Nil(t, template) + assert.Equal(t, err, fmt.Errorf("two Dry-Run metric rules have the same name 'foo'")) + }) t.Run("Merge multiple args successfully", func(t *testing.T) { fooArgs := arg("foo", pointer.StringPtr("true")) barArgs := arg("bar", pointer.StringPtr("true")) @@ -506,7 +547,7 @@ func TestNewAnalysisRunFromTemplates(t *testing.T) { } args := []v1alpha1.Argument{arg, secretArg} - run, err := NewAnalysisRunFromTemplates(templates, clustertemplates, args, "foo-run", "foo-run-generate-", "my-ns") + run, err := NewAnalysisRunFromTemplates(templates, clustertemplates, args, []v1alpha1.DryRun{}, "foo-run", "foo-run-generate-", "my-ns") assert.NoError(t, err) assert.Equal(t, "foo-run", run.Name) assert.Equal(t, "foo-run-generate-", run.GenerateName) @@ -519,7 +560,7 @@ func TestNewAnalysisRunFromTemplates(t *testing.T) { // Fail Merge Args unresolvedArg := v1alpha1.Argument{Name: "unresolved"} templates[0].Spec.Args = append(templates[0].Spec.Args, unresolvedArg) - run, err = NewAnalysisRunFromTemplates(templates, clustertemplates, args, "foo-run", "foo-run-generate-", "my-ns") + run, err = NewAnalysisRunFromTemplates(templates, clustertemplates, args, []v1alpha1.DryRun{}, "foo-run", "foo-run-generate-", "my-ns") assert.Nil(t, run) assert.Equal(t, fmt.Errorf("args.unresolved was not resolved"), err) // Fail flatten metric @@ -532,7 +573,7 @@ func TestNewAnalysisRunFromTemplates(t *testing.T) { } // Fail Flatten Templates templates = append(templates, matchingMetric) - run, err = NewAnalysisRunFromTemplates(templates, clustertemplates, args, "foo-run", "foo-run-generate-", "my-ns") + run, err = NewAnalysisRunFromTemplates(templates, clustertemplates, args, []v1alpha1.DryRun{}, "foo-run", "foo-run-generate-", "my-ns") assert.Nil(t, run) assert.Equal(t, fmt.Errorf("two metrics have the same name 'success-rate'"), err) } @@ -773,3 +814,86 @@ func TestGetInstanceID(t *testing.T) { assert.Panics(t, func() { GetInstanceID(nilRun) }) } + +func TestGetDryRunMetrics(t *testing.T) { + t.Run("GetDryRunMetrics returns the metric names map", func(t *testing.T) { + failureLimit := intstr.FromInt(2) + count := intstr.FromInt(1) + spec := v1alpha1.AnalysisTemplateSpec{ + Metrics: []v1alpha1.Metric{ + { + Name: "success-rate", + Count: &count, + FailureLimit: &failureLimit, + Provider: v1alpha1.MetricProvider{ + Prometheus: &v1alpha1.PrometheusMetric{}, + }, + }, + }, + DryRun: []v1alpha1.DryRun{ + { + MetricName: "success-rate", + }, + }, + } + dryRunMetricNamesMap, err := GetDryRunMetrics(spec.DryRun, spec.Metrics) + assert.Nil(t, err) + assert.True(t, dryRunMetricNamesMap["success-rate"]) + }) + t.Run("GetDryRunMetrics handles the RegEx rules", func(t *testing.T) { + failureLimit := intstr.FromInt(2) + count := intstr.FromInt(1) + spec := v1alpha1.AnalysisTemplateSpec{ + Metrics: []v1alpha1.Metric{ + { + Name: "success-rate", + Count: &count, + FailureLimit: &failureLimit, + Provider: v1alpha1.MetricProvider{ + Prometheus: &v1alpha1.PrometheusMetric{}, + }, + }, + { + Name: "error-rate", + Count: &count, + FailureLimit: &failureLimit, + Provider: v1alpha1.MetricProvider{ + Prometheus: &v1alpha1.PrometheusMetric{}, + }, + }, + }, + DryRun: []v1alpha1.DryRun{ + { + MetricName: ".*", + }, + }, + } + dryRunMetricNamesMap, err := GetDryRunMetrics(spec.DryRun, spec.Metrics) + assert.Nil(t, err) + assert.Equal(t, len(dryRunMetricNamesMap), 2) + }) + t.Run("GetDryRunMetrics throw error when a rule doesn't get matched", func(t *testing.T) { + failureLimit := intstr.FromInt(2) + count := intstr.FromInt(1) + spec := v1alpha1.AnalysisTemplateSpec{ + Metrics: []v1alpha1.Metric{ + { + Name: "success-rate", + Count: &count, + FailureLimit: &failureLimit, + Provider: v1alpha1.MetricProvider{ + Prometheus: &v1alpha1.PrometheusMetric{}, + }, + }, + }, + DryRun: []v1alpha1.DryRun{ + { + MetricName: "error-rate", + }, + }, + } + dryRunMetricNamesMap, err := GetDryRunMetrics(spec.DryRun, spec.Metrics) + assert.EqualError(t, err, "dryRun[0]: Rule didn't match any metric name(s)") + assert.Equal(t, len(dryRunMetricNamesMap), 0) + }) +} From 0f277ac6b8ef74c1201cdbef618363640244607e Mon Sep 17 00:00:00 2001 From: cskh Date: Thu, 2 Dec 2021 17:15:17 -0500 Subject: [PATCH 011/175] docs(analysis): add missing explanation about failureLimit (#1674) Signed-off-by: Hui Kang Co-authored-by: Rohit Agrawal --- docs/features/analysis.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/features/analysis.md b/docs/features/analysis.md index f43374b1e6..65e36db179 100644 --- a/docs/features/analysis.md +++ b/docs/features/analysis.md @@ -520,13 +520,14 @@ spec: value: preview-svc.default.svc.cluster.local ``` -## Failure Conditions +## Failure Conditions and Failure Limit -`failureCondition` can be used to cause an analysis run to fail. The following example continually polls a prometheus -server to get the total number of errors every 5 minutes, causing the analysis run to fail if 10 or more errors were -encountered. +`failureCondition` can be used to cause an analysis run to fail. +`failureLimit` is the maximum number of failed run an analysis is allowed. +The following example continually polls the defined Prometheus server to get the total number of errors(i.e., HTTP response code >= 500) every 5 minutes, causing the measurement to fail if ten or more errors are encountered. +The entire analysis run is considered as Failed after three failed measurements. -```yaml hl_lines="4" +```yaml hl_lines="4 5" metrics: - name: total-errors interval: 5m @@ -537,7 +538,7 @@ encountered. address: http://prometheus.example.com:9090 query: | sum(irate( - istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code~"5.*"}[5m] + istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code=~"5.*"}[5m] )) ``` From 4d3b9925bcaaad1bcb8ae0b180ccf0e2c7afaac8 Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Fri, 3 Dec 2021 10:16:44 -0800 Subject: [PATCH 012/175] feat: increase default QPS/Burst to 40/80. Allow values to be tunable (#1679) Signed-off-by: Jesse Suen --- Makefile | 2 +- cmd/rollouts-controller/main.go | 6 ++++++ test/fixtures/e2e_suite.go | 5 +++-- utils/defaults/defaults.go | 4 ++++ 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index ea5b1f9115..e29d6912e9 100644 --- a/Makefile +++ b/Makefile @@ -240,7 +240,7 @@ test-kustomize: .PHONY: start-e2e start-e2e: - go run ./cmd/rollouts-controller/main.go --instance-id ${E2E_INSTANCE_ID} --loglevel debug + go run ./cmd/rollouts-controller/main.go --instance-id ${E2E_INSTANCE_ID} --loglevel debug --kloglevel 6 .PHONY: test-e2e test-e2e: diff --git a/cmd/rollouts-controller/main.go b/cmd/rollouts-controller/main.go index ce7c18e7c9..6a3942e1c6 100644 --- a/cmd/rollouts-controller/main.go +++ b/cmd/rollouts-controller/main.go @@ -48,6 +48,8 @@ func newCommand() *cobra.Command { metricsPort int healthzPort int instanceID string + qps float32 + burst int rolloutThreads int experimentThreads int analysisThreads int @@ -90,6 +92,8 @@ func newCommand() *cobra.Command { config, err := clientConfig.ClientConfig() checkError(err) + config.QPS = qps + config.Burst = burst namespace := metav1.NamespaceAll configNS, _, err := clientConfig.Namespace() checkError(err) @@ -213,6 +217,8 @@ func newCommand() *cobra.Command { command.Flags().IntVar(&metricsPort, "metricsport", controller.DefaultMetricsPort, "Set the port the metrics endpoint should be exposed over") command.Flags().IntVar(&healthzPort, "healthzPort", controller.DefaultHealthzPort, "Set the port the healthz endpoint should be exposed over") command.Flags().StringVar(&instanceID, "instance-id", "", "Indicates which argo rollout objects the controller should operate on") + command.Flags().Float32Var(&qps, "qps", defaults.DefaultQPS, "Maximum QPS (queries per second) to the K8s API server") + command.Flags().IntVar(&burst, "burst", defaults.DefaultBurst, "Maximum burst for throttle.") command.Flags().IntVar(&rolloutThreads, "rollout-threads", controller.DefaultRolloutThreads, "Set the number of worker threads for the Rollout controller") command.Flags().IntVar(&experimentThreads, "experiment-threads", controller.DefaultExperimentThreads, "Set the number of worker threads for the Experiment controller") command.Flags().IntVar(&analysisThreads, "analysis-threads", controller.DefaultAnalysisThreads, "Set the number of worker threads for the Experiment controller") diff --git a/test/fixtures/e2e_suite.go b/test/fixtures/e2e_suite.go index e7ac739ab6..ac4df4c66d 100644 --- a/test/fixtures/e2e_suite.go +++ b/test/fixtures/e2e_suite.go @@ -26,6 +26,7 @@ import ( rov1 "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" clientset "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned" + "github.com/argoproj/argo-rollouts/utils/defaults" istioutil "github.com/argoproj/argo-rollouts/utils/istio" logutil "github.com/argoproj/argo-rollouts/utils/log" smiutil "github.com/argoproj/argo-rollouts/utils/smi" @@ -137,8 +138,8 @@ func (s *E2ESuite) SetupSuite() { restConfig, err := config.ClientConfig() s.CheckError(err) s.Common.kubernetesHost = restConfig.Host - restConfig.Burst = 50 - restConfig.QPS = 20 + restConfig.Burst = defaults.DefaultBurst + restConfig.QPS = defaults.DefaultQPS s.namespace, _, err = config.Namespace() s.CheckError(err) s.kubeClient, err = kubernetes.NewForConfig(restConfig) diff --git a/utils/defaults/defaults.go b/utils/defaults/defaults.go index 5395552532..46497816f3 100644 --- a/utils/defaults/defaults.go +++ b/utils/defaults/defaults.go @@ -36,6 +36,10 @@ const ( // DefaultConsecutiveErrorLimit is the default number times a metric can error in sequence before // erroring the entire metric. DefaultConsecutiveErrorLimit int32 = 4 + // DefaultQPS is the default Queries Per Second (QPS) for client side throttling to the K8s API server + DefaultQPS float32 = 40.0 + // DefaultBurst is the default value for Burst for client side throttling to the K8s API server + DefaultBurst int = 80 ) const ( From ba936364e2afaa0a334699c5aa9ccb95db1468ca Mon Sep 17 00:00:00 2001 From: Alexander Matyushentsev Date: Fri, 10 Dec 2021 13:53:18 -0800 Subject: [PATCH 013/175] fix: use patch to update workload-generation annotation (#1678) Signed-off-by: Alexander Matyushentsev --- rollout/temlateref.go | 21 ++++++++++++++++----- utils/annotations/annotations.go | 2 +- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/rollout/temlateref.go b/rollout/temlateref.go index 58cdf5d778..a8faf92b8b 100644 --- a/rollout/temlateref.go +++ b/rollout/temlateref.go @@ -20,6 +20,7 @@ import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/discovery" "k8s.io/client-go/dynamic" "k8s.io/client-go/dynamic/dynamicinformer" @@ -245,12 +246,22 @@ func (r *informerBasedTemplateResolver) updateRolloutsReferenceAnnotation(obj in updateAnnotation = func(ro *v1alpha1.Rollout) { updated := annotations.SetRolloutWorkloadRefGeneration(ro, generation) if updated { - // update the annotation causes the rollout to be requeued and the template will be resolved to the referred - // workload during next reconciliation - ro.Spec.Template.Spec.Containers = []corev1.Container{} - _, err := r.argoprojclientset.ArgoprojV1alpha1().Rollouts(ro.Namespace).Update(context.TODO(), ro, v1.UpdateOptions{}) + + patch := map[string]interface{}{ + "metadata": map[string]interface{}{ + "annotations": map[string]interface{}{ + annotations.WorkloadGenerationAnnotation: ro.Annotations[annotations.WorkloadGenerationAnnotation], + }, + }, + } + patchData, err := json.Marshal(patch) + if err == nil { + _, err = r.argoprojclientset.ArgoprojV1alpha1().Rollouts(ro.Namespace).Patch( + context.TODO(), ro.GetName(), types.MergePatchType, patchData, v1.PatchOptions{}) + } + if err != nil { - log.Errorf("Cannot update the workload-ref/annotation for %s/%s", ro.GetName(), ro.GetNamespace()) + log.Errorf("Cannot update the workload-ref/annotation for %s/%s: %v", ro.GetName(), ro.GetNamespace(), err) } } } diff --git a/utils/annotations/annotations.go b/utils/annotations/annotations.go index a99da3fcbb..e3fead8e8f 100644 --- a/utils/annotations/annotations.go +++ b/utils/annotations/annotations.go @@ -79,7 +79,7 @@ func SetRolloutRevision(rollout *v1alpha1.Rollout, revision string) bool { return false } -// SetRolloutRevision updates the revision for a rollout. +// SetRolloutWorkloadRefGeneration updates the workflow generation annotation for a rollout. func SetRolloutWorkloadRefGeneration(rollout *v1alpha1.Rollout, workloadGeneration string) bool { if rollout.Annotations == nil { rollout.Annotations = make(map[string]string) From c67735a7dffa7aae28792c88a403b80b88a35596 Mon Sep 17 00:00:00 2001 From: cskh Date: Fri, 10 Dec 2021 18:27:23 -0500 Subject: [PATCH 014/175] chore: pin sys module in go.mod to resolve a fatal runtime execution in go 1.17 (#1692) * chore: pin sys module to resolve a fatal runtime execution in go 1.17 Signed-off-by: Hui Kang * go mod tidy Signed-off-by: Hui Kang --- go.mod | 1 + go.sum | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 4e5eb688da..a30b8ecea6 100644 --- a/go.mod +++ b/go.mod @@ -36,6 +36,7 @@ require ( github.com/tj/assert v0.0.3 github.com/undefinedlabs/go-mpatch v1.0.6 github.com/valyala/fasttemplate v1.2.1 + golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a google.golang.org/grpc v1.33.1 google.golang.org/grpc/examples v0.0.0-20210331235824-f6bb3972ed15 // indirect diff --git a/go.sum b/go.sum index 3784ded5aa..d88e7cd579 100644 --- a/go.sum +++ b/go.sum @@ -1415,8 +1415,9 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 h1:46ULzRKLh1CwgRq2dC5SlBzEqqNCi8rreOZnNrbqcIY= golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E= +golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= From 271c3c00efedde25aa839e0abe75c6f739e3cf62 Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Sat, 11 Dec 2021 13:32:44 -0800 Subject: [PATCH 015/175] fix: missing rollout informer writeback (#1698) Signed-off-by: Jesse Suen --- rollout/controller.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rollout/controller.go b/rollout/controller.go index 3e9c5d88ca..6b02621f9a 100644 --- a/rollout/controller.go +++ b/rollout/controller.go @@ -389,7 +389,10 @@ func (c *Controller) syncHandler(key string) error { if rollout.Spec.Replicas == nil { logCtx.Info("Defaulting .spec.replica to 1") r.Spec.Replicas = pointer.Int32Ptr(defaults.DefaultReplicas) - _, err := c.argoprojclientset.ArgoprojV1alpha1().Rollouts(r.Namespace).Update(ctx, r, metav1.UpdateOptions{}) + newRollout, err := c.argoprojclientset.ArgoprojV1alpha1().Rollouts(r.Namespace).Update(ctx, r, metav1.UpdateOptions{}) + if err == nil { + c.writeBackToInformer(newRollout) + } return err } From b3d50d1583835ea275ec96df47ec11b2acb9aa0b Mon Sep 17 00:00:00 2001 From: Alexander Matyushentsev Date: Sat, 11 Dec 2021 15:04:50 -0800 Subject: [PATCH 016/175] refactor: stop using mpatch (#1654) Signed-off-by: Alexander Matyushentsev --- analysis/analysis.go | 20 +++++----- analysis/analysis_test.go | 3 +- analysis/controller.go | 3 +- analysis/controller_test.go | 13 ++++--- experiments/conditions_test.go | 5 ++- experiments/controller.go | 8 ++-- experiments/controller_test.go | 37 ++++++++++--------- experiments/experiment.go | 11 +++--- experiments/experiment_test.go | 18 ++++----- experiments/replicaset.go | 5 ++- go.mod | 1 - go.sum | 2 - metricproviders/cloudwatch/cloudwatch.go | 8 ++-- metricproviders/datadog/datadog.go | 8 ++-- metricproviders/graphite/graphite.go | 6 +-- metricproviders/job/job.go | 7 ++-- metricproviders/kayenta/kayenta.go | 13 +++---- metricproviders/newrelic/newrelic.go | 5 ++- metricproviders/prometheus/prometheus.go | 6 +-- metricproviders/wavefront/wavefront.go | 5 ++- metricproviders/webmetric/webmetric.go | 8 ++-- pkg/kubectl-argo-rollouts/cmd/get/get_test.go | 9 ++--- .../cmd/list/list_experiments.go | 3 +- .../cmd/list/list_test.go | 15 ++------ .../cmd/list/rollloutinfo.go | 3 +- .../cmd/restart/restart.go | 3 +- pkg/kubectl-argo-rollouts/info/info.go | 3 +- pkg/kubectl-argo-rollouts/info/info_test.go | 3 +- .../info/replicaset_info.go | 7 ++-- rollout/analysis_test.go | 28 +++++++------- rollout/bluegreen_test.go | 23 ++++++------ rollout/canary_test.go | 9 +++-- rollout/controller.go | 3 +- rollout/controller_test.go | 36 +++++++++--------- rollout/pause.go | 9 +++-- rollout/replicaset.go | 5 ++- rollout/replicaset_test.go | 5 ++- rollout/restart.go | 3 +- rollout/service_test.go | 3 +- rollout/sync_test.go | 7 ++-- rollout/trafficrouting_test.go | 4 +- utils/conditions/conditions.go | 8 ++-- utils/conditions/experiments.go | 7 ++-- utils/experiment/experiment.go | 3 +- utils/metric/metric.go | 5 +-- utils/replicaset/replicaset.go | 5 ++- utils/replicaset/replicaset_test.go | 5 ++- utils/time/now.go | 15 ++++++++ 48 files changed, 228 insertions(+), 193 deletions(-) create mode 100644 utils/time/now.go diff --git a/analysis/analysis.go b/analysis/analysis.go index 952994146d..7d9793182d 100644 --- a/analysis/analysis.go +++ b/analysis/analysis.go @@ -7,17 +7,17 @@ import ( "sync" "time" - "k8s.io/utils/pointer" - log "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/pointer" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" analysisutil "github.com/argoproj/argo-rollouts/utils/analysis" "github.com/argoproj/argo-rollouts/utils/defaults" logutil "github.com/argoproj/argo-rollouts/utils/log" "github.com/argoproj/argo-rollouts/utils/record" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) const ( @@ -109,7 +109,7 @@ func (c *Controller) reconcileAnalysisRun(origRun *v1alpha1.AnalysisRun) *v1alph nextReconcileTime := calculateNextReconcileTime(run, resolvedMetrics) if nextReconcileTime != nil { - enqueueSeconds := nextReconcileTime.Sub(time.Now()) + enqueueSeconds := nextReconcileTime.Sub(timeutil.Now()) if enqueueSeconds < 0 { enqueueSeconds = 0 } @@ -165,7 +165,7 @@ func generateMetricTasks(run *v1alpha1.AnalysisRun, metrics []v1alpha1.Metric) [ logCtx := logger.WithField("metric", metric.Name) lastMeasurement := analysisutil.LastMeasurement(run, metric.Name) if lastMeasurement != nil && lastMeasurement.FinishedAt == nil { - now := metav1.Now() + now := timeutil.MetaNow() if lastMeasurement.ResumeAt != nil && lastMeasurement.ResumeAt.After(now.Time) { continue } @@ -191,7 +191,7 @@ func generateMetricTasks(run *v1alpha1.AnalysisRun, metrics []v1alpha1.Metric) [ logCtx.Warnf("failed to parse duration: %v", err) continue } - if run.Status.StartedAt.Add(duration).After(time.Now()) { + if run.Status.StartedAt.Add(duration).After(timeutil.Now()) { logCtx.Infof("Waiting until start delay duration passes") continue } @@ -220,7 +220,7 @@ func generateMetricTasks(run *v1alpha1.AnalysisRun, metrics []v1alpha1.Metric) [ } interval = parsedInterval } - if time.Now().After(lastMeasurement.FinishedAt.Add(interval)) { + if timeutil.Now().After(lastMeasurement.FinishedAt.Add(interval)) { tasks = append(tasks, metricTask{metric: run.Spec.Metrics[i]}) logCtx.Infof("Running overdue measurement") continue @@ -329,7 +329,7 @@ func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTa if t.incompleteMeasurement != nil { newMeasurement = *t.incompleteMeasurement } else { - startedAt := metav1.Now() + startedAt := timeutil.MetaNow() newMeasurement.StartedAt = &startedAt } newMeasurement.Phase = v1alpha1.AnalysisPhaseError @@ -354,7 +354,7 @@ func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTa if newMeasurement.Phase.Completed() { logger.Infof("Measurement Completed. Result: %s", newMeasurement.Phase) if newMeasurement.FinishedAt == nil { - finishedAt := metav1.Now() + finishedAt := timeutil.MetaNow() newMeasurement.FinishedAt = &finishedAt } switch newMeasurement.Phase { @@ -411,7 +411,7 @@ func (c *Controller) assessRunStatus(run *v1alpha1.AnalysisRun, metrics []v1alph everythingCompleted := true if run.Status.StartedAt == nil { - now := metav1.Now() + now := timeutil.MetaNow() run.Status.StartedAt = &now } if run.Spec.Terminate { @@ -633,7 +633,7 @@ func calculateNextReconcileTime(run *v1alpha1.AnalysisRun, metrics []v1alpha1.Me lastMeasurement := analysisutil.LastMeasurement(run, metric.Name) if lastMeasurement == nil { if metric.InitialDelay != "" { - startTime := metav1.Now() + startTime := timeutil.MetaNow() if run.Status.StartedAt != nil { startTime = *run.Status.StartedAt } diff --git a/analysis/analysis_test.go b/analysis/analysis_test.go index 4273fe3b68..6533565e47 100644 --- a/analysis/analysis_test.go +++ b/analysis/analysis_test.go @@ -8,13 +8,12 @@ import ( "testing" "time" - "k8s.io/apimachinery/pkg/util/intstr" - log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/utils/pointer" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" diff --git a/analysis/controller.go b/analysis/controller.go index 98a9144d6e..2be67de829 100644 --- a/analysis/controller.go +++ b/analysis/controller.go @@ -22,6 +22,7 @@ import ( controllerutil "github.com/argoproj/argo-rollouts/utils/controller" logutil "github.com/argoproj/argo-rollouts/utils/log" "github.com/argoproj/argo-rollouts/utils/record" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) // Controller is the controller implementation for Analysis resources @@ -136,7 +137,7 @@ func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error { } func (c *Controller) syncHandler(key string) error { - startTime := time.Now() + startTime := timeutil.Now() namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { return err diff --git a/analysis/controller_test.go b/analysis/controller_test.go index 4ef0872c65..4e3f571b8e 100644 --- a/analysis/controller_test.go +++ b/analysis/controller_test.go @@ -6,11 +6,12 @@ import ( "testing" "time" + timeutil "github.com/argoproj/argo-rollouts/utils/time" + "github.com/argoproj/argo-rollouts/utils/queue" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" - "github.com/undefinedlabs/go-mpatch" "k8s.io/apimachinery/pkg/api/equality" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -59,11 +60,13 @@ func newFixture(t *testing.T) *fixture { f.objects = []runtime.Object{} f.enqueuedObjects = make(map[string]int) now := time.Now() - patch, err := mpatch.PatchMethod(time.Now, func() time.Time { + timeutil.Now = func() time.Time { return now - }) - assert.NoError(t, err) - f.unfreezeTime = patch.Unpatch + } + f.unfreezeTime = func() error { + timeutil.Now = time.Now + return nil + } return f } diff --git a/experiments/conditions_test.go b/experiments/conditions_test.go index 71b9f59922..cefbc1c2e7 100644 --- a/experiments/conditions_test.go +++ b/experiments/conditions_test.go @@ -9,6 +9,7 @@ import ( "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/conditions" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) func TestUpdateProgressingLastUpdateTime(t *testing.T) { @@ -20,7 +21,7 @@ func TestUpdateProgressingLastUpdateTime(t *testing.T) { Name: "bar", }} prevCond := newCondition(conditions.ReplicaSetUpdatedReason, e) - prevTime := metav1.NewTime(metav1.Now().Add(-10 * time.Second)) + prevTime := metav1.NewTime(timeutil.Now().Add(-10 * time.Second)) prevCond.LastUpdateTime = prevTime prevCond.LastTransitionTime = prevTime e.Status.Conditions = []v1alpha1.ExperimentCondition{ @@ -53,7 +54,7 @@ func TestEnterTimeoutDegradedState(t *testing.T) { Status: v1alpha1.TemplateStatusProgressing, }} e.Spec.ProgressDeadlineSeconds = pointer.Int32Ptr(30) - prevTime := metav1.NewTime(metav1.Now().Add(-1 * time.Minute).Truncate(time.Second)) + prevTime := metav1.NewTime(timeutil.Now().Add(-1 * time.Minute).Truncate(time.Second)) e.Status.TemplateStatuses[0].LastTransitionTime = &prevTime rs := templateToRS(e, templates[0], 0) diff --git a/experiments/controller.go b/experiments/controller.go index 59de00f3aa..76d3841cc2 100644 --- a/experiments/controller.go +++ b/experiments/controller.go @@ -4,9 +4,6 @@ import ( "context" "time" - informersv1 "k8s.io/client-go/informers/core/v1" - listersv1 "k8s.io/client-go/listers/core/v1" - log "github.com/sirupsen/logrus" appsv1 "k8s.io/api/apps/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" @@ -15,8 +12,10 @@ import ( patchtypes "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" appsinformers "k8s.io/client-go/informers/apps/v1" + informersv1 "k8s.io/client-go/informers/core/v1" "k8s.io/client-go/kubernetes" appslisters "k8s.io/client-go/listers/apps/v1" + listersv1 "k8s.io/client-go/listers/core/v1" "k8s.io/client-go/tools/cache" "k8s.io/client-go/util/workqueue" "k8s.io/kubernetes/pkg/controller" @@ -33,6 +32,7 @@ import ( "github.com/argoproj/argo-rollouts/utils/diff" logutil "github.com/argoproj/argo-rollouts/utils/log" "github.com/argoproj/argo-rollouts/utils/record" + timeutil "github.com/argoproj/argo-rollouts/utils/time" unstructuredutil "github.com/argoproj/argo-rollouts/utils/unstructured" ) @@ -233,7 +233,7 @@ func (ec *Controller) Run(threadiness int, stopCh <-chan struct{}) error { } func (ec *Controller) syncHandler(key string) error { - startTime := time.Now() + startTime := timeutil.Now() namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { return err diff --git a/experiments/controller_test.go b/experiments/controller_test.go index 960397c2b8..d86889c550 100644 --- a/experiments/controller_test.go +++ b/experiments/controller_test.go @@ -8,10 +8,11 @@ import ( "testing" "time" + timeutil "github.com/argoproj/argo-rollouts/utils/time" + "k8s.io/apimachinery/pkg/util/intstr" "github.com/stretchr/testify/assert" - "github.com/undefinedlabs/go-mpatch" "github.com/argoproj/argo-rollouts/utils/queue" @@ -52,12 +53,12 @@ const ( ) func now() *metav1.Time { - now := metav1.Time{Time: time.Now().Truncate(time.Second)} + now := metav1.Time{Time: timeutil.Now().Truncate(time.Second)} return &now } func secondsAgo(seconds int) *metav1.Time { - ago := metav1.Time{Time: time.Now().Add(-1 * time.Second * time.Duration(seconds)).Truncate(time.Second)} + ago := metav1.Time{Time: timeutil.Now().Add(-1 * time.Second * time.Duration(seconds)).Truncate(time.Second)} return &ago } @@ -114,11 +115,13 @@ func newFixture(t *testing.T, objects ...runtime.Object) *fixture { f.kubeclient = k8sfake.NewSimpleClientset(f.kubeobjects...) f.enqueuedObjects = make(map[string]int) now := time.Now() - patch, err := mpatch.PatchMethod(time.Now, func() time.Time { + timeutil.Now = func() time.Time { return now - }) - assert.NoError(t, err) - f.unfreezeTime = patch.Unpatch + } + f.unfreezeTime = func() error { + timeutil.Now = time.Now + return nil + } return f } @@ -200,8 +203,8 @@ func newCondition(reason string, experiment *v1alpha1.Experiment) *v1alpha1.Expe return &v1alpha1.ExperimentCondition{ Type: v1alpha1.ExperimentProgressing, Status: corev1.ConditionTrue, - LastUpdateTime: metav1.Now().Rfc3339Copy(), - LastTransitionTime: metav1.Now().Rfc3339Copy(), + LastUpdateTime: timeutil.MetaNow().Rfc3339Copy(), + LastTransitionTime: timeutil.MetaNow().Rfc3339Copy(), Reason: reason, Message: fmt.Sprintf(conditions.ExperimentProgressingMessage, experiment.Name), } @@ -210,8 +213,8 @@ func newCondition(reason string, experiment *v1alpha1.Experiment) *v1alpha1.Expe return &v1alpha1.ExperimentCondition{ Type: v1alpha1.ExperimentProgressing, Status: corev1.ConditionFalse, - LastUpdateTime: metav1.Now().Rfc3339Copy(), - LastTransitionTime: metav1.Now().Rfc3339Copy(), + LastUpdateTime: timeutil.MetaNow().Rfc3339Copy(), + LastTransitionTime: timeutil.MetaNow().Rfc3339Copy(), Reason: reason, Message: fmt.Sprintf(conditions.ExperimentCompletedMessage, experiment.Name), } @@ -220,8 +223,8 @@ func newCondition(reason string, experiment *v1alpha1.Experiment) *v1alpha1.Expe return &v1alpha1.ExperimentCondition{ Type: v1alpha1.ExperimentProgressing, Status: corev1.ConditionFalse, - LastUpdateTime: metav1.Now().Rfc3339Copy(), - LastTransitionTime: metav1.Now().Rfc3339Copy(), + LastUpdateTime: timeutil.MetaNow().Rfc3339Copy(), + LastTransitionTime: timeutil.MetaNow().Rfc3339Copy(), Reason: reason, Message: fmt.Sprintf(conditions.ExperimentRunningMessage, experiment.Name), } @@ -230,8 +233,8 @@ func newCondition(reason string, experiment *v1alpha1.Experiment) *v1alpha1.Expe return &v1alpha1.ExperimentCondition{ Type: v1alpha1.InvalidExperimentSpec, Status: corev1.ConditionTrue, - LastUpdateTime: metav1.Now().Rfc3339Copy(), - LastTransitionTime: metav1.Now().Rfc3339Copy(), + LastUpdateTime: timeutil.MetaNow().Rfc3339Copy(), + LastTransitionTime: timeutil.MetaNow().Rfc3339Copy(), Reason: reason, Message: fmt.Sprintf(conditions.ExperimentTemplateNameEmpty, experiment.Name, 0), } @@ -643,7 +646,7 @@ func (f *fixture) verifyPatchedReplicaSetAddScaleDownDelay(index int, scaleDownD if !ok { assert.Fail(f.t, "Expected Patch action, not %s", action.GetVerb()) } - now := metav1.Now().Add(time.Duration(scaleDownDelaySeconds) * time.Second).UTC().Format(time.RFC3339) + now := timeutil.Now().Add(time.Duration(scaleDownDelaySeconds) * time.Second).UTC().Format(time.RFC3339) patch := fmt.Sprintf(addScaleDownAtAnnotationsPatch, v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey, now) assert.Equal(f.t, string(patchAction.GetPatch()), patch) } @@ -728,7 +731,7 @@ func TestNoReconcileForDeletedExperiment(t *testing.T) { defer f.Close() e := newExperiment("foo", nil, "10s") - now := metav1.Now() + now := timeutil.MetaNow() e.DeletionTimestamp = &now f.experimentLister = append(f.experimentLister, e) diff --git a/experiments/experiment.go b/experiments/experiment.go index 17e19b7762..2c06b7413d 100644 --- a/experiments/experiment.go +++ b/experiments/experiment.go @@ -5,8 +5,6 @@ import ( "fmt" "time" - "k8s.io/utils/pointer" - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" clientset "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned" rolloutslisters "github.com/argoproj/argo-rollouts/pkg/client/listers/rollouts/v1alpha1" @@ -17,6 +15,8 @@ import ( "github.com/argoproj/argo-rollouts/utils/record" replicasetutil "github.com/argoproj/argo-rollouts/utils/replicaset" templateutil "github.com/argoproj/argo-rollouts/utils/template" + timeutil "github.com/argoproj/argo-rollouts/utils/time" + log "github.com/sirupsen/logrus" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -25,6 +25,7 @@ import ( "k8s.io/client-go/kubernetes" appslisters "k8s.io/client-go/listers/apps/v1" v1 "k8s.io/client-go/listers/core/v1" + "k8s.io/utils/pointer" ) const ( @@ -123,7 +124,7 @@ func (ec *experimentContext) reconcileTemplate(template v1alpha1.TemplateSpec) { } prevStatus := templateStatus.DeepCopy() desiredReplicaCount := experimentutil.CalculateTemplateReplicasCount(ec.ex, template) - now := metav1.Now() + now := timeutil.MetaNow() rs := ec.templateRSs[template.Name] @@ -348,7 +349,7 @@ func calculateEnqueueDuration(ex *v1alpha1.Experiment, newStatus *v1alpha1.Exper } } deadlineSeconds := defaults.GetExperimentProgressDeadlineSecondsOrDefault(ex) - now := time.Now() + now := timeutil.Now() for _, template := range ex.Spec.Templates { // Set candidate to the earliest of LastTransitionTime + progressDeadlineSeconds ts := experimentutil.GetTemplateStatus(ex.Status, template.Name) @@ -511,7 +512,7 @@ func (ec *experimentContext) calculateStatus() *v1alpha1.ExperimentStatus { templateStatus, templateMessage := ec.assessTemplates() analysesStatus, analysesMessage := ec.assessAnalysisRuns() if templateStatus == v1alpha1.AnalysisPhaseRunning && ec.newStatus.AvailableAt == nil { - now := metav1.Now() + now := timeutil.MetaNow() ec.newStatus.AvailableAt = &now ec.log.Infof("Marked AvailableAt: %v", now) } diff --git a/experiments/experiment_test.go b/experiments/experiment_test.go index ebb7e7bea3..f26ee1038b 100644 --- a/experiments/experiment_test.go +++ b/experiments/experiment_test.go @@ -20,10 +20,10 @@ import ( "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned/fake" - informers "github.com/argoproj/argo-rollouts/pkg/client/informers/externalversions" "github.com/argoproj/argo-rollouts/utils/conditions" "github.com/argoproj/argo-rollouts/utils/record" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) func newTestContext(ex *v1alpha1.Experiment, objects ...runtime.Object) *experimentContext { @@ -123,7 +123,7 @@ func TestRemoveScaleDownDelayFromRS(t *testing.T) { cond := conditions.NewExperimentConditions(v1alpha1.ExperimentProgressing, corev1.ConditionTrue, conditions.NewRSAvailableReason, "Experiment \"foo\" is running.") e.Status.Conditions = append(e.Status.Conditions, *cond) rs := templateToRS(e, templates[0], 1) - rs.ObjectMeta.Annotations[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey] = metav1.Now().Add(600 * time.Second).UTC().Format(time.RFC3339) + rs.ObjectMeta.Annotations[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey] = timeutil.Now().Add(600 * time.Second).UTC().Format(time.RFC3339) e.Status.TemplateStatuses = []v1alpha1.TemplateStatus{ generateTemplatesStatus("bar", 1, 1, v1alpha1.TemplateStatusSuccessful, now()), } @@ -160,7 +160,7 @@ func TestScaleDownRSAfterFinish(t *testing.T) { cond := conditions.NewExperimentConditions(v1alpha1.ExperimentProgressing, corev1.ConditionTrue, conditions.NewRSAvailableReason, "Experiment \"foo\" is running.") e.Status.Conditions = append(e.Status.Conditions, *cond) - inThePast := metav1.Now().Add(-10 * time.Second).UTC().Format(time.RFC3339) + inThePast := timeutil.Now().Add(-10 * time.Second).UTC().Format(time.RFC3339) rs1.Annotations[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey] = inThePast rs2.Annotations[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey] = inThePast @@ -219,9 +219,9 @@ func TestNoPatch(t *testing.T) { Type: v1alpha1.ExperimentProgressing, Reason: conditions.NewRSAvailableReason, Message: fmt.Sprintf(conditions.ExperimentRunningMessage, e.Name), - LastTransitionTime: metav1.Now(), + LastTransitionTime: timeutil.MetaNow(), Status: corev1.ConditionTrue, - LastUpdateTime: metav1.Now(), + LastUpdateTime: timeutil.MetaNow(), }} e.Status.AvailableAt = now() @@ -243,7 +243,7 @@ func TestSuccessAfterDurationPasses(t *testing.T) { templates := generateTemplates("bar", "baz") e := newExperiment("foo", templates, "5s") - tenSecondsAgo := metav1.Now().Add(-10 * time.Second) + tenSecondsAgo := timeutil.Now().Add(-10 * time.Second) e.Status.AvailableAt = &metav1.Time{Time: tenSecondsAgo} e.Status.Phase = v1alpha1.AnalysisPhaseRunning e.Status.TemplateStatuses = []v1alpha1.TemplateStatus{ @@ -278,7 +278,7 @@ func TestSuccessAfterDurationPasses(t *testing.T) { func TestDontRequeueWithoutDuration(t *testing.T) { templates := generateTemplates("bar") ex := newExperiment("foo", templates, "") - ex.Status.AvailableAt = &metav1.Time{Time: metav1.Now().Add(-10 * time.Second)} + ex.Status.AvailableAt = &metav1.Time{Time: timeutil.MetaNow().Add(-10 * time.Second)} ex.Status.TemplateStatuses = []v1alpha1.TemplateStatus{ generateTemplatesStatus("bar", 1, 1, v1alpha1.TemplateStatusRunning, now()), } @@ -303,7 +303,7 @@ func TestRequeueAfterDuration(t *testing.T) { templates := generateTemplates("bar") ex := newExperiment("foo", templates, "") ex.Spec.Duration = "30s" - ex.Status.AvailableAt = &metav1.Time{Time: metav1.Now().Add(-10 * time.Second)} + ex.Status.AvailableAt = &metav1.Time{Time: timeutil.MetaNow().Add(-10 * time.Second)} ex.Status.TemplateStatuses = []v1alpha1.TemplateStatus{ generateTemplatesStatus("bar", 1, 1, v1alpha1.TemplateStatusRunning, now()), } @@ -332,7 +332,7 @@ func TestRequeueAfterProgressDeadlineSeconds(t *testing.T) { ex.Status.TemplateStatuses = []v1alpha1.TemplateStatus{ generateTemplatesStatus("bar", 0, 0, v1alpha1.TemplateStatusProgressing, now()), } - now := metav1.Now() + now := timeutil.MetaNow() ex.Status.TemplateStatuses[0].LastTransitionTime = &now exCtx := newTestContext(ex) rs1 := templateToRS(ex, ex.Spec.Templates[0], 0) diff --git a/experiments/replicaset.go b/experiments/replicaset.go index 5d97eb15c1..4d0c165425 100644 --- a/experiments/replicaset.go +++ b/experiments/replicaset.go @@ -7,7 +7,9 @@ import ( "time" "github.com/argoproj/argo-rollouts/utils/defaults" + timeutil "github.com/argoproj/argo-rollouts/utils/time" + log "github.com/sirupsen/logrus" appsv1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -22,7 +24,6 @@ import ( logutil "github.com/argoproj/argo-rollouts/utils/log" "github.com/argoproj/argo-rollouts/utils/record" replicasetutil "github.com/argoproj/argo-rollouts/utils/replicaset" - log "github.com/sirupsen/logrus" ) const ( @@ -227,7 +228,7 @@ func (ec *experimentContext) addScaleDownDelay(rs *appsv1.ReplicaSet) (bool, err } } - deadline := metav1.Now().Add(scaleDownDelaySeconds * time.Second).UTC().Format(time.RFC3339) + deadline := timeutil.MetaNow().Add(scaleDownDelaySeconds * time.Second).UTC().Format(time.RFC3339) patch := fmt.Sprintf(addScaleDownAtAnnotationsPatch, v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey, deadline) _, err := ec.kubeclientset.AppsV1().ReplicaSets(rs.Namespace).Patch(ctx, rs.Name, patchtypes.JSONPatchType, []byte(patch), metav1.PatchOptions{}) if err == nil { diff --git a/go.mod b/go.mod index a30b8ecea6..06cf4f2b64 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,6 @@ require ( github.com/spf13/cobra v1.1.3 github.com/stretchr/testify v1.7.0 github.com/tj/assert v0.0.3 - github.com/undefinedlabs/go-mpatch v1.0.6 github.com/valyala/fasttemplate v1.2.1 golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a diff --git a/go.sum b/go.sum index d88e7cd579..21e8ab6ad8 100644 --- a/go.sum +++ b/go.sum @@ -1134,8 +1134,6 @@ github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oW github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= -github.com/undefinedlabs/go-mpatch v1.0.6 h1:h8q5ORH/GaOE1Se1DMhrOyljXZEhRcROO7agMqWXCOY= -github.com/undefinedlabs/go-mpatch v1.0.6/go.mod h1:TyJZDQ/5AgyN7FSLiBJ8RO9u2c6wbtRvK827b6AVqY4= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= diff --git a/metricproviders/cloudwatch/cloudwatch.go b/metricproviders/cloudwatch/cloudwatch.go index 09312cb25e..90569c1548 100644 --- a/metricproviders/cloudwatch/cloudwatch.go +++ b/metricproviders/cloudwatch/cloudwatch.go @@ -9,11 +9,11 @@ import ( "github.com/aws/aws-sdk-go-v2/service/cloudwatch" "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types" log "github.com/sirupsen/logrus" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/evaluate" metricutil "github.com/argoproj/argo-rollouts/utils/metric" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) const ( @@ -30,7 +30,7 @@ type CloudWatchClient struct { } func (c *CloudWatchClient) Query(interval time.Duration, query []types.MetricDataQuery) (*cloudwatch.GetMetricDataOutput, error) { - endTime := time.Now() + endTime := timeutil.Now() startTime := endTime.Add(-interval) return c.client.GetMetricData(context.TODO(), &cloudwatch.GetMetricDataInput{ StartTime: &startTime, @@ -52,7 +52,7 @@ func (p *Provider) Type() string { // Run queries with CloudWatch provider for the metric func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alpha1.Measurement { - startTime := metav1.Now() + startTime := timeutil.MetaNow() measurement := v1alpha1.Measurement{ StartedAt: &startTime, Metadata: map[string]string{}, @@ -92,7 +92,7 @@ func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alph } measurement.Phase = status - finishedTime := metav1.Now() + finishedTime := timeutil.MetaNow() measurement.FinishedAt = &finishedTime return measurement diff --git a/metricproviders/datadog/datadog.go b/metricproviders/datadog/datadog.go index a436523a99..f8dc6eba12 100644 --- a/metricproviders/datadog/datadog.go +++ b/metricproviders/datadog/datadog.go @@ -17,12 +17,14 @@ import ( "github.com/argoproj/argo-rollouts/utils/defaults" "github.com/argoproj/argo-rollouts/utils/evaluate" metricutil "github.com/argoproj/argo-rollouts/utils/metric" + timeutil "github.com/argoproj/argo-rollouts/utils/time" + log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" ) -var unixNow = func() int64 { return time.Now().Unix() } +var unixNow = func() int64 { return timeutil.Now().Unix() } const ( //ProviderType indicates the provider is datadog @@ -58,7 +60,7 @@ func (p *Provider) Type() string { } func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alpha1.Measurement { - startTime := metav1.Now() + startTime := timeutil.MetaNow() // Measurement to pass back measurement := v1alpha1.Measurement{ @@ -116,7 +118,7 @@ func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alph measurement.Value = value measurement.Phase = status - finishedTime := metav1.Now() + finishedTime := timeutil.MetaNow() measurement.FinishedAt = &finishedTime return measurement diff --git a/metricproviders/graphite/graphite.go b/metricproviders/graphite/graphite.go index c12fb3142b..8ad9de4b2c 100644 --- a/metricproviders/graphite/graphite.go +++ b/metricproviders/graphite/graphite.go @@ -8,11 +8,11 @@ import ( "time" log "github.com/sirupsen/logrus" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/evaluate" metricutil "github.com/argoproj/argo-rollouts/utils/metric" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) const ( @@ -51,7 +51,7 @@ func (p *Provider) Type() string { // Run queries Graphite for the metric. func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alpha1.Measurement { - startTime := metav1.Now() + startTime := timeutil.MetaNow() newMeasurement := v1alpha1.Measurement{ StartedAt: &startTime, } @@ -72,7 +72,7 @@ func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alph } newMeasurement.Phase = newStatus - finishedTime := metav1.Now() + finishedTime := timeutil.MetaNow() newMeasurement.FinishedAt = &finishedTime return newMeasurement diff --git a/metricproviders/job/job.go b/metricproviders/job/job.go index 1f3c42d096..10021c2324 100644 --- a/metricproviders/job/job.go +++ b/metricproviders/job/job.go @@ -17,6 +17,7 @@ import ( "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" analysisutil "github.com/argoproj/argo-rollouts/utils/analysis" metricutil "github.com/argoproj/argo-rollouts/utils/metric" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) const ( @@ -93,7 +94,7 @@ func newMetricJob(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) (*batchv1.J func (p *JobProvider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alpha1.Measurement { ctx := context.TODO() - now := metav1.Now() + now := timeutil.MetaNow() measurement := v1alpha1.Measurement{ StartedAt: &now, Phase: v1alpha1.AnalysisPhaseRunning, @@ -133,7 +134,7 @@ func (p *JobProvider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1a func (p *JobProvider) Resume(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric, measurement v1alpha1.Measurement) v1alpha1.Measurement { jobName, err := getJobName(measurement) - now := metav1.Now() + now := timeutil.MetaNow() if err != nil { return metricutil.MarkMeasurementError(measurement, err) } @@ -166,7 +167,7 @@ func (p *JobProvider) Terminate(run *v1alpha1.AnalysisRun, metric v1alpha1.Metri if err != nil { return metricutil.MarkMeasurementError(measurement, err) } - now := metav1.Now() + now := timeutil.MetaNow() measurement.FinishedAt = &now measurement.Phase = v1alpha1.AnalysisPhaseSuccessful p.logCtx.Infof("job %s/%s terminated", run.Namespace, jobName) diff --git a/metricproviders/kayenta/kayenta.go b/metricproviders/kayenta/kayenta.go index e15da1ed3d..e7d0980923 100644 --- a/metricproviders/kayenta/kayenta.go +++ b/metricproviders/kayenta/kayenta.go @@ -9,14 +9,13 @@ import ( "net/http" "time" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" - metricutil "github.com/argoproj/argo-rollouts/utils/metric" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) const ( @@ -97,7 +96,7 @@ func getCanaryConfigId(metric v1alpha1.Metric, p *Provider) (string, error) { // Run queries kayentd for the metric func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alpha1.Measurement { - startTime := metav1.Now() + startTime := timeutil.MetaNow() newMeasurement := v1alpha1.Measurement{ StartedAt: &startTime, } @@ -157,7 +156,7 @@ func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alph newMeasurement.Phase = v1alpha1.AnalysisPhaseRunning - resumeTime := metav1.NewTime(time.Now().Add(resumeDelay)) + resumeTime := metav1.NewTime(timeutil.Now().Add(resumeDelay)) newMeasurement.ResumeAt = &resumeTime return newMeasurement @@ -191,7 +190,7 @@ func (p *Provider) Resume(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric, mea status, ok, err := unstructured.NestedBool(patch, "complete") if ok { if !status { //resume later since it is incomplete - resumeTime := metav1.NewTime(time.Now().Add(resumeDelay)) + resumeTime := metav1.NewTime(timeutil.Now().Add(resumeDelay)) measurement.ResumeAt = &resumeTime measurement.Phase = v1alpha1.AnalysisPhaseRunning @@ -217,7 +216,7 @@ func (p *Provider) Resume(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric, mea return metricutil.MarkMeasurementError(measurement, err) } - finishTime := metav1.Now() + finishTime := timeutil.MetaNow() measurement.FinishedAt = &finishTime return measurement diff --git a/metricproviders/newrelic/newrelic.go b/metricproviders/newrelic/newrelic.go index 8b52ed66ec..441c3a978e 100644 --- a/metricproviders/newrelic/newrelic.go +++ b/metricproviders/newrelic/newrelic.go @@ -17,6 +17,7 @@ import ( "github.com/argoproj/argo-rollouts/utils/defaults" "github.com/argoproj/argo-rollouts/utils/evaluate" metricutil "github.com/argoproj/argo-rollouts/utils/metric" + timeutil "github.com/argoproj/argo-rollouts/utils/time" "github.com/argoproj/argo-rollouts/utils/version" ) @@ -55,7 +56,7 @@ type Provider struct { // Run queries NewRelic for the metric func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alpha1.Measurement { - startTime := metav1.Now() + startTime := timeutil.MetaNow() newMeasurement := v1alpha1.Measurement{ StartedAt: &startTime, } @@ -72,7 +73,7 @@ func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alph newMeasurement.Value = valueStr newMeasurement.Phase = newStatus - finishedTime := metav1.Now() + finishedTime := timeutil.MetaNow() newMeasurement.FinishedAt = &finishedTime return newMeasurement } diff --git a/metricproviders/prometheus/prometheus.go b/metricproviders/prometheus/prometheus.go index 5243a4a342..8334dc2a39 100644 --- a/metricproviders/prometheus/prometheus.go +++ b/metricproviders/prometheus/prometheus.go @@ -9,11 +9,11 @@ import ( v1 "github.com/prometheus/client_golang/api/prometheus/v1" "github.com/prometheus/common/model" log "github.com/sirupsen/logrus" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/evaluate" metricutil "github.com/argoproj/argo-rollouts/utils/metric" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) const ( @@ -34,7 +34,7 @@ func (p *Provider) Type() string { // Run queries prometheus for the metric func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alpha1.Measurement { - startTime := metav1.Now() + startTime := timeutil.MetaNow() newMeasurement := v1alpha1.Measurement{ StartedAt: &startTime, } @@ -67,7 +67,7 @@ func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alph } newMeasurement.Phase = newStatus - finishedTime := metav1.Now() + finishedTime := timeutil.MetaNow() newMeasurement.FinishedAt = &finishedTime return newMeasurement } diff --git a/metricproviders/wavefront/wavefront.go b/metricproviders/wavefront/wavefront.go index d6e3f28f77..177d135769 100644 --- a/metricproviders/wavefront/wavefront.go +++ b/metricproviders/wavefront/wavefront.go @@ -17,6 +17,7 @@ import ( "github.com/argoproj/argo-rollouts/utils/defaults" "github.com/argoproj/argo-rollouts/utils/evaluate" metricutil "github.com/argoproj/argo-rollouts/utils/metric" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) const ( @@ -68,7 +69,7 @@ type wavefrontResponse struct { // Run queries with wavefront provider for the metric func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alpha1.Measurement { - startTime := metav1.Now() + startTime := timeutil.MetaNow() newMeasurement := v1alpha1.Measurement{ StartedAt: &startTime, Metadata: map[string]string{}, @@ -103,7 +104,7 @@ func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alph newMeasurement.Phase = result.newStatus newMeasurement.Metadata["timestamps"] = result.epochsUsed newMeasurement.Metadata["drift"] = result.drift - finishedTime := metav1.Now() + finishedTime := timeutil.MetaNow() newMeasurement.FinishedAt = &finishedTime return newMeasurement } diff --git a/metricproviders/webmetric/webmetric.go b/metricproviders/webmetric/webmetric.go index 1def6a94b1..18ce94a6dd 100644 --- a/metricproviders/webmetric/webmetric.go +++ b/metricproviders/webmetric/webmetric.go @@ -12,13 +12,13 @@ import ( "strings" "time" - metricutil "github.com/argoproj/argo-rollouts/utils/metric" log "github.com/sirupsen/logrus" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/util/jsonpath" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/evaluate" + metricutil "github.com/argoproj/argo-rollouts/utils/metric" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) const ( @@ -40,7 +40,7 @@ func (p *Provider) Type() string { } func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alpha1.Measurement { - startTime := metav1.Now() + startTime := timeutil.MetaNow() // Measurement to pass back measurement := v1alpha1.Measurement{ @@ -91,7 +91,7 @@ func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alph measurement.Value = value measurement.Phase = status - finishedTime := metav1.Now() + finishedTime := timeutil.MetaNow() measurement.FinishedAt = &finishedTime return measurement diff --git a/pkg/kubectl-argo-rollouts/cmd/get/get_test.go b/pkg/kubectl-argo-rollouts/cmd/get/get_test.go index 3ca3872be1..8758d11145 100644 --- a/pkg/kubectl-argo-rollouts/cmd/get/get_test.go +++ b/pkg/kubectl-argo-rollouts/cmd/get/get_test.go @@ -7,14 +7,13 @@ import ( "testing" "time" - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/stretchr/testify/assert" "k8s.io/cli-runtime/pkg/genericclioptions" + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/info/testdata" options "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/options/fake" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) func assertStdout(t *testing.T, expectedOut string, o genericclioptions.IOStreams) { @@ -163,7 +162,7 @@ NAME KIND STATUS AGE INFO func TestGetBlueGreenRolloutScaleDownDelay(t *testing.T) { rolloutObjs := testdata.NewBlueGreenRollout() - inFourHours := metav1.Now().Add(4 * time.Hour).Truncate(time.Second).UTC().Format(time.RFC3339) + inFourHours := timeutil.Now().Add(4 * time.Hour).Truncate(time.Second).UTC().Format(time.RFC3339) rolloutObjs.ReplicaSets[2].Annotations[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey] = inFourHours delete(rolloutObjs.ReplicaSets[2].Labels, v1alpha1.DefaultRolloutUniqueLabelKey) @@ -211,7 +210,7 @@ NAME KIND STATUS AGE INFO func TestGetBlueGreenRolloutScaleDownDelayPassed(t *testing.T) { rolloutObjs := testdata.NewBlueGreenRollout() - anHourAgo := metav1.Now().Add(-1 * time.Hour).Truncate(time.Second).UTC().Format(time.RFC3339) + anHourAgo := timeutil.Now().Add(-1 * time.Hour).Truncate(time.Second).UTC().Format(time.RFC3339) rolloutObjs.ReplicaSets[2].Annotations[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey] = anHourAgo delete(rolloutObjs.ReplicaSets[2].Labels, v1alpha1.DefaultRolloutUniqueLabelKey) diff --git a/pkg/kubectl-argo-rollouts/cmd/list/list_experiments.go b/pkg/kubectl-argo-rollouts/cmd/list/list_experiments.go index 336e043183..493a8aaa18 100644 --- a/pkg/kubectl-argo-rollouts/cmd/list/list_experiments.go +++ b/pkg/kubectl-argo-rollouts/cmd/list/list_experiments.go @@ -11,6 +11,7 @@ import ( "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/options" experimentutil "github.com/argoproj/argo-rollouts/utils/experiment" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) const ( @@ -85,7 +86,7 @@ func (o *ListOptions) PrintExperimentTable(expList *v1alpha1.ExperimentList) err } fmt.Fprintf(w, headerStr) for _, exp := range expList.Items { - age := duration.HumanDuration(metav1.Now().Sub(exp.CreationTimestamp.Time)) + age := duration.HumanDuration(timeutil.MetaNow().Sub(exp.CreationTimestamp.Time)) dur := "-" remaining := "-" if exp.Spec.Duration != "" { diff --git a/pkg/kubectl-argo-rollouts/cmd/list/list_test.go b/pkg/kubectl-argo-rollouts/cmd/list/list_test.go index b67f482b31..705363b394 100644 --- a/pkg/kubectl-argo-rollouts/cmd/list/list_test.go +++ b/pkg/kubectl-argo-rollouts/cmd/list/list_test.go @@ -8,7 +8,6 @@ import ( "time" "github.com/stretchr/testify/assert" - "github.com/undefinedlabs/go-mpatch" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/watch" kubetesting "k8s.io/client-go/testing" @@ -176,22 +175,14 @@ func TestListNamespaceAndTimestamp(t *testing.T) { cmd.PersistentPreRunE = o.PersistentPreRunE cmd.SetArgs([]string{"--all-namespaces", "--timestamps"}) - patch, err := mpatch.PatchMethod(time.Now, func() time.Time { - return time.Time{} - }) - assert.NoError(t, err) - err = cmd.Execute() - patch.Unpatch() + err := cmd.Execute() assert.NoError(t, err) stdout := o.Out.(*bytes.Buffer).String() stderr := o.ErrOut.(*bytes.Buffer).String() assert.Empty(t, stderr) - expectedOut := strings.TrimPrefix(` -TIMESTAMP NAMESPACE NAME STRATEGY STATUS STEP SET-WEIGHT READY DESIRED UP-TO-DATE AVAILABLE -0001-01-01T00:00:00Z test can-guestbook Canary Progressing 1/3 10 1/4 5 3 2 -`, "\n") - assert.Equal(t, expectedOut, stdout) + assert.Contains(t, stdout, "TIMESTAMP NAMESPACE NAME STRATEGY STATUS STEP SET-WEIGHT READY DESIRED UP-TO-DATE AVAILABLE") + assert.Contains(t, stdout, "test can-guestbook Canary Progressing 1/3 10 1/4 5 3 2") } func TestListWithWatch(t *testing.T) { diff --git a/pkg/kubectl-argo-rollouts/cmd/list/rollloutinfo.go b/pkg/kubectl-argo-rollouts/cmd/list/rollloutinfo.go index 05a37a02e8..d015939f69 100644 --- a/pkg/kubectl-argo-rollouts/cmd/list/rollloutinfo.go +++ b/pkg/kubectl-argo-rollouts/cmd/list/rollloutinfo.go @@ -8,6 +8,7 @@ import ( "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" replicasetutil "github.com/argoproj/argo-rollouts/utils/replicaset" rolloututil "github.com/argoproj/argo-rollouts/utils/rollout" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) const ( @@ -92,7 +93,7 @@ func (ri *rolloutInfo) String(timestamp, namespace bool) string { } if timestamp { fmtString = "%-20s\t" + fmtString - timestampStr := time.Now().UTC().Truncate(time.Second).Format("2006-01-02T15:04:05Z") + timestampStr := timeutil.Now().UTC().Truncate(time.Second).Format("2006-01-02T15:04:05Z") args = append([]interface{}{timestampStr}, args...) } return fmt.Sprintf(fmtString, args...) diff --git a/pkg/kubectl-argo-rollouts/cmd/restart/restart.go b/pkg/kubectl-argo-rollouts/cmd/restart/restart.go index 1438360da1..c99ac12009 100644 --- a/pkg/kubectl-argo-rollouts/cmd/restart/restart.go +++ b/pkg/kubectl-argo-rollouts/cmd/restart/restart.go @@ -12,6 +12,7 @@ import ( "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" clientset "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned/typed/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/options" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) const ( @@ -70,7 +71,7 @@ func NewCmdRestart(o *options.ArgoRolloutsOptions) *cobra.Command { func RestartRollout(rolloutIf clientset.RolloutInterface, name string, restartAt *time.Time) (*v1alpha1.Rollout, error) { ctx := context.TODO() if restartAt == nil { - t := time.Now().UTC() + t := timeutil.Now().UTC() restartAt = &t } patch := fmt.Sprintf(restartPatch, restartAt.Format(time.RFC3339)) diff --git a/pkg/kubectl-argo-rollouts/info/info.go b/pkg/kubectl-argo-rollouts/info/info.go index 01fd1ebb5c..bbc65c289b 100644 --- a/pkg/kubectl-argo-rollouts/info/info.go +++ b/pkg/kubectl-argo-rollouts/info/info.go @@ -10,6 +10,7 @@ import ( "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/annotations" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) const ( @@ -38,7 +39,7 @@ type ImageInfo struct { } func Age(m v1.ObjectMeta) string { - return duration.HumanDuration(metav1.Now().Sub(m.CreationTimestamp.Time)) + return duration.HumanDuration(timeutil.MetaNow().Sub(m.CreationTimestamp.Time)) } func ownerRef(ownerRefs []metav1.OwnerReference, uids []types.UID) *metav1.OwnerReference { diff --git a/pkg/kubectl-argo-rollouts/info/info_test.go b/pkg/kubectl-argo-rollouts/info/info_test.go index 6e61680565..45c3bac921 100644 --- a/pkg/kubectl-argo-rollouts/info/info_test.go +++ b/pkg/kubectl-argo-rollouts/info/info_test.go @@ -9,6 +9,7 @@ import ( "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/info/testdata" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) func TestAge(t *testing.T) { @@ -63,7 +64,7 @@ func TestBlueGreenRolloutInfo(t *testing.T) { } { rolloutObjs := testdata.NewBlueGreenRollout() - inFourHours := metav1.Now().Add(4 * time.Hour).Truncate(time.Second).UTC().Format(time.RFC3339) + inFourHours := timeutil.Now().Add(4 * time.Hour).Truncate(time.Second).UTC().Format(time.RFC3339) rolloutObjs.ReplicaSets[0].Annotations[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey] = inFourHours delayedRs := rolloutObjs.ReplicaSets[0].ObjectMeta.UID roInfo := NewRolloutInfo(rolloutObjs.Rollouts[0], rolloutObjs.ReplicaSets, rolloutObjs.Pods, rolloutObjs.Experiments, rolloutObjs.AnalysisRuns) diff --git a/pkg/kubectl-argo-rollouts/info/replicaset_info.go b/pkg/kubectl-argo-rollouts/info/replicaset_info.go index 44f148f0b5..ade7b287dc 100644 --- a/pkg/kubectl-argo-rollouts/info/replicaset_info.go +++ b/pkg/kubectl-argo-rollouts/info/replicaset_info.go @@ -4,17 +4,16 @@ import ( "sort" "time" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/duration" "github.com/argoproj/argo-rollouts/pkg/apiclient/rollout" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" replicasetutil "github.com/argoproj/argo-rollouts/utils/replicaset" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) func GetReplicaSetInfo(ownerUID types.UID, ro *v1alpha1.Rollout, allReplicaSets []*appsv1.ReplicaSet, allPods []*corev1.Pod) []*rollout.ReplicaSetInfo { @@ -121,7 +120,7 @@ func getReplicaSetCondition(status appsv1.ReplicaSetStatus, condType appsv1.Repl func ScaleDownDelay(rs rollout.ReplicaSetInfo) string { if deadline, err := time.Parse(time.RFC3339, rs.ScaleDownDeadline); err == nil { - now := metav1.Now().Time + now := timeutil.MetaNow().Time if deadline.Before(now) { return "passed" } diff --git a/rollout/analysis_test.go b/rollout/analysis_test.go index 2678c26b1a..61ce7d6991 100644 --- a/rollout/analysis_test.go +++ b/rollout/analysis_test.go @@ -8,6 +8,8 @@ import ( "testing" "time" + timeutil "github.com/argoproj/argo-rollouts/utils/time" + "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -977,7 +979,7 @@ func TestDeleteAnalysisRunsAfterRSDelete(t *testing.T) { arToDelete.Spec.Terminate = true arAlreadyDeleted := arToDelete.DeepCopy() arAlreadyDeleted.Name = "already-deleted-analysis-run" - now := metav1.Now() + now := timeutil.MetaNow() arAlreadyDeleted.DeletionTimestamp = &now r3 = updateCanaryRolloutStatus(r3, rs2PodHash, 1, 0, 1, false) @@ -1100,7 +1102,7 @@ func TestPausedOnInconclusiveBackgroundAnalysisRun(t *testing.T) { patchIndex := f.expectPatchRolloutAction(r2) f.run(getKey(r2, t)) patch := f.getPatchedRollout(patchIndex) - now := metav1.Now().UTC().Format(time.RFC3339) + now := timeutil.MetaNow().UTC().Format(time.RFC3339) expectedPatch := `{ "status": { "conditions": %s, @@ -1164,7 +1166,7 @@ func TestPausedStepAfterInconclusiveAnalysisRun(t *testing.T) { patchIndex := f.expectPatchRolloutAction(r2) f.run(getKey(r2, t)) patch := f.getPatchedRollout(patchIndex) - now := metav1.Now().UTC().Format(time.RFC3339) + now := timeutil.MetaNow().UTC().Format(time.RFC3339) expectedPatch := `{ "status": { "conditions": %s, @@ -1246,7 +1248,7 @@ func TestErrorConditionAfterErrorAnalysisRunStep(t *testing.T) { "message": "RolloutAborted: %s" } }` - now := metav1.Now().UTC().Format(time.RFC3339) + now := timeutil.MetaNow().UTC().Format(time.RFC3339) errmsg := fmt.Sprintf(conditions.RolloutAbortedMessage, 2) + ": " + ar.Status.Message condition := generateConditionsPatch(true, conditions.RolloutAbortedReason, r2, false, errmsg) expectedPatch = fmt.Sprintf(expectedPatch, condition, now, errmsg) @@ -1325,7 +1327,7 @@ func TestErrorConditionAfterErrorAnalysisRunBackground(t *testing.T) { errmsg := fmt.Sprintf(conditions.RolloutAbortedMessage, 2) condition := generateConditionsPatch(true, conditions.RolloutAbortedReason, r2, false, "") - now := metav1.Now().UTC().Format(time.RFC3339) + now := timeutil.Now().UTC().Format(time.RFC3339) assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, condition, now, errmsg)), patch) } @@ -1386,7 +1388,7 @@ func TestCancelAnalysisRunsWhenAborted(t *testing.T) { } }` errmsg := fmt.Sprintf(conditions.RolloutAbortedMessage, 2) - now := metav1.Now().UTC().Format(time.RFC3339) + now := timeutil.Now().UTC().Format(time.RFC3339) assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, newConditions, now, errmsg)), patch) } @@ -1465,7 +1467,7 @@ func TestDoNotCreateBackgroundAnalysisRunAfterInconclusiveRun(t *testing.T) { r2.Status.PauseConditions = []v1alpha1.PauseCondition{{ Reason: v1alpha1.PauseReasonInconclusiveAnalysis, - StartTime: metav1.Now(), + StartTime: timeutil.MetaNow(), }} r2 = updateCanaryRolloutStatus(r2, rs1PodHash, 1, 0, 1, false) @@ -1781,7 +1783,7 @@ func TestRolloutPrePromotionAnalysisBecomesInconclusive(t *testing.T) { patchIndex := f.expectPatchRolloutActionWithPatch(r2, OnlyObservedGenerationPatch) f.run(getKey(r2, t)) patch := f.getPatchedRollout(patchIndex) - now := metav1.Now().UTC().Format(time.RFC3339) + now := timeutil.MetaNow().UTC().Format(time.RFC3339) expectedPatch := fmt.Sprintf(`{ "status": { "pauseConditions":[ @@ -1894,7 +1896,7 @@ func TestRolloutPrePromotionAnalysisHonorAutoPromotionSeconds(t *testing.T) { rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] r2 = updateBlueGreenRolloutStatus(r2, "", rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true) - now := metav1.NewTime(metav1.Now().Add(-10 * time.Second)) + now := metav1.NewTime(timeutil.MetaNow().Add(-10 * time.Second)) r2.Status.PauseConditions[0].StartTime = now progressingCondition, _ := newProgressingCondition(conditions.RolloutPausedReason, r2, "") conditions.SetRolloutCondition(&r2.Status, progressingCondition) @@ -1959,7 +1961,7 @@ func TestRolloutPrePromotionAnalysisDoNothingOnInconclusiveAnalysis(t *testing.T r2 = updateBlueGreenRolloutStatus(r2, "", rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true) inconclusivePauseCondition := v1alpha1.PauseCondition{ Reason: v1alpha1.PauseReasonInconclusiveAnalysis, - StartTime: metav1.Now(), + StartTime: timeutil.MetaNow(), } r2.Status.PauseConditions = append(r2.Status.PauseConditions, inconclusivePauseCondition) r2.Status.ObservedGeneration = strconv.Itoa(int(r2.Generation)) @@ -2049,7 +2051,7 @@ func TestAbortRolloutOnErrorPrePromotionAnalysis(t *testing.T) { "message": "%s: %s" } }` - now := metav1.Now().UTC().Format(time.RFC3339) + now := timeutil.MetaNow().UTC().Format(time.RFC3339) progressingFalseAborted, _ := newProgressingCondition(conditions.RolloutAbortedReason, r2, "") newConditions := updateConditionsPatch(*r2, progressingFalseAborted) assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, now, newConditions, conditions.RolloutAbortedReason, progressingFalseAborted.Message)), patch) @@ -2183,7 +2185,7 @@ func TestPostPromotionAnalysisRunHandleInconclusive(t *testing.T) { r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs1PodHash, 1, 1, 2, 1, false, true) r2.Status.PauseConditions = []v1alpha1.PauseCondition{{ Reason: v1alpha1.PauseReasonInconclusiveAnalysis, - StartTime: metav1.Now(), + StartTime: timeutil.MetaNow(), }} progressingCondition, _ := newProgressingCondition(conditions.RolloutPausedReason, r2, "") conditions.SetRolloutCondition(&r2.Status, progressingCondition) @@ -2278,7 +2280,7 @@ func TestAbortRolloutOnErrorPostPromotionAnalysis(t *testing.T) { "message": "%s: %s" } }` - now := metav1.Now().UTC().Format(time.RFC3339) + now := timeutil.MetaNow().UTC().Format(time.RFC3339) progressingFalseAborted, _ := newProgressingCondition(conditions.RolloutAbortedReason, r2, "") newConditions := updateConditionsPatch(*r2, progressingFalseAborted) assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, now, newConditions, conditions.RolloutAbortedReason, progressingFalseAborted.Message)), patch) diff --git a/rollout/bluegreen_test.go b/rollout/bluegreen_test.go index ea81faa88a..5bd965df61 100644 --- a/rollout/bluegreen_test.go +++ b/rollout/bluegreen_test.go @@ -18,6 +18,7 @@ import ( "github.com/argoproj/argo-rollouts/utils/annotations" "github.com/argoproj/argo-rollouts/utils/conditions" rolloututil "github.com/argoproj/argo-rollouts/utils/rollout" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) var ( @@ -330,7 +331,7 @@ func TestBlueGreenHandlePause(t *testing.T) { "message": "BlueGreenPause" } }` - now := metav1.Now().UTC().Format(time.RFC3339) + now := timeutil.Now().UTC().Format(time.RFC3339) assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, v1alpha1.PauseReasonBlueGreenPause, now)), patch) }) @@ -433,7 +434,7 @@ func TestBlueGreenHandlePause(t *testing.T) { rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, false, true) - now := metav1.Now() + now := timeutil.MetaNow() r2.Status.PauseConditions = append(r2.Status.PauseConditions, v1alpha1.PauseCondition{ Reason: v1alpha1.PauseReasonInconclusiveAnalysis, StartTime: now, @@ -517,7 +518,7 @@ func TestBlueGreenHandlePause(t *testing.T) { rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true) - now := metav1.Now() + now := timeutil.MetaNow() before := metav1.NewTime(now.Add(-1 * time.Minute)) r2.Status.PauseConditions[0].StartTime = before r2.Status.ControllerPause = true @@ -575,7 +576,7 @@ func TestBlueGreenHandlePause(t *testing.T) { rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true) - now := metav1.Now() + now := timeutil.MetaNow() before := metav1.NewTime(now.Add(-1 * time.Minute)) r2.Status.PauseConditions[0].StartTime = before r2.Status.ControllerPause = true @@ -682,7 +683,7 @@ func TestBlueGreenHandlePause(t *testing.T) { f.replicaSetLister = append(f.replicaSetLister, rs1, rs2) f.serviceLister = append(f.serviceLister, activeSvc) - now := metav1.Now().UTC().Format(time.RFC3339) + now := timeutil.MetaNow().UTC().Format(time.RFC3339) expectedPatchWithoutSubs := `{ "status": { "pauseConditions": [{ @@ -1247,7 +1248,7 @@ func TestBlueGreenNotReadyToScaleDownOldReplica(t *testing.T) { rs2 := newReplicaSetWithStatus(r2, 1, 1) rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - inTheFuture := metav1.Now().Add(10 * time.Second).UTC().Format(time.RFC3339) + inTheFuture := timeutil.Now().Add(10 * time.Second).UTC().Format(time.RFC3339) rs1.Annotations[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey] = inTheFuture @@ -1280,7 +1281,7 @@ func TestBlueGreenReadyToScaleDownOldReplica(t *testing.T) { rs2 := newReplicaSetWithStatus(r2, 1, 1) rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - inThePast := metav1.Now().Add(-10 * time.Second).UTC().Format(time.RFC3339) + inThePast := timeutil.Now().Add(-10 * time.Second).UTC().Format(time.RFC3339) rs1.Annotations[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey] = inThePast @@ -1319,7 +1320,7 @@ func TestFastRollback(t *testing.T) { rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] //Setting the scaleDownAt time - inTheFuture := metav1.Now().Add(10 * time.Second).UTC().Format(time.RFC3339) + inTheFuture := timeutil.Now().Add(10 * time.Second).UTC().Format(time.RFC3339) rs1.Annotations[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey] = inTheFuture rs2.Annotations[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey] = inTheFuture @@ -1363,7 +1364,7 @@ func TestBlueGreenScaleDownLimit(t *testing.T) { rs3PodHash := rs3.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] //Setting the scaleDownAt time - inTheFuture := metav1.Now().Add(10 * time.Second).UTC().Format(time.RFC3339) + inTheFuture := timeutil.MetaNow().Add(10 * time.Second).UTC().Format(time.RFC3339) rs1.Annotations[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey] = inTheFuture rs2.Annotations[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey] = inTheFuture @@ -1398,7 +1399,7 @@ func TestBlueGreenAbort(t *testing.T) { r1 := newBlueGreenRollout("foo", 1, nil, "bar", "") r2 := bumpVersion(r1) r2.Status.Abort = true - now := metav1.Now() + now := timeutil.MetaNow() r2.Status.AbortedAt = &now rs1 := newReplicaSetWithStatus(r1, 1, 1) @@ -1449,7 +1450,7 @@ func TestBlueGreenHandlePauseAutoPromoteWithConditions(t *testing.T) { rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true) - now := metav1.Now() + now := timeutil.MetaNow() before := metav1.NewTime(now.Add(-1 * time.Minute)) r2.Status.PauseConditions[0].StartTime = before r2.Status.ControllerPause = true diff --git a/rollout/canary_test.go b/rollout/canary_test.go index 60cf79f49e..6ec62ba50d 100644 --- a/rollout/canary_test.go +++ b/rollout/canary_test.go @@ -25,6 +25,7 @@ import ( logutil "github.com/argoproj/argo-rollouts/utils/log" "github.com/argoproj/argo-rollouts/utils/record" rolloututil "github.com/argoproj/argo-rollouts/utils/rollout" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) func newCanaryRollout(name string, replicas int, revisionHistoryLimit *int32, steps []v1alpha1.CanaryStep, stepIndex *int32, maxSurge, maxUnavailable intstr.IntOrString) *v1alpha1.Rollout { @@ -177,7 +178,7 @@ func TestCanaryRolloutEnterPauseState(t *testing.T) { }` conditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "") - now := metav1.Now().UTC().Format(time.RFC3339) + now := timeutil.MetaNow().UTC().Format(time.RFC3339) expectedPatchWithoutObservedGen := fmt.Sprintf(expectedPatchTemplate, v1alpha1.PauseReasonCanaryPauseStep, now, conditions, v1alpha1.PauseReasonCanaryPauseStep) expectedPatch := calculatePatch(r2, expectedPatchWithoutObservedGen) assert.Equal(t, expectedPatch, patch) @@ -1089,7 +1090,7 @@ func TestSyncRolloutWaitIncrementStepIndex(t *testing.T) { pausedCondition, _ := newPausedCondition(true) conditions.SetRolloutCondition(&r2.Status, pausedCondition) - earlier := metav1.Now() + earlier := timeutil.MetaNow() earlier.Time = earlier.Add(-10 * time.Second) r2.Status.ControllerPause = true r2.Status.PauseConditions = []v1alpha1.PauseCondition{{ @@ -1560,7 +1561,7 @@ func TestHandleCanaryAbort(t *testing.T) { r2 = updateCanaryRolloutStatus(r2, rs1PodHash, 10, 1, 10, false) r2.Status.Abort = true - now := metav1.Now() + now := timeutil.MetaNow() r2.Status.AbortedAt = &now f.rolloutLister = append(f.rolloutLister, r2) f.objects = append(f.objects, r2) @@ -1597,7 +1598,7 @@ func TestHandleCanaryAbort(t *testing.T) { } r1 := newCanaryRollout("foo", 2, nil, steps, int32Ptr(3), intstr.FromInt(1), intstr.FromInt(0)) r1.Status.Abort = true - now := metav1.Now() + now := timeutil.MetaNow() r1.Status.AbortedAt = &now rs1 := newReplicaSetWithStatus(r1, 2, 2) rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] diff --git a/rollout/controller.go b/rollout/controller.go index 6b02621f9a..46ca2e1099 100644 --- a/rollout/controller.go +++ b/rollout/controller.go @@ -52,6 +52,7 @@ import ( "github.com/argoproj/argo-rollouts/utils/record" replicasetutil "github.com/argoproj/argo-rollouts/utils/replicaset" serviceutil "github.com/argoproj/argo-rollouts/utils/service" + timeutil "github.com/argoproj/argo-rollouts/utils/time" unstructuredutil "github.com/argoproj/argo-rollouts/utils/unstructured" ) @@ -341,7 +342,7 @@ func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error { // with the current status of the resource. func (c *Controller) syncHandler(key string) error { ctx := context.TODO() - startTime := time.Now() + startTime := timeutil.Now() namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { return err diff --git a/rollout/controller_test.go b/rollout/controller_test.go index 7d545d4e79..32ce3b269c 100644 --- a/rollout/controller_test.go +++ b/rollout/controller_test.go @@ -13,7 +13,6 @@ import ( "github.com/ghodss/yaml" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" - "github.com/undefinedlabs/go-mpatch" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" extensionsv1beta1 "k8s.io/api/extensions/v1beta1" @@ -54,6 +53,7 @@ import ( "github.com/argoproj/argo-rollouts/utils/record" replicasetutil "github.com/argoproj/argo-rollouts/utils/replicaset" rolloututil "github.com/argoproj/argo-rollouts/utils/rollout" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) var ( @@ -115,9 +115,11 @@ func newFixture(t *testing.T) *fixture { f.kubeobjects = []runtime.Object{} f.enqueuedObjects = make(map[string]int) now := time.Now() - patch, err := mpatch.PatchMethod(time.Now, func() time.Time { return now }) - assert.NoError(t, err) - f.unfreezeTime = patch.Unpatch + timeutil.Now = func() time.Time { return now } + f.unfreezeTime = func() error { + timeutil.Now = time.Now + return nil + } f.fakeTrafficRouting = newFakeTrafficRoutingReconciler() f.fakeSingleTrafficRouting = newFakeSingleTrafficRoutingReconciler() @@ -178,8 +180,8 @@ func newPausedCondition(isPaused bool) (v1alpha1.RolloutCondition, string) { status = corev1.ConditionFalse } condition := v1alpha1.RolloutCondition{ - LastTransitionTime: metav1.Now(), - LastUpdateTime: metav1.Now(), + LastTransitionTime: timeutil.MetaNow(), + LastUpdateTime: timeutil.MetaNow(), Message: conditions.RolloutPausedMessage, Reason: conditions.RolloutPausedReason, Status: status, @@ -198,8 +200,8 @@ func newCompletedCondition(isCompleted bool) (v1alpha1.RolloutCondition, string) status = corev1.ConditionFalse } condition := v1alpha1.RolloutCondition{ - LastTransitionTime: metav1.Now(), - LastUpdateTime: metav1.Now(), + LastTransitionTime: timeutil.MetaNow(), + LastUpdateTime: timeutil.MetaNow(), Message: conditions.RolloutCompletedReason, Reason: conditions.RolloutCompletedReason, Status: status, @@ -279,8 +281,8 @@ func newProgressingCondition(reason string, resourceObj runtime.Object, optional } condition := v1alpha1.RolloutCondition{ - LastTransitionTime: metav1.Now(), - LastUpdateTime: metav1.Now(), + LastTransitionTime: timeutil.MetaNow(), + LastUpdateTime: timeutil.MetaNow(), Message: msg, Reason: reason, Status: status, @@ -303,8 +305,8 @@ func newAvailableCondition(available bool) (v1alpha1.RolloutCondition, string) { } condition := v1alpha1.RolloutCondition{ - LastTransitionTime: metav1.Now(), - LastUpdateTime: metav1.Now(), + LastTransitionTime: timeutil.MetaNow(), + LastUpdateTime: timeutil.MetaNow(), Message: message, Reason: conditions.AvailableReason, Status: status, @@ -363,7 +365,7 @@ func updateBlueGreenRolloutStatus(r *v1alpha1.Rollout, preview, active, stable s cond, _ := newAvailableCondition(available) newRollout.Status.Conditions = append(newRollout.Status.Conditions, cond) if pause { - now := metav1.Now() + now := timeutil.MetaNow() cond := v1alpha1.PauseCondition{ Reason: v1alpha1.PauseReasonBlueGreenPause, StartTime: now, @@ -895,7 +897,7 @@ func (f *fixture) verifyPatchedReplicaSet(index int, scaleDownDelaySeconds int32 if !ok { assert.Fail(f.t, "Expected Patch action, not %s", action.GetVerb()) } - now := metav1.Now().Add(time.Duration(scaleDownDelaySeconds) * time.Second).UTC().Format(time.RFC3339) + now := timeutil.Now().Add(time.Duration(scaleDownDelaySeconds) * time.Second).UTC().Format(time.RFC3339) patch := fmt.Sprintf(addScaleDownAtAnnotationsPatch, v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey, now) assert.Equal(f.t, string(patchAction.GetPatch()), patch) } @@ -1177,7 +1179,7 @@ func TestRequeueStuckRollout(t *testing.T) { if progressingConditionReason != "" { lastUpdated := metav1.Time{ - Time: metav1.Now().Add(-10 * time.Second), + Time: timeutil.MetaNow().Add(-10 * time.Second), } r.Status.Conditions = []v1alpha1.RolloutCondition{{ Type: v1alpha1.RolloutProgressing, @@ -1501,8 +1503,8 @@ func newInvalidSpecCondition(reason string, resourceObj runtime.Object, optional } condition := v1alpha1.RolloutCondition{ - LastTransitionTime: metav1.Now(), - LastUpdateTime: metav1.Now(), + LastTransitionTime: timeutil.MetaNow(), + LastUpdateTime: timeutil.MetaNow(), Message: msg, Reason: reason, Status: status, diff --git a/rollout/pause.go b/rollout/pause.go index c3ee87aa3a..25ae24c3ba 100644 --- a/rollout/pause.go +++ b/rollout/pause.go @@ -7,6 +7,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) type pauseContext struct { @@ -56,7 +57,7 @@ func (pCtx *pauseContext) ClearPauseConditions() { } func (pCtx *pauseContext) CalculatePauseStatus(newStatus *v1alpha1.RolloutStatus) { - now := metav1.Now() + now := timeutil.MetaNow() // if we are already aborted, preserve the original timestamp, otherwise we'll cause a // reconciliation hot-loop. newAbortedAt := pCtx.rollout.Status.AbortedAt @@ -163,7 +164,7 @@ func (pCtx *pauseContext) CompletedBlueGreenPause() bool { } if pauseCond != nil { switchDeadline := pauseCond.StartTime.Add(time.Duration(autoPromotionSeconds) * time.Second) - now := metav1.Now() + now := timeutil.MetaNow() if now.After(switchDeadline) { return true } @@ -189,7 +190,7 @@ func (pCtx *pauseContext) CompletedCanaryPauseStep(pause v1alpha1.RolloutPause) pCtx.log.Info("Rollout has been unpaused") return true } else if pause.Duration != nil { - now := metav1.Now() + now := timeutil.MetaNow() if pauseCondition != nil { expiredTime := pauseCondition.StartTime.Add(time.Duration(pause.DurationSeconds()) * time.Second) if now.After(expiredTime) { @@ -202,7 +203,7 @@ func (pCtx *pauseContext) CompletedCanaryPauseStep(pause v1alpha1.RolloutPause) } func (c *rolloutContext) checkEnqueueRolloutDuringWait(startTime metav1.Time, durationInSeconds int32) { - now := metav1.Now() + now := timeutil.MetaNow() expiredTime := startTime.Add(time.Duration(durationInSeconds) * time.Second) nextResync := now.Add(c.resyncPeriod) if nextResync.After(expiredTime) && expiredTime.After(now.Time) { diff --git a/rollout/replicaset.go b/rollout/replicaset.go index 71b6682f9c..8a39e657ef 100644 --- a/rollout/replicaset.go +++ b/rollout/replicaset.go @@ -15,6 +15,7 @@ import ( "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/defaults" replicasetutil "github.com/argoproj/argo-rollouts/utils/replicaset" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) var controllerKind = v1alpha1.SchemeGroupVersion.WithKind("Rollout") @@ -53,7 +54,7 @@ func (c *rolloutContext) addScaleDownDelay(rs *appsv1.ReplicaSet, scaleDownDelay } return nil } - deadline := metav1.Now().Add(scaleDownDelaySeconds).UTC().Format(time.RFC3339) + deadline := timeutil.MetaNow().Add(scaleDownDelaySeconds).UTC().Format(time.RFC3339) patch := fmt.Sprintf(addScaleDownAtAnnotationsPatch, v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey, deadline) _, err := c.kubeclientset.AppsV1().ReplicaSets(rs.Namespace).Patch(ctx, rs.Name, patchtypes.JSONPatchType, []byte(patch), metav1.PatchOptions{}) if err == nil { @@ -131,7 +132,7 @@ func (c *rolloutContext) reconcileNewReplicaSet() (bool, error) { if err != nil { c.log.Warnf("Unable to read scaleDownAt label on rs '%s'", c.newRS.Name) } else { - now := metav1.Now() + now := timeutil.MetaNow() scaleDownAt := metav1.NewTime(scaleDownAtTime) if scaleDownAt.After(now.Time) { c.log.Infof("RS '%s' has not reached the scaleDownTime", c.newRS.Name) diff --git a/rollout/replicaset_test.go b/rollout/replicaset_test.go index 89bf020f32..b1588ff4ce 100644 --- a/rollout/replicaset_test.go +++ b/rollout/replicaset_test.go @@ -17,6 +17,7 @@ import ( "github.com/argoproj/argo-rollouts/utils/annotations" logutil "github.com/argoproj/argo-rollouts/utils/log" "github.com/argoproj/argo-rollouts/utils/record" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) func newRolloutControllerRef(r *v1alpha1.Rollout) *metav1.OwnerReference { @@ -221,9 +222,9 @@ func TestReconcileNewReplicaSet(t *testing.T) { if test.abortScaleDownAnnotated { var deadline string if test.abortScaleDownDelayPassed { - deadline = metav1.Now().Add(-time.Duration(test.abortScaleDownDelaySeconds) * time.Second).UTC().Format(time.RFC3339) + deadline = timeutil.Now().Add(-time.Duration(test.abortScaleDownDelaySeconds) * time.Second).UTC().Format(time.RFC3339) } else { - deadline = metav1.Now().Add(time.Duration(test.abortScaleDownDelaySeconds) * time.Second).UTC().Format(time.RFC3339) + deadline = timeutil.Now().Add(time.Duration(test.abortScaleDownDelaySeconds) * time.Second).UTC().Format(time.RFC3339) } roCtx.newRS.Annotations[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey] = deadline } diff --git a/rollout/restart.go b/rollout/restart.go index 51ebd13840..be8e49a9b9 100644 --- a/rollout/restart.go +++ b/rollout/restart.go @@ -18,6 +18,7 @@ import ( "github.com/argoproj/argo-rollouts/utils/defaults" "github.com/argoproj/argo-rollouts/utils/replicaset" replicasetutil "github.com/argoproj/argo-rollouts/utils/replicaset" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) const ( @@ -167,7 +168,7 @@ func (p *RolloutPodRestarter) getRolloutPods(ctx context.Context, ro *v1alpha1.R func getAvailablePodCount(pods []*corev1.Pod, minReadySeconds int32) int32 { var available int32 - now := metav1.Now() + now := timeutil.MetaNow() for _, pod := range pods { if podutil.IsPodAvailable(pod, minReadySeconds, now) && pod.DeletionTimestamp == nil { available += 1 diff --git a/rollout/service_test.go b/rollout/service_test.go index 7dda838271..c55be8ef7a 100644 --- a/rollout/service_test.go +++ b/rollout/service_test.go @@ -25,6 +25,7 @@ import ( "github.com/argoproj/argo-rollouts/utils/conditions" "github.com/argoproj/argo-rollouts/utils/defaults" ingressutil "github.com/argoproj/argo-rollouts/utils/ingress" + timeutil "github.com/argoproj/argo-rollouts/utils/time" unstructuredutil "github.com/argoproj/argo-rollouts/utils/unstructured" ) @@ -622,7 +623,7 @@ func TestCanaryAWSVerifyTargetGroupsSkip(t *testing.T) { rs1 := newReplicaSetWithStatus(r1, 3, 3) // set an annotation on old RS to cause verification to be skipped - rs1.Annotations[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey] = metav1.Now().Add(600 * time.Second).UTC().Format(time.RFC3339) + rs1.Annotations[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey] = timeutil.Now().Add(600 * time.Second).UTC().Format(time.RFC3339) rs2 := newReplicaSetWithStatus(r2, 3, 3) rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] diff --git a/rollout/sync_test.go b/rollout/sync_test.go index 2687d55fce..ca92ba1b35 100644 --- a/rollout/sync_test.go +++ b/rollout/sync_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -19,7 +20,7 @@ import ( "github.com/argoproj/argo-rollouts/utils/conditions" logutil "github.com/argoproj/argo-rollouts/utils/log" "github.com/argoproj/argo-rollouts/utils/record" - "github.com/stretchr/testify/assert" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) func rs(name string, replicas int, selector map[string]string, timestamp metav1.Time, ownerRef *metav1.OwnerReference) *appsv1.ReplicaSet { @@ -46,7 +47,7 @@ func rs(name string, replicas int, selector map[string]string, timestamp metav1. } func TestReconcileRevisionHistoryLimit(t *testing.T) { - now := metav1.Now() + now := timeutil.MetaNow() before := metav1.Time{Time: now.Add(-time.Minute)} newRS := func(name string) *appsv1.ReplicaSet { @@ -376,7 +377,7 @@ func TestBlueGreenPromoteFull(t *testing.T) { // TestSendStateChangeEvents verifies we emit appropriate events on rollout state changes func TestSendStateChangeEvents(t *testing.T) { - now := metav1.Now() + now := timeutil.MetaNow() tests := []struct { prevStatus v1alpha1.RolloutStatus newStatus v1alpha1.RolloutStatus diff --git a/rollout/trafficrouting_test.go b/rollout/trafficrouting_test.go index a7e83557ea..d825342f97 100644 --- a/rollout/trafficrouting_test.go +++ b/rollout/trafficrouting_test.go @@ -8,7 +8,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/client-go/dynamic/dynamicinformer" "k8s.io/client-go/dynamic/dynamiclister" @@ -24,6 +23,7 @@ import ( "github.com/argoproj/argo-rollouts/utils/conditions" istioutil "github.com/argoproj/argo-rollouts/utils/istio" logutil "github.com/argoproj/argo-rollouts/utils/log" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) // newFakeTrafficRoutingReconciler returns a fake TrafficRoutingReconciler with mocked success return values @@ -605,7 +605,7 @@ func TestCanaryWithTrafficRoutingScaleDownLimit(t *testing.T) { f := newFixture(t) defer f.Close() - inTheFuture := metav1.Now().Add(10 * time.Second).UTC().Format(time.RFC3339) + inTheFuture := timeutil.MetaNow().Add(10 * time.Second).UTC().Format(time.RFC3339) r1 := newCanaryRollout("foo", 1, nil, nil, pointer.Int32Ptr(1), intstr.FromInt(1), intstr.FromInt(1)) rs1 := newReplicaSetWithStatus(r1, 1, 1) diff --git a/utils/conditions/conditions.go b/utils/conditions/conditions.go index 4f4cf04004..d84bc9cb8e 100644 --- a/utils/conditions/conditions.go +++ b/utils/conditions/conditions.go @@ -9,12 +9,12 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/rand" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/defaults" logutil "github.com/argoproj/argo-rollouts/utils/log" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) const ( @@ -163,8 +163,8 @@ func NewRolloutCondition(condType v1alpha1.RolloutConditionType, status corev1.C return &v1alpha1.RolloutCondition{ Type: condType, Status: status, - LastUpdateTime: metav1.Now(), - LastTransitionTime: metav1.Now(), + LastUpdateTime: timeutil.MetaNow(), + LastTransitionTime: timeutil.MetaNow(), Reason: reason, Message: message, } @@ -322,7 +322,7 @@ func RolloutTimedOut(rollout *v1alpha1.Rollout, newStatus *v1alpha1.RolloutStatu // progress or tried to create a replica set, or resumed a paused rollout and // compare against progressDeadlineSeconds. from := condition.LastUpdateTime - now := time.Now() + now := timeutil.Now() progressDeadlineSeconds := defaults.GetProgressDeadlineSecondsOrDefault(rollout) delta := time.Duration(progressDeadlineSeconds) * time.Second diff --git a/utils/conditions/experiments.go b/utils/conditions/experiments.go index 4acb6b1bbd..e424c5df15 100644 --- a/utils/conditions/experiments.go +++ b/utils/conditions/experiments.go @@ -10,6 +10,7 @@ import ( "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/defaults" experimentutil "github.com/argoproj/argo-rollouts/utils/experiment" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) const ( @@ -39,8 +40,8 @@ func NewExperimentConditions(condType v1alpha1.ExperimentConditionType, status c return &v1alpha1.ExperimentCondition{ Type: condType, Status: status, - LastUpdateTime: metav1.Now(), - LastTransitionTime: metav1.Now(), + LastUpdateTime: timeutil.MetaNow(), + LastTransitionTime: timeutil.MetaNow(), Reason: reason, Message: message, } @@ -127,7 +128,7 @@ func ExperimentRunning(experiment *v1alpha1.Experiment) bool { func newInvalidSpecExperimentCondition(prevCond *v1alpha1.ExperimentCondition, reason string, message string) *v1alpha1.ExperimentCondition { if prevCond != nil && prevCond.Message == message { - prevCond.LastUpdateTime = metav1.Now() + prevCond.LastUpdateTime = timeutil.MetaNow() return prevCond } return NewExperimentConditions(v1alpha1.InvalidExperimentSpec, corev1.ConditionTrue, reason, message) diff --git a/utils/experiment/experiment.go b/utils/experiment/experiment.go index cf87d7e263..cf7b4b6344 100644 --- a/utils/experiment/experiment.go +++ b/utils/experiment/experiment.go @@ -13,6 +13,7 @@ import ( "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" rolloutsclient "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned/typed/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/defaults" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) var terminateExperimentPatch = []byte(`{"spec":{"terminate":true}}`) @@ -88,7 +89,7 @@ func PassedDurations(experiment *v1alpha1.Experiment) (bool, time.Duration) { if experiment.Status.AvailableAt == nil { return false, 0 } - now := metav1.Now() + now := timeutil.MetaNow() dur, err := experiment.Spec.Duration.Duration() if err != nil { return false, 0 diff --git a/utils/metric/metric.go b/utils/metric/metric.go index 4d9003164f..cab54161d3 100644 --- a/utils/metric/metric.go +++ b/utils/metric/metric.go @@ -1,9 +1,8 @@ package metric import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) // MarkMeasurementError sets an error message on a measurement along with finish time @@ -11,7 +10,7 @@ func MarkMeasurementError(m v1alpha1.Measurement, err error) v1alpha1.Measuremen m.Phase = v1alpha1.AnalysisPhaseError m.Message = err.Error() if m.FinishedAt == nil { - finishedTime := metav1.Now() + finishedTime := timeutil.MetaNow() m.FinishedAt = &finishedTime } return m diff --git a/utils/replicaset/replicaset.go b/utils/replicaset/replicaset.go index 04134b2450..ce72d90e56 100644 --- a/utils/replicaset/replicaset.go +++ b/utils/replicaset/replicaset.go @@ -25,6 +25,7 @@ import ( "github.com/argoproj/argo-rollouts/utils/conditions" "github.com/argoproj/argo-rollouts/utils/defaults" logutil "github.com/argoproj/argo-rollouts/utils/log" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) // FindNewReplicaSet returns the new RS this given rollout targets from the given list. @@ -204,7 +205,7 @@ func IfInjectedAntiAffinityRuleNeedsUpdate(affinity *corev1.Affinity, rollout v1 } func NeedsRestart(rollout *v1alpha1.Rollout) bool { - now := metav1.Now().UTC() + now := timeutil.MetaNow().UTC() if rollout.Spec.RestartAt == nil { return false } @@ -594,7 +595,7 @@ func GetTimeRemainingBeforeScaleDownDeadline(rs *appsv1.ReplicaSet) (*time.Durat if err != nil { return nil, fmt.Errorf("unable to read scaleDownAt label on rs '%s'", rs.Name) } - now := metav1.Now() + now := timeutil.MetaNow() scaleDownAt := metav1.NewTime(scaleDownAtTime) if scaleDownAt.After(now.Time) { remainingTime := scaleDownAt.Sub(now.Time) diff --git a/utils/replicaset/replicaset_test.go b/utils/replicaset/replicaset_test.go index 4e3f3809e4..89c1933d9f 100644 --- a/utils/replicaset/replicaset_test.go +++ b/utils/replicaset/replicaset_test.go @@ -23,6 +23,7 @@ import ( "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/annotations" "github.com/argoproj/argo-rollouts/utils/conditions" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) // generateRollout creates a rollout, with the input image as its template @@ -1184,13 +1185,13 @@ func TestGetTimeRemainingBeforeScaleDownDeadline(t *testing.T) { assert.Nil(t, remainingTime) } { - rs.ObjectMeta.Annotations = map[string]string{v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey: metav1.Now().Add(-600 * time.Second).UTC().Format(time.RFC3339)} + rs.ObjectMeta.Annotations = map[string]string{v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey: timeutil.Now().Add(-600 * time.Second).UTC().Format(time.RFC3339)} remainingTime, err := GetTimeRemainingBeforeScaleDownDeadline(&rs) assert.Nil(t, err) assert.Nil(t, remainingTime) } { - rs.ObjectMeta.Annotations = map[string]string{v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey: metav1.Now().Add(600 * time.Second).UTC().Format(time.RFC3339)} + rs.ObjectMeta.Annotations = map[string]string{v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey: timeutil.Now().Add(600 * time.Second).UTC().Format(time.RFC3339)} remainingTime, err := GetTimeRemainingBeforeScaleDownDeadline(&rs) assert.Nil(t, err) assert.NotNil(t, remainingTime) diff --git a/utils/time/now.go b/utils/time/now.go new file mode 100644 index 0000000000..4103857811 --- /dev/null +++ b/utils/time/now.go @@ -0,0 +1,15 @@ +package time + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// Now is a wrapper around time.Now() and used to override behavior in tests. +var Now = time.Now + +// MetaNow is a wrapper around metav1.Now() and used to override behavior in tests. +var MetaNow = func() metav1.Time { + return metav1.Time{Time: Now()} +} From 3c1e87c95cf8734f2eded8f6457f07e80ea4cc46 Mon Sep 17 00:00:00 2001 From: Alexander Matyushentsev Date: Mon, 13 Dec 2021 13:59:22 -0800 Subject: [PATCH 017/175] chore: fix flaky TestAbortRolloutAfterFailedExperiment test (#1710) Signed-off-by: Alexander Matyushentsev --- rollout/experiment_test.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/rollout/experiment_test.go b/rollout/experiment_test.go index 6ba0ca43b0..6c96080c3b 100644 --- a/rollout/experiment_test.go +++ b/rollout/experiment_test.go @@ -5,14 +5,15 @@ import ( "testing" "time" - "k8s.io/apimachinery/pkg/util/uuid" - - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" - "github.com/argoproj/argo-rollouts/utils/conditions" "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/apimachinery/pkg/util/uuid" "k8s.io/utils/pointer" + + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + "github.com/argoproj/argo-rollouts/utils/conditions" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) func TestRolloutCreateExperiment(t *testing.T) { @@ -308,7 +309,7 @@ func TestAbortRolloutAfterFailedExperiment(t *testing.T) { "message": "%s: %s" } }` - now := metav1.Now().UTC().Format(time.RFC3339) + now := timeutil.Now().UTC().Format(time.RFC3339) generatedConditions := generateConditionsPatch(true, conditions.RolloutAbortedReason, r2, false, "") assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, now, generatedConditions, conditions.RolloutAbortedReason, fmt.Sprintf(conditions.RolloutAbortedMessage, 2))), patch) } From 5e188f94ac5f678d27774249100078d88c8225ee Mon Sep 17 00:00:00 2001 From: Sebastian J Date: Mon, 13 Dec 2021 23:54:57 -0500 Subject: [PATCH 018/175] fix(controller): Sticky session correction for AWS ALB. Fixes #1572 (#1577) * fix: use patch to update workload-generation annotation Signed-off-by: Alexander Matyushentsev * Add support for AWS ALB TargetGroupStickinessConfig Adds support for AWS ALB [TargetGroupStickinessConfig](https://aws.amazon.com/blogs/aws/new-application-load-balancer-simplifies-deployment-with-weighted-target-groups/) This is required to support sticky session on the listener level while Argo is using ALB's weighting Signed-off-by: Sebastian J * Remove code smells Signed-off-by: Sebastian J * more code smells Signed-off-by: Sebastian J * PR feedback Signed-off-by: Sebastian J * Revert Signed-off-by: Sebastian J * Another test round Signed-off-by: Sebastian J * Force codegen GO 1.16 Forced codegen via downgrading to Go 1.16: ``` $ env|grep GO GOPATH=/Users/sebastian/go ``` ``` $ go version go version go1.16.10 darwin/amd64 ``` ``` $ echo $PATH /Users/sebastian/.sdkman/candidates/micronaut/current/bin:/Users/sebastian/.sdkman/candidates/java/current/bin:/Users/sebastian/.cargo/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/TeX/texbin:/usr/local/MacGPG2/bin:/usr/local/share/dotnet:/Library/Frameworks/Mono.framework/Versions/Current/Commands:/bin:/Users/sebastian/go/bin ``` Signed-off-by: Sebastian J * Added documentaiton Signed-off-by: Sebastian J Co-authored-by: Alexander Matyushentsev --- docs/features/traffic-management/alb.md | 46 +- ingress/alb.go | 8 + ingress/alb_test.go | 62 +- manifests/crds/rollout-crd.yaml | 11 + manifests/install.yaml | 11 + manifests/namespace-install.yaml | 11 + pkg/apiclient/rollout/rollout.swagger.json | 16 + pkg/apis/rollouts/v1alpha1/generated.pb.go | 1724 ++++++++++++----- pkg/apis/rollouts/v1alpha1/generated.proto | 35 +- .../rollouts/v1alpha1/openapi_generated.go | 120 +- pkg/apis/rollouts/v1alpha1/types.go | 8 + .../v1alpha1/zz_generated.deepcopy.go | 23 +- rollout/trafficrouting/alb/alb.go | 25 +- rollout/trafficrouting/alb/alb_test.go | 135 +- utils/ingress/ingress.go | 9 +- 15 files changed, 1698 insertions(+), 546 deletions(-) diff --git a/docs/features/traffic-management/alb.md b/docs/features/traffic-management/alb.md index b315514c30..7f84bb1570 100644 --- a/docs/features/traffic-management/alb.md +++ b/docs/features/traffic-management/alb.md @@ -5,7 +5,7 @@ ## Overview -[AWS Load Balancer Controller](https://github.com/kubernetes-sigs/aws-load-balancer-controller) +[AWS Load Balancer Controller](https://github.com/kubernetes-sigs/aws-load-balancer-controller) (also known as AWS ALB Ingress Controller) enables traffic management through an Ingress object, which configures an AWS Application Load Balancer (ALB) to route traffic to one or more Kubernetes services. ALBs provides advanced traffic splitting capability through the concept of @@ -31,7 +31,7 @@ the desired traffic weights. ## Usage -To configure a Rollout to use the ALB integration and split traffic between the canary and stable +To configure a Rollout to use the ALB integration and split traffic between the canary and stable services during updates, the Rollout should be configured with the following fields: ```yaml @@ -83,9 +83,9 @@ spec: During an update, the rollout controller injects the `alb.ingress.kubernetes.io/actions.` annotation, containing a JSON payload understood by the AWS Load Balancer Controller, directing it -to split traffic between the `canaryService` and `stableService` according to the current canary weight. +to split traffic between the `canaryService` and `stableService` according to the current canary weight. -The following is an example of our example Ingress after the rollout has injected the custom action +The following is an example of our example Ingress after the rollout has injected the custom action annotation that splits traffic between the canary-service and stable-service, with a traffic weight of 10 and 90 respectively: @@ -97,16 +97,16 @@ metadata: annotations: kubernetes.io/ingress.class: alb alb.ingress.kubernetes.io/actions.root-service: | - { + { "Type":"forward", - "ForwardConfig":{ - "TargetGroups":[ - { + "ForwardConfig":{ + "TargetGroups":[ + { "Weight":10, "ServiceName":"canary-service", "ServicePort":"80" }, - { + { "Weight":90, "ServiceName":"stable-service", "ServicePort":"80" @@ -158,9 +158,31 @@ spec: ... ``` +### Sticky session + +Because at least two target groups (canary and stable) are used, target group stickiness requires additional configuration: +Sticky session must be activated on the target group via + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +spec: + strategy: + canary: +... + trafficRouting: + alb: + stickinessConfig: + enabled: true + durationSeconds: 3600 +... +``` + +More information can be found in the [AWS ALB API](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/sticky-sessions.html) + ### Zero-Downtime Updates with AWS TargetGroup Verification -Argo Rollouts contains two features to help ensure zero-downtime updates when used with the AWS +Argo Rollouts contains two features to help ensure zero-downtime updates when used with the AWS LoadBalancer controller: TargetGroup IP verification and TargetGroup weight verification. Both features involve the Rollout controller performing additional safety checks to AWS, to verify the changes made to the Ingress object are reflected in the underlying AWS TargetGroup. @@ -185,7 +207,7 @@ errors when the TargetGroup points to pods which have already been scaled down. To mitigate this risk, AWS recommends the use of [pod readiness gate injection](https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.2/deploy/pod_readiness_gate/) -when running the AWS LoadBalancer in IP mode. Readiness gates allow for the AWS LoadBalancer +when running the AWS LoadBalancer in IP mode. Readiness gates allow for the AWS LoadBalancer controller to verify that TargetGroups are accurate before marking newly created Pods as "ready", preventing premature scale down of the older ReplicaSet. @@ -218,7 +240,7 @@ downtime in the following problematic scenario during an update from V1 to V2: 5. V1 ReplicaSet is scaled down to complete the update After step 5, when the V1 ReplicaSet is scaled down, the outdated TargetGroup would still be pointing -to the V1 Pods IPs which no longer exist, causing downtime. +to the V1 Pods IPs which no longer exist, causing downtime. To allow for zero-downtime updates, Argo Rollouts has the ability to perform TargetGroup IP verification as an additional safety measure during an update. When this feature is enabled, whenever diff --git a/ingress/alb.go b/ingress/alb.go index 01288c86e7..3fdff50932 100644 --- a/ingress/alb.go +++ b/ingress/alb.go @@ -101,6 +101,14 @@ func getResetALBActionStr(ingress *ingressutil.Ingress, action string) (string, }, }, } + + if previousAction.ForwardConfig.TargetGroupStickinessConfig != nil { + albAction.ForwardConfig.TargetGroupStickinessConfig = &ingressutil.ALBTargetGroupStickinessConfig{ + Enabled: previousAction.ForwardConfig.TargetGroupStickinessConfig.Enabled, + DurationSeconds: previousAction.ForwardConfig.TargetGroupStickinessConfig.DurationSeconds, + } + } + bytes := jsonutil.MustMarshal(albAction) return string(bytes), nil } diff --git a/ingress/alb_test.go b/ingress/alb_test.go index a8ca3db64d..d3b9a8bfe2 100644 --- a/ingress/alb_test.go +++ b/ingress/alb_test.go @@ -32,15 +32,39 @@ const actionTemplate = `{ } }` +const actionTemplateWithStickyConfig = `{ + "Type":"forward", + "ForwardConfig":{ + "TargetGroups":[ + { + "ServiceName":"%s", + "ServicePort":"%d", + "Weight": 85 + },{ + "ServiceName":"%s", + "ServicePort":"%d", + "Weight": 15 + } + ], + "TargetGroupStickinessConfig":{ + "DurationSeconds" : 300, + "Enabled" : true + } + } +}` + func albActionAnnotation(stable string) string { return fmt.Sprintf("%s%s%s", ingressutil.ALBIngressAnnotation, ingressutil.ALBActionPrefix, stable) } -func newALBIngress(name string, port int, serviceName string, rollout string) *extensionsv1beta1.Ingress { +func newALBIngress(name string, port int, serviceName string, rollout string, includeStickyConfig bool) *extensionsv1beta1.Ingress { canaryService := fmt.Sprintf("%s-canary", serviceName) albActionKey := albActionAnnotation(serviceName) managedBy := fmt.Sprintf("%s:%s", rollout, albActionKey) action := fmt.Sprintf(actionTemplate, serviceName, port, canaryService, port) + if includeStickyConfig { + action = fmt.Sprintf(actionTemplateWithStickyConfig, serviceName, port, canaryService, port) + } return &extensionsv1beta1.Ingress{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -98,7 +122,7 @@ func rollout(name, service, ingress string) *v1alpha1.Rollout { func TestInvalidManagedALBActions(t *testing.T) { rollout := rollout("rollout", "stable-service", "test-ingress") - ing := newALBIngress("test-ingress", 80, "stable-service", rollout.Name) + ing := newALBIngress("test-ingress", 80, "stable-service", rollout.Name, false) ing.Annotations[ingressutil.ManagedActionsAnnotation] = "invalid-managed-by" ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, rollout) @@ -110,7 +134,7 @@ func TestInvalidManagedALBActions(t *testing.T) { } func TestInvalidPreviousALBActionAnnotationValue(t *testing.T) { - ing := newALBIngress("test-ingress", 80, "stable-service", "not-existing-rollout") + ing := newALBIngress("test-ingress", 80, "stable-service", "not-existing-rollout", false) ing.Annotations[albActionAnnotation("stable-service")] = "{" ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, nil) @@ -122,7 +146,7 @@ func TestInvalidPreviousALBActionAnnotationValue(t *testing.T) { } func TestInvalidPreviousALBActionAnnotationKey(t *testing.T) { - ing := newALBIngress("test-ingress", 80, "stable-service", "not-existing-rollout") + ing := newALBIngress("test-ingress", 80, "stable-service", "also-not-existing-rollout", false) ing.Annotations[ingressutil.ManagedActionsAnnotation] = "invalid-action-key" ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, nil) @@ -133,7 +157,7 @@ func TestInvalidPreviousALBActionAnnotationKey(t *testing.T) { } func TestResetActionFailureFindNoPort(t *testing.T) { - ing := newALBIngress("test-ingress", 80, "stable-service", "not-existing-rollout") + ing := newALBIngress("test-ingress", 80, "stable-service", "still-not-existing-rollout", false) ing.Annotations[albActionAnnotation("stable-service")] = "{}" ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, nil) @@ -146,7 +170,7 @@ func TestResetActionFailureFindNoPort(t *testing.T) { func TestALBIngressNoModifications(t *testing.T) { rollout := rollout("rollout", "stable-service", "test-ingress") - ing := newALBIngress("test-ingress", 80, "stable-service", rollout.Name) + ing := newALBIngress("test-ingress", 80, "stable-service", rollout.Name, false) ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, rollout) @@ -157,7 +181,7 @@ func TestALBIngressNoModifications(t *testing.T) { } func TestALBIngressResetAction(t *testing.T) { - ing := newALBIngress("test-ingress", 80, "stable-service", "non-existing-rollout") + ing := newALBIngress("test-ingress", 80, "stable-service", "non-existing-rollout", false) ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, nil) err := ctrl.syncIngress("default/test-ingress") @@ -179,3 +203,27 @@ func TestALBIngressResetAction(t *testing.T) { expectedAction := `{"Type":"forward","ForwardConfig":{"TargetGroups":[{"ServiceName":"stable-service","ServicePort":"80","Weight":100}]}}` assert.Equal(t, expectedAction, annotations[albActionAnnotation("stable-service")]) } + +func TestALBIngressResetActionWithStickyConfig(t *testing.T) { + ing := newALBIngress("test-ingress", 80, "stable-service", "non-existing-rollout", true) + + ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, nil) + err := ctrl.syncIngress("default/test-ingress") + assert.Nil(t, err) + assert.Len(t, enqueuedObjects, 0) + actions := kubeclient.Actions() + assert.Len(t, actions, 1) + updateAction, ok := actions[0].(k8stesting.UpdateAction) + if !ok { + assert.Fail(t, "Client call was not an update") + updateAction.GetObject() + } + acc, err := meta.Accessor(updateAction.GetObject()) + if err != nil { + panic(err) + } + annotations := acc.GetAnnotations() + assert.NotContains(t, annotations, ingressutil.ManagedActionsAnnotation) + expectedAction := `{"Type":"forward","ForwardConfig":{"TargetGroups":[{"ServiceName":"stable-service","ServicePort":"80","Weight":100}],"TargetGroupStickinessConfig":{"Enabled":true,"DurationSeconds":300}}}` + assert.Equal(t, expectedAction, annotations[albActionAnnotation("stable-service")]) +} diff --git a/manifests/crds/rollout-crd.yaml b/manifests/crds/rollout-crd.yaml index 03d8e70cfe..22a475b1c4 100644 --- a/manifests/crds/rollout-crd.yaml +++ b/manifests/crds/rollout-crd.yaml @@ -549,6 +549,17 @@ spec: servicePort: format: int32 type: integer + stickinessConfig: + properties: + durationSeconds: + format: int64 + type: integer + enabled: + type: boolean + required: + - durationSeconds + - enabled + type: object required: - ingress - servicePort diff --git a/manifests/install.yaml b/manifests/install.yaml index acdacb2b8f..226370cb5d 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -11012,6 +11012,17 @@ spec: servicePort: format: int32 type: integer + stickinessConfig: + properties: + durationSeconds: + format: int64 + type: integer + enabled: + type: boolean + required: + - durationSeconds + - enabled + type: object required: - ingress - servicePort diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 111a412647..9787a00334 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -11012,6 +11012,17 @@ spec: servicePort: format: int32 type: integer + stickinessConfig: + properties: + durationSeconds: + format: int64 + type: integer + enabled: + type: boolean + required: + - durationSeconds + - enabled + type: object required: - ingress - servicePort diff --git a/pkg/apiclient/rollout/rollout.swagger.json b/pkg/apiclient/rollout/rollout.swagger.json index 9d20f18ab3..ce0073d16a 100644 --- a/pkg/apiclient/rollout/rollout.swagger.json +++ b/pkg/apiclient/rollout/rollout.swagger.json @@ -526,6 +526,10 @@ "type": "string", "title": "RootService references the service in the ingress to the controller should add the action to" }, + "stickinessConfig": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.StickinessConfig", + "title": "AdditionalForwardConfig allows to specify further settings on the ForwaredConfig\n+optional" + }, "annotationPrefix": { "type": "string", "title": "AnnotationPrefix has to match the configured annotation prefix on the alb ingress controller\n+optional" @@ -1455,6 +1459,18 @@ }, "title": "SetCanaryScale defines how to scale the newRS without changing traffic weight" }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.StickinessConfig": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "durationSeconds": { + "type": "string", + "format": "int64" + } + } + }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.TLSRoute": { "type": "object", "properties": { diff --git a/pkg/apis/rollouts/v1alpha1/generated.pb.go b/pkg/apis/rollouts/v1alpha1/generated.pb.go index 53c7c7d425..5ff91102e2 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.pb.go +++ b/pkg/apis/rollouts/v1alpha1/generated.pb.go @@ -48,10 +48,38 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +func (m *ALBStatus) Reset() { *m = ALBStatus{} } +func (*ALBStatus) ProtoMessage() {} +func (*ALBStatus) Descriptor() ([]byte, []int) { + return fileDescriptor_e0e705f843545fab, []int{0} +} +func (m *ALBStatus) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ALBStatus) 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 *ALBStatus) XXX_Merge(src proto.Message) { + xxx_messageInfo_ALBStatus.Merge(m, src) +} +func (m *ALBStatus) XXX_Size() int { + return m.Size() +} +func (m *ALBStatus) XXX_DiscardUnknown() { + xxx_messageInfo_ALBStatus.DiscardUnknown(m) +} + +var xxx_messageInfo_ALBStatus proto.InternalMessageInfo + func (m *ALBTrafficRouting) Reset() { *m = ALBTrafficRouting{} } func (*ALBTrafficRouting) ProtoMessage() {} func (*ALBTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{0} + return fileDescriptor_e0e705f843545fab, []int{1} } func (m *ALBTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -79,7 +107,7 @@ var xxx_messageInfo_ALBTrafficRouting proto.InternalMessageInfo func (m *AmbassadorTrafficRouting) Reset() { *m = AmbassadorTrafficRouting{} } func (*AmbassadorTrafficRouting) ProtoMessage() {} func (*AmbassadorTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{1} + return fileDescriptor_e0e705f843545fab, []int{2} } func (m *AmbassadorTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -107,7 +135,7 @@ var xxx_messageInfo_AmbassadorTrafficRouting proto.InternalMessageInfo func (m *AnalysisRun) Reset() { *m = AnalysisRun{} } func (*AnalysisRun) ProtoMessage() {} func (*AnalysisRun) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{2} + return fileDescriptor_e0e705f843545fab, []int{3} } func (m *AnalysisRun) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -135,7 +163,7 @@ var xxx_messageInfo_AnalysisRun proto.InternalMessageInfo func (m *AnalysisRunArgument) Reset() { *m = AnalysisRunArgument{} } func (*AnalysisRunArgument) ProtoMessage() {} func (*AnalysisRunArgument) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{3} + return fileDescriptor_e0e705f843545fab, []int{4} } func (m *AnalysisRunArgument) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -163,7 +191,7 @@ var xxx_messageInfo_AnalysisRunArgument proto.InternalMessageInfo func (m *AnalysisRunList) Reset() { *m = AnalysisRunList{} } func (*AnalysisRunList) ProtoMessage() {} func (*AnalysisRunList) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{4} + return fileDescriptor_e0e705f843545fab, []int{5} } func (m *AnalysisRunList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -191,7 +219,7 @@ var xxx_messageInfo_AnalysisRunList proto.InternalMessageInfo func (m *AnalysisRunSpec) Reset() { *m = AnalysisRunSpec{} } func (*AnalysisRunSpec) ProtoMessage() {} func (*AnalysisRunSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{5} + return fileDescriptor_e0e705f843545fab, []int{6} } func (m *AnalysisRunSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -219,7 +247,7 @@ var xxx_messageInfo_AnalysisRunSpec proto.InternalMessageInfo func (m *AnalysisRunStatus) Reset() { *m = AnalysisRunStatus{} } func (*AnalysisRunStatus) ProtoMessage() {} func (*AnalysisRunStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{6} + return fileDescriptor_e0e705f843545fab, []int{7} } func (m *AnalysisRunStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -247,7 +275,7 @@ var xxx_messageInfo_AnalysisRunStatus proto.InternalMessageInfo func (m *AnalysisRunStrategy) Reset() { *m = AnalysisRunStrategy{} } func (*AnalysisRunStrategy) ProtoMessage() {} func (*AnalysisRunStrategy) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{7} + return fileDescriptor_e0e705f843545fab, []int{8} } func (m *AnalysisRunStrategy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -275,7 +303,7 @@ var xxx_messageInfo_AnalysisRunStrategy proto.InternalMessageInfo func (m *AnalysisTemplate) Reset() { *m = AnalysisTemplate{} } func (*AnalysisTemplate) ProtoMessage() {} func (*AnalysisTemplate) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{8} + return fileDescriptor_e0e705f843545fab, []int{9} } func (m *AnalysisTemplate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -303,7 +331,7 @@ var xxx_messageInfo_AnalysisTemplate proto.InternalMessageInfo func (m *AnalysisTemplateList) Reset() { *m = AnalysisTemplateList{} } func (*AnalysisTemplateList) ProtoMessage() {} func (*AnalysisTemplateList) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{9} + return fileDescriptor_e0e705f843545fab, []int{10} } func (m *AnalysisTemplateList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -331,7 +359,7 @@ var xxx_messageInfo_AnalysisTemplateList proto.InternalMessageInfo func (m *AnalysisTemplateSpec) Reset() { *m = AnalysisTemplateSpec{} } func (*AnalysisTemplateSpec) ProtoMessage() {} func (*AnalysisTemplateSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{10} + return fileDescriptor_e0e705f843545fab, []int{11} } func (m *AnalysisTemplateSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -359,7 +387,7 @@ var xxx_messageInfo_AnalysisTemplateSpec proto.InternalMessageInfo func (m *AntiAffinity) Reset() { *m = AntiAffinity{} } func (*AntiAffinity) ProtoMessage() {} func (*AntiAffinity) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{11} + return fileDescriptor_e0e705f843545fab, []int{12} } func (m *AntiAffinity) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -387,7 +415,7 @@ var xxx_messageInfo_AntiAffinity proto.InternalMessageInfo func (m *Argument) Reset() { *m = Argument{} } func (*Argument) ProtoMessage() {} func (*Argument) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{12} + return fileDescriptor_e0e705f843545fab, []int{13} } func (m *Argument) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -415,7 +443,7 @@ var xxx_messageInfo_Argument proto.InternalMessageInfo func (m *ArgumentValueFrom) Reset() { *m = ArgumentValueFrom{} } func (*ArgumentValueFrom) ProtoMessage() {} func (*ArgumentValueFrom) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{13} + return fileDescriptor_e0e705f843545fab, []int{14} } func (m *ArgumentValueFrom) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -440,10 +468,38 @@ func (m *ArgumentValueFrom) XXX_DiscardUnknown() { var xxx_messageInfo_ArgumentValueFrom proto.InternalMessageInfo +func (m *AwsResourceRef) Reset() { *m = AwsResourceRef{} } +func (*AwsResourceRef) ProtoMessage() {} +func (*AwsResourceRef) Descriptor() ([]byte, []int) { + return fileDescriptor_e0e705f843545fab, []int{15} +} +func (m *AwsResourceRef) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AwsResourceRef) 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 *AwsResourceRef) XXX_Merge(src proto.Message) { + xxx_messageInfo_AwsResourceRef.Merge(m, src) +} +func (m *AwsResourceRef) XXX_Size() int { + return m.Size() +} +func (m *AwsResourceRef) XXX_DiscardUnknown() { + xxx_messageInfo_AwsResourceRef.DiscardUnknown(m) +} + +var xxx_messageInfo_AwsResourceRef proto.InternalMessageInfo + func (m *BlueGreenStatus) Reset() { *m = BlueGreenStatus{} } func (*BlueGreenStatus) ProtoMessage() {} func (*BlueGreenStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{14} + return fileDescriptor_e0e705f843545fab, []int{16} } func (m *BlueGreenStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -471,7 +527,7 @@ var xxx_messageInfo_BlueGreenStatus proto.InternalMessageInfo func (m *BlueGreenStrategy) Reset() { *m = BlueGreenStrategy{} } func (*BlueGreenStrategy) ProtoMessage() {} func (*BlueGreenStrategy) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{15} + return fileDescriptor_e0e705f843545fab, []int{17} } func (m *BlueGreenStrategy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -499,7 +555,7 @@ var xxx_messageInfo_BlueGreenStrategy proto.InternalMessageInfo func (m *CanaryStatus) Reset() { *m = CanaryStatus{} } func (*CanaryStatus) ProtoMessage() {} func (*CanaryStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{16} + return fileDescriptor_e0e705f843545fab, []int{18} } func (m *CanaryStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -527,7 +583,7 @@ var xxx_messageInfo_CanaryStatus proto.InternalMessageInfo func (m *CanaryStep) Reset() { *m = CanaryStep{} } func (*CanaryStep) ProtoMessage() {} func (*CanaryStep) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{17} + return fileDescriptor_e0e705f843545fab, []int{19} } func (m *CanaryStep) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -555,7 +611,7 @@ var xxx_messageInfo_CanaryStep proto.InternalMessageInfo func (m *CanaryStrategy) Reset() { *m = CanaryStrategy{} } func (*CanaryStrategy) ProtoMessage() {} func (*CanaryStrategy) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{18} + return fileDescriptor_e0e705f843545fab, []int{20} } func (m *CanaryStrategy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -583,7 +639,7 @@ var xxx_messageInfo_CanaryStrategy proto.InternalMessageInfo func (m *CloudWatchMetric) Reset() { *m = CloudWatchMetric{} } func (*CloudWatchMetric) ProtoMessage() {} func (*CloudWatchMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{19} + return fileDescriptor_e0e705f843545fab, []int{21} } func (m *CloudWatchMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -611,7 +667,7 @@ var xxx_messageInfo_CloudWatchMetric proto.InternalMessageInfo func (m *CloudWatchMetricDataQuery) Reset() { *m = CloudWatchMetricDataQuery{} } func (*CloudWatchMetricDataQuery) ProtoMessage() {} func (*CloudWatchMetricDataQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{20} + return fileDescriptor_e0e705f843545fab, []int{22} } func (m *CloudWatchMetricDataQuery) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -639,7 +695,7 @@ var xxx_messageInfo_CloudWatchMetricDataQuery proto.InternalMessageInfo func (m *CloudWatchMetricStat) Reset() { *m = CloudWatchMetricStat{} } func (*CloudWatchMetricStat) ProtoMessage() {} func (*CloudWatchMetricStat) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{21} + return fileDescriptor_e0e705f843545fab, []int{23} } func (m *CloudWatchMetricStat) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -667,7 +723,7 @@ var xxx_messageInfo_CloudWatchMetricStat proto.InternalMessageInfo func (m *CloudWatchMetricStatMetric) Reset() { *m = CloudWatchMetricStatMetric{} } func (*CloudWatchMetricStatMetric) ProtoMessage() {} func (*CloudWatchMetricStatMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{22} + return fileDescriptor_e0e705f843545fab, []int{24} } func (m *CloudWatchMetricStatMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -695,7 +751,7 @@ var xxx_messageInfo_CloudWatchMetricStatMetric proto.InternalMessageInfo func (m *CloudWatchMetricStatMetricDimension) Reset() { *m = CloudWatchMetricStatMetricDimension{} } func (*CloudWatchMetricStatMetricDimension) ProtoMessage() {} func (*CloudWatchMetricStatMetricDimension) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{23} + return fileDescriptor_e0e705f843545fab, []int{25} } func (m *CloudWatchMetricStatMetricDimension) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -723,7 +779,7 @@ var xxx_messageInfo_CloudWatchMetricStatMetricDimension proto.InternalMessageInf func (m *ClusterAnalysisTemplate) Reset() { *m = ClusterAnalysisTemplate{} } func (*ClusterAnalysisTemplate) ProtoMessage() {} func (*ClusterAnalysisTemplate) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{24} + return fileDescriptor_e0e705f843545fab, []int{26} } func (m *ClusterAnalysisTemplate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -751,7 +807,7 @@ var xxx_messageInfo_ClusterAnalysisTemplate proto.InternalMessageInfo func (m *ClusterAnalysisTemplateList) Reset() { *m = ClusterAnalysisTemplateList{} } func (*ClusterAnalysisTemplateList) ProtoMessage() {} func (*ClusterAnalysisTemplateList) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{25} + return fileDescriptor_e0e705f843545fab, []int{27} } func (m *ClusterAnalysisTemplateList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -779,7 +835,7 @@ var xxx_messageInfo_ClusterAnalysisTemplateList proto.InternalMessageInfo func (m *DatadogMetric) Reset() { *m = DatadogMetric{} } func (*DatadogMetric) ProtoMessage() {} func (*DatadogMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{26} + return fileDescriptor_e0e705f843545fab, []int{28} } func (m *DatadogMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -807,7 +863,7 @@ var xxx_messageInfo_DatadogMetric proto.InternalMessageInfo func (m *Experiment) Reset() { *m = Experiment{} } func (*Experiment) ProtoMessage() {} func (*Experiment) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{27} + return fileDescriptor_e0e705f843545fab, []int{29} } func (m *Experiment) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -835,7 +891,7 @@ var xxx_messageInfo_Experiment proto.InternalMessageInfo func (m *ExperimentAnalysisRunStatus) Reset() { *m = ExperimentAnalysisRunStatus{} } func (*ExperimentAnalysisRunStatus) ProtoMessage() {} func (*ExperimentAnalysisRunStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{28} + return fileDescriptor_e0e705f843545fab, []int{30} } func (m *ExperimentAnalysisRunStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -863,7 +919,7 @@ var xxx_messageInfo_ExperimentAnalysisRunStatus proto.InternalMessageInfo func (m *ExperimentAnalysisTemplateRef) Reset() { *m = ExperimentAnalysisTemplateRef{} } func (*ExperimentAnalysisTemplateRef) ProtoMessage() {} func (*ExperimentAnalysisTemplateRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{29} + return fileDescriptor_e0e705f843545fab, []int{31} } func (m *ExperimentAnalysisTemplateRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -891,7 +947,7 @@ var xxx_messageInfo_ExperimentAnalysisTemplateRef proto.InternalMessageInfo func (m *ExperimentCondition) Reset() { *m = ExperimentCondition{} } func (*ExperimentCondition) ProtoMessage() {} func (*ExperimentCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{30} + return fileDescriptor_e0e705f843545fab, []int{32} } func (m *ExperimentCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -919,7 +975,7 @@ var xxx_messageInfo_ExperimentCondition proto.InternalMessageInfo func (m *ExperimentList) Reset() { *m = ExperimentList{} } func (*ExperimentList) ProtoMessage() {} func (*ExperimentList) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{31} + return fileDescriptor_e0e705f843545fab, []int{33} } func (m *ExperimentList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -947,7 +1003,7 @@ var xxx_messageInfo_ExperimentList proto.InternalMessageInfo func (m *ExperimentSpec) Reset() { *m = ExperimentSpec{} } func (*ExperimentSpec) ProtoMessage() {} func (*ExperimentSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{32} + return fileDescriptor_e0e705f843545fab, []int{34} } func (m *ExperimentSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -975,7 +1031,7 @@ var xxx_messageInfo_ExperimentSpec proto.InternalMessageInfo func (m *ExperimentStatus) Reset() { *m = ExperimentStatus{} } func (*ExperimentStatus) ProtoMessage() {} func (*ExperimentStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{33} + return fileDescriptor_e0e705f843545fab, []int{35} } func (m *ExperimentStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1003,7 +1059,7 @@ var xxx_messageInfo_ExperimentStatus proto.InternalMessageInfo func (m *FieldRef) Reset() { *m = FieldRef{} } func (*FieldRef) ProtoMessage() {} func (*FieldRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{34} + return fileDescriptor_e0e705f843545fab, []int{36} } func (m *FieldRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1031,7 +1087,7 @@ var xxx_messageInfo_FieldRef proto.InternalMessageInfo func (m *GraphiteMetric) Reset() { *m = GraphiteMetric{} } func (*GraphiteMetric) ProtoMessage() {} func (*GraphiteMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{35} + return fileDescriptor_e0e705f843545fab, []int{37} } func (m *GraphiteMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1059,7 +1115,7 @@ var xxx_messageInfo_GraphiteMetric proto.InternalMessageInfo func (m *IstioDestinationRule) Reset() { *m = IstioDestinationRule{} } func (*IstioDestinationRule) ProtoMessage() {} func (*IstioDestinationRule) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{36} + return fileDescriptor_e0e705f843545fab, []int{38} } func (m *IstioDestinationRule) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1087,7 +1143,7 @@ var xxx_messageInfo_IstioDestinationRule proto.InternalMessageInfo func (m *IstioTrafficRouting) Reset() { *m = IstioTrafficRouting{} } func (*IstioTrafficRouting) ProtoMessage() {} func (*IstioTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{37} + return fileDescriptor_e0e705f843545fab, []int{39} } func (m *IstioTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1115,7 +1171,7 @@ var xxx_messageInfo_IstioTrafficRouting proto.InternalMessageInfo func (m *IstioVirtualService) Reset() { *m = IstioVirtualService{} } func (*IstioVirtualService) ProtoMessage() {} func (*IstioVirtualService) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{38} + return fileDescriptor_e0e705f843545fab, []int{40} } func (m *IstioVirtualService) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1143,7 +1199,7 @@ var xxx_messageInfo_IstioVirtualService proto.InternalMessageInfo func (m *JobMetric) Reset() { *m = JobMetric{} } func (*JobMetric) ProtoMessage() {} func (*JobMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{39} + return fileDescriptor_e0e705f843545fab, []int{41} } func (m *JobMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1171,7 +1227,7 @@ var xxx_messageInfo_JobMetric proto.InternalMessageInfo func (m *KayentaMetric) Reset() { *m = KayentaMetric{} } func (*KayentaMetric) ProtoMessage() {} func (*KayentaMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{40} + return fileDescriptor_e0e705f843545fab, []int{42} } func (m *KayentaMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1199,7 +1255,7 @@ var xxx_messageInfo_KayentaMetric proto.InternalMessageInfo func (m *KayentaScope) Reset() { *m = KayentaScope{} } func (*KayentaScope) ProtoMessage() {} func (*KayentaScope) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{41} + return fileDescriptor_e0e705f843545fab, []int{43} } func (m *KayentaScope) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1227,7 +1283,7 @@ var xxx_messageInfo_KayentaScope proto.InternalMessageInfo func (m *KayentaThreshold) Reset() { *m = KayentaThreshold{} } func (*KayentaThreshold) ProtoMessage() {} func (*KayentaThreshold) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{42} + return fileDescriptor_e0e705f843545fab, []int{44} } func (m *KayentaThreshold) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1255,7 +1311,7 @@ var xxx_messageInfo_KayentaThreshold proto.InternalMessageInfo func (m *Measurement) Reset() { *m = Measurement{} } func (*Measurement) ProtoMessage() {} func (*Measurement) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{43} + return fileDescriptor_e0e705f843545fab, []int{45} } func (m *Measurement) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1283,7 +1339,7 @@ var xxx_messageInfo_Measurement proto.InternalMessageInfo func (m *Metric) Reset() { *m = Metric{} } func (*Metric) ProtoMessage() {} func (*Metric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{44} + return fileDescriptor_e0e705f843545fab, []int{46} } func (m *Metric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1311,7 +1367,7 @@ var xxx_messageInfo_Metric proto.InternalMessageInfo func (m *MetricProvider) Reset() { *m = MetricProvider{} } func (*MetricProvider) ProtoMessage() {} func (*MetricProvider) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{45} + return fileDescriptor_e0e705f843545fab, []int{47} } func (m *MetricProvider) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1339,7 +1395,7 @@ var xxx_messageInfo_MetricProvider proto.InternalMessageInfo func (m *MetricResult) Reset() { *m = MetricResult{} } func (*MetricResult) ProtoMessage() {} func (*MetricResult) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{46} + return fileDescriptor_e0e705f843545fab, []int{48} } func (m *MetricResult) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1367,7 +1423,7 @@ var xxx_messageInfo_MetricResult proto.InternalMessageInfo func (m *NewRelicMetric) Reset() { *m = NewRelicMetric{} } func (*NewRelicMetric) ProtoMessage() {} func (*NewRelicMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{47} + return fileDescriptor_e0e705f843545fab, []int{49} } func (m *NewRelicMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1395,7 +1451,7 @@ var xxx_messageInfo_NewRelicMetric proto.InternalMessageInfo func (m *NginxTrafficRouting) Reset() { *m = NginxTrafficRouting{} } func (*NginxTrafficRouting) ProtoMessage() {} func (*NginxTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{48} + return fileDescriptor_e0e705f843545fab, []int{50} } func (m *NginxTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1423,7 +1479,7 @@ var xxx_messageInfo_NginxTrafficRouting proto.InternalMessageInfo func (m *ObjectRef) Reset() { *m = ObjectRef{} } func (*ObjectRef) ProtoMessage() {} func (*ObjectRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{49} + return fileDescriptor_e0e705f843545fab, []int{51} } func (m *ObjectRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1451,7 +1507,7 @@ var xxx_messageInfo_ObjectRef proto.InternalMessageInfo func (m *PauseCondition) Reset() { *m = PauseCondition{} } func (*PauseCondition) ProtoMessage() {} func (*PauseCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{50} + return fileDescriptor_e0e705f843545fab, []int{52} } func (m *PauseCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1479,7 +1535,7 @@ var xxx_messageInfo_PauseCondition proto.InternalMessageInfo func (m *PodTemplateMetadata) Reset() { *m = PodTemplateMetadata{} } func (*PodTemplateMetadata) ProtoMessage() {} func (*PodTemplateMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{51} + return fileDescriptor_e0e705f843545fab, []int{53} } func (m *PodTemplateMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1509,7 +1565,7 @@ func (m *PreferredDuringSchedulingIgnoredDuringExecution) Reset() { } func (*PreferredDuringSchedulingIgnoredDuringExecution) ProtoMessage() {} func (*PreferredDuringSchedulingIgnoredDuringExecution) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{52} + return fileDescriptor_e0e705f843545fab, []int{54} } func (m *PreferredDuringSchedulingIgnoredDuringExecution) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1537,7 +1593,7 @@ var xxx_messageInfo_PreferredDuringSchedulingIgnoredDuringExecution proto.Intern func (m *PrometheusMetric) Reset() { *m = PrometheusMetric{} } func (*PrometheusMetric) ProtoMessage() {} func (*PrometheusMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{53} + return fileDescriptor_e0e705f843545fab, []int{55} } func (m *PrometheusMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1567,7 +1623,7 @@ func (m *RequiredDuringSchedulingIgnoredDuringExecution) Reset() { } func (*RequiredDuringSchedulingIgnoredDuringExecution) ProtoMessage() {} func (*RequiredDuringSchedulingIgnoredDuringExecution) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{54} + return fileDescriptor_e0e705f843545fab, []int{56} } func (m *RequiredDuringSchedulingIgnoredDuringExecution) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1595,7 +1651,7 @@ var xxx_messageInfo_RequiredDuringSchedulingIgnoredDuringExecution proto.Interna func (m *Rollout) Reset() { *m = Rollout{} } func (*Rollout) ProtoMessage() {} func (*Rollout) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{55} + return fileDescriptor_e0e705f843545fab, []int{57} } func (m *Rollout) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1623,7 +1679,7 @@ var xxx_messageInfo_Rollout proto.InternalMessageInfo func (m *RolloutAnalysis) Reset() { *m = RolloutAnalysis{} } func (*RolloutAnalysis) ProtoMessage() {} func (*RolloutAnalysis) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{56} + return fileDescriptor_e0e705f843545fab, []int{58} } func (m *RolloutAnalysis) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1651,7 +1707,7 @@ var xxx_messageInfo_RolloutAnalysis proto.InternalMessageInfo func (m *RolloutAnalysisBackground) Reset() { *m = RolloutAnalysisBackground{} } func (*RolloutAnalysisBackground) ProtoMessage() {} func (*RolloutAnalysisBackground) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{57} + return fileDescriptor_e0e705f843545fab, []int{59} } func (m *RolloutAnalysisBackground) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1679,7 +1735,7 @@ var xxx_messageInfo_RolloutAnalysisBackground proto.InternalMessageInfo func (m *RolloutAnalysisRunStatus) Reset() { *m = RolloutAnalysisRunStatus{} } func (*RolloutAnalysisRunStatus) ProtoMessage() {} func (*RolloutAnalysisRunStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{58} + return fileDescriptor_e0e705f843545fab, []int{60} } func (m *RolloutAnalysisRunStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1707,7 +1763,7 @@ var xxx_messageInfo_RolloutAnalysisRunStatus proto.InternalMessageInfo func (m *RolloutAnalysisTemplate) Reset() { *m = RolloutAnalysisTemplate{} } func (*RolloutAnalysisTemplate) ProtoMessage() {} func (*RolloutAnalysisTemplate) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{59} + return fileDescriptor_e0e705f843545fab, []int{61} } func (m *RolloutAnalysisTemplate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1735,7 +1791,7 @@ var xxx_messageInfo_RolloutAnalysisTemplate proto.InternalMessageInfo func (m *RolloutCondition) Reset() { *m = RolloutCondition{} } func (*RolloutCondition) ProtoMessage() {} func (*RolloutCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{60} + return fileDescriptor_e0e705f843545fab, []int{62} } func (m *RolloutCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1763,7 +1819,7 @@ var xxx_messageInfo_RolloutCondition proto.InternalMessageInfo func (m *RolloutExperimentStep) Reset() { *m = RolloutExperimentStep{} } func (*RolloutExperimentStep) ProtoMessage() {} func (*RolloutExperimentStep) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{61} + return fileDescriptor_e0e705f843545fab, []int{63} } func (m *RolloutExperimentStep) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1793,7 +1849,7 @@ func (m *RolloutExperimentStepAnalysisTemplateRef) Reset() { } func (*RolloutExperimentStepAnalysisTemplateRef) ProtoMessage() {} func (*RolloutExperimentStepAnalysisTemplateRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{62} + return fileDescriptor_e0e705f843545fab, []int{64} } func (m *RolloutExperimentStepAnalysisTemplateRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1821,7 +1877,7 @@ var xxx_messageInfo_RolloutExperimentStepAnalysisTemplateRef proto.InternalMessa func (m *RolloutExperimentTemplate) Reset() { *m = RolloutExperimentTemplate{} } func (*RolloutExperimentTemplate) ProtoMessage() {} func (*RolloutExperimentTemplate) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{63} + return fileDescriptor_e0e705f843545fab, []int{65} } func (m *RolloutExperimentTemplate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1849,7 +1905,7 @@ var xxx_messageInfo_RolloutExperimentTemplate proto.InternalMessageInfo func (m *RolloutList) Reset() { *m = RolloutList{} } func (*RolloutList) ProtoMessage() {} func (*RolloutList) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{64} + return fileDescriptor_e0e705f843545fab, []int{66} } func (m *RolloutList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1877,7 +1933,7 @@ var xxx_messageInfo_RolloutList proto.InternalMessageInfo func (m *RolloutPause) Reset() { *m = RolloutPause{} } func (*RolloutPause) ProtoMessage() {} func (*RolloutPause) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{65} + return fileDescriptor_e0e705f843545fab, []int{67} } func (m *RolloutPause) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1905,7 +1961,7 @@ var xxx_messageInfo_RolloutPause proto.InternalMessageInfo func (m *RolloutSpec) Reset() { *m = RolloutSpec{} } func (*RolloutSpec) ProtoMessage() {} func (*RolloutSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{66} + return fileDescriptor_e0e705f843545fab, []int{68} } func (m *RolloutSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1933,7 +1989,7 @@ var xxx_messageInfo_RolloutSpec proto.InternalMessageInfo func (m *RolloutStatus) Reset() { *m = RolloutStatus{} } func (*RolloutStatus) ProtoMessage() {} func (*RolloutStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{67} + return fileDescriptor_e0e705f843545fab, []int{69} } func (m *RolloutStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1961,7 +2017,7 @@ var xxx_messageInfo_RolloutStatus proto.InternalMessageInfo func (m *RolloutStrategy) Reset() { *m = RolloutStrategy{} } func (*RolloutStrategy) ProtoMessage() {} func (*RolloutStrategy) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{68} + return fileDescriptor_e0e705f843545fab, []int{70} } func (m *RolloutStrategy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1989,7 +2045,7 @@ var xxx_messageInfo_RolloutStrategy proto.InternalMessageInfo func (m *RolloutTrafficRouting) Reset() { *m = RolloutTrafficRouting{} } func (*RolloutTrafficRouting) ProtoMessage() {} func (*RolloutTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{69} + return fileDescriptor_e0e705f843545fab, []int{71} } func (m *RolloutTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2017,7 +2073,7 @@ var xxx_messageInfo_RolloutTrafficRouting proto.InternalMessageInfo func (m *SMITrafficRouting) Reset() { *m = SMITrafficRouting{} } func (*SMITrafficRouting) ProtoMessage() {} func (*SMITrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{70} + return fileDescriptor_e0e705f843545fab, []int{72} } func (m *SMITrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2045,7 +2101,7 @@ var xxx_messageInfo_SMITrafficRouting proto.InternalMessageInfo func (m *ScopeDetail) Reset() { *m = ScopeDetail{} } func (*ScopeDetail) ProtoMessage() {} func (*ScopeDetail) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{71} + return fileDescriptor_e0e705f843545fab, []int{73} } func (m *ScopeDetail) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2073,7 +2129,7 @@ var xxx_messageInfo_ScopeDetail proto.InternalMessageInfo func (m *SecretKeyRef) Reset() { *m = SecretKeyRef{} } func (*SecretKeyRef) ProtoMessage() {} func (*SecretKeyRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{72} + return fileDescriptor_e0e705f843545fab, []int{74} } func (m *SecretKeyRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2101,7 +2157,7 @@ var xxx_messageInfo_SecretKeyRef proto.InternalMessageInfo func (m *SetCanaryScale) Reset() { *m = SetCanaryScale{} } func (*SetCanaryScale) ProtoMessage() {} func (*SetCanaryScale) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{73} + return fileDescriptor_e0e705f843545fab, []int{75} } func (m *SetCanaryScale) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2126,10 +2182,38 @@ func (m *SetCanaryScale) XXX_DiscardUnknown() { var xxx_messageInfo_SetCanaryScale proto.InternalMessageInfo +func (m *StickinessConfig) Reset() { *m = StickinessConfig{} } +func (*StickinessConfig) ProtoMessage() {} +func (*StickinessConfig) Descriptor() ([]byte, []int) { + return fileDescriptor_e0e705f843545fab, []int{76} +} +func (m *StickinessConfig) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StickinessConfig) 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 *StickinessConfig) XXX_Merge(src proto.Message) { + xxx_messageInfo_StickinessConfig.Merge(m, src) +} +func (m *StickinessConfig) XXX_Size() int { + return m.Size() +} +func (m *StickinessConfig) XXX_DiscardUnknown() { + xxx_messageInfo_StickinessConfig.DiscardUnknown(m) +} + +var xxx_messageInfo_StickinessConfig proto.InternalMessageInfo + func (m *TLSRoute) Reset() { *m = TLSRoute{} } func (*TLSRoute) ProtoMessage() {} func (*TLSRoute) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{74} + return fileDescriptor_e0e705f843545fab, []int{77} } func (m *TLSRoute) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2157,7 +2241,7 @@ var xxx_messageInfo_TLSRoute proto.InternalMessageInfo func (m *TemplateService) Reset() { *m = TemplateService{} } func (*TemplateService) ProtoMessage() {} func (*TemplateService) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{75} + return fileDescriptor_e0e705f843545fab, []int{78} } func (m *TemplateService) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2185,7 +2269,7 @@ var xxx_messageInfo_TemplateService proto.InternalMessageInfo func (m *TemplateSpec) Reset() { *m = TemplateSpec{} } func (*TemplateSpec) ProtoMessage() {} func (*TemplateSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{76} + return fileDescriptor_e0e705f843545fab, []int{79} } func (m *TemplateSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2213,7 +2297,7 @@ var xxx_messageInfo_TemplateSpec proto.InternalMessageInfo func (m *TemplateStatus) Reset() { *m = TemplateStatus{} } func (*TemplateStatus) ProtoMessage() {} func (*TemplateStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{77} + return fileDescriptor_e0e705f843545fab, []int{80} } func (m *TemplateStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2241,7 +2325,7 @@ var xxx_messageInfo_TemplateStatus proto.InternalMessageInfo func (m *TrafficWeights) Reset() { *m = TrafficWeights{} } func (*TrafficWeights) ProtoMessage() {} func (*TrafficWeights) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{78} + return fileDescriptor_e0e705f843545fab, []int{81} } func (m *TrafficWeights) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2269,7 +2353,7 @@ var xxx_messageInfo_TrafficWeights proto.InternalMessageInfo func (m *ValueFrom) Reset() { *m = ValueFrom{} } func (*ValueFrom) ProtoMessage() {} func (*ValueFrom) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{79} + return fileDescriptor_e0e705f843545fab, []int{82} } func (m *ValueFrom) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2297,7 +2381,7 @@ var xxx_messageInfo_ValueFrom proto.InternalMessageInfo func (m *WavefrontMetric) Reset() { *m = WavefrontMetric{} } func (*WavefrontMetric) ProtoMessage() {} func (*WavefrontMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{80} + return fileDescriptor_e0e705f843545fab, []int{83} } func (m *WavefrontMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2325,7 +2409,7 @@ var xxx_messageInfo_WavefrontMetric proto.InternalMessageInfo func (m *WebMetric) Reset() { *m = WebMetric{} } func (*WebMetric) ProtoMessage() {} func (*WebMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{81} + return fileDescriptor_e0e705f843545fab, []int{84} } func (m *WebMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2353,7 +2437,7 @@ var xxx_messageInfo_WebMetric proto.InternalMessageInfo func (m *WebMetricHeader) Reset() { *m = WebMetricHeader{} } func (*WebMetricHeader) ProtoMessage() {} func (*WebMetricHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{82} + return fileDescriptor_e0e705f843545fab, []int{85} } func (m *WebMetricHeader) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2381,7 +2465,7 @@ var xxx_messageInfo_WebMetricHeader proto.InternalMessageInfo func (m *WeightDestination) Reset() { *m = WeightDestination{} } func (*WeightDestination) ProtoMessage() {} func (*WeightDestination) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{83} + return fileDescriptor_e0e705f843545fab, []int{86} } func (m *WeightDestination) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2407,6 +2491,7 @@ func (m *WeightDestination) XXX_DiscardUnknown() { var xxx_messageInfo_WeightDestination proto.InternalMessageInfo func init() { + proto.RegisterType((*ALBStatus)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ALBStatus") proto.RegisterType((*ALBTrafficRouting)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ALBTrafficRouting") proto.RegisterType((*AmbassadorTrafficRouting)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AmbassadorTrafficRouting") proto.RegisterType((*AnalysisRun)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AnalysisRun") @@ -2421,6 +2506,7 @@ func init() { proto.RegisterType((*AntiAffinity)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AntiAffinity") proto.RegisterType((*Argument)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.Argument") proto.RegisterType((*ArgumentValueFrom)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ArgumentValueFrom") + proto.RegisterType((*AwsResourceRef)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AwsResourceRef") proto.RegisterType((*BlueGreenStatus)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.BlueGreenStatus") proto.RegisterType((*BlueGreenStrategy)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.BlueGreenStrategy") proto.RegisterType((*CanaryStatus)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.CanaryStatus") @@ -2485,6 +2571,7 @@ func init() { proto.RegisterType((*ScopeDetail)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ScopeDetail") proto.RegisterType((*SecretKeyRef)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SecretKeyRef") proto.RegisterType((*SetCanaryScale)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SetCanaryScale") + proto.RegisterType((*StickinessConfig)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.StickinessConfig") proto.RegisterType((*TLSRoute)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.TLSRoute") proto.RegisterType((*TemplateService)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.TemplateService") proto.RegisterType((*TemplateSpec)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.TemplateSpec") @@ -2502,411 +2589,477 @@ func init() { } var fileDescriptor_e0e705f843545fab = []byte{ - // 6463 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3d, 0x6d, 0x8c, 0x1c, 0xc9, - 0x55, 0xd7, 0x33, 0xfb, 0x31, 0xfb, 0x66, 0x3f, 0xcb, 0xeb, 0x78, 0x6f, 0xef, 0xec, 0x71, 0xfa, - 0xa2, 0xc3, 0x81, 0x64, 0x9d, 0xf8, 0xee, 0xe0, 0x92, 0x8b, 0x4e, 0xcc, 0xec, 0xda, 0xe7, 0xf5, - 0xed, 0xda, 0xeb, 0x9a, 0xb5, 0x9d, 0x5c, 0x72, 0x21, 0xbd, 0x33, 0xb5, 0xb3, 0x6d, 0xf7, 0x74, - 0x4f, 0xba, 0x7b, 0xd6, 0xde, 0x4b, 0x94, 0x0f, 0xa2, 0x84, 0x80, 0x12, 0x25, 0x90, 0xe4, 0x07, - 0x42, 0x41, 0x11, 0xe2, 0x07, 0x22, 0xfc, 0x40, 0x11, 0x88, 0x3f, 0x41, 0x20, 0x20, 0x52, 0xf8, - 0x01, 0x0a, 0x12, 0x70, 0x01, 0x25, 0x43, 0x32, 0xe1, 0x0f, 0xfc, 0x41, 0x41, 0x41, 0x28, 0x96, - 0x90, 0x50, 0x7d, 0x76, 0x75, 0x4f, 0xcf, 0xee, 0xcc, 0x4e, 0xaf, 0x89, 0x80, 0x7f, 0x33, 0xf5, - 0x5e, 0xbd, 0x57, 0x1f, 0xaf, 0x5e, 0xbd, 0x7a, 0xf5, 0xea, 0x35, 0x6c, 0x34, 0xec, 0x70, 0xaf, - 0xbd, 0xb3, 0x52, 0xf3, 0x9a, 0x17, 0x2d, 0xbf, 0xe1, 0xb5, 0x7c, 0xef, 0x2e, 0xfb, 0xf1, 0x56, - 0xdf, 0x73, 0x1c, 0xaf, 0x1d, 0x06, 0x17, 0x5b, 0xf7, 0x1a, 0x17, 0xad, 0x96, 0x1d, 0x5c, 0x54, - 0x25, 0xfb, 0x6f, 0xb7, 0x9c, 0xd6, 0x9e, 0xf5, 0xf6, 0x8b, 0x0d, 0xe2, 0x12, 0xdf, 0x0a, 0x49, - 0x7d, 0xa5, 0xe5, 0x7b, 0xa1, 0x87, 0xde, 0x15, 0x51, 0x5b, 0x91, 0xd4, 0xd8, 0x8f, 0x5f, 0x90, - 0x75, 0x57, 0x5a, 0xf7, 0x1a, 0x2b, 0x94, 0xda, 0x8a, 0x2a, 0x91, 0xd4, 0x96, 0xdf, 0xaa, 0xb5, - 0xa5, 0xe1, 0x35, 0xbc, 0x8b, 0x8c, 0xe8, 0x4e, 0x7b, 0x97, 0xfd, 0x63, 0x7f, 0xd8, 0x2f, 0xce, - 0x6c, 0xf9, 0xa9, 0x7b, 0xcf, 0x07, 0x2b, 0xb6, 0x47, 0xdb, 0x76, 0x71, 0xc7, 0x0a, 0x6b, 0x7b, - 0x17, 0xf7, 0x7b, 0x5a, 0xb4, 0x6c, 0x6a, 0x48, 0x35, 0xcf, 0x27, 0x69, 0x38, 0xcf, 0x46, 0x38, - 0x4d, 0xab, 0xb6, 0x67, 0xbb, 0xc4, 0x3f, 0x88, 0x7a, 0xdd, 0x24, 0xa1, 0x95, 0x56, 0xeb, 0x62, - 0xbf, 0x5a, 0x7e, 0xdb, 0x0d, 0xed, 0x26, 0xe9, 0xa9, 0xf0, 0xb3, 0x47, 0x55, 0x08, 0x6a, 0x7b, - 0xa4, 0x69, 0xf5, 0xd4, 0x7b, 0xa6, 0x5f, 0xbd, 0x76, 0x68, 0x3b, 0x17, 0x6d, 0x37, 0x0c, 0x42, - 0x3f, 0x59, 0xc9, 0xfc, 0x77, 0x03, 0x16, 0xca, 0x1b, 0x95, 0x6d, 0xdf, 0xda, 0xdd, 0xb5, 0x6b, - 0xd8, 0x6b, 0x87, 0xb6, 0xdb, 0x40, 0x6f, 0x86, 0x49, 0xdb, 0x6d, 0xf8, 0x24, 0x08, 0x96, 0x8c, - 0xf3, 0xc6, 0x85, 0xa9, 0xca, 0xdc, 0x37, 0x3b, 0xa5, 0xc7, 0xba, 0x9d, 0xd2, 0xe4, 0x3a, 0x2f, - 0xc6, 0x12, 0x8e, 0x9e, 0x83, 0x62, 0x40, 0xfc, 0x7d, 0xbb, 0x46, 0xb6, 0x3c, 0x3f, 0x5c, 0xca, - 0x9d, 0x37, 0x2e, 0x8c, 0x57, 0x4e, 0x09, 0xf4, 0x62, 0x35, 0x02, 0x61, 0x1d, 0x8f, 0x56, 0xf3, - 0x3d, 0x2f, 0x14, 0xf0, 0xa5, 0x3c, 0xe3, 0xa2, 0xaa, 0xe1, 0x08, 0x84, 0x75, 0x3c, 0xb4, 0x06, - 0xf3, 0x96, 0xeb, 0x7a, 0xa1, 0x15, 0xda, 0x9e, 0xbb, 0xe5, 0x93, 0x5d, 0xfb, 0xc1, 0xd2, 0x18, - 0xab, 0xbb, 0x24, 0xea, 0xce, 0x97, 0x13, 0x70, 0xdc, 0x53, 0xc3, 0x5c, 0x83, 0xa5, 0x72, 0x73, - 0xc7, 0x0a, 0x02, 0xab, 0xee, 0xf9, 0x89, 0xae, 0x5f, 0x80, 0x42, 0xd3, 0x6a, 0xb5, 0x6c, 0xb7, - 0x41, 0xfb, 0x9e, 0xbf, 0x30, 0x55, 0x99, 0xee, 0x76, 0x4a, 0x85, 0x4d, 0x51, 0x86, 0x15, 0xd4, - 0xfc, 0x87, 0x1c, 0x14, 0xcb, 0xae, 0xe5, 0x1c, 0x04, 0x76, 0x80, 0xdb, 0x2e, 0xfa, 0x00, 0x14, - 0xa8, 0x0c, 0xd4, 0xad, 0xd0, 0x62, 0xa3, 0x56, 0xbc, 0xf4, 0xb6, 0x15, 0x3e, 0x25, 0x2b, 0xfa, - 0x94, 0x44, 0x92, 0x4d, 0xb1, 0x57, 0xf6, 0xdf, 0xbe, 0x72, 0x63, 0xe7, 0x2e, 0xa9, 0x85, 0x9b, - 0x24, 0xb4, 0x2a, 0x48, 0xf4, 0x02, 0xa2, 0x32, 0xac, 0xa8, 0x22, 0x0f, 0xc6, 0x82, 0x16, 0xa9, - 0xb1, 0x41, 0x2e, 0x5e, 0xda, 0x5c, 0x19, 0x65, 0x15, 0xad, 0x68, 0x4d, 0xaf, 0xb6, 0x48, 0xad, - 0x32, 0x2d, 0x58, 0x8f, 0xd1, 0x7f, 0x98, 0x31, 0x42, 0xf7, 0x61, 0x22, 0x08, 0xad, 0xb0, 0x1d, - 0xb0, 0x09, 0x2a, 0x5e, 0xba, 0x91, 0x1d, 0x4b, 0x46, 0xb6, 0x32, 0x2b, 0x98, 0x4e, 0xf0, 0xff, - 0x58, 0xb0, 0x33, 0xff, 0xd1, 0x80, 0x53, 0x1a, 0x76, 0xd9, 0x6f, 0xb4, 0x9b, 0xc4, 0x0d, 0xd1, - 0x79, 0x18, 0x73, 0xad, 0x26, 0x11, 0x52, 0xa9, 0x9a, 0x7c, 0xdd, 0x6a, 0x12, 0xcc, 0x20, 0xe8, - 0x29, 0x18, 0xdf, 0xb7, 0x9c, 0x36, 0x61, 0x83, 0x34, 0x55, 0x99, 0x11, 0x28, 0xe3, 0xb7, 0x69, - 0x21, 0xe6, 0x30, 0xf4, 0x61, 0x98, 0x62, 0x3f, 0xae, 0xf8, 0x5e, 0x33, 0xa3, 0xae, 0x89, 0x16, - 0xde, 0x96, 0x64, 0x2b, 0x33, 0xdd, 0x4e, 0x69, 0x4a, 0xfd, 0xc5, 0x11, 0x43, 0xf3, 0x9f, 0x0c, - 0x98, 0xd3, 0x3a, 0xb7, 0x61, 0x07, 0x21, 0x7a, 0x5f, 0x8f, 0xf0, 0xac, 0x0c, 0x26, 0x3c, 0xb4, - 0x36, 0x13, 0x9d, 0x79, 0xd1, 0xd3, 0x82, 0x2c, 0xd1, 0x04, 0xc7, 0x85, 0x71, 0x3b, 0x24, 0xcd, - 0x60, 0x29, 0x77, 0x3e, 0x7f, 0xa1, 0x78, 0x69, 0x3d, 0xb3, 0x69, 0x8c, 0xc6, 0x77, 0x9d, 0xd2, - 0xc7, 0x9c, 0x8d, 0xf9, 0xe5, 0x5c, 0xac, 0x87, 0x54, 0xa2, 0x90, 0x07, 0x93, 0x4d, 0x12, 0xfa, - 0x76, 0x8d, 0xaf, 0xab, 0xe2, 0xa5, 0xb5, 0xd1, 0x5a, 0xb1, 0xc9, 0x88, 0x45, 0x9a, 0x89, 0xff, - 0x0f, 0xb0, 0xe4, 0x82, 0xf6, 0x60, 0xcc, 0xf2, 0x1b, 0xb2, 0xcf, 0x57, 0xb2, 0x99, 0xdf, 0x48, - 0xe6, 0xca, 0x7e, 0x23, 0xc0, 0x8c, 0x03, 0xba, 0x08, 0x53, 0x21, 0xf1, 0x9b, 0xb6, 0x6b, 0x85, - 0x5c, 0x95, 0x15, 0x2a, 0x0b, 0x02, 0x6d, 0x6a, 0x5b, 0x02, 0x70, 0x84, 0x63, 0xbe, 0x9e, 0x83, - 0x85, 0x9e, 0xc5, 0x80, 0x9e, 0x85, 0xf1, 0xd6, 0x9e, 0x15, 0x48, 0xe9, 0x3e, 0x27, 0x87, 0x76, - 0x8b, 0x16, 0x3e, 0xec, 0x94, 0x66, 0x64, 0x15, 0x56, 0x80, 0x39, 0x32, 0xd5, 0xd5, 0x4d, 0x12, - 0x04, 0x56, 0x43, 0x8a, 0xbc, 0x36, 0x22, 0xac, 0x18, 0x4b, 0x38, 0xfa, 0x25, 0x03, 0x66, 0xf8, - 0xe8, 0x60, 0x12, 0xb4, 0x9d, 0x90, 0x2e, 0x6b, 0x3a, 0x36, 0xd7, 0xb2, 0x98, 0x09, 0x4e, 0xb2, - 0x72, 0x5a, 0x70, 0x9f, 0xd1, 0x4b, 0x03, 0x1c, 0xe7, 0x8b, 0xee, 0xc0, 0x54, 0x10, 0x5a, 0x7e, - 0x48, 0xea, 0xe5, 0x90, 0x29, 0xf0, 0xe2, 0xa5, 0x9f, 0x1e, 0x4c, 0xde, 0xb7, 0xed, 0x26, 0xe1, - 0x6b, 0xab, 0x2a, 0x09, 0xe0, 0x88, 0x96, 0xf9, 0x77, 0x71, 0xc5, 0x51, 0x0d, 0xe9, 0x66, 0xd7, - 0x38, 0x40, 0xef, 0x85, 0xc7, 0x83, 0x76, 0xad, 0x46, 0x82, 0x60, 0xb7, 0xed, 0xe0, 0xb6, 0x7b, - 0xd5, 0x0e, 0x42, 0xcf, 0x3f, 0xd8, 0xb0, 0x9b, 0x76, 0xc8, 0xc6, 0x7b, 0xbc, 0x72, 0xb6, 0xdb, - 0x29, 0x3d, 0x5e, 0xed, 0x87, 0x84, 0xfb, 0xd7, 0x47, 0x16, 0x3c, 0xd1, 0x76, 0xfb, 0x93, 0xe7, - 0x7b, 0x62, 0xa9, 0xdb, 0x29, 0x3d, 0x71, 0xab, 0x3f, 0x1a, 0x3e, 0x8c, 0x86, 0xf9, 0xaf, 0x06, - 0xcc, 0xcb, 0x7e, 0x6d, 0x93, 0x66, 0xcb, 0xb1, 0x42, 0xf2, 0x08, 0x76, 0x9c, 0x30, 0xb6, 0xe3, - 0xe0, 0x6c, 0xf4, 0x86, 0x6c, 0x7f, 0xbf, 0x6d, 0xc7, 0xfc, 0x17, 0x03, 0x16, 0x93, 0xc8, 0x8f, - 0x40, 0x4b, 0x06, 0x71, 0x2d, 0x79, 0x3d, 0xdb, 0xde, 0xf6, 0x51, 0x95, 0x3f, 0x4c, 0xe9, 0xeb, - 0xff, 0x72, 0x7d, 0x69, 0xfe, 0xce, 0x18, 0x4c, 0x97, 0xdd, 0xd0, 0x2e, 0xef, 0xee, 0xda, 0xae, - 0x1d, 0x1e, 0xa0, 0xcf, 0xe4, 0xe0, 0x62, 0xcb, 0x27, 0xbb, 0xc4, 0xf7, 0x49, 0x7d, 0xad, 0xed, - 0xdb, 0x6e, 0xa3, 0x5a, 0xdb, 0x23, 0xf5, 0xb6, 0x63, 0xbb, 0x8d, 0xf5, 0x86, 0xeb, 0xa9, 0xe2, - 0xcb, 0x0f, 0x48, 0xad, 0x4d, 0x4d, 0x39, 0x31, 0xff, 0xcd, 0xd1, 0x9a, 0xb9, 0x35, 0x1c, 0xd3, - 0xca, 0x33, 0xdd, 0x4e, 0xe9, 0xe2, 0x90, 0x95, 0xf0, 0xb0, 0x5d, 0x43, 0x9f, 0xce, 0xc1, 0x8a, - 0x4f, 0x3e, 0xd8, 0xb6, 0x07, 0x1f, 0x0d, 0xbe, 0x40, 0x9d, 0xd1, 0x46, 0x03, 0x0f, 0xc5, 0xb3, - 0x72, 0xa9, 0xdb, 0x29, 0x0d, 0x59, 0x07, 0x0f, 0xd9, 0x2f, 0xf3, 0xcf, 0x0d, 0x28, 0x0c, 0x61, - 0xfd, 0x95, 0xe2, 0xd6, 0xdf, 0x54, 0x8f, 0xe5, 0x17, 0xf6, 0x5a, 0x7e, 0x2f, 0x8d, 0x36, 0x68, - 0x83, 0x58, 0x7c, 0xff, 0x46, 0x4f, 0x59, 0x49, 0x0b, 0x11, 0xed, 0xc1, 0x62, 0xcb, 0xab, 0xcb, - 0x45, 0x7f, 0xd5, 0x0a, 0xf6, 0x18, 0x4c, 0x74, 0xef, 0xd9, 0x6e, 0xa7, 0xb4, 0xb8, 0x95, 0x02, - 0x7f, 0xd8, 0x29, 0x2d, 0x29, 0x22, 0x09, 0x04, 0x9c, 0x4a, 0x11, 0xb5, 0xa0, 0xb0, 0x6b, 0x13, - 0xa7, 0x8e, 0xc9, 0xae, 0x90, 0x94, 0x11, 0x97, 0xf7, 0x15, 0x41, 0x8d, 0x1f, 0x8e, 0xe4, 0x3f, - 0xac, 0xb8, 0x98, 0x3f, 0x1e, 0x83, 0xb9, 0x8a, 0xd3, 0x26, 0x2f, 0xf9, 0x84, 0x48, 0xfb, 0xa6, - 0x0c, 0x73, 0x2d, 0x9f, 0xec, 0xdb, 0xe4, 0x7e, 0x95, 0x38, 0xa4, 0x16, 0x7a, 0xbe, 0xe8, 0xea, - 0x19, 0x31, 0x93, 0x73, 0x5b, 0x71, 0x30, 0x4e, 0xe2, 0xa3, 0x17, 0x61, 0xd6, 0xaa, 0x85, 0xf6, - 0x3e, 0x51, 0x14, 0xf8, 0x44, 0xbf, 0x41, 0x50, 0x98, 0x2d, 0xc7, 0xa0, 0x38, 0x81, 0x8d, 0xde, - 0x07, 0x4b, 0x41, 0xcd, 0x72, 0xc8, 0xad, 0x96, 0x60, 0xb5, 0xba, 0x47, 0x6a, 0xf7, 0xb6, 0x3c, - 0xdb, 0x0d, 0x85, 0xe1, 0x76, 0x5e, 0x50, 0x5a, 0xaa, 0xf6, 0xc1, 0xc3, 0x7d, 0x29, 0xa0, 0x3f, - 0x31, 0xe0, 0x6c, 0xcb, 0x27, 0x5b, 0xbe, 0xd7, 0xf4, 0xa8, 0xf4, 0xf6, 0x98, 0x78, 0xc2, 0xd4, - 0xb9, 0x3d, 0xe2, 0x32, 0xe5, 0x25, 0xbd, 0xa7, 0xa9, 0x37, 0x76, 0x3b, 0xa5, 0xb3, 0x5b, 0x87, - 0x35, 0x00, 0x1f, 0xde, 0x3e, 0xf4, 0x67, 0x06, 0x9c, 0x6b, 0x79, 0x41, 0x78, 0x48, 0x17, 0xc6, - 0x4f, 0xb4, 0x0b, 0x66, 0xb7, 0x53, 0x3a, 0xb7, 0x75, 0x68, 0x0b, 0xf0, 0x11, 0x2d, 0x34, 0xbb, - 0x45, 0x58, 0xd0, 0x64, 0x4f, 0x58, 0x80, 0x2f, 0xc0, 0x8c, 0x14, 0x06, 0xee, 0x73, 0xe0, 0xb2, - 0xa7, 0xec, 0xd5, 0xb2, 0x0e, 0xc4, 0x71, 0x5c, 0x2a, 0x77, 0x4a, 0x14, 0x79, 0xed, 0x84, 0xdc, - 0x6d, 0xc5, 0xa0, 0x38, 0x81, 0x8d, 0xd6, 0xe1, 0x94, 0x28, 0xc1, 0xa4, 0xe5, 0xd8, 0x35, 0x6b, - 0xd5, 0x6b, 0x0b, 0x91, 0x1b, 0xaf, 0x9c, 0xe9, 0x76, 0x4a, 0xa7, 0xb6, 0x7a, 0xc1, 0x38, 0xad, - 0x0e, 0xda, 0x80, 0x45, 0xab, 0x1d, 0x7a, 0xaa, 0xff, 0x97, 0x5d, 0x6b, 0xc7, 0x21, 0x75, 0x26, - 0x5a, 0x85, 0xca, 0x12, 0xd5, 0x1a, 0xe5, 0x14, 0x38, 0x4e, 0xad, 0x85, 0xb6, 0x12, 0xd4, 0xaa, - 0xa4, 0xe6, 0xb9, 0x75, 0x3e, 0xcb, 0xe3, 0x95, 0x27, 0x45, 0xf7, 0xe2, 0x14, 0x05, 0x0e, 0x4e, - 0xad, 0x89, 0x1c, 0x98, 0x6d, 0x5a, 0x0f, 0x6e, 0xb9, 0xd6, 0xbe, 0x65, 0x3b, 0x94, 0xc9, 0xd2, - 0xc4, 0x11, 0xa6, 0x69, 0x3b, 0xb4, 0x9d, 0x15, 0xee, 0x9f, 0x5a, 0x59, 0x77, 0xc3, 0x1b, 0x7e, - 0x35, 0xa4, 0x9b, 0x40, 0x05, 0xd1, 0x81, 0xdd, 0x8c, 0xd1, 0xc2, 0x09, 0xda, 0xe8, 0x06, 0x9c, - 0x66, 0xcb, 0x71, 0xcd, 0xbb, 0xef, 0xae, 0x11, 0xc7, 0x3a, 0x90, 0x1d, 0x98, 0x64, 0x1d, 0x78, - 0xbc, 0xdb, 0x29, 0x9d, 0xae, 0xa6, 0x21, 0xe0, 0xf4, 0x7a, 0xd4, 0x96, 0x8f, 0x03, 0x30, 0xd9, - 0xb7, 0x03, 0xdb, 0x73, 0xb9, 0x2d, 0x5f, 0x88, 0x6c, 0xf9, 0x6a, 0x7f, 0x34, 0x7c, 0x18, 0x0d, - 0xf4, 0x1b, 0x06, 0x2c, 0xa6, 0x2d, 0xc3, 0xa5, 0xa9, 0x2c, 0xfc, 0x3a, 0x89, 0xa5, 0xc5, 0x25, - 0x22, 0x55, 0x29, 0xa4, 0x36, 0x02, 0x7d, 0xcc, 0x80, 0x69, 0x4b, 0x33, 0xce, 0x96, 0x80, 0xb5, - 0xea, 0xda, 0xa8, 0xd6, 0x70, 0x44, 0xb1, 0x32, 0xdf, 0xed, 0x94, 0x62, 0x06, 0x20, 0x8e, 0x71, - 0x44, 0xbf, 0x69, 0xc0, 0xe9, 0xd4, 0x35, 0xbe, 0x54, 0x3c, 0x89, 0x11, 0x62, 0x42, 0x92, 0xae, - 0x73, 0xd2, 0x9b, 0x81, 0x3e, 0x6f, 0xa8, 0xad, 0x6c, 0x53, 0x9e, 0x47, 0xa6, 0x59, 0xd3, 0x6e, - 0x8e, 0x68, 0x8f, 0x46, 0xbb, 0xb7, 0x24, 0x5c, 0x39, 0xa5, 0xed, 0x8c, 0xb2, 0x10, 0x27, 0xd9, - 0xa3, 0xcf, 0x1a, 0x72, 0x6b, 0x54, 0x2d, 0x9a, 0x39, 0xa9, 0x16, 0xa1, 0x68, 0xa7, 0x55, 0x0d, - 0x4a, 0x30, 0x47, 0xef, 0x87, 0x65, 0x6b, 0xc7, 0xf3, 0xc3, 0xd4, 0xc5, 0xb7, 0x34, 0xcb, 0x96, - 0xd1, 0xb9, 0x6e, 0xa7, 0xb4, 0x5c, 0xee, 0x8b, 0x85, 0x0f, 0xa1, 0x60, 0x7e, 0x67, 0x0c, 0xa6, - 0x57, 0x2d, 0xd7, 0xf2, 0x0f, 0xc4, 0xd6, 0xf5, 0x75, 0x03, 0x9e, 0xac, 0xb5, 0x7d, 0x9f, 0xb8, - 0x61, 0x35, 0x24, 0xad, 0xde, 0x8d, 0xcb, 0x38, 0xd1, 0x8d, 0xeb, 0x7c, 0xb7, 0x53, 0x7a, 0x72, - 0xf5, 0x10, 0xfe, 0xf8, 0xd0, 0xd6, 0xa1, 0xbf, 0x36, 0xc0, 0x14, 0x08, 0x15, 0xab, 0x76, 0xaf, - 0xe1, 0x7b, 0x6d, 0xb7, 0xde, 0xdb, 0x89, 0xdc, 0x89, 0x76, 0xe2, 0xe9, 0x6e, 0xa7, 0x64, 0xae, - 0x1e, 0xd9, 0x0a, 0x3c, 0x40, 0x4b, 0xd1, 0x4b, 0xb0, 0x20, 0xb0, 0x2e, 0x3f, 0x68, 0x11, 0xdf, - 0xa6, 0xb6, 0xaf, 0xf0, 0xf3, 0x3f, 0x2e, 0xb6, 0x95, 0x85, 0xd5, 0x24, 0x02, 0xee, 0xad, 0x83, - 0x02, 0x98, 0xbc, 0x4f, 0xec, 0xc6, 0x5e, 0x28, 0xcd, 0xa7, 0x8d, 0xd1, 0x7a, 0x2f, 0x1c, 0xfe, - 0x77, 0x38, 0xcd, 0x4a, 0x91, 0x1e, 0x86, 0xc5, 0x1f, 0x2c, 0x39, 0x99, 0xbf, 0x3f, 0x06, 0x20, - 0xc5, 0x8b, 0xb4, 0xd0, 0xcf, 0xc0, 0x54, 0x40, 0x42, 0x8e, 0x25, 0xdc, 0x45, 0xdc, 0x07, 0x25, - 0x0b, 0x71, 0x04, 0x47, 0xf7, 0x60, 0xbc, 0x65, 0xb5, 0x03, 0x22, 0x26, 0xeb, 0x5a, 0x26, 0x93, - 0xb5, 0x45, 0x29, 0xf2, 0x03, 0x0d, 0xfb, 0x89, 0x39, 0x0f, 0xf4, 0x09, 0x03, 0x80, 0xc4, 0x07, - 0xb8, 0x78, 0xa9, 0x9a, 0x09, 0xcb, 0x68, 0x0e, 0xe8, 0x18, 0x54, 0x66, 0xbb, 0x9d, 0x12, 0x68, - 0x53, 0xa5, 0xb1, 0x45, 0xf7, 0xa1, 0x60, 0x49, 0x1d, 0x3d, 0x76, 0x12, 0x3a, 0x9a, 0x9d, 0x33, - 0x94, 0x90, 0x29, 0x66, 0xe8, 0xd3, 0x06, 0xcc, 0x06, 0x24, 0x14, 0x53, 0x45, 0x35, 0x85, 0x30, - 0x50, 0x47, 0x14, 0x92, 0x6a, 0x8c, 0x26, 0xd7, 0x78, 0xf1, 0x32, 0x9c, 0xe0, 0x6b, 0x7e, 0xa7, - 0x08, 0xb3, 0x52, 0x64, 0x22, 0x9b, 0xb3, 0xc6, 0x4b, 0xd2, 0x6d, 0xce, 0x55, 0x1d, 0x88, 0xe3, - 0xb8, 0xb4, 0x72, 0x10, 0x52, 0x23, 0x27, 0x6e, 0x72, 0xaa, 0xca, 0x55, 0x1d, 0x88, 0xe3, 0xb8, - 0xa8, 0x09, 0xe3, 0x41, 0x48, 0x5a, 0xd2, 0xc3, 0x7b, 0x75, 0xb4, 0xd1, 0x88, 0x56, 0x42, 0xe4, - 0xc5, 0xa2, 0xff, 0x02, 0xcc, 0xb9, 0xa0, 0xcf, 0x19, 0x30, 0x1b, 0xc6, 0x2e, 0xd2, 0x84, 0x18, - 0x64, 0x23, 0x89, 0xf1, 0x3b, 0x3a, 0x3e, 0x1b, 0xf1, 0x32, 0x9c, 0x60, 0x9f, 0x62, 0x86, 0x8e, - 0x9f, 0xa0, 0x19, 0xfa, 0x0a, 0x14, 0x9a, 0xd6, 0x83, 0x6a, 0xdb, 0x6f, 0x1c, 0xdf, 0xdc, 0x15, - 0xf7, 0x8c, 0x9c, 0x0a, 0x56, 0xf4, 0xd0, 0xc7, 0x0d, 0x6d, 0x71, 0x4d, 0x32, 0xe2, 0x77, 0xb2, - 0x5d, 0x5c, 0x4a, 0x8b, 0xf7, 0x5d, 0x66, 0x3d, 0x46, 0x61, 0xe1, 0x91, 0x1b, 0x85, 0xd4, 0xc0, - 0xe1, 0x0b, 0x44, 0x19, 0x38, 0x53, 0x27, 0x6a, 0xe0, 0xac, 0xc6, 0x98, 0xe1, 0x04, 0x73, 0xd6, - 0x1e, 0xbe, 0xe6, 0x54, 0x7b, 0xe0, 0x44, 0xdb, 0x53, 0x8d, 0x31, 0xc3, 0x09, 0xe6, 0xfd, 0x4f, - 0x42, 0xc5, 0x93, 0x39, 0x09, 0x4d, 0x67, 0x70, 0x12, 0x3a, 0xdc, 0x48, 0x9c, 0x19, 0xd5, 0x48, - 0x44, 0xd7, 0x00, 0xd5, 0x0f, 0x5c, 0xab, 0x69, 0xd7, 0x84, 0xb2, 0x64, 0x1b, 0xc4, 0x2c, 0x3b, - 0x29, 0x2f, 0x0b, 0x45, 0x86, 0xd6, 0x7a, 0x30, 0x70, 0x4a, 0x2d, 0xf3, 0x3f, 0x0c, 0x98, 0x5f, - 0x75, 0xbc, 0x76, 0xfd, 0x8e, 0x15, 0xd6, 0xf6, 0xb8, 0xf7, 0x1c, 0xbd, 0x08, 0x05, 0xdb, 0x0d, - 0x89, 0xbf, 0x6f, 0x39, 0x42, 0xb7, 0x9b, 0xf2, 0x82, 0x61, 0x5d, 0x94, 0x3f, 0xec, 0x94, 0x66, - 0xd7, 0xda, 0x3e, 0x8b, 0x3f, 0xe0, 0x2b, 0x1d, 0xab, 0x3a, 0xe8, 0x2b, 0x06, 0x2c, 0x70, 0xff, - 0xfb, 0x9a, 0x15, 0x5a, 0x37, 0xdb, 0xc4, 0xb7, 0x89, 0xf4, 0xc0, 0x8f, 0xb8, 0xc8, 0x93, 0x6d, - 0x95, 0x0c, 0x0e, 0x22, 0xf3, 0x6b, 0x33, 0xc9, 0x19, 0xf7, 0x36, 0xc6, 0xfc, 0x42, 0x1e, 0x1e, - 0xef, 0x4b, 0x0b, 0x2d, 0x43, 0xce, 0xae, 0x8b, 0xae, 0x83, 0xa0, 0x9b, 0x5b, 0xaf, 0xe3, 0x9c, - 0x5d, 0x47, 0x2b, 0xcc, 0x32, 0xf1, 0x49, 0x10, 0x48, 0x0f, 0xf5, 0x94, 0x32, 0x22, 0x44, 0x29, - 0xd6, 0x30, 0x50, 0x09, 0xc6, 0x1d, 0x6b, 0x87, 0x38, 0xc2, 0x4a, 0x64, 0xb6, 0xce, 0x06, 0x2d, - 0xc0, 0xbc, 0x1c, 0xfd, 0xa2, 0x01, 0xc0, 0x1b, 0x48, 0x6d, 0x4c, 0xb1, 0xc3, 0xe0, 0x6c, 0x87, - 0x89, 0x52, 0xe6, 0xad, 0x8c, 0xfe, 0x63, 0x8d, 0x2b, 0xda, 0x86, 0x09, 0x6a, 0xf6, 0x78, 0xf5, - 0x63, 0x6f, 0x28, 0xd0, 0xed, 0x94, 0x26, 0xb6, 0x18, 0x0d, 0x2c, 0x68, 0xd1, 0xb1, 0xf2, 0x49, - 0xd8, 0xf6, 0x5d, 0x3a, 0xb4, 0x6c, 0x0b, 0x29, 0xf0, 0x56, 0x60, 0x55, 0x8a, 0x35, 0x0c, 0xf3, - 0x8f, 0x72, 0xb0, 0x98, 0xd6, 0x74, 0xaa, 0xa9, 0x27, 0x78, 0x6b, 0xc5, 0x81, 0xe7, 0xdd, 0xd9, - 0x8f, 0x8f, 0xb8, 0x4a, 0x52, 0xc1, 0x1b, 0xe2, 0xaa, 0x57, 0xf0, 0x45, 0xef, 0x56, 0x23, 0x94, - 0x3b, 0xe6, 0x08, 0x29, 0xca, 0x89, 0x51, 0x3a, 0x0f, 0x63, 0x01, 0x9d, 0xf9, 0x7c, 0xfc, 0x02, - 0x80, 0xcd, 0x11, 0x83, 0x50, 0x8c, 0xb6, 0x6b, 0x87, 0x22, 0x28, 0x48, 0x61, 0xdc, 0x72, 0xed, - 0x10, 0x33, 0x88, 0xf9, 0xa5, 0x1c, 0x2c, 0xf7, 0xef, 0x14, 0xfa, 0x92, 0x01, 0x50, 0xa7, 0x46, - 0x2d, 0x15, 0x49, 0x79, 0xf5, 0x66, 0x9d, 0xd4, 0x18, 0xae, 0x49, 0x4e, 0xd1, 0x3d, 0xac, 0x2a, - 0x0a, 0xb0, 0xd6, 0x10, 0x74, 0x49, 0x8a, 0xfe, 0x75, 0xab, 0x29, 0x4d, 0x41, 0x55, 0x67, 0x53, - 0x41, 0xb0, 0x86, 0x45, 0x4f, 0x2d, 0xae, 0xd5, 0x24, 0x41, 0xcb, 0x52, 0x21, 0x56, 0xec, 0xd4, - 0x72, 0x5d, 0x16, 0xe2, 0x08, 0x6e, 0x3a, 0xf0, 0xd4, 0x00, 0xed, 0xcc, 0x28, 0x02, 0xc7, 0xfc, - 0xa1, 0x01, 0x67, 0x56, 0x9d, 0x76, 0x10, 0x12, 0xff, 0xff, 0xcc, 0xb5, 0xf6, 0x7f, 0x1a, 0xf0, - 0x44, 0x9f, 0x3e, 0x3f, 0x82, 0xdb, 0xed, 0xd7, 0xe2, 0xb7, 0xdb, 0xb7, 0x46, 0x15, 0xe9, 0xd4, - 0x7e, 0xf4, 0xb9, 0xe4, 0x0e, 0x61, 0x86, 0x6a, 0xad, 0xba, 0xd7, 0xc8, 0x68, 0xdf, 0x7c, 0x0a, - 0xc6, 0x3f, 0x48, 0xf7, 0x9f, 0xa4, 0x8c, 0xb1, 0x4d, 0x09, 0x73, 0x98, 0xf9, 0xf7, 0x39, 0xd0, - 0xce, 0xab, 0x8f, 0x40, 0xac, 0xdc, 0x98, 0x58, 0x8d, 0x78, 0x02, 0xd5, 0x4e, 0xdf, 0xfd, 0xc2, - 0xf3, 0xf6, 0x13, 0xe1, 0x79, 0xd7, 0x33, 0xe3, 0x78, 0x78, 0x74, 0xde, 0xeb, 0x06, 0x3c, 0x11, - 0x21, 0xf7, 0xba, 0x7e, 0x8e, 0xd6, 0x11, 0xcf, 0x41, 0xd1, 0x8a, 0xaa, 0x89, 0x59, 0x54, 0xe1, - 0x9f, 0x1a, 0x45, 0xac, 0xe3, 0x45, 0x11, 0x52, 0xf9, 0x63, 0x46, 0x48, 0x8d, 0x1d, 0x1e, 0x21, - 0x65, 0xfe, 0x28, 0x07, 0x67, 0x7b, 0x7b, 0x26, 0xa5, 0x1b, 0x93, 0xdd, 0x01, 0xfa, 0xf6, 0x3c, - 0x4c, 0x87, 0xa2, 0x82, 0xa6, 0xab, 0x17, 0x05, 0xe6, 0xf4, 0xb6, 0x06, 0xc3, 0x31, 0x4c, 0x5a, - 0xb3, 0xc6, 0xd7, 0x55, 0xb5, 0xe6, 0xb5, 0x64, 0x28, 0x99, 0xaa, 0xb9, 0xaa, 0xc1, 0x70, 0x0c, - 0x53, 0xc5, 0x6e, 0x8c, 0x9d, 0x78, 0xac, 0x5b, 0x15, 0x4e, 0xcb, 0x2b, 0xfc, 0x2b, 0x9e, 0xbf, - 0xea, 0x35, 0x5b, 0x0e, 0x61, 0x11, 0x08, 0xe3, 0xac, 0xb1, 0x67, 0x45, 0x95, 0xd3, 0x38, 0x0d, - 0x09, 0xa7, 0xd7, 0x35, 0x5f, 0xcf, 0xc3, 0xa9, 0x68, 0xd8, 0x57, 0x3d, 0xb7, 0x6e, 0xb3, 0x40, - 0x88, 0x17, 0x60, 0x2c, 0x3c, 0x68, 0xc9, 0xc1, 0xfe, 0x29, 0xd9, 0x9c, 0xed, 0x83, 0x16, 0x9d, - 0xed, 0x33, 0x29, 0x55, 0x28, 0x08, 0xb3, 0x4a, 0x68, 0x43, 0xad, 0x0e, 0x3e, 0x03, 0xcf, 0xc6, - 0xa5, 0xf9, 0x61, 0xa7, 0x94, 0x12, 0xf4, 0xbd, 0xa2, 0x28, 0xc5, 0x65, 0x1e, 0xdd, 0x85, 0x59, - 0xc7, 0x0a, 0xc2, 0x5b, 0xad, 0xba, 0x15, 0x92, 0x6d, 0xbb, 0x49, 0xc4, 0x9a, 0x1b, 0x26, 0x6c, - 0x4d, 0xdd, 0x16, 0x6e, 0xc4, 0x28, 0xe1, 0x04, 0x65, 0xb4, 0x0f, 0x88, 0x96, 0x6c, 0xfb, 0x96, - 0x1b, 0xf0, 0x5e, 0x51, 0x7e, 0xc3, 0x87, 0xc9, 0xa9, 0x23, 0xce, 0x46, 0x0f, 0x35, 0x9c, 0xc2, - 0x01, 0x3d, 0x0d, 0x13, 0x3e, 0xb1, 0x02, 0x31, 0x99, 0x53, 0xd1, 0xfa, 0xc7, 0xac, 0x14, 0x0b, - 0xa8, 0xbe, 0xa0, 0x26, 0x8e, 0x58, 0x50, 0xdf, 0x35, 0x60, 0x36, 0x9a, 0xa6, 0x47, 0xb0, 0xcd, - 0x35, 0xe3, 0xdb, 0xdc, 0xd5, 0xac, 0x54, 0x62, 0x9f, 0x9d, 0xed, 0x6b, 0x63, 0x7a, 0xff, 0x58, - 0xe0, 0xd6, 0x87, 0x60, 0x4a, 0xae, 0x6a, 0x69, 0x3f, 0x8e, 0xe8, 0x27, 0x89, 0x59, 0x16, 0x5a, - 0x64, 0xa9, 0x60, 0x82, 0x23, 0x7e, 0x74, 0x63, 0xad, 0x8b, 0x4d, 0x53, 0x88, 0xbd, 0xda, 0x58, - 0xe5, 0x66, 0x9a, 0xb6, 0xb1, 0xca, 0x3a, 0xe8, 0x16, 0x9c, 0x69, 0xf9, 0x1e, 0x0b, 0xed, 0x5f, - 0x23, 0x56, 0xdd, 0xb1, 0x5d, 0x22, 0x8f, 0xe3, 0xfc, 0xb2, 0xfa, 0x89, 0x6e, 0xa7, 0x74, 0x66, - 0x2b, 0x1d, 0x05, 0xf7, 0xab, 0x1b, 0x8f, 0x90, 0x1d, 0x3b, 0x3a, 0x42, 0x16, 0xfd, 0xb2, 0x72, - 0x7a, 0x91, 0x60, 0x69, 0x9c, 0x0d, 0xe2, 0x7b, 0xb3, 0x9a, 0xca, 0x14, 0xb5, 0x1e, 0x89, 0x54, - 0x59, 0x30, 0xc5, 0x8a, 0x7d, 0x7f, 0xcf, 0xca, 0xc4, 0xf1, 0x3c, 0x2b, 0xe6, 0x27, 0xc7, 0x61, - 0x3e, 0xb9, 0xd9, 0x9e, 0x7c, 0xf4, 0xef, 0xaf, 0x19, 0x30, 0x2f, 0x05, 0x85, 0xf3, 0x24, 0xd2, - 0x3d, 0xbc, 0x91, 0x91, 0x7c, 0x72, 0xb3, 0x41, 0x3d, 0xc5, 0xd8, 0x4e, 0x70, 0xc3, 0x3d, 0xfc, - 0xd1, 0xab, 0x50, 0x54, 0x5e, 0xd4, 0x63, 0x85, 0x02, 0xcf, 0x31, 0x83, 0x21, 0x22, 0x81, 0x75, - 0x7a, 0xe8, 0x93, 0x06, 0x40, 0x4d, 0x6a, 0x74, 0x29, 0x48, 0x37, 0xb3, 0x12, 0x24, 0xb5, 0x57, - 0x44, 0x76, 0xa1, 0x2a, 0x0a, 0xb0, 0xc6, 0x18, 0x7d, 0x81, 0xf9, 0x4f, 0x95, 0x21, 0x43, 0x45, - 0x87, 0xb6, 0xe4, 0x3d, 0x59, 0x8b, 0x74, 0x74, 0x95, 0xa7, 0xac, 0x06, 0x0d, 0x14, 0xe0, 0x58, - 0x23, 0xcc, 0x17, 0x40, 0x85, 0x6e, 0xd1, 0x15, 0xca, 0x82, 0xb7, 0xb6, 0xac, 0x70, 0x4f, 0x88, - 0xa0, 0x5a, 0xa1, 0x57, 0x24, 0x00, 0x47, 0x38, 0xe6, 0x07, 0x60, 0xf6, 0x25, 0xdf, 0x6a, 0xed, - 0xd9, 0xcc, 0x4f, 0x49, 0x8d, 0xfa, 0x37, 0xc3, 0xa4, 0x55, 0xaf, 0xa7, 0xbd, 0x1a, 0x2a, 0xf3, - 0x62, 0x2c, 0xe1, 0x83, 0xd9, 0xef, 0x7f, 0x61, 0xc0, 0xe2, 0x7a, 0x10, 0xda, 0xde, 0x1a, 0x09, - 0x42, 0xaa, 0x16, 0xa8, 0x05, 0xd1, 0x76, 0xc8, 0x00, 0x36, 0xd8, 0x1a, 0xcc, 0x8b, 0xcb, 0x94, - 0xf6, 0x4e, 0x40, 0x42, 0xcd, 0x0e, 0x53, 0xc2, 0xb9, 0x9a, 0x80, 0xe3, 0x9e, 0x1a, 0x94, 0x8a, - 0xb8, 0x55, 0x89, 0xa8, 0xe4, 0xe3, 0x54, 0xaa, 0x09, 0x38, 0xee, 0xa9, 0x61, 0x7e, 0x2b, 0x0f, - 0xa7, 0x58, 0x37, 0x12, 0x2f, 0x8d, 0x3e, 0x6b, 0xc0, 0xec, 0xbe, 0xed, 0x87, 0x6d, 0xcb, 0xd1, - 0xaf, 0x87, 0x46, 0x96, 0x4f, 0xc6, 0xeb, 0x76, 0x8c, 0x30, 0x77, 0x20, 0xc7, 0xcb, 0x70, 0x82, - 0x39, 0xfa, 0x55, 0x03, 0xe6, 0xea, 0xf1, 0x91, 0xce, 0xe6, 0x80, 0x9c, 0x36, 0x87, 0x3c, 0xaa, - 0x21, 0x51, 0x88, 0x93, 0xfc, 0xd1, 0x17, 0x0d, 0x98, 0x8b, 0x37, 0x53, 0xaa, 0xac, 0x13, 0x18, - 0x24, 0x15, 0x86, 0x18, 0x2f, 0x0f, 0x70, 0xb2, 0x09, 0xe6, 0xdf, 0x1a, 0x62, 0x4a, 0xe3, 0x98, - 0x03, 0x08, 0xa6, 0x09, 0x13, 0xbe, 0xd7, 0x0e, 0x85, 0x93, 0x77, 0x8a, 0xfb, 0x02, 0x31, 0x2b, - 0xc1, 0x02, 0x82, 0xee, 0xc3, 0x54, 0xe8, 0x04, 0xbc, 0x50, 0xf4, 0x76, 0x44, 0x8b, 0x7e, 0x7b, - 0xa3, 0xca, 0xc8, 0x69, 0x9b, 0xae, 0x28, 0xa1, 0xc6, 0x83, 0xe4, 0x65, 0x7e, 0xd5, 0x80, 0xa9, - 0x6b, 0xde, 0x8e, 0x58, 0xce, 0xef, 0xcf, 0xe0, 0xbc, 0xac, 0xb6, 0x55, 0x75, 0x6d, 0x11, 0x59, - 0x6a, 0x2f, 0xc6, 0x4e, 0xcb, 0x4f, 0x6a, 0xb4, 0x57, 0xd8, 0x33, 0x4d, 0x4a, 0xea, 0x9a, 0xb7, - 0xd3, 0xd7, 0x9d, 0xf2, 0x5b, 0xe3, 0x30, 0xf3, 0xb2, 0x75, 0x40, 0xdc, 0xd0, 0x1a, 0x5e, 0x01, - 0xd1, 0x03, 0x68, 0x8b, 0x45, 0xd5, 0x69, 0xa6, 0x52, 0x74, 0x00, 0x8d, 0x40, 0x58, 0xc7, 0x8b, - 0xf4, 0xca, 0xaa, 0xe7, 0xee, 0xda, 0x8d, 0x34, 0x8d, 0xb0, 0x9a, 0x80, 0xe3, 0x9e, 0x1a, 0xe8, - 0x1a, 0x20, 0x11, 0x74, 0x5f, 0xae, 0xd5, 0xbc, 0xb6, 0xcb, 0x35, 0x0b, 0x3f, 0x9b, 0x2a, 0x9b, - 0x7d, 0xb3, 0x07, 0x03, 0xa7, 0xd4, 0x42, 0xef, 0x83, 0xa5, 0x1a, 0xa3, 0x2c, 0x2c, 0x38, 0x9d, - 0x22, 0xb7, 0xe2, 0x55, 0x44, 0xeb, 0x6a, 0x1f, 0x3c, 0xdc, 0x97, 0x02, 0x6d, 0x69, 0x10, 0x7a, - 0xbe, 0xd5, 0x20, 0x3a, 0xdd, 0x89, 0x78, 0x4b, 0xab, 0x3d, 0x18, 0x38, 0xa5, 0x16, 0xfa, 0x28, - 0x4c, 0x85, 0x7b, 0x3e, 0x09, 0xf6, 0x3c, 0xa7, 0x2e, 0xee, 0x31, 0x47, 0x74, 0x58, 0x88, 0xd9, - 0xdf, 0x96, 0x54, 0x35, 0xf1, 0x96, 0x45, 0x38, 0xe2, 0x89, 0x7c, 0x98, 0x08, 0xe8, 0x69, 0x39, - 0x58, 0x2a, 0x64, 0x61, 0x95, 0x0b, 0xee, 0xec, 0x00, 0xae, 0xb9, 0x4a, 0x18, 0x07, 0x2c, 0x38, - 0x99, 0xdf, 0xc8, 0xc1, 0xb4, 0x8e, 0x38, 0x80, 0x8a, 0xf8, 0x84, 0x01, 0xd3, 0x35, 0xcf, 0x0d, - 0x7d, 0xcf, 0xe1, 0x6e, 0x00, 0xbe, 0x40, 0x46, 0x7c, 0xb4, 0xc7, 0x48, 0xad, 0x91, 0xd0, 0xb2, - 0x1d, 0xcd, 0xa3, 0xa0, 0xb1, 0xc1, 0x31, 0xa6, 0xe8, 0x33, 0x06, 0xcc, 0x45, 0x01, 0x1e, 0x91, - 0x3f, 0x22, 0xd3, 0x86, 0x28, 0x8d, 0x7b, 0x39, 0xce, 0x09, 0x27, 0x59, 0x9b, 0x3b, 0x30, 0x9f, - 0x9c, 0x6d, 0x3a, 0x94, 0x2d, 0x4b, 0xac, 0xf5, 0x7c, 0x34, 0x94, 0x5b, 0x56, 0x10, 0x60, 0x06, - 0x41, 0x6f, 0x81, 0x42, 0xd3, 0xf2, 0x1b, 0xb6, 0x6b, 0x39, 0x6c, 0x14, 0xf3, 0x9a, 0x42, 0x12, - 0xe5, 0x58, 0x61, 0x98, 0x3f, 0x18, 0x83, 0xe2, 0x26, 0xb1, 0x82, 0xb6, 0x4f, 0x98, 0xc3, 0xf0, - 0xc4, 0x2d, 0xf2, 0xd8, 0x2b, 0xb8, 0x7c, 0x76, 0xaf, 0xe0, 0xd0, 0x2b, 0x00, 0xbb, 0xb6, 0x6b, - 0x07, 0x7b, 0xc7, 0x7c, 0x5f, 0xc7, 0x6e, 0x9e, 0xae, 0x28, 0x0a, 0x58, 0xa3, 0x16, 0xb9, 0xf7, - 0xc7, 0x0f, 0x79, 0x60, 0xfb, 0x49, 0x43, 0xdb, 0x3c, 0x26, 0xb2, 0xb8, 0xce, 0xd4, 0x26, 0x66, - 0x45, 0x6e, 0x26, 0x97, 0xdd, 0xd0, 0x3f, 0x38, 0x74, 0x8f, 0xd9, 0x86, 0x82, 0x4f, 0x82, 0x76, - 0x93, 0x9e, 0x2d, 0x26, 0x87, 0x1e, 0x06, 0x16, 0x0d, 0x81, 0x45, 0x7d, 0xac, 0x28, 0x2d, 0xbf, - 0x00, 0x33, 0xb1, 0x26, 0xa0, 0x79, 0xc8, 0xdf, 0x23, 0x07, 0x5c, 0x4e, 0x30, 0xfd, 0x89, 0x16, - 0x63, 0x97, 0x20, 0x62, 0x58, 0xde, 0x99, 0x7b, 0xde, 0x30, 0x7f, 0x34, 0x01, 0xe2, 0xc2, 0x6c, - 0x00, 0x5d, 0xa0, 0xfb, 0xc9, 0x73, 0xc7, 0xf0, 0x93, 0x5f, 0x83, 0x69, 0xdb, 0xb5, 0x43, 0xdb, - 0x72, 0xd8, 0x01, 0x54, 0xec, 0x55, 0x4f, 0xcb, 0xf5, 0xbf, 0xae, 0xc1, 0x52, 0xe8, 0xc4, 0xea, - 0xa2, 0x9b, 0x30, 0xce, 0x94, 0xb9, 0x90, 0xa7, 0xe1, 0x6f, 0xf5, 0xd8, 0x85, 0x2e, 0x8f, 0x6c, - 0xe7, 0x94, 0x98, 0x81, 0xcd, 0x9f, 0x3c, 0xaa, 0x73, 0x93, 0x10, 0xab, 0xc8, 0xc0, 0x4e, 0xc0, - 0x71, 0x4f, 0x0d, 0x4a, 0x65, 0xd7, 0xb2, 0x9d, 0xb6, 0x4f, 0x22, 0x2a, 0x13, 0x71, 0x2a, 0x57, - 0x12, 0x70, 0xdc, 0x53, 0x03, 0xed, 0xc2, 0xb4, 0x28, 0xe3, 0xf1, 0x0d, 0x93, 0xc7, 0xec, 0x25, - 0x8b, 0x63, 0xb9, 0xa2, 0x51, 0xc2, 0x31, 0xba, 0xa8, 0x0d, 0x0b, 0xb6, 0x5b, 0xf3, 0xdc, 0x9a, - 0xd3, 0x0e, 0xec, 0x7d, 0x12, 0x85, 0x95, 0x1f, 0x87, 0xd9, 0xe9, 0x6e, 0xa7, 0xb4, 0xb0, 0x9e, - 0x24, 0x87, 0x7b, 0x39, 0xa0, 0x8f, 0x1b, 0x70, 0xba, 0xe6, 0xb9, 0x01, 0x7b, 0x58, 0xb5, 0x4f, - 0x2e, 0xfb, 0xbe, 0xe7, 0x73, 0xde, 0x53, 0xc7, 0xe4, 0xcd, 0xfc, 0x1e, 0xab, 0x69, 0x24, 0x71, - 0x3a, 0x27, 0xf4, 0x1a, 0x14, 0x5a, 0xbe, 0xb7, 0x6f, 0xd7, 0x89, 0x2f, 0x62, 0x65, 0x36, 0xb2, - 0x78, 0xd3, 0xb8, 0x25, 0x68, 0x46, 0x9a, 0x40, 0x96, 0x60, 0xc5, 0xcf, 0xfc, 0xbd, 0x02, 0xcc, - 0xc6, 0xd1, 0xd1, 0x47, 0x00, 0x5a, 0xbe, 0xd7, 0x24, 0xe1, 0x1e, 0x51, 0xe1, 0xc1, 0xd7, 0x47, - 0x7d, 0x4f, 0x28, 0xe9, 0xc9, 0x3b, 0x72, 0xaa, 0x49, 0xa3, 0x52, 0xac, 0x71, 0x44, 0x3e, 0x4c, - 0xde, 0xe3, 0x7b, 0x9a, 0xd8, 0xe2, 0x5f, 0xce, 0xc4, 0x20, 0x11, 0x9c, 0x59, 0x5c, 0xab, 0x28, - 0xc2, 0x92, 0x11, 0xda, 0x81, 0xfc, 0x7d, 0xb2, 0x93, 0xcd, 0xcb, 0xb7, 0x3b, 0x44, 0x1c, 0x15, - 0x2a, 0x93, 0xdd, 0x4e, 0x29, 0x7f, 0x87, 0xec, 0x60, 0x4a, 0x9c, 0xf6, 0xab, 0xce, 0x6f, 0xfb, - 0x84, 0xaa, 0x18, 0xb1, 0x5f, 0xb1, 0xab, 0x43, 0xde, 0x2f, 0x51, 0x84, 0x25, 0x23, 0xf4, 0x1a, - 0x4c, 0xdd, 0xb7, 0xf6, 0xc9, 0xae, 0xef, 0xb9, 0xa1, 0x08, 0xcc, 0x18, 0x31, 0x02, 0xf5, 0x8e, - 0x24, 0x27, 0xf8, 0xb2, 0xdd, 0x56, 0x15, 0xe2, 0x88, 0x1d, 0xda, 0x87, 0x82, 0x4b, 0xee, 0x63, - 0xe2, 0xd8, 0x35, 0x11, 0xfc, 0x37, 0xa2, 0x58, 0x5f, 0x17, 0xd4, 0x04, 0x67, 0xb6, 0x0d, 0xc9, - 0x32, 0xac, 0x78, 0xd1, 0xb9, 0xbc, 0xeb, 0xed, 0x08, 0x45, 0x35, 0xe2, 0x5c, 0xaa, 0x63, 0x1f, - 0x9f, 0xcb, 0x6b, 0xde, 0x0e, 0xa6, 0xc4, 0xe9, 0x1a, 0xa9, 0xa9, 0xa8, 0x00, 0xa1, 0xa6, 0xae, - 0x67, 0x1b, 0x0d, 0xc1, 0xd7, 0x48, 0x54, 0x8a, 0x35, 0x8e, 0x74, 0x6c, 0x1b, 0xc2, 0xcb, 0x24, - 0x14, 0xd5, 0x88, 0x63, 0x1b, 0xf7, 0x59, 0xf1, 0xb1, 0x95, 0x65, 0x58, 0xf1, 0x32, 0xff, 0x78, - 0x0c, 0xa6, 0xf5, 0x0c, 0x06, 0x03, 0xec, 0xd5, 0xca, 0x5c, 0xcc, 0x0d, 0x63, 0x2e, 0x52, 0x6b, - 0xbf, 0x19, 0xd9, 0x36, 0xf2, 0xc0, 0xbf, 0x9e, 0x99, 0xb5, 0x14, 0x59, 0xfb, 0x5a, 0x61, 0x80, - 0x63, 0x4c, 0x87, 0xb8, 0x22, 0xa5, 0xf6, 0x1f, 0x37, 0x03, 0xf8, 0x13, 0x31, 0x65, 0xff, 0xc5, - 0x36, 0xf6, 0x4b, 0x00, 0x51, 0x2e, 0x03, 0xe1, 0x27, 0x57, 0x3e, 0x52, 0x2d, 0xc7, 0x82, 0x86, - 0x85, 0x9e, 0x86, 0x09, 0xba, 0x51, 0x92, 0xba, 0x78, 0xbb, 0xa5, 0x8e, 0x54, 0x57, 0x58, 0x29, - 0x16, 0x50, 0xf4, 0x3c, 0xb5, 0x69, 0xa2, 0xed, 0x4d, 0x3c, 0xc9, 0x5a, 0x8c, 0x6c, 0x9a, 0x08, - 0x86, 0x63, 0x98, 0xb4, 0xe9, 0x84, 0xee, 0x46, 0x4c, 0x92, 0xb4, 0xa6, 0xb3, 0x2d, 0x0a, 0x73, - 0x18, 0x3b, 0xe2, 0x27, 0x76, 0x2f, 0xb6, 0x59, 0x8d, 0x6b, 0x47, 0xfc, 0x04, 0x1c, 0xf7, 0xd4, - 0x30, 0x3f, 0x00, 0xb3, 0xf1, 0x55, 0x4c, 0x87, 0xb8, 0xe5, 0x7b, 0xbb, 0xb6, 0x43, 0x92, 0xce, - 0x89, 0x2d, 0x5e, 0x8c, 0x25, 0x7c, 0x30, 0xef, 0xe8, 0x5f, 0xe6, 0xe1, 0xd4, 0xf5, 0x86, 0xed, - 0x3e, 0x48, 0xb8, 0x15, 0xd3, 0x52, 0x24, 0x19, 0xc3, 0xa6, 0x48, 0x8a, 0x82, 0xcf, 0x45, 0xc2, - 0xa7, 0xf4, 0xe0, 0x73, 0x99, 0x0d, 0x2a, 0x8e, 0x8b, 0xbe, 0x6b, 0xc0, 0x93, 0x56, 0x9d, 0xdb, - 0x55, 0x96, 0x23, 0x4a, 0x23, 0xa6, 0x52, 0xc6, 0x83, 0x11, 0xb5, 0x64, 0x6f, 0xe7, 0x57, 0xca, - 0x87, 0x70, 0xe5, 0xa7, 0x85, 0x37, 0x89, 0x1e, 0x3c, 0x79, 0x18, 0x2a, 0x3e, 0xb4, 0xf9, 0xcb, - 0x37, 0xe0, 0x8d, 0x47, 0x32, 0x1a, 0xea, 0x4c, 0xf0, 0x09, 0x03, 0xa6, 0xb8, 0xd7, 0x0c, 0x93, - 0x5d, 0xba, 0x78, 0xac, 0x96, 0x7d, 0x9b, 0xf8, 0x81, 0xcc, 0x73, 0xa0, 0x85, 0x7a, 0x95, 0xb7, - 0xd6, 0x05, 0x04, 0x6b, 0x58, 0x54, 0x3d, 0xdd, 0xb3, 0xdd, 0xba, 0x98, 0x26, 0xa5, 0x9e, 0x5e, - 0xb6, 0xdd, 0x3a, 0x66, 0x10, 0xa5, 0xc0, 0xf2, 0xfd, 0x14, 0x98, 0xf9, 0xdb, 0x06, 0xcc, 0xb2, - 0xb7, 0x25, 0x91, 0x51, 0xfc, 0x9c, 0xba, 0x11, 0xe6, 0xcd, 0x38, 0x1b, 0xbf, 0x11, 0x7e, 0xd8, - 0x29, 0x15, 0xf9, 0x6b, 0x94, 0xf8, 0x05, 0xf1, 0x7b, 0xc5, 0xc1, 0x96, 0xdd, 0x5b, 0xe7, 0x86, - 0x3e, 0x77, 0x29, 0x37, 0x4e, 0x55, 0x12, 0xc1, 0x11, 0x3d, 0xf3, 0x0f, 0xf2, 0x70, 0x2a, 0x25, - 0x48, 0x9a, 0x9e, 0x39, 0x27, 0x58, 0x9c, 0xa8, 0xbc, 0x75, 0x7d, 0x35, 0xf3, 0x40, 0xec, 0x15, - 0x16, 0x8e, 0x2a, 0x24, 0x49, 0xe9, 0x27, 0x5e, 0x88, 0x05, 0x73, 0xf4, 0xeb, 0x06, 0x14, 0x2d, - 0x4d, 0xd8, 0xf9, 0x45, 0xf4, 0x4e, 0xf6, 0x8d, 0xe9, 0x91, 0x6d, 0x2d, 0x80, 0x26, 0x12, 0x65, - 0xbd, 0x2d, 0xcb, 0xef, 0x80, 0xa2, 0xd6, 0x85, 0x61, 0x64, 0x74, 0xf9, 0x45, 0x98, 0x1f, 0x49, - 0xc6, 0xdf, 0x03, 0xc3, 0x26, 0xce, 0xa0, 0x3b, 0xc2, 0x7d, 0xfd, 0xc9, 0x95, 0x1a, 0x71, 0xf1, - 0xe6, 0x4a, 0x40, 0xcd, 0x1d, 0x98, 0x4f, 0x1a, 0xde, 0x99, 0x5f, 0x46, 0xbd, 0x0d, 0x86, 0x4c, - 0x75, 0x61, 0xfe, 0x55, 0x0e, 0x26, 0xc5, 0x4b, 0x8b, 0x47, 0x10, 0x7b, 0x76, 0x2f, 0xe6, 0x4d, - 0x5f, 0xcf, 0xe4, 0x81, 0x48, 0xdf, 0xc0, 0xb3, 0x20, 0x11, 0x78, 0xf6, 0x72, 0x36, 0xec, 0x0e, - 0x8f, 0x3a, 0xfb, 0x5c, 0x0e, 0xe6, 0x12, 0x2f, 0x57, 0xd0, 0xa7, 0x8c, 0xde, 0x60, 0x8b, 0x5b, - 0x99, 0x3e, 0x8e, 0x51, 0x91, 0x8d, 0x87, 0xc7, 0x5d, 0x04, 0xb1, 0xe4, 0x39, 0x37, 0x33, 0x4b, - 0xb0, 0x76, 0x68, 0x1e, 0x9d, 0x7f, 0x36, 0xe0, 0xf1, 0xbe, 0x6f, 0x79, 0xd8, 0x23, 0x65, 0x3f, - 0x0e, 0x15, 0xb2, 0x97, 0xf1, 0xdb, 0x3c, 0xe5, 0xc5, 0x4d, 0xbe, 0x2b, 0x4d, 0xb2, 0x47, 0xcf, - 0xc2, 0x34, 0xd3, 0xe3, 0x74, 0xf9, 0x84, 0xa4, 0x25, 0x32, 0x63, 0x31, 0x8f, 0x49, 0x55, 0x2b, - 0xc7, 0x31, 0x2c, 0xf3, 0x2b, 0x06, 0x2c, 0xf5, 0x7b, 0xb2, 0x3a, 0x80, 0x5d, 0xfe, 0x73, 0x89, - 0x38, 0xb0, 0x52, 0x4f, 0x1c, 0x58, 0xc2, 0x32, 0x97, 0x21, 0x5f, 0x9a, 0x51, 0x9c, 0x3f, 0x22, - 0xcc, 0xe9, 0xb3, 0x06, 0x9c, 0xe9, 0x23, 0x38, 0x3d, 0xf1, 0x80, 0xc6, 0xb1, 0xe3, 0x01, 0x73, - 0x83, 0xc6, 0x03, 0x9a, 0x7f, 0x93, 0x87, 0x79, 0xd1, 0x9e, 0x68, 0x33, 0x7f, 0x3e, 0x16, 0x4d, - 0xf7, 0xa6, 0x44, 0x34, 0xdd, 0x62, 0x12, 0xff, 0xff, 0x43, 0xe9, 0x7e, 0xb2, 0x42, 0xe9, 0x7e, - 0x9c, 0x83, 0xd3, 0xa9, 0x2f, 0x73, 0xd1, 0xa7, 0x53, 0xb4, 0xe0, 0x9d, 0x8c, 0x9f, 0x00, 0x0f, - 0xa8, 0x07, 0x47, 0x8d, 0x3f, 0xfb, 0xa2, 0x1e, 0xf7, 0xc5, 0x8f, 0x09, 0xbb, 0x27, 0xf0, 0x98, - 0x79, 0xc8, 0x10, 0x30, 0xf3, 0x57, 0xf2, 0x70, 0x61, 0x50, 0x42, 0x3f, 0xa1, 0x21, 0xc2, 0x41, - 0x2c, 0x44, 0xf8, 0xd1, 0xec, 0x50, 0x27, 0x13, 0x2d, 0xfc, 0xd5, 0xbc, 0xda, 0xf6, 0x7a, 0xe5, - 0x73, 0xa0, 0x4b, 0x95, 0x49, 0x6a, 0xc5, 0xc8, 0x64, 0x58, 0x91, 0x2a, 0x9c, 0xac, 0xf2, 0xe2, - 0x87, 0x9d, 0xd2, 0x82, 0xc8, 0xb9, 0x53, 0x25, 0xa1, 0x28, 0xc4, 0xb2, 0x12, 0xba, 0x00, 0x05, - 0x9f, 0x43, 0x65, 0x50, 0xa4, 0xb8, 0x28, 0xe2, 0x65, 0x58, 0x41, 0xd1, 0x47, 0x35, 0xb3, 0x6f, - 0xec, 0xa4, 0x1e, 0x87, 0x1e, 0x76, 0xff, 0xf5, 0x2a, 0x14, 0x02, 0x99, 0x29, 0x8b, 0x7b, 0x45, - 0x9f, 0x19, 0x30, 0xd6, 0x96, 0x9e, 0x12, 0x64, 0xda, 0x2c, 0xde, 0x3f, 0x95, 0x54, 0x4b, 0x91, - 0x44, 0xa6, 0x32, 0xd0, 0xb9, 0x8b, 0x07, 0x52, 0x8c, 0xf3, 0xd7, 0x0d, 0x28, 0x8a, 0xd9, 0x7a, - 0x04, 0xe1, 0xbf, 0x77, 0xe3, 0xe1, 0xbf, 0x97, 0x33, 0xd1, 0x1d, 0x7d, 0x62, 0x7f, 0xef, 0xc2, - 0xb4, 0x9e, 0x9c, 0x01, 0xbd, 0xa2, 0xe9, 0x3e, 0x63, 0x94, 0x47, 0xe0, 0x52, 0x3b, 0x46, 0x7a, - 0xd1, 0xfc, 0x72, 0x41, 0x8d, 0x22, 0x0b, 0x32, 0xd6, 0x65, 0xd0, 0x38, 0x54, 0x06, 0x75, 0x11, - 0xc8, 0x65, 0x2f, 0x02, 0x37, 0xa1, 0x20, 0x15, 0x94, 0xd8, 0xc6, 0x9f, 0xd2, 0x23, 0x79, 0xa8, - 0x2d, 0x40, 0x89, 0x69, 0x82, 0xcb, 0x4e, 0x15, 0x6a, 0x0e, 0x95, 0xe2, 0x54, 0x64, 0xd0, 0x6b, - 0x50, 0xbc, 0xef, 0xf9, 0xf7, 0x1c, 0xcf, 0x62, 0x09, 0xeb, 0x20, 0x0b, 0xff, 0xb6, 0xf2, 0xae, - 0xf0, 0x80, 0xd1, 0x3b, 0x11, 0x7d, 0xac, 0x33, 0x43, 0x65, 0x98, 0x6b, 0xda, 0x2e, 0x26, 0x56, - 0x5d, 0x45, 0xf9, 0x8e, 0xf1, 0x24, 0x5d, 0xd2, 0xc8, 0xdd, 0x8c, 0x83, 0x71, 0x12, 0x1f, 0x7d, - 0x08, 0x0a, 0x81, 0x48, 0x00, 0x91, 0xcd, 0x4d, 0x84, 0x3a, 0x1e, 0x71, 0xa2, 0xd1, 0xd8, 0xc9, - 0x12, 0xac, 0x18, 0xa2, 0x0d, 0x58, 0xf4, 0xc5, 0x13, 0xeb, 0x58, 0x0e, 0x5a, 0xbe, 0x3e, 0x59, - 0x2e, 0x28, 0x9c, 0x02, 0xc7, 0xa9, 0xb5, 0xa8, 0x15, 0xc3, 0xb2, 0x8c, 0x70, 0x97, 0x6c, 0x41, - 0x7b, 0x97, 0xc9, 0x4a, 0xb1, 0x80, 0x1e, 0x16, 0x35, 0x5e, 0x18, 0x21, 0x6a, 0xbc, 0x0a, 0xa7, - 0x93, 0x20, 0xf6, 0x10, 0x9c, 0xbd, 0x3d, 0xd7, 0x76, 0x8f, 0xad, 0x34, 0x24, 0x9c, 0x5e, 0x17, - 0xdd, 0x81, 0x29, 0x9f, 0xb0, 0xf3, 0x45, 0x59, 0xde, 0x7d, 0x0e, 0x1d, 0x74, 0x81, 0x25, 0x01, - 0x1c, 0xd1, 0xa2, 0xf3, 0x6e, 0xc5, 0xf3, 0x54, 0xdd, 0xcc, 0x30, 0x5d, 0xba, 0x98, 0xfb, 0x3e, - 0x09, 0x1a, 0xcc, 0xff, 0x9a, 0x81, 0x99, 0xd8, 0x31, 0x1a, 0x3d, 0x05, 0xe3, 0xec, 0x65, 0x3c, - 0x53, 0x0f, 0x85, 0x48, 0x85, 0xf1, 0xc1, 0xe1, 0x30, 0xf4, 0x39, 0x03, 0xe6, 0x5a, 0x31, 0x97, - 0x9f, 0xd4, 0x9c, 0x23, 0x5e, 0xb3, 0xc4, 0xfd, 0x88, 0x5a, 0x86, 0xc7, 0x38, 0x33, 0x9c, 0xe4, - 0x4e, 0x17, 0xa0, 0x88, 0x43, 0x72, 0x88, 0xcf, 0xb0, 0x85, 0x8d, 0xa3, 0x48, 0xac, 0xc6, 0xc1, - 0x38, 0x89, 0x4f, 0x67, 0x98, 0xf5, 0x6e, 0x94, 0xe4, 0xd2, 0x65, 0x49, 0x00, 0x47, 0xb4, 0xd0, - 0x8b, 0x30, 0x2b, 0xd2, 0x13, 0x6d, 0x79, 0xf5, 0xab, 0x56, 0xb0, 0x27, 0x8c, 0x7b, 0x75, 0x18, - 0x59, 0x8d, 0x41, 0x71, 0x02, 0x9b, 0xf5, 0x2d, 0xca, 0x01, 0xc5, 0x08, 0x4c, 0xc4, 0x13, 0x60, - 0xae, 0xc6, 0xc1, 0x38, 0x89, 0x8f, 0xde, 0xa2, 0xe9, 0x7d, 0x7e, 0x4d, 0xa2, 0xb4, 0x41, 0x8a, - 0xee, 0x2f, 0xc3, 0x5c, 0x9b, 0x9d, 0x85, 0xea, 0x12, 0x28, 0xd6, 0xa3, 0x62, 0x78, 0x2b, 0x0e, - 0xc6, 0x49, 0x7c, 0xf4, 0x02, 0xcc, 0xf8, 0x54, 0xbb, 0x29, 0x02, 0xfc, 0xee, 0x44, 0x5d, 0x04, - 0x60, 0x1d, 0x88, 0xe3, 0xb8, 0xe8, 0x25, 0x58, 0x88, 0x72, 0xa6, 0x48, 0x02, 0xfc, 0x32, 0x45, - 0x25, 0x21, 0x28, 0x27, 0x11, 0x70, 0x6f, 0x1d, 0xf4, 0xf3, 0x30, 0xaf, 0x8d, 0xc4, 0xba, 0x5b, - 0x27, 0x0f, 0x44, 0x5e, 0x8b, 0x45, 0x76, 0x21, 0x93, 0x80, 0xe1, 0x1e, 0x6c, 0xf4, 0x4e, 0x98, - 0xad, 0x79, 0x8e, 0xc3, 0x74, 0x1c, 0x4f, 0xbe, 0xc8, 0x13, 0x58, 0xf0, 0x54, 0x1f, 0x31, 0x08, - 0x4e, 0x60, 0xa2, 0x6b, 0x80, 0xbc, 0x9d, 0x80, 0xf8, 0xfb, 0xa4, 0xfe, 0x12, 0xff, 0x7e, 0x06, - 0xdd, 0xe2, 0x67, 0xe2, 0x51, 0x90, 0x37, 0x7a, 0x30, 0x70, 0x4a, 0x2d, 0xb4, 0x03, 0xcb, 0x72, - 0xbf, 0xe9, 0xad, 0xb1, 0xb4, 0x14, 0x3b, 0x32, 0x2d, 0xdf, 0xe9, 0x8b, 0x89, 0x0f, 0xa1, 0xc2, - 0xf2, 0x24, 0x68, 0xaf, 0x1e, 0x66, 0xb3, 0x48, 0x67, 0x9d, 0xf4, 0x0e, 0x1c, 0xf9, 0xe4, 0xc1, - 0x87, 0x09, 0x1e, 0xf8, 0xba, 0x34, 0x97, 0x45, 0xae, 0x18, 0x3d, 0xd7, 0x5b, 0xb4, 0x0f, 0xf1, - 0x52, 0x2c, 0x38, 0xa1, 0x8f, 0xc0, 0xd4, 0x8e, 0x4c, 0xfc, 0xb9, 0x34, 0x9f, 0xc5, 0xde, 0x9b, - 0xc8, 0x61, 0x1b, 0x9d, 0x7e, 0x15, 0x00, 0x47, 0x2c, 0xd1, 0xd3, 0x50, 0xbc, 0xba, 0x55, 0x56, - 0x92, 0xbe, 0xc0, 0x24, 0x6c, 0x8c, 0x56, 0xc1, 0x3a, 0x80, 0xae, 0x62, 0x65, 0x93, 0x21, 0x36, - 0xe5, 0xd1, 0x9e, 0xde, 0x6b, 0x62, 0x51, 0x6c, 0x76, 0xbf, 0x86, 0xab, 0x4b, 0xa7, 0x12, 0xd8, - 0xa2, 0x1c, 0x2b, 0x0c, 0xf4, 0x2a, 0x14, 0xc5, 0x9e, 0xc4, 0xf4, 0xdf, 0xe2, 0xf1, 0x5e, 0xd4, - 0xe0, 0x88, 0x04, 0xd6, 0xe9, 0xa1, 0xe7, 0xa0, 0xd8, 0x62, 0xf9, 0x10, 0xc9, 0x95, 0xb6, 0xe3, - 0x2c, 0x9d, 0x66, 0xba, 0x59, 0x5d, 0x3c, 0x6c, 0x45, 0x20, 0xac, 0xe3, 0xa1, 0x67, 0xe4, 0xe5, - 0xf8, 0x1b, 0x62, 0xf7, 0x48, 0xea, 0x72, 0x5c, 0x59, 0xd2, 0x7d, 0x42, 0x29, 0xcf, 0x1c, 0xe1, - 0x1c, 0xf9, 0x78, 0xe4, 0x1c, 0x56, 0xd9, 0xb7, 0x3e, 0xac, 0x4b, 0x83, 0x91, 0xc5, 0x57, 0x3e, - 0x7a, 0xb2, 0xca, 0xf2, 0xcd, 0x22, 0x55, 0x16, 0x5a, 0x4a, 0xfe, 0x33, 0x79, 0x0e, 0x1e, 0xcf, - 0x2c, 0xc6, 0x4f, 0x5a, 0x71, 0xe9, 0x37, 0xbf, 0x37, 0xa6, 0x1c, 0x44, 0x89, 0x3b, 0x61, 0x1f, - 0xc6, 0xed, 0x20, 0xb4, 0xbd, 0x0c, 0x1f, 0x98, 0x24, 0x52, 0x72, 0xb1, 0xd8, 0x3e, 0x06, 0xc0, - 0x9c, 0x15, 0xe5, 0xe9, 0x36, 0x6c, 0xf7, 0x81, 0xe8, 0xfe, 0xcd, 0xcc, 0x2f, 0x7b, 0x39, 0x4f, - 0x06, 0xc0, 0x9c, 0x15, 0xba, 0x0b, 0x79, 0xcb, 0xd9, 0xc9, 0xe8, 0x8b, 0x2e, 0xc9, 0xaf, 0x22, - 0xf1, 0xc8, 0x98, 0xf2, 0x46, 0x05, 0x53, 0x26, 0x94, 0x57, 0xd0, 0xb4, 0x85, 0x7d, 0x31, 0x22, - 0xaf, 0xea, 0xe6, 0x7a, 0x1a, 0xaf, 0xea, 0xe6, 0x3a, 0xa6, 0x4c, 0xd0, 0xa7, 0x0c, 0x00, 0x4b, - 0x7d, 0xb1, 0x28, 0x9b, 0x14, 0xcc, 0xfd, 0xbe, 0x80, 0xc4, 0xc3, 0x71, 0x22, 0x28, 0xd6, 0x38, - 0x9b, 0x9f, 0x37, 0x60, 0xa1, 0xa7, 0xb1, 0xc9, 0x8f, 0x39, 0x19, 0x83, 0x7f, 0xcc, 0x49, 0x24, - 0x6d, 0xab, 0xb6, 0x1c, 0x3b, 0xf5, 0x91, 0xd6, 0x76, 0x02, 0x8e, 0x7b, 0x6a, 0x98, 0x7f, 0x6a, - 0x40, 0x51, 0x8b, 0x29, 0xa7, 0x76, 0x2f, 0x8b, 0xbd, 0x17, 0xcd, 0x88, 0xf2, 0xd5, 0x31, 0x9f, - 0x18, 0x87, 0x71, 0xf7, 0x6c, 0x43, 0x4b, 0x4b, 0x14, 0xb9, 0x67, 0x69, 0x29, 0x16, 0x50, 0x9e, - 0x70, 0x86, 0xb4, 0x98, 0x44, 0xe5, 0xf5, 0x84, 0x33, 0xa4, 0x85, 0x19, 0x84, 0xb1, 0xa3, 0xca, - 0x51, 0xc4, 0xcd, 0x68, 0xe9, 0xf1, 0x2c, 0x6a, 0x66, 0x33, 0x18, 0x3a, 0x0b, 0x79, 0xe2, 0xd6, - 0x85, 0xb5, 0x58, 0x14, 0x28, 0xf9, 0xcb, 0x6e, 0x1d, 0xd3, 0x72, 0xf3, 0x06, 0x4c, 0x57, 0x49, - 0xcd, 0x27, 0xe1, 0xcb, 0xe4, 0x60, 0x30, 0x07, 0xe2, 0x59, 0x7e, 0xf1, 0x9a, 0x8b, 0x13, 0xa4, - 0xd5, 0x69, 0xb9, 0xf9, 0xbb, 0x06, 0x24, 0xb2, 0x15, 0x6a, 0xae, 0x1a, 0xa3, 0x9f, 0xab, 0x26, - 0xe6, 0x54, 0xc8, 0x1d, 0xea, 0x54, 0xb8, 0x06, 0xa8, 0x69, 0x85, 0xb5, 0xbd, 0x58, 0x2e, 0x4d, - 0x61, 0xa8, 0x47, 0x2f, 0x58, 0x7a, 0x30, 0x70, 0x4a, 0x2d, 0xf3, 0x36, 0x14, 0xe4, 0x6b, 0x24, - 0x16, 0xd2, 0x2f, 0xcf, 0x2c, 0x7a, 0x48, 0x3f, 0x3d, 0xb2, 0x30, 0x08, 0x6d, 0x63, 0xe0, 0xda, - 0x57, 0xbd, 0x20, 0x94, 0x4f, 0xa8, 0xb8, 0x67, 0xe2, 0xfa, 0x3a, 0x2b, 0xc3, 0x0a, 0x6a, 0x2e, - 0xc0, 0x9c, 0x72, 0x39, 0x70, 0x89, 0x33, 0xbf, 0x91, 0x87, 0xe9, 0xd8, 0x47, 0x36, 0x8e, 0x1e, - 0xe9, 0xc1, 0xc7, 0x24, 0xc5, 0x75, 0x90, 0x1f, 0xd2, 0x75, 0xa0, 0xfb, 0x6a, 0xc6, 0x4e, 0xd6, - 0x57, 0x33, 0x9e, 0x8d, 0xaf, 0x26, 0x84, 0x49, 0xf1, 0x59, 0x37, 0x11, 0xfa, 0xb8, 0x99, 0xd1, - 0x53, 0x62, 0xf1, 0x26, 0x8f, 0x45, 0x7b, 0x4a, 0xed, 0x21, 0x59, 0x99, 0x5f, 0x1f, 0x87, 0xd9, - 0xf8, 0xe3, 0xe2, 0x01, 0x66, 0xf2, 0x2d, 0x3d, 0x33, 0x39, 0xe4, 0xd1, 0x29, 0x3f, 0xea, 0xd1, - 0x69, 0x6c, 0xd4, 0xa3, 0xd3, 0xf8, 0x31, 0x8e, 0x4e, 0xbd, 0x07, 0x9f, 0x89, 0x81, 0x0f, 0x3e, - 0xef, 0x52, 0xf7, 0x7e, 0x93, 0x31, 0x47, 0x79, 0x74, 0xef, 0x87, 0xe2, 0xd3, 0xb0, 0xea, 0xd5, - 0x53, 0xef, 0x4f, 0x0b, 0x47, 0x04, 0x15, 0xfa, 0xa9, 0xd7, 0x74, 0xc3, 0x7b, 0x67, 0xde, 0x30, - 0xc4, 0x15, 0x5d, 0xf4, 0xe5, 0x42, 0xb6, 0xf3, 0x40, 0x7c, 0xd7, 0xaa, 0x46, 0x20, 0xac, 0xe3, - 0xb1, 0xaf, 0x58, 0xc4, 0xbf, 0xb1, 0xc1, 0x4e, 0xa2, 0xfa, 0x57, 0x2c, 0x12, 0xdf, 0xe4, 0x48, - 0xe2, 0x9b, 0x5f, 0xcb, 0xc3, 0x6c, 0x3c, 0x0b, 0x31, 0xba, 0xaf, 0xac, 0xc5, 0x4c, 0x0c, 0x55, - 0x4e, 0x56, 0x7b, 0x5e, 0xdb, 0xf7, 0xc8, 0xc4, 0x3f, 0xf1, 0xb7, 0xa3, 0xde, 0xfa, 0x9e, 0x1c, - 0x63, 0x71, 0x56, 0x11, 0xec, 0x58, 0xe2, 0xe2, 0x28, 0xca, 0x4e, 0xdc, 0xf5, 0x65, 0xce, 0x3d, - 0x8a, 0x9b, 0x53, 0xac, 0xb0, 0xc6, 0x96, 0xaa, 0xf7, 0x7d, 0xe2, 0xdb, 0xbb, 0xb6, 0xfa, 0x82, - 0x02, 0x53, 0x9e, 0xb7, 0x45, 0x19, 0x56, 0x50, 0xf3, 0x63, 0x39, 0x88, 0x3e, 0xee, 0xc2, 0x12, - 0xa2, 0x06, 0xda, 0x9e, 0x2d, 0xa6, 0xed, 0xda, 0xa8, 0x59, 0x87, 0x23, 0x8a, 0x22, 0x2c, 0x42, - 0x2b, 0xc1, 0x31, 0x8e, 0xff, 0x03, 0x1f, 0x75, 0xb1, 0x60, 0x2e, 0x11, 0x15, 0x9f, 0x79, 0x98, - 0xd5, 0x97, 0xf3, 0x30, 0xa5, 0xde, 0x15, 0xa0, 0x77, 0xb0, 0x5c, 0x86, 0x7b, 0x9e, 0xcc, 0x30, - 0xf9, 0x46, 0x2d, 0xe3, 0xe0, 0x9e, 0x57, 0x7f, 0xd8, 0x29, 0xcd, 0x29, 0x64, 0x5e, 0x84, 0x45, - 0x05, 0x6a, 0x21, 0xb5, 0x7d, 0x27, 0x69, 0x21, 0xdd, 0xc2, 0x1b, 0x98, 0x96, 0xa3, 0x07, 0x30, - 0xb9, 0x47, 0xac, 0x3a, 0xf1, 0xe5, 0x2d, 0xf3, 0x66, 0x46, 0x6f, 0x21, 0xae, 0x32, 0xaa, 0xd1, - 0x30, 0xf0, 0xff, 0x01, 0x96, 0xec, 0xe8, 0x46, 0xb5, 0xe3, 0xd5, 0x0f, 0x92, 0x19, 0x0a, 0x2b, - 0x5e, 0xfd, 0x00, 0x33, 0x08, 0x7a, 0x11, 0x66, 0x43, 0xbb, 0x49, 0xe8, 0x51, 0x56, 0xfb, 0x1a, - 0x47, 0x3e, 0x72, 0x33, 0x6e, 0xc7, 0xa0, 0x38, 0x81, 0x4d, 0x37, 0xba, 0xbb, 0x81, 0xe7, 0xb2, - 0x4c, 0x0e, 0x13, 0x71, 0x7f, 0xc1, 0xb5, 0xea, 0x8d, 0xeb, 0x2c, 0x91, 0x83, 0xc2, 0xa0, 0xd8, - 0x36, 0x0b, 0x5e, 0xf6, 0x89, 0xf0, 0xf2, 0xcf, 0x47, 0x4f, 0xcc, 0x78, 0x39, 0x56, 0x18, 0xe6, - 0x2d, 0x98, 0x4b, 0x74, 0x55, 0xda, 0xa2, 0x46, 0xba, 0x2d, 0x3a, 0x58, 0x3a, 0xc0, 0x3f, 0x34, - 0x60, 0xa1, 0x67, 0xf1, 0x0e, 0x1a, 0xff, 0x97, 0xd4, 0xe4, 0xb9, 0xe3, 0x6b, 0xf2, 0xfc, 0x70, - 0x9a, 0xbc, 0xb2, 0xf2, 0xcd, 0xef, 0x9f, 0x7b, 0xec, 0x5b, 0xdf, 0x3f, 0xf7, 0xd8, 0xb7, 0xbf, - 0x7f, 0xee, 0xb1, 0x8f, 0x75, 0xcf, 0x19, 0xdf, 0xec, 0x9e, 0x33, 0xbe, 0xd5, 0x3d, 0x67, 0x7c, - 0xbb, 0x7b, 0xce, 0xf8, 0x5e, 0xf7, 0x9c, 0xf1, 0xf9, 0x1f, 0x9c, 0x7b, 0xec, 0x95, 0x82, 0x14, - 0x93, 0xff, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xc4, 0xe9, 0xbc, 0xfd, 0x47, 0x79, 0x00, 0x00, + // 6668 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3d, 0x5b, 0x8c, 0x24, 0xc9, + 0x51, 0x57, 0xdd, 0xf3, 0xe8, 0x89, 0x79, 0xe7, 0xce, 0x7a, 0x7b, 0xe7, 0x6e, 0xb7, 0xcf, 0x75, + 0xd6, 0x71, 0x06, 0x7b, 0xd6, 0xde, 0xbb, 0x83, 0xb3, 0xcf, 0x3a, 0xd1, 0x3d, 0xb3, 0x8f, 0xd9, + 0x9b, 0xd9, 0x9d, 0xcd, 0x9e, 0xdd, 0xb5, 0xcf, 0x3e, 0xe3, 0x9a, 0xee, 0x9c, 0x9e, 0xda, 0xad, + 0xae, 0x6a, 0x57, 0x55, 0xcf, 0xee, 0x9c, 0x2d, 0xfb, 0x8c, 0x75, 0xc6, 0x20, 0x5b, 0x3e, 0xb0, + 0xfd, 0x81, 0x90, 0x91, 0x85, 0xf8, 0x40, 0x98, 0x0f, 0x64, 0x81, 0xf8, 0x31, 0x02, 0x81, 0x2d, + 0x99, 0x0f, 0x90, 0x91, 0x80, 0x33, 0xc8, 0x6e, 0x7c, 0x6d, 0xf8, 0x80, 0x1f, 0x64, 0xc9, 0x08, + 0x79, 0xbf, 0x50, 0x3e, 0x2b, 0xab, 0xba, 0x7a, 0xb6, 0x7b, 0xba, 0x66, 0xb1, 0x80, 0xbf, 0xee, + 0x8c, 0xc8, 0x88, 0x7c, 0x44, 0x46, 0x46, 0x46, 0x46, 0x46, 0xc1, 0x46, 0xc3, 0x0e, 0xf7, 0xda, + 0x3b, 0x2b, 0x35, 0xaf, 0x79, 0xce, 0xf2, 0x1b, 0x5e, 0xcb, 0xf7, 0x6e, 0xb3, 0x1f, 0xef, 0xf4, + 0x3d, 0xc7, 0xf1, 0xda, 0x61, 0x70, 0xae, 0x75, 0xa7, 0x71, 0xce, 0x6a, 0xd9, 0xc1, 0x39, 0x55, + 0xb2, 0xff, 0x6e, 0xcb, 0x69, 0xed, 0x59, 0xef, 0x3e, 0xd7, 0x20, 0x2e, 0xf1, 0xad, 0x90, 0xd4, + 0x57, 0x5a, 0xbe, 0x17, 0x7a, 0xe8, 0x7d, 0x11, 0xb5, 0x15, 0x49, 0x8d, 0xfd, 0xf8, 0x25, 0x59, + 0x77, 0xa5, 0x75, 0xa7, 0xb1, 0x42, 0xa9, 0xad, 0xa8, 0x12, 0x49, 0x6d, 0xf9, 0x9d, 0x5a, 0x5b, + 0x1a, 0x5e, 0xc3, 0x3b, 0xc7, 0x88, 0xee, 0xb4, 0x77, 0xd9, 0x3f, 0xf6, 0x87, 0xfd, 0xe2, 0xcc, + 0x96, 0x9f, 0xb8, 0xf3, 0x5c, 0xb0, 0x62, 0x7b, 0xb4, 0x6d, 0xe7, 0x76, 0xac, 0xb0, 0xb6, 0x77, + 0x6e, 0xbf, 0xa7, 0x45, 0xcb, 0xa6, 0x86, 0x54, 0xf3, 0x7c, 0x92, 0x86, 0xf3, 0x4c, 0x84, 0xd3, + 0xb4, 0x6a, 0x7b, 0xb6, 0x4b, 0xfc, 0x83, 0xa8, 0xd7, 0x4d, 0x12, 0x5a, 0x69, 0xb5, 0xce, 0xf5, + 0xab, 0xe5, 0xb7, 0xdd, 0xd0, 0x6e, 0x92, 0x9e, 0x0a, 0x3f, 0xff, 0xa0, 0x0a, 0x41, 0x6d, 0x8f, + 0x34, 0xad, 0x9e, 0x7a, 0x4f, 0xf7, 0xab, 0xd7, 0x0e, 0x6d, 0xe7, 0x9c, 0xed, 0x86, 0x41, 0xe8, + 0x27, 0x2b, 0x99, 0xdf, 0xcc, 0xc3, 0x54, 0x79, 0xa3, 0x52, 0x0d, 0xad, 0xb0, 0x1d, 0xa0, 0xcf, + 0x18, 0x30, 0xe3, 0x78, 0x56, 0xbd, 0x62, 0x39, 0x96, 0x5b, 0x23, 0x7e, 0xd1, 0x78, 0xdc, 0x78, + 0x6a, 0xfa, 0xfc, 0xc6, 0xca, 0x28, 0xf3, 0xb5, 0x52, 0xbe, 0x1b, 0x60, 0x12, 0x78, 0x6d, 0xbf, + 0x46, 0x30, 0xd9, 0xad, 0x2c, 0x7d, 0xbb, 0x53, 0x7a, 0xa4, 0xdb, 0x29, 0xcd, 0x6c, 0x68, 0x9c, + 0x70, 0x8c, 0x2f, 0xfa, 0xb2, 0x01, 0x8b, 0x35, 0xcb, 0xb5, 0xfc, 0x83, 0x6d, 0xcb, 0x6f, 0x90, + 0xf0, 0x92, 0xef, 0xb5, 0x5b, 0xc5, 0xdc, 0x31, 0xb4, 0xe6, 0xb4, 0x68, 0xcd, 0xe2, 0x6a, 0x92, + 0x1d, 0xee, 0x6d, 0x01, 0x6b, 0x57, 0x10, 0x5a, 0x3b, 0x0e, 0xd1, 0xdb, 0x95, 0x3f, 0xce, 0x76, + 0x55, 0x93, 0xec, 0x70, 0x6f, 0x0b, 0xcc, 0xd7, 0xf2, 0xb0, 0x58, 0xde, 0xa8, 0x6c, 0xfb, 0xd6, + 0xee, 0xae, 0x5d, 0xc3, 0x5e, 0x3b, 0xb4, 0xdd, 0x06, 0x7a, 0x3b, 0x4c, 0xda, 0x6e, 0xc3, 0x27, + 0x41, 0xc0, 0x26, 0x72, 0xaa, 0x32, 0x2f, 0x88, 0x4e, 0xae, 0xf3, 0x62, 0x2c, 0xe1, 0xe8, 0x59, + 0x98, 0x0e, 0x88, 0xbf, 0x6f, 0xd7, 0xc8, 0x96, 0xe7, 0x87, 0x6c, 0xa4, 0xc7, 0x2b, 0x27, 0x04, + 0xfa, 0x74, 0x35, 0x02, 0x61, 0x1d, 0x8f, 0x56, 0xf3, 0x3d, 0x2f, 0x14, 0x70, 0x36, 0x10, 0x53, + 0x51, 0x35, 0x1c, 0x81, 0xb0, 0x8e, 0x87, 0x5e, 0x37, 0x60, 0x21, 0x08, 0xed, 0xda, 0x1d, 0xdb, + 0x25, 0x41, 0xb0, 0xea, 0xb9, 0xbb, 0x76, 0xa3, 0x38, 0xce, 0x46, 0xf1, 0xea, 0x68, 0xa3, 0x58, + 0x4d, 0x50, 0xad, 0x2c, 0x75, 0x3b, 0xa5, 0x85, 0x64, 0x29, 0xee, 0xe1, 0x8e, 0xd6, 0x60, 0xc1, + 0x72, 0x5d, 0x2f, 0xb4, 0x42, 0xdb, 0x73, 0xb7, 0x7c, 0xb2, 0x6b, 0xdf, 0x2b, 0x8e, 0xb1, 0xee, + 0x14, 0x45, 0x77, 0x16, 0xca, 0x09, 0x38, 0xee, 0xa9, 0x61, 0xae, 0x41, 0xb1, 0xdc, 0xdc, 0xb1, + 0x82, 0xc0, 0xaa, 0x7b, 0x7e, 0x62, 0x36, 0x9e, 0x82, 0x42, 0xd3, 0x6a, 0xb5, 0x6c, 0xb7, 0x41, + 0xa7, 0x23, 0xff, 0xd4, 0x54, 0x65, 0xa6, 0xdb, 0x29, 0x15, 0x36, 0x45, 0x19, 0x56, 0x50, 0xf3, + 0x1f, 0x73, 0x30, 0x5d, 0x76, 0x2d, 0xe7, 0x20, 0xb0, 0x03, 0xdc, 0x76, 0xd1, 0x47, 0xa0, 0x40, + 0xb5, 0x4b, 0xdd, 0x0a, 0x2d, 0xb1, 0x22, 0xdf, 0xb5, 0xc2, 0x17, 0xfb, 0x8a, 0xbe, 0xd8, 0xa3, + 0x71, 0xa1, 0xd8, 0x2b, 0xfb, 0xef, 0x5e, 0xb9, 0xb6, 0x73, 0x9b, 0xd4, 0xc2, 0x4d, 0x12, 0x5a, + 0x15, 0x24, 0x7a, 0x01, 0x51, 0x19, 0x56, 0x54, 0x91, 0x07, 0x63, 0x41, 0x8b, 0xd4, 0xc4, 0x0a, + 0xdb, 0x1c, 0x51, 0x92, 0xa3, 0xa6, 0x57, 0x5b, 0xa4, 0x56, 0x99, 0x11, 0xac, 0xc7, 0xe8, 0x3f, + 0xcc, 0x18, 0xa1, 0xbb, 0x30, 0x11, 0x30, 0x9d, 0x23, 0x16, 0xcf, 0xb5, 0xec, 0x58, 0x32, 0xb2, + 0x95, 0x39, 0xc1, 0x74, 0x82, 0xff, 0xc7, 0x82, 0x9d, 0xf9, 0x4f, 0x06, 0x9c, 0xd0, 0xb0, 0xcb, + 0x7e, 0xa3, 0xdd, 0x24, 0x6e, 0x88, 0x1e, 0x87, 0x31, 0xd7, 0x6a, 0x12, 0xb1, 0x50, 0x54, 0x93, + 0xaf, 0x5a, 0x4d, 0x82, 0x19, 0x04, 0x3d, 0x01, 0xe3, 0xfb, 0x96, 0xd3, 0x26, 0x6c, 0x90, 0xa6, + 0x2a, 0xb3, 0x02, 0x65, 0xfc, 0x26, 0x2d, 0xc4, 0x1c, 0x86, 0x3e, 0x0e, 0x53, 0xec, 0xc7, 0x45, + 0xdf, 0x6b, 0x66, 0xd4, 0x35, 0xd1, 0xc2, 0x9b, 0x92, 0x6c, 0x65, 0xb6, 0xdb, 0x29, 0x4d, 0xa9, + 0xbf, 0x38, 0x62, 0x68, 0xfe, 0xb3, 0x01, 0xf3, 0x5a, 0xe7, 0x36, 0xec, 0x20, 0x44, 0x1f, 0xea, + 0x11, 0x9e, 0x95, 0xc1, 0x84, 0x87, 0xd6, 0x66, 0xa2, 0xb3, 0x20, 0x7a, 0x5a, 0x90, 0x25, 0x9a, + 0xe0, 0xb8, 0x30, 0x6e, 0x87, 0xa4, 0x19, 0x14, 0x73, 0x8f, 0xe7, 0x9f, 0x9a, 0x3e, 0xbf, 0x9e, + 0xd9, 0x34, 0x46, 0xe3, 0xbb, 0x4e, 0xe9, 0x63, 0xce, 0xc6, 0xfc, 0x4a, 0x2e, 0xd6, 0x43, 0x2a, + 0x51, 0xc8, 0x83, 0xc9, 0x26, 0x09, 0x7d, 0xbb, 0xc6, 0xd7, 0xd5, 0xf4, 0xf9, 0xb5, 0xd1, 0x5a, + 0xb1, 0xc9, 0x88, 0x45, 0xca, 0x92, 0xff, 0x0f, 0xb0, 0xe4, 0x82, 0xf6, 0x60, 0xcc, 0xf2, 0x1b, + 0xb2, 0xcf, 0x17, 0xb3, 0x99, 0xdf, 0x48, 0xe6, 0xca, 0x7e, 0x23, 0xc0, 0x8c, 0x03, 0x3a, 0x07, + 0x53, 0x21, 0xf1, 0x9b, 0xb6, 0x6b, 0x85, 0x5c, 0xbb, 0x16, 0x2a, 0x8b, 0x02, 0x6d, 0x6a, 0x5b, + 0x02, 0x70, 0x84, 0x63, 0xbe, 0x91, 0x83, 0xc5, 0x9e, 0xc5, 0x80, 0x9e, 0x81, 0xf1, 0xd6, 0x9e, + 0x15, 0x48, 0xe9, 0x3e, 0x2b, 0x87, 0x76, 0x8b, 0x16, 0xde, 0xef, 0x94, 0x66, 0x65, 0x15, 0x56, + 0x80, 0x39, 0x32, 0xdd, 0x3e, 0x9a, 0x24, 0x08, 0xac, 0x86, 0x14, 0x79, 0x6d, 0x44, 0x58, 0x31, + 0x96, 0x70, 0xf4, 0x2b, 0x06, 0xcc, 0xf2, 0xd1, 0xc1, 0x24, 0x68, 0x3b, 0x21, 0x5d, 0xd6, 0x74, + 0x6c, 0xae, 0x64, 0x31, 0x13, 0x9c, 0x64, 0xe5, 0xa4, 0xe0, 0x3e, 0xab, 0x97, 0x06, 0x38, 0xce, + 0x17, 0xdd, 0x82, 0xa9, 0x20, 0xb4, 0xfc, 0x90, 0xd4, 0xcb, 0x21, 0x53, 0xe0, 0xd3, 0xe7, 0x7f, + 0x76, 0x30, 0x79, 0xdf, 0xb6, 0x9b, 0x84, 0xaf, 0xad, 0xaa, 0x24, 0x80, 0x23, 0x5a, 0xe6, 0xdf, + 0xc7, 0x15, 0x47, 0x35, 0xa4, 0x66, 0x54, 0xe3, 0x00, 0x7d, 0x10, 0x4e, 0x07, 0xed, 0x5a, 0x8d, + 0x04, 0xc1, 0x6e, 0xdb, 0xc1, 0x6d, 0xf7, 0xb2, 0x1d, 0x84, 0x9e, 0x7f, 0xb0, 0x61, 0x37, 0xed, + 0x90, 0x8d, 0xf7, 0x78, 0xe5, 0x4c, 0xb7, 0x53, 0x3a, 0x5d, 0xed, 0x87, 0x84, 0xfb, 0xd7, 0x47, + 0x16, 0x3c, 0xda, 0x76, 0xfb, 0x93, 0xe7, 0xdb, 0x74, 0xa9, 0xdb, 0x29, 0x3d, 0x7a, 0xa3, 0x3f, + 0x1a, 0x3e, 0x8c, 0x86, 0xf9, 0xef, 0x06, 0x2c, 0xc8, 0x7e, 0x6d, 0x93, 0x66, 0xcb, 0xb1, 0x42, + 0xf2, 0x10, 0x76, 0x9c, 0x30, 0xb6, 0xe3, 0xe0, 0x6c, 0xf4, 0x86, 0x6c, 0x7f, 0xbf, 0x6d, 0xc7, + 0xfc, 0x37, 0x03, 0x96, 0x92, 0xc8, 0x0f, 0x41, 0x4b, 0x06, 0x71, 0x2d, 0x79, 0x35, 0xdb, 0xde, + 0xf6, 0x51, 0x95, 0x3f, 0x4a, 0xe9, 0xeb, 0xff, 0x72, 0x7d, 0x69, 0xfe, 0xde, 0x18, 0xcc, 0x94, + 0xdd, 0xd0, 0x2e, 0xef, 0xee, 0xda, 0xae, 0x1d, 0x1e, 0xa0, 0xcf, 0xe5, 0xe0, 0x5c, 0xcb, 0x27, + 0xbb, 0xc4, 0xf7, 0x49, 0x7d, 0xad, 0xed, 0xdb, 0x6e, 0xa3, 0x5a, 0xdb, 0x23, 0xf5, 0xb6, 0x63, + 0xbb, 0x8d, 0xf5, 0x86, 0xeb, 0xa9, 0xe2, 0x0b, 0xf7, 0x48, 0xad, 0x4d, 0x4d, 0x39, 0x31, 0xff, + 0xcd, 0xd1, 0x9a, 0xb9, 0x35, 0x1c, 0xd3, 0xca, 0xd3, 0xdd, 0x4e, 0xe9, 0xdc, 0x90, 0x95, 0xf0, + 0xb0, 0x5d, 0x43, 0x9f, 0xcd, 0xc1, 0x8a, 0x4f, 0x3e, 0xda, 0xb6, 0x07, 0x1f, 0x0d, 0xbe, 0x40, + 0x9d, 0xd1, 0x46, 0x03, 0x0f, 0xc5, 0xb3, 0x72, 0xbe, 0xdb, 0x29, 0x0d, 0x59, 0x07, 0x0f, 0xd9, + 0x2f, 0xf3, 0x2f, 0x0d, 0x28, 0x0c, 0x61, 0xfd, 0x95, 0xe2, 0xd6, 0xdf, 0x54, 0x8f, 0xe5, 0x17, + 0xf6, 0x5a, 0x7e, 0x97, 0x46, 0x1b, 0xb4, 0x41, 0x2c, 0xbe, 0xff, 0x30, 0x60, 0xb1, 0xc7, 0x42, + 0x44, 0x7b, 0xb0, 0xd4, 0xf2, 0xea, 0x72, 0xd1, 0x5f, 0xb6, 0x82, 0x3d, 0x06, 0x13, 0xdd, 0x7b, + 0xa6, 0xdb, 0x29, 0x2d, 0x6d, 0xa5, 0xc0, 0xef, 0x77, 0x4a, 0x45, 0x45, 0x24, 0x81, 0x80, 0x53, + 0x29, 0xa2, 0x16, 0x14, 0x76, 0x6d, 0xe2, 0xd4, 0x31, 0xd9, 0x15, 0x92, 0x32, 0xe2, 0xf2, 0xbe, + 0x28, 0xa8, 0xf1, 0xc3, 0x91, 0xfc, 0x87, 0x15, 0x17, 0xf3, 0x3a, 0xcc, 0xc5, 0x8f, 0xca, 0x03, + 0x4c, 0xde, 0x19, 0xc8, 0x5b, 0xbe, 0x2b, 0xa6, 0x6e, 0x5a, 0x20, 0xe4, 0xcb, 0xf8, 0x2a, 0xa6, + 0xe5, 0xe6, 0x4f, 0xc6, 0x60, 0xbe, 0xe2, 0xb4, 0xc9, 0x25, 0x9f, 0x10, 0x69, 0x32, 0x95, 0x61, + 0xbe, 0xe5, 0x93, 0x7d, 0x9b, 0xdc, 0xad, 0x12, 0x87, 0xd4, 0x42, 0xcf, 0x17, 0xf4, 0x4f, 0x89, + 0xea, 0xf3, 0x5b, 0x71, 0x30, 0x4e, 0xe2, 0xa3, 0x17, 0x60, 0xce, 0xaa, 0x85, 0xf6, 0x3e, 0x51, + 0x14, 0x78, 0x03, 0xde, 0x22, 0x28, 0xcc, 0x95, 0x63, 0x50, 0x9c, 0xc0, 0x46, 0x1f, 0x82, 0x62, + 0x50, 0xb3, 0x1c, 0x72, 0xa3, 0x25, 0x58, 0xad, 0xee, 0x91, 0xda, 0x9d, 0x2d, 0xcf, 0x76, 0x43, + 0x61, 0x0b, 0x3e, 0x2e, 0x28, 0x15, 0xab, 0x7d, 0xf0, 0x70, 0x5f, 0x0a, 0xe8, 0xcf, 0x0c, 0x38, + 0xd3, 0xf2, 0xc9, 0x96, 0xef, 0x35, 0x3d, 0xba, 0x20, 0x7a, 0xac, 0x46, 0x61, 0x3d, 0xdd, 0x1c, + 0x71, 0xe5, 0xf3, 0x92, 0xde, 0x03, 0xda, 0x5b, 0xbb, 0x9d, 0xd2, 0x99, 0xad, 0xc3, 0x1a, 0x80, + 0x0f, 0x6f, 0x1f, 0xfa, 0x0b, 0x03, 0xce, 0xb6, 0xbc, 0x20, 0x3c, 0xa4, 0x0b, 0xe3, 0xc7, 0xda, + 0x05, 0xb3, 0xdb, 0x29, 0x9d, 0xdd, 0x3a, 0xb4, 0x05, 0xf8, 0x01, 0x2d, 0x34, 0xbb, 0xd3, 0xb0, + 0xa8, 0xc9, 0x9e, 0x30, 0x2a, 0x9f, 0x87, 0x59, 0x29, 0x0c, 0xdc, 0xb3, 0xc2, 0x65, 0x4f, 0x99, + 0xc0, 0x65, 0x1d, 0x88, 0xe3, 0xb8, 0x54, 0xee, 0x94, 0x28, 0xf2, 0xda, 0x09, 0xb9, 0xdb, 0x8a, + 0x41, 0x71, 0x02, 0x1b, 0xad, 0xc3, 0x09, 0x51, 0x82, 0x49, 0xcb, 0xb1, 0x6b, 0xd6, 0xaa, 0xd7, + 0x16, 0x22, 0x37, 0x5e, 0x39, 0xd5, 0xed, 0x94, 0x4e, 0x6c, 0xf5, 0x82, 0x71, 0x5a, 0x1d, 0xb4, + 0x01, 0x4b, 0x56, 0x3b, 0xf4, 0x54, 0xff, 0x2f, 0xb8, 0xd6, 0x8e, 0x43, 0xea, 0x4c, 0xb4, 0x0a, + 0x95, 0x22, 0x55, 0x44, 0xe5, 0x14, 0x38, 0x4e, 0xad, 0x85, 0xb6, 0x12, 0xd4, 0xaa, 0xa4, 0xe6, + 0xb9, 0x75, 0x3e, 0xcb, 0xe3, 0x95, 0xc7, 0x44, 0xf7, 0xe2, 0x14, 0x05, 0x0e, 0x4e, 0xad, 0x89, + 0x1c, 0x98, 0x6b, 0x5a, 0xf7, 0x6e, 0xb8, 0xd6, 0xbe, 0x65, 0x3b, 0x94, 0x49, 0x71, 0xe2, 0x01, + 0xd6, 0x6e, 0x3b, 0xb4, 0x9d, 0x15, 0xee, 0x4c, 0x5d, 0x59, 0x77, 0xc3, 0x6b, 0x7e, 0x35, 0xa4, + 0xfb, 0x4a, 0x05, 0xd1, 0x81, 0xdd, 0x8c, 0xd1, 0xc2, 0x09, 0xda, 0xe8, 0x1a, 0x9c, 0x64, 0xcb, + 0x71, 0xcd, 0xbb, 0xeb, 0xae, 0x11, 0xc7, 0x3a, 0x90, 0x1d, 0x98, 0x64, 0x1d, 0x38, 0xdd, 0xed, + 0x94, 0x4e, 0x56, 0xd3, 0x10, 0x70, 0x7a, 0x3d, 0x7a, 0x3c, 0x88, 0x03, 0x30, 0xd9, 0xb7, 0x03, + 0xdb, 0x73, 0xf9, 0xf1, 0xa0, 0x10, 0x1d, 0x0f, 0xaa, 0xfd, 0xd1, 0xf0, 0x61, 0x34, 0xd0, 0x6f, + 0x19, 0xb0, 0x94, 0xb6, 0x0c, 0x8b, 0x53, 0x59, 0xb8, 0x8a, 0x12, 0x4b, 0x8b, 0x4b, 0x44, 0xaa, + 0x52, 0x48, 0x6d, 0x04, 0x7a, 0xd5, 0x80, 0x19, 0x4b, 0xb3, 0xf7, 0x8a, 0xc0, 0x5a, 0x75, 0x65, + 0x54, 0x03, 0x3b, 0xa2, 0x58, 0x59, 0xe8, 0x76, 0x4a, 0x31, 0x9b, 0x12, 0xc7, 0x38, 0xa2, 0xdf, + 0x36, 0xe0, 0x64, 0xea, 0x1a, 0x2f, 0x4e, 0x1f, 0xc7, 0x08, 0x31, 0x21, 0x49, 0xd7, 0x39, 0xe9, + 0xcd, 0x40, 0xaf, 0x1b, 0x6a, 0x2b, 0xdb, 0x94, 0x47, 0x9c, 0x19, 0xd6, 0xb4, 0xeb, 0x23, 0x9a, + 0xb8, 0x91, 0x41, 0x20, 0x09, 0x57, 0x4e, 0x68, 0x3b, 0xa3, 0x2c, 0xc4, 0x49, 0xf6, 0xe8, 0xf3, + 0x86, 0xdc, 0x1a, 0x55, 0x8b, 0x66, 0x8f, 0xab, 0x45, 0x28, 0xda, 0x69, 0x55, 0x83, 0x12, 0xcc, + 0xd1, 0x87, 0x61, 0xd9, 0xda, 0xf1, 0xfc, 0x30, 0x75, 0xf1, 0x15, 0xe7, 0xd8, 0x32, 0x3a, 0xdb, + 0xed, 0x94, 0x96, 0xcb, 0x7d, 0xb1, 0xf0, 0x21, 0x14, 0xcc, 0xef, 0x8d, 0xc1, 0x0c, 0xbf, 0x5f, + 0x10, 0x5b, 0xd7, 0x37, 0x0c, 0x78, 0xac, 0xd6, 0xf6, 0x7d, 0xe2, 0x86, 0xd5, 0x90, 0xb4, 0x7a, + 0x37, 0x2e, 0xe3, 0x58, 0x37, 0xae, 0xc7, 0xbb, 0x9d, 0xd2, 0x63, 0xab, 0x87, 0xf0, 0xc7, 0x87, + 0xb6, 0x0e, 0xfd, 0x8d, 0x01, 0xa6, 0x40, 0xa8, 0x58, 0xb5, 0x3b, 0x0d, 0xdf, 0x6b, 0xbb, 0xf5, + 0xde, 0x4e, 0xe4, 0x8e, 0xb5, 0x13, 0x4f, 0x76, 0x3b, 0x25, 0x73, 0xf5, 0x81, 0xad, 0xc0, 0x03, + 0xb4, 0x14, 0x5d, 0x82, 0x45, 0x81, 0x75, 0xe1, 0x5e, 0x8b, 0xf8, 0x36, 0x35, 0xa7, 0xc5, 0x6d, + 0x46, 0x74, 0x41, 0x94, 0x44, 0xc0, 0xbd, 0x75, 0x50, 0x00, 0x93, 0x77, 0x89, 0xdd, 0xd8, 0x0b, + 0xa5, 0xf9, 0x34, 0xe2, 0xad, 0x90, 0xb8, 0x43, 0xb8, 0xc5, 0x69, 0x56, 0xa6, 0xe9, 0xf9, 0x5a, + 0xfc, 0xc1, 0x92, 0x93, 0xf9, 0x87, 0x63, 0x00, 0x52, 0xbc, 0x48, 0x0b, 0xfd, 0x1c, 0x4c, 0x05, + 0x24, 0xe4, 0x58, 0xc2, 0x03, 0xc5, 0xdd, 0x5a, 0xb2, 0x10, 0x47, 0x70, 0x74, 0x07, 0xc6, 0x5b, + 0x56, 0x3b, 0x20, 0x62, 0xb2, 0xae, 0x64, 0x32, 0x59, 0x5b, 0x94, 0x22, 0x3f, 0x23, 0xb1, 0x9f, + 0x98, 0xf3, 0x40, 0x9f, 0x36, 0x00, 0x48, 0x7c, 0x80, 0xa7, 0xcf, 0x57, 0x33, 0x61, 0x19, 0xcd, + 0x01, 0x1d, 0x83, 0xca, 0x5c, 0xb7, 0x53, 0x02, 0x6d, 0xaa, 0x34, 0xb6, 0xe8, 0x2e, 0x14, 0x2c, + 0xa9, 0xa3, 0xc7, 0x8e, 0x43, 0x47, 0xb3, 0xa3, 0x8b, 0x12, 0x32, 0xc5, 0x0c, 0x7d, 0xd6, 0x80, + 0xb9, 0x80, 0x84, 0x62, 0xaa, 0xa8, 0xa6, 0x10, 0x06, 0xea, 0x88, 0x42, 0x52, 0x8d, 0xd1, 0xe4, + 0x1a, 0x2f, 0x5e, 0x86, 0x13, 0x7c, 0xcd, 0xef, 0x4d, 0xc3, 0x9c, 0x14, 0x99, 0xc8, 0xe6, 0xe4, + 0x17, 0x9e, 0x7d, 0x6c, 0xce, 0x55, 0x1d, 0x88, 0xe3, 0xb8, 0xb4, 0x32, 0xbf, 0x95, 0x8c, 0x9b, + 0x9c, 0xaa, 0x72, 0x55, 0x07, 0xe2, 0x38, 0x2e, 0x6a, 0xc2, 0x78, 0x10, 0x92, 0x96, 0x74, 0x1a, + 0x5f, 0x1e, 0x6d, 0x34, 0xa2, 0x95, 0x10, 0x39, 0xc6, 0xe8, 0xbf, 0x00, 0x73, 0x2e, 0xe8, 0x0b, + 0x06, 0xcc, 0x85, 0xb1, 0xbb, 0x39, 0x21, 0x06, 0xd9, 0x48, 0x62, 0xfc, 0xda, 0x8f, 0xcf, 0x46, + 0xbc, 0x0c, 0x27, 0xd8, 0xa7, 0x98, 0xa1, 0xe3, 0xc7, 0x68, 0x86, 0xbe, 0x04, 0x85, 0xa6, 0x75, + 0xaf, 0xda, 0xf6, 0x1b, 0x47, 0x37, 0x77, 0xc5, 0xd5, 0x25, 0xa7, 0x82, 0x15, 0x3d, 0xf4, 0x29, + 0x43, 0x5b, 0x5c, 0x93, 0x8c, 0xf8, 0xad, 0x6c, 0x17, 0x97, 0xd2, 0xe2, 0x7d, 0x97, 0x59, 0x8f, + 0x51, 0x58, 0x78, 0xe8, 0x46, 0x21, 0x35, 0x70, 0xf8, 0x02, 0x51, 0x06, 0xce, 0xd4, 0xb1, 0x1a, + 0x38, 0xab, 0x31, 0x66, 0x38, 0xc1, 0x9c, 0xb5, 0x87, 0xaf, 0x39, 0xd5, 0x1e, 0x38, 0xd6, 0xf6, + 0x54, 0x63, 0xcc, 0x70, 0x82, 0x79, 0xff, 0x93, 0xd0, 0xf4, 0xf1, 0x9c, 0x84, 0x66, 0x32, 0x38, + 0x09, 0x1d, 0x6e, 0x24, 0xce, 0x8e, 0x6a, 0x24, 0xa2, 0x2b, 0x80, 0xea, 0x07, 0xae, 0xd5, 0xb4, + 0x6b, 0x42, 0x59, 0xb2, 0x0d, 0x62, 0x8e, 0x9d, 0x94, 0x97, 0x85, 0x22, 0x43, 0x6b, 0x3d, 0x18, + 0x38, 0xa5, 0x96, 0xf9, 0x9f, 0x06, 0x2c, 0xac, 0x3a, 0x5e, 0xbb, 0x7e, 0xcb, 0x0a, 0x6b, 0x7b, + 0xdc, 0x21, 0x8f, 0x5e, 0x80, 0x82, 0xed, 0x86, 0xc4, 0xdf, 0xb7, 0x1c, 0xa1, 0xdb, 0x4d, 0x79, + 0x67, 0xb1, 0x2e, 0xca, 0xef, 0x77, 0x4a, 0x73, 0x6b, 0x6d, 0x9f, 0x85, 0x34, 0xf0, 0x95, 0x8e, + 0x55, 0x1d, 0xf4, 0x55, 0x03, 0x16, 0xb9, 0x4b, 0x7f, 0xcd, 0x0a, 0xad, 0xeb, 0x6d, 0xe2, 0xdb, + 0x44, 0x3a, 0xf5, 0x47, 0x5c, 0xe4, 0xc9, 0xb6, 0x4a, 0x06, 0x07, 0x91, 0xf9, 0xb5, 0x99, 0xe4, + 0x8c, 0x7b, 0x1b, 0x63, 0x7e, 0x31, 0x0f, 0xa7, 0xfb, 0xd2, 0x42, 0xcb, 0x90, 0xb3, 0xeb, 0xa2, + 0xeb, 0x20, 0xe8, 0xe6, 0xd6, 0xeb, 0x38, 0x67, 0xd7, 0xd1, 0x0a, 0xb3, 0x4c, 0x7c, 0x12, 0x04, + 0xd2, 0xe9, 0x3d, 0xa5, 0x8c, 0x08, 0x51, 0x8a, 0x35, 0x0c, 0x54, 0x82, 0x71, 0xc7, 0xda, 0x21, + 0x8e, 0xb0, 0x12, 0x99, 0xad, 0xb3, 0x41, 0x0b, 0x30, 0x2f, 0x47, 0xbf, 0x6c, 0x00, 0xf0, 0x06, + 0x52, 0x1b, 0x53, 0xec, 0x30, 0x38, 0xdb, 0x61, 0xa2, 0x94, 0x79, 0x2b, 0xa3, 0xff, 0x58, 0xe3, + 0x8a, 0xb6, 0x61, 0x82, 0x9a, 0x3d, 0x5e, 0xfd, 0xc8, 0x1b, 0x0a, 0x74, 0x3b, 0xa5, 0x89, 0x2d, + 0x46, 0x03, 0x0b, 0x5a, 0x74, 0xac, 0x7c, 0x12, 0xb6, 0x7d, 0x97, 0x0e, 0x2d, 0xdb, 0x42, 0x0a, + 0xbc, 0x15, 0x58, 0x95, 0x62, 0x0d, 0xc3, 0xfc, 0x93, 0x1c, 0x2c, 0xa5, 0x35, 0x9d, 0x6a, 0xea, + 0x09, 0xde, 0x5a, 0x71, 0xe0, 0x79, 0x7f, 0xf6, 0xe3, 0x23, 0x6e, 0xa7, 0x54, 0x3c, 0x88, 0xb8, + 0x3d, 0x16, 0x7c, 0xd1, 0xfb, 0xd5, 0x08, 0xe5, 0x8e, 0x38, 0x42, 0x8a, 0x72, 0x62, 0x94, 0x1e, + 0x87, 0xb1, 0x80, 0xce, 0x7c, 0x3e, 0xee, 0x96, 0x66, 0x73, 0xc4, 0x20, 0x14, 0xa3, 0xed, 0xda, + 0xa1, 0x88, 0x33, 0x52, 0x18, 0x37, 0x5c, 0x3b, 0xc4, 0x0c, 0x62, 0x7e, 0x39, 0x07, 0xcb, 0xfd, + 0x3b, 0x85, 0xbe, 0x6c, 0x00, 0xd4, 0xa9, 0x51, 0x4b, 0x45, 0x52, 0xde, 0xe6, 0x59, 0xc7, 0x35, + 0x86, 0x6b, 0x92, 0x53, 0x74, 0xb5, 0xab, 0x8a, 0x02, 0xac, 0x35, 0x04, 0x9d, 0x97, 0xa2, 0x7f, + 0xd5, 0x6a, 0x4a, 0x53, 0x50, 0xd5, 0xd9, 0x54, 0x10, 0xac, 0x61, 0xd1, 0x53, 0x8b, 0x6b, 0x35, + 0x49, 0xd0, 0xb2, 0x54, 0x20, 0x19, 0x3b, 0xb5, 0x5c, 0x95, 0x85, 0x38, 0x82, 0x9b, 0x0e, 0x3c, + 0x31, 0x40, 0x3b, 0x33, 0x0a, 0xea, 0x31, 0x7f, 0x64, 0xc0, 0xa9, 0x55, 0xa7, 0x1d, 0x84, 0xc4, + 0xff, 0x3f, 0x73, 0x53, 0xfe, 0x5f, 0x06, 0x3c, 0xda, 0xa7, 0xcf, 0x0f, 0xe1, 0xc2, 0xfc, 0x95, + 0xf8, 0x85, 0xf9, 0x8d, 0x51, 0x45, 0x3a, 0xb5, 0x1f, 0x7d, 0xee, 0xcd, 0x43, 0x98, 0xa5, 0x5a, + 0xab, 0xee, 0x35, 0x32, 0xda, 0x37, 0x9f, 0x80, 0xf1, 0x8f, 0xd2, 0xfd, 0x27, 0x29, 0x63, 0x6c, + 0x53, 0xc2, 0x1c, 0x66, 0xfe, 0x43, 0x0e, 0xb4, 0xf3, 0xea, 0x43, 0x10, 0x2b, 0x37, 0x26, 0x56, + 0x23, 0x9e, 0x40, 0xb5, 0xd3, 0x77, 0xbf, 0x88, 0xbf, 0xfd, 0x44, 0xc4, 0xdf, 0xd5, 0xcc, 0x38, + 0x1e, 0x1e, 0xf0, 0xf7, 0x86, 0x01, 0x8f, 0x46, 0xc8, 0xbd, 0xae, 0x9f, 0x07, 0xeb, 0x88, 0x67, + 0x61, 0xda, 0x8a, 0xaa, 0x89, 0x59, 0x54, 0x41, 0xae, 0x1a, 0x45, 0xac, 0xe3, 0x45, 0x41, 0x57, + 0xf9, 0x23, 0x06, 0x5d, 0x8d, 0x1d, 0x1e, 0x74, 0x65, 0xfe, 0x38, 0x07, 0x67, 0x7a, 0x7b, 0x26, + 0xa5, 0x7b, 0xb0, 0x9b, 0xd1, 0xe7, 0x60, 0x26, 0x14, 0x15, 0x34, 0x5d, 0xad, 0x42, 0xb4, 0xb7, + 0x35, 0x18, 0x8e, 0x61, 0xd2, 0x9a, 0x35, 0xbe, 0xae, 0xaa, 0x35, 0xaf, 0x25, 0xa3, 0xd3, 0x54, + 0xcd, 0x55, 0x0d, 0x86, 0x63, 0x98, 0x2a, 0x1c, 0x64, 0xec, 0xd8, 0xc3, 0xe7, 0xaa, 0x70, 0x52, + 0x46, 0x05, 0x5c, 0xf4, 0xfc, 0x55, 0xaf, 0xd9, 0x72, 0x08, 0x0b, 0x6a, 0x18, 0x67, 0x8d, 0x3d, + 0x23, 0xaa, 0x9c, 0xc4, 0x69, 0x48, 0x38, 0xbd, 0xae, 0xf9, 0x46, 0x1e, 0x4e, 0x44, 0xc3, 0xbe, + 0xea, 0xb9, 0x75, 0x9b, 0xc5, 0x56, 0x3c, 0x0f, 0x63, 0xe1, 0x41, 0x4b, 0x0e, 0xf6, 0xcf, 0xc8, + 0xe6, 0x6c, 0x1f, 0xb4, 0xe8, 0x6c, 0x9f, 0x4a, 0xa9, 0x42, 0x41, 0x98, 0x55, 0x42, 0x1b, 0x6a, + 0x75, 0xf0, 0x19, 0x78, 0x26, 0x2e, 0xcd, 0xf7, 0x3b, 0xa5, 0x94, 0x17, 0x0a, 0x2b, 0x8a, 0x52, + 0x5c, 0xe6, 0xd1, 0x6d, 0x98, 0x73, 0xac, 0x20, 0xbc, 0xd1, 0xaa, 0x5b, 0x21, 0xd9, 0xb6, 0x9b, + 0x44, 0xac, 0xb9, 0x61, 0x22, 0xe1, 0xd4, 0x6d, 0xe1, 0x46, 0x8c, 0x12, 0x4e, 0x50, 0x46, 0xfb, + 0x80, 0x68, 0xc9, 0xb6, 0x6f, 0xb9, 0x01, 0xef, 0x15, 0xe5, 0x37, 0x7c, 0xe4, 0x9d, 0x3a, 0xe2, + 0x6c, 0xf4, 0x50, 0xc3, 0x29, 0x1c, 0xd0, 0x93, 0x30, 0xe1, 0x13, 0x2b, 0x10, 0x93, 0x39, 0x15, + 0xad, 0x7f, 0xcc, 0x4a, 0xb1, 0x80, 0xea, 0x0b, 0x6a, 0xe2, 0x01, 0x0b, 0xea, 0xfb, 0x06, 0xcc, + 0x45, 0xd3, 0xf4, 0x10, 0xb6, 0xb9, 0x66, 0x7c, 0x9b, 0xbb, 0x9c, 0x95, 0x4a, 0xec, 0xb3, 0xb3, + 0x7d, 0x7d, 0x4c, 0xef, 0x1f, 0x8b, 0x05, 0xfb, 0x18, 0x4c, 0xc9, 0x55, 0x2d, 0xed, 0xc7, 0x11, + 0xfd, 0x24, 0x31, 0xcb, 0x42, 0x0b, 0x56, 0x15, 0x4c, 0x70, 0xc4, 0x8f, 0x6e, 0xac, 0x75, 0xb1, + 0x69, 0x0a, 0xb1, 0x57, 0x1b, 0xab, 0xdc, 0x4c, 0xd3, 0x36, 0x56, 0x59, 0x07, 0xdd, 0x80, 0x53, + 0x2d, 0xdf, 0x63, 0x0f, 0x18, 0xd6, 0x88, 0x55, 0x77, 0x6c, 0x97, 0xc8, 0xe3, 0x38, 0xbf, 0xac, + 0x7e, 0xb4, 0xdb, 0x29, 0x9d, 0xda, 0x4a, 0x47, 0xc1, 0xfd, 0xea, 0xc6, 0x83, 0x6e, 0xc7, 0x1e, + 0x1c, 0x74, 0x8b, 0x7e, 0x55, 0x39, 0xbd, 0x48, 0x50, 0x1c, 0x67, 0x83, 0xf8, 0xc1, 0xac, 0xa6, + 0x32, 0x45, 0xad, 0x47, 0x22, 0x55, 0x16, 0x4c, 0xb1, 0x62, 0xdf, 0xdf, 0xb3, 0x32, 0x71, 0x34, + 0xcf, 0x8a, 0xf9, 0xda, 0x38, 0x2c, 0x24, 0x37, 0xdb, 0xe3, 0x0f, 0x28, 0xfe, 0x0d, 0x03, 0x16, + 0xa4, 0xa0, 0x70, 0x9e, 0x44, 0xba, 0x87, 0x37, 0x32, 0x92, 0x4f, 0x6e, 0x36, 0xa8, 0xd7, 0x1d, + 0xdb, 0x09, 0x6e, 0xb8, 0x87, 0x3f, 0x7a, 0x19, 0xa6, 0x95, 0x17, 0xf5, 0x48, 0xd1, 0xc5, 0xf3, + 0xcc, 0x60, 0x88, 0x48, 0x60, 0x9d, 0x1e, 0x7a, 0xcd, 0x00, 0xa8, 0x49, 0x8d, 0x2e, 0x05, 0xe9, + 0x7a, 0x56, 0x82, 0xa4, 0xf6, 0x8a, 0xc8, 0x2e, 0x54, 0x45, 0x01, 0xd6, 0x18, 0xa3, 0x2f, 0x32, + 0xff, 0xa9, 0x32, 0x64, 0xa8, 0xe8, 0xd0, 0x96, 0x7c, 0x20, 0x6b, 0x91, 0x8e, 0xae, 0xf2, 0x94, + 0xd5, 0xa0, 0x81, 0x02, 0x1c, 0x6b, 0x84, 0xf9, 0x3c, 0xa8, 0x68, 0x30, 0xba, 0x42, 0x59, 0x3c, + 0xd8, 0x96, 0x15, 0xee, 0x09, 0x11, 0x54, 0x2b, 0xf4, 0xa2, 0x04, 0xe0, 0x08, 0xc7, 0xfc, 0x08, + 0xcc, 0x5d, 0xf2, 0xad, 0xd6, 0x9e, 0xcd, 0xfc, 0x94, 0xd4, 0xa8, 0x7f, 0x3b, 0x4c, 0x5a, 0xf5, + 0x7a, 0xda, 0xdb, 0xa8, 0x32, 0x2f, 0xc6, 0x12, 0x3e, 0x98, 0xfd, 0xfe, 0x4d, 0x03, 0x96, 0xd6, + 0x83, 0xd0, 0xf6, 0xd6, 0x48, 0x10, 0x52, 0xb5, 0x40, 0x2d, 0x88, 0xb6, 0x43, 0x06, 0xb0, 0xc1, + 0xd6, 0x60, 0x41, 0x5c, 0xa6, 0xb4, 0x77, 0x02, 0x12, 0x6a, 0x76, 0x98, 0x12, 0xce, 0xd5, 0x04, + 0x1c, 0xf7, 0xd4, 0xa0, 0x54, 0xc4, 0xad, 0x4a, 0x44, 0x25, 0x1f, 0xa7, 0x52, 0x4d, 0xc0, 0x71, + 0x4f, 0x0d, 0xf3, 0x3b, 0x79, 0x38, 0xc1, 0xba, 0x91, 0x78, 0xbc, 0xf4, 0x79, 0x03, 0xe6, 0xf6, + 0x6d, 0x3f, 0x6c, 0x5b, 0x8e, 0x7e, 0x3d, 0x34, 0xb2, 0x7c, 0x32, 0x5e, 0x37, 0x63, 0x84, 0xb9, + 0x03, 0x39, 0x5e, 0x86, 0x13, 0xcc, 0xd1, 0xaf, 0x1b, 0x30, 0x5f, 0x8f, 0x8f, 0x74, 0x36, 0x07, + 0xe4, 0xb4, 0x39, 0xe4, 0x51, 0x0d, 0x89, 0x42, 0x9c, 0xe4, 0x8f, 0xbe, 0x64, 0xc0, 0x7c, 0xbc, + 0x99, 0x52, 0x65, 0x1d, 0xc3, 0x20, 0xa9, 0x30, 0xc4, 0x78, 0x79, 0x80, 0x93, 0x4d, 0x30, 0xff, + 0xce, 0x10, 0x53, 0x1a, 0xc7, 0x1c, 0x40, 0x30, 0x4d, 0x98, 0xf0, 0xbd, 0x76, 0x28, 0x9c, 0xbc, + 0x53, 0xdc, 0x17, 0x88, 0x59, 0x09, 0x16, 0x10, 0x74, 0x17, 0xa6, 0x42, 0x27, 0xe0, 0x85, 0xa2, + 0xb7, 0x23, 0x5a, 0xf4, 0xdb, 0x1b, 0x55, 0x46, 0x4e, 0xdb, 0x74, 0x45, 0x09, 0x35, 0x1e, 0x24, + 0x2f, 0xf3, 0x6b, 0x06, 0x4c, 0x5d, 0xf1, 0x76, 0xc4, 0x72, 0xfe, 0x70, 0x06, 0xe7, 0x65, 0xb5, + 0xad, 0xaa, 0x6b, 0x8b, 0xc8, 0x52, 0x7b, 0x21, 0x76, 0x5a, 0x7e, 0x4c, 0xa3, 0xbd, 0xc2, 0xde, + 0x14, 0x53, 0x52, 0x57, 0xbc, 0x9d, 0xbe, 0xee, 0x94, 0xdf, 0x19, 0x87, 0xd9, 0x17, 0xad, 0x03, + 0xe2, 0x86, 0xd6, 0xf0, 0x0a, 0x88, 0x1e, 0x40, 0x5b, 0x2c, 0xaa, 0x4e, 0x33, 0x95, 0xa2, 0x03, + 0x68, 0x04, 0xc2, 0x3a, 0x5e, 0xa4, 0x57, 0xf8, 0x13, 0xc7, 0x34, 0x8d, 0xb0, 0x9a, 0x80, 0xe3, + 0x9e, 0x1a, 0xe8, 0x0a, 0x20, 0x11, 0xc7, 0x5f, 0xae, 0xd5, 0xbc, 0xb6, 0xcb, 0x35, 0x0b, 0x3f, + 0x9b, 0x2a, 0x9b, 0x7d, 0xb3, 0x07, 0x03, 0xa7, 0xd4, 0x42, 0x1f, 0x82, 0x62, 0x8d, 0x51, 0x16, + 0x16, 0x9c, 0x4e, 0x91, 0x5b, 0xf1, 0x2a, 0xa2, 0x75, 0xb5, 0x0f, 0x1e, 0xee, 0x4b, 0x81, 0xb6, + 0x34, 0x08, 0x3d, 0xdf, 0x6a, 0x10, 0x9d, 0xee, 0x44, 0xbc, 0xa5, 0xd5, 0x1e, 0x0c, 0x9c, 0x52, + 0x0b, 0x7d, 0x12, 0xa6, 0xc2, 0x3d, 0x9f, 0x04, 0x7b, 0x9e, 0x53, 0x17, 0xf7, 0x98, 0x23, 0x3a, + 0x2c, 0xc4, 0xec, 0x6f, 0x4b, 0xaa, 0x9a, 0x78, 0xcb, 0x22, 0x1c, 0xf1, 0x44, 0x3e, 0x4c, 0x04, + 0xf4, 0xb4, 0x1c, 0x14, 0x0b, 0x59, 0x58, 0xe5, 0x82, 0x3b, 0x3b, 0x80, 0x6b, 0xae, 0x12, 0xc6, + 0x01, 0x0b, 0x4e, 0xe6, 0xb7, 0x72, 0x30, 0xa3, 0x23, 0x0e, 0xa0, 0x22, 0x3e, 0x6d, 0xc0, 0x4c, + 0xcd, 0x73, 0x43, 0xdf, 0x73, 0xb8, 0x1b, 0x80, 0x2f, 0x90, 0x11, 0xdf, 0x01, 0x32, 0x52, 0x6b, + 0x24, 0xb4, 0x6c, 0x47, 0xf3, 0x28, 0x68, 0x6c, 0x70, 0x8c, 0x29, 0xfa, 0x9c, 0x01, 0xf3, 0x51, + 0x80, 0x47, 0xe4, 0x8f, 0xc8, 0xb4, 0x21, 0x4a, 0xe3, 0x5e, 0x88, 0x73, 0xc2, 0x49, 0xd6, 0xe6, + 0x0e, 0x2c, 0x24, 0x67, 0x9b, 0x0e, 0x65, 0xcb, 0x12, 0x6b, 0x3d, 0x1f, 0x0d, 0xe5, 0x96, 0x15, + 0x04, 0x98, 0x41, 0xd0, 0x3b, 0xa0, 0xd0, 0xb4, 0xfc, 0x86, 0xed, 0x5a, 0x0e, 0x1b, 0xc5, 0xbc, + 0xa6, 0x90, 0x44, 0x39, 0x56, 0x18, 0xe6, 0x0f, 0xc7, 0x60, 0x7a, 0x93, 0x58, 0x41, 0xdb, 0x27, + 0xcc, 0x61, 0x78, 0xec, 0x16, 0x79, 0xec, 0x61, 0x5d, 0x3e, 0xbb, 0x87, 0x75, 0xe8, 0x25, 0x80, + 0x5d, 0xdb, 0xb5, 0x83, 0xbd, 0x23, 0x3e, 0xd9, 0x63, 0x37, 0x4f, 0x17, 0x15, 0x05, 0xac, 0x51, + 0x8b, 0xdc, 0xfb, 0xe3, 0x87, 0xbc, 0xd9, 0x7d, 0xcd, 0xd0, 0x36, 0x8f, 0x89, 0x2c, 0xae, 0x33, + 0xb5, 0x89, 0x59, 0x91, 0x9b, 0xc9, 0x05, 0x37, 0xf4, 0x0f, 0x0e, 0xdd, 0x63, 0xb6, 0xa1, 0xe0, + 0x93, 0xa0, 0xdd, 0xa4, 0x67, 0x8b, 0xc9, 0xa1, 0x87, 0x81, 0x45, 0x43, 0x60, 0x51, 0x1f, 0x2b, + 0x4a, 0xcb, 0xcf, 0xc3, 0x6c, 0xac, 0x09, 0x68, 0x01, 0xf2, 0x77, 0xc8, 0x01, 0x97, 0x13, 0x4c, + 0x7f, 0xa2, 0xa5, 0xd8, 0x25, 0x88, 0x18, 0x96, 0xf7, 0xe6, 0x9e, 0x33, 0xcc, 0x1f, 0x4f, 0x80, + 0xb8, 0x30, 0x1b, 0x40, 0x17, 0xe8, 0x7e, 0xf2, 0xdc, 0x11, 0xfc, 0xe4, 0x57, 0x60, 0xc6, 0x76, + 0xed, 0xd0, 0xb6, 0x1c, 0x76, 0x00, 0x15, 0x7b, 0xd5, 0x93, 0x72, 0xfd, 0xaf, 0x6b, 0xb0, 0x14, + 0x3a, 0xb1, 0xba, 0xe8, 0x3a, 0x8c, 0x33, 0x65, 0x2e, 0xe4, 0x69, 0xf8, 0x5b, 0x3d, 0x76, 0xa1, + 0xcb, 0x23, 0xdb, 0x39, 0x25, 0x66, 0x60, 0xf3, 0x57, 0x94, 0xea, 0xdc, 0x24, 0xc4, 0x2a, 0x32, + 0xb0, 0x13, 0x70, 0xdc, 0x53, 0x83, 0x52, 0xd9, 0xb5, 0x6c, 0xa7, 0xed, 0x93, 0x88, 0xca, 0x44, + 0x9c, 0xca, 0xc5, 0x04, 0x1c, 0xf7, 0xd4, 0x40, 0xbb, 0x30, 0x23, 0xca, 0x78, 0x7c, 0xc3, 0xe4, + 0x11, 0x7b, 0xc9, 0xe2, 0x58, 0x2e, 0x6a, 0x94, 0x70, 0x8c, 0x2e, 0x6a, 0xc3, 0xa2, 0xed, 0xd6, + 0x3c, 0xb7, 0xe6, 0xb4, 0x03, 0x7b, 0x9f, 0x44, 0x61, 0xe5, 0x47, 0x61, 0x76, 0xb2, 0xdb, 0x29, + 0x2d, 0xae, 0x27, 0xc9, 0xe1, 0x5e, 0x0e, 0xe8, 0x53, 0x06, 0x9c, 0xac, 0x79, 0x6e, 0xc0, 0xde, + 0x6a, 0xed, 0x93, 0x0b, 0xbe, 0xef, 0xf9, 0x9c, 0xf7, 0xd4, 0x11, 0x79, 0x33, 0xbf, 0xc7, 0x6a, + 0x1a, 0x49, 0x9c, 0xce, 0x09, 0xbd, 0x02, 0x85, 0x96, 0xef, 0xed, 0xdb, 0x75, 0xe2, 0x8b, 0x58, + 0x99, 0x8d, 0x2c, 0x9e, 0x49, 0x6e, 0x09, 0x9a, 0x91, 0x26, 0x90, 0x25, 0x58, 0xf1, 0x33, 0xff, + 0xa0, 0x00, 0x73, 0x71, 0x74, 0xf4, 0x09, 0x80, 0x96, 0xef, 0x35, 0x49, 0xb8, 0x47, 0x54, 0x78, + 0xf0, 0xd5, 0x51, 0x9f, 0x28, 0x4a, 0x7a, 0xf2, 0x8e, 0x9c, 0x6a, 0xd2, 0xa8, 0x14, 0x6b, 0x1c, + 0x91, 0x0f, 0x93, 0x77, 0xf8, 0x9e, 0x26, 0xb6, 0xf8, 0x17, 0x33, 0x31, 0x48, 0x04, 0x67, 0x16, + 0xd7, 0x2a, 0x8a, 0xb0, 0x64, 0x84, 0x76, 0x20, 0x7f, 0x97, 0xec, 0x64, 0xf3, 0x98, 0xee, 0x16, + 0x11, 0x47, 0x85, 0xca, 0x64, 0xb7, 0x53, 0xca, 0xdf, 0x22, 0x3b, 0x98, 0x12, 0xa7, 0xfd, 0xaa, + 0xf3, 0xdb, 0x3e, 0xa1, 0x2a, 0x46, 0xec, 0x57, 0xec, 0xea, 0x90, 0xf7, 0x4b, 0x14, 0x61, 0xc9, + 0x08, 0xbd, 0x02, 0x53, 0x77, 0xad, 0x7d, 0xb2, 0xeb, 0x7b, 0x6e, 0x28, 0x02, 0x33, 0x46, 0x8c, + 0x40, 0xbd, 0x25, 0xc9, 0x09, 0xbe, 0x6c, 0xb7, 0x55, 0x85, 0x38, 0x62, 0x87, 0xf6, 0xa1, 0xe0, + 0x92, 0xbb, 0x98, 0x38, 0x76, 0x4d, 0x04, 0xff, 0x8d, 0x28, 0xd6, 0x57, 0x05, 0x35, 0xc1, 0x99, + 0x6d, 0x43, 0xb2, 0x0c, 0x2b, 0x5e, 0x74, 0x2e, 0x6f, 0x7b, 0x3b, 0x42, 0x51, 0x8d, 0x38, 0x97, + 0xea, 0xd8, 0xc7, 0xe7, 0xf2, 0x8a, 0xb7, 0x83, 0x29, 0x71, 0xba, 0x46, 0x6a, 0x2a, 0x2a, 0x40, + 0xa8, 0xa9, 0xab, 0xd9, 0x46, 0x43, 0xf0, 0x35, 0x12, 0x95, 0x62, 0x8d, 0x23, 0x1d, 0xdb, 0x86, + 0xf0, 0x32, 0x09, 0x45, 0x35, 0xe2, 0xd8, 0xc6, 0x7d, 0x56, 0x7c, 0x6c, 0x65, 0x19, 0x56, 0xbc, + 0xcc, 0x3f, 0x1d, 0x83, 0x19, 0x3d, 0x29, 0xc2, 0x00, 0x7b, 0xb5, 0x32, 0x17, 0x73, 0xc3, 0x98, + 0x8b, 0xd4, 0xda, 0x6f, 0x46, 0xb6, 0x8d, 0x3c, 0xf0, 0xaf, 0x67, 0x66, 0x2d, 0x45, 0xd6, 0xbe, + 0x56, 0x18, 0xe0, 0x18, 0xd3, 0x21, 0xae, 0x48, 0xa9, 0xfd, 0xc7, 0xcd, 0x00, 0xfe, 0x44, 0x4c, + 0xd9, 0x7f, 0xb1, 0x8d, 0xfd, 0x3c, 0x40, 0x94, 0x1e, 0x41, 0xf8, 0xc9, 0x95, 0x8f, 0x54, 0x4b, + 0xdb, 0xa0, 0x61, 0xa1, 0x27, 0x61, 0x82, 0x6e, 0x94, 0xa4, 0x2e, 0xde, 0x6e, 0xa9, 0x23, 0xd5, + 0x45, 0x56, 0x8a, 0x05, 0x14, 0x3d, 0x47, 0x6d, 0x9a, 0x68, 0x7b, 0x13, 0x4f, 0xb2, 0x96, 0x22, + 0x9b, 0x26, 0x82, 0xe1, 0x18, 0x26, 0x6d, 0x3a, 0xa1, 0xbb, 0x11, 0x93, 0x24, 0xad, 0xe9, 0x6c, + 0x8b, 0xc2, 0x1c, 0xc6, 0x8e, 0xf8, 0x89, 0xdd, 0x8b, 0x6d, 0x56, 0xe3, 0xda, 0x11, 0x3f, 0x01, + 0xc7, 0x3d, 0x35, 0xcc, 0x8f, 0xc0, 0x5c, 0x7c, 0x15, 0xd3, 0x21, 0x6e, 0xf9, 0xde, 0xae, 0xed, + 0x90, 0xa4, 0x73, 0x62, 0x8b, 0x17, 0x63, 0x09, 0x1f, 0xcc, 0x3b, 0xfa, 0x57, 0x79, 0x38, 0x71, + 0xb5, 0x61, 0xbb, 0xf7, 0x12, 0x6e, 0xc5, 0xb4, 0xac, 0x4b, 0xc6, 0xb0, 0x59, 0x97, 0xa2, 0xe0, + 0x73, 0x91, 0xd6, 0x2a, 0x3d, 0xf8, 0x5c, 0xe6, 0xbc, 0x8a, 0xe3, 0xa2, 0xef, 0x1b, 0xf0, 0x98, + 0x55, 0xe7, 0x76, 0x95, 0xe5, 0x88, 0xd2, 0x88, 0xa9, 0x94, 0xf1, 0x60, 0x44, 0x2d, 0xd9, 0xdb, + 0xf9, 0x95, 0xf2, 0x21, 0x5c, 0xf9, 0x69, 0xe1, 0x6d, 0xa2, 0x07, 0x8f, 0x1d, 0x86, 0x8a, 0x0f, + 0x6d, 0xfe, 0xf2, 0x35, 0x78, 0xeb, 0x03, 0x19, 0x0d, 0x75, 0x26, 0xf8, 0xb4, 0x01, 0x53, 0xdc, + 0x6b, 0x86, 0xc9, 0x2e, 0x5d, 0x3c, 0x56, 0xcb, 0xbe, 0x49, 0xfc, 0x40, 0xa6, 0x4e, 0xd0, 0x42, + 0xbd, 0xca, 0x5b, 0xeb, 0x02, 0x82, 0x35, 0x2c, 0xaa, 0x9e, 0xee, 0xd8, 0x6e, 0x5d, 0x4c, 0x93, + 0x52, 0x4f, 0x2f, 0xda, 0x6e, 0x1d, 0x33, 0x88, 0x52, 0x60, 0xf9, 0x7e, 0x0a, 0xcc, 0xfc, 0x5d, + 0x03, 0xe6, 0xd8, 0xdb, 0x92, 0xc8, 0x28, 0x7e, 0x56, 0xdd, 0x08, 0xf3, 0x66, 0x9c, 0x89, 0xdf, + 0x08, 0xdf, 0xef, 0x94, 0xa6, 0xf9, 0x6b, 0x94, 0xf8, 0x05, 0xf1, 0x07, 0xc5, 0xc1, 0x96, 0xdd, + 0x5b, 0xe7, 0x86, 0x3e, 0x77, 0x29, 0x37, 0x4e, 0x55, 0x12, 0xc1, 0x11, 0x3d, 0xf3, 0x8f, 0xf2, + 0x70, 0x22, 0x25, 0x48, 0x9a, 0x9e, 0x39, 0x27, 0x58, 0x9c, 0xa8, 0xbc, 0x75, 0x7d, 0x39, 0xf3, + 0x40, 0xec, 0x15, 0x16, 0x8e, 0x2a, 0x24, 0x49, 0xe9, 0x27, 0x5e, 0x88, 0x05, 0x73, 0xf4, 0x9b, + 0x06, 0x4c, 0x5b, 0x9a, 0xb0, 0xf3, 0x8b, 0xe8, 0x9d, 0xec, 0x1b, 0xd3, 0x23, 0xdb, 0x5a, 0x00, + 0x4d, 0x24, 0xca, 0x7a, 0x5b, 0x96, 0xdf, 0x03, 0xd3, 0x5a, 0x17, 0x86, 0x91, 0xd1, 0xe5, 0x17, + 0x60, 0x61, 0x24, 0x19, 0xff, 0x00, 0x0c, 0x9b, 0x8b, 0x83, 0xee, 0x08, 0x77, 0xf5, 0x27, 0x57, + 0x6a, 0xc4, 0xc5, 0x9b, 0x2b, 0x01, 0x35, 0x77, 0x60, 0x21, 0x69, 0x78, 0x67, 0x7e, 0x19, 0xf5, + 0x2e, 0x18, 0x32, 0x7b, 0x86, 0xf9, 0xd7, 0x39, 0x98, 0x14, 0x2f, 0x2d, 0x1e, 0x42, 0xec, 0xd9, + 0x9d, 0x98, 0x37, 0x7d, 0x3d, 0x93, 0x07, 0x22, 0x7d, 0x03, 0xcf, 0x82, 0x44, 0xe0, 0xd9, 0x8b, + 0xd9, 0xb0, 0x3b, 0x3c, 0xea, 0xec, 0x0b, 0x39, 0x98, 0x4f, 0xbc, 0x5c, 0x41, 0x9f, 0x31, 0x7a, + 0x83, 0x2d, 0x6e, 0x64, 0xfa, 0x38, 0x46, 0x45, 0x36, 0x1e, 0x1e, 0x77, 0x11, 0xc4, 0xf2, 0xf1, + 0x5c, 0xcf, 0x2c, 0x67, 0xdb, 0xa1, 0xa9, 0x79, 0xfe, 0xc5, 0x80, 0xd3, 0x7d, 0xdf, 0xf2, 0xb0, + 0x47, 0xca, 0x7e, 0x1c, 0x2a, 0x64, 0x2f, 0xe3, 0xb7, 0x79, 0xca, 0x8b, 0x9b, 0x7c, 0x57, 0x9a, + 0x64, 0x8f, 0x9e, 0x81, 0x19, 0xa6, 0xc7, 0xe9, 0xf2, 0x09, 0x49, 0x4b, 0x24, 0xdb, 0x62, 0x1e, + 0x93, 0xaa, 0x56, 0x8e, 0x63, 0x58, 0xe6, 0x57, 0x0d, 0x28, 0xf6, 0x7b, 0xb2, 0x3a, 0x80, 0x5d, + 0xfe, 0x0b, 0x89, 0x38, 0xb0, 0x52, 0x4f, 0x1c, 0x58, 0xc2, 0x32, 0x97, 0x21, 0x5f, 0x9a, 0x51, + 0x9c, 0x7f, 0x40, 0x98, 0xd3, 0xe7, 0x0d, 0x38, 0xd5, 0x47, 0x70, 0x7a, 0xe2, 0x01, 0x8d, 0x23, + 0xc7, 0x03, 0xe6, 0x06, 0x8d, 0x07, 0x34, 0xff, 0x36, 0x0f, 0x0b, 0xa2, 0x3d, 0xd1, 0x66, 0xfe, + 0x5c, 0x2c, 0x9a, 0xee, 0x6d, 0x89, 0x68, 0xba, 0xa5, 0x24, 0xfe, 0xff, 0x87, 0xd2, 0xfd, 0x74, + 0x85, 0xd2, 0xfd, 0x24, 0x07, 0x27, 0x53, 0x5f, 0xe6, 0xa2, 0xcf, 0xa6, 0x68, 0xc1, 0x5b, 0x19, + 0x3f, 0x01, 0x1e, 0x50, 0x0f, 0x8e, 0x1a, 0x7f, 0xf6, 0x25, 0x3d, 0xee, 0x8b, 0x1f, 0x13, 0x76, + 0x8f, 0xe1, 0x31, 0xf3, 0x90, 0x21, 0x60, 0xe6, 0xaf, 0xe5, 0xe1, 0xa9, 0x41, 0x09, 0xfd, 0x94, + 0x86, 0x08, 0x07, 0xb1, 0x10, 0xe1, 0x87, 0xb3, 0x43, 0x1d, 0x4f, 0xb4, 0xf0, 0xd7, 0xf2, 0x6a, + 0xdb, 0xeb, 0x95, 0xcf, 0x81, 0x2e, 0x55, 0x26, 0xa9, 0x15, 0x23, 0xf3, 0x6b, 0x45, 0xaa, 0x70, + 0xb2, 0xca, 0x8b, 0xef, 0x77, 0x4a, 0x8b, 0x22, 0xe7, 0x4e, 0x95, 0x84, 0xa2, 0x10, 0xcb, 0x4a, + 0xe8, 0x29, 0x28, 0xf8, 0x1c, 0x2a, 0x83, 0x22, 0xc5, 0x45, 0x11, 0x2f, 0xc3, 0x0a, 0x8a, 0x3e, + 0xa9, 0x99, 0x7d, 0x63, 0xc7, 0xf5, 0x38, 0xf4, 0xb0, 0xfb, 0xaf, 0x97, 0xa1, 0x10, 0xc8, 0x4c, + 0x59, 0xdc, 0x2b, 0xfa, 0xf4, 0x80, 0xb1, 0xb6, 0xf4, 0x94, 0x20, 0xd3, 0x66, 0xf1, 0xfe, 0xa9, + 0xa4, 0x5a, 0x8a, 0x24, 0x32, 0x95, 0x81, 0xce, 0x5d, 0x3c, 0x90, 0x62, 0x9c, 0xbf, 0x61, 0xc0, + 0xb4, 0x98, 0xad, 0x87, 0x10, 0xfe, 0x7b, 0x3b, 0x1e, 0xfe, 0x7b, 0x21, 0x13, 0xdd, 0xd1, 0x27, + 0xf6, 0xf7, 0x36, 0xcc, 0xe8, 0xc9, 0x19, 0xd0, 0x4b, 0x9a, 0xee, 0x33, 0x46, 0x79, 0x04, 0x2e, + 0xb5, 0x63, 0xa4, 0x17, 0xcd, 0xaf, 0x14, 0xd4, 0x28, 0xb2, 0x20, 0x63, 0x5d, 0x06, 0x8d, 0x43, + 0x65, 0x50, 0x17, 0x81, 0x5c, 0xf6, 0x22, 0x70, 0x1d, 0x0a, 0x52, 0x41, 0x89, 0x6d, 0xfc, 0x09, + 0x3d, 0x92, 0x87, 0xda, 0x02, 0x94, 0x98, 0x26, 0xb8, 0xec, 0x54, 0xa1, 0xe6, 0x50, 0x29, 0x4e, + 0x45, 0x06, 0xbd, 0x02, 0xd3, 0x77, 0x3d, 0xff, 0x8e, 0xe3, 0x59, 0x2c, 0x07, 0x1e, 0x64, 0xe1, + 0xdf, 0x56, 0xde, 0x15, 0x1e, 0x30, 0x7a, 0x2b, 0xa2, 0x8f, 0x75, 0x66, 0xa8, 0x0c, 0xf3, 0x4d, + 0xdb, 0xc5, 0xc4, 0xaa, 0xab, 0x28, 0xdf, 0x31, 0x9e, 0xa4, 0x4b, 0x1a, 0xb9, 0x9b, 0x71, 0x30, + 0x4e, 0xe2, 0xa3, 0x8f, 0x41, 0x21, 0x10, 0x09, 0x20, 0xb2, 0xb9, 0x89, 0x50, 0xc7, 0x23, 0x4e, + 0x34, 0x1a, 0x3b, 0x59, 0x82, 0x15, 0x43, 0xb4, 0x01, 0x4b, 0xbe, 0x78, 0x62, 0x1d, 0x4b, 0x6b, + 0xcb, 0xd7, 0x27, 0xcb, 0x05, 0x85, 0x53, 0xe0, 0x38, 0xb5, 0x16, 0xb5, 0x62, 0x58, 0x96, 0x11, + 0xee, 0x92, 0x2d, 0x68, 0xef, 0x32, 0x59, 0x29, 0x16, 0xd0, 0xc3, 0xa2, 0xc6, 0x0b, 0x23, 0x44, + 0x8d, 0x57, 0xe1, 0x64, 0x12, 0xc4, 0x1e, 0x82, 0xb3, 0xb7, 0xe7, 0xda, 0xee, 0xb1, 0x95, 0x86, + 0x84, 0xd3, 0xeb, 0xa2, 0x5b, 0x30, 0xe5, 0x13, 0x76, 0xbe, 0x28, 0xcb, 0xbb, 0xcf, 0xa1, 0x83, + 0x2e, 0xb0, 0x24, 0x80, 0x23, 0x5a, 0x74, 0xde, 0xad, 0x78, 0x9e, 0xaa, 0xeb, 0x19, 0x66, 0x60, + 0x17, 0x73, 0xdf, 0x27, 0x41, 0x83, 0xf9, 0xaf, 0x73, 0x30, 0x1b, 0x3b, 0x46, 0xa3, 0x27, 0x60, + 0x9c, 0xbd, 0x8c, 0x67, 0xea, 0xa1, 0x10, 0xa9, 0x30, 0x3e, 0x38, 0x1c, 0x86, 0xbe, 0x60, 0xc0, + 0x7c, 0x2b, 0xe6, 0xf2, 0x93, 0x9a, 0x73, 0xc4, 0x6b, 0x96, 0xb8, 0x1f, 0x51, 0xcb, 0xf0, 0x18, + 0x67, 0x86, 0x93, 0xdc, 0xe9, 0x02, 0x14, 0x71, 0x48, 0x0e, 0xf1, 0x19, 0xb6, 0xb0, 0x71, 0x14, + 0x89, 0xd5, 0x38, 0x18, 0x27, 0xf1, 0xe9, 0x0c, 0xb3, 0xde, 0x8d, 0x92, 0xaf, 0xba, 0x2c, 0x09, + 0xe0, 0x88, 0x16, 0x7a, 0x01, 0xe6, 0x44, 0x7a, 0xa2, 0x2d, 0xaf, 0x7e, 0xd9, 0x0a, 0xf6, 0x84, + 0x71, 0xaf, 0x0e, 0x23, 0xab, 0x31, 0x28, 0x4e, 0x60, 0xb3, 0xbe, 0x45, 0x39, 0xa0, 0x18, 0x81, + 0x89, 0x78, 0x02, 0xcc, 0xd5, 0x38, 0x18, 0x27, 0xf1, 0xd1, 0x3b, 0x34, 0xbd, 0xcf, 0xaf, 0x49, + 0x94, 0x36, 0x48, 0xd1, 0xfd, 0x65, 0x98, 0x6f, 0xb3, 0xb3, 0x50, 0x5d, 0x02, 0xc5, 0x7a, 0x54, + 0x0c, 0x6f, 0xc4, 0xc1, 0x38, 0x89, 0x8f, 0x9e, 0x87, 0x59, 0x9f, 0x6a, 0x37, 0x45, 0x80, 0xdf, + 0x9d, 0xa8, 0x8b, 0x00, 0xac, 0x03, 0x71, 0x1c, 0x17, 0x5d, 0x82, 0xc5, 0x28, 0x67, 0x8a, 0x24, + 0xc0, 0x2f, 0x53, 0x54, 0x12, 0x82, 0x72, 0x12, 0x01, 0xf7, 0xd6, 0x41, 0xbf, 0x08, 0x0b, 0xda, + 0x48, 0xac, 0xbb, 0x75, 0x72, 0x4f, 0xe4, 0xb5, 0x60, 0x1f, 0xa3, 0x58, 0x4d, 0xc0, 0x70, 0x0f, + 0x36, 0x7a, 0x2f, 0xcc, 0xd5, 0x3c, 0xc7, 0x61, 0x3a, 0x8e, 0x27, 0x5f, 0xe4, 0x09, 0x2c, 0x78, + 0xaa, 0x8f, 0x18, 0x04, 0x27, 0x30, 0xd1, 0x15, 0x40, 0xde, 0x4e, 0x40, 0xfc, 0x7d, 0x52, 0xbf, + 0xc4, 0x3f, 0xf6, 0x42, 0xb7, 0xf8, 0xd9, 0x78, 0x14, 0xe4, 0xb5, 0x1e, 0x0c, 0x9c, 0x52, 0x8b, + 0xe5, 0x30, 0xd0, 0x5e, 0x24, 0xcc, 0x65, 0x91, 0xbd, 0x3a, 0x79, 0x72, 0x7f, 0xe0, 0x73, 0x04, + 0x1f, 0x26, 0x78, 0x50, 0x6a, 0x71, 0x3e, 0x8b, 0x3c, 0x2e, 0x7a, 0x1e, 0xb6, 0x68, 0x8f, 0xe0, + 0xa5, 0x58, 0x70, 0x42, 0x9f, 0x80, 0xa9, 0x1d, 0x99, 0x94, 0xb3, 0xb8, 0x90, 0xc5, 0xbe, 0x98, + 0xc8, 0x2f, 0x1b, 0x9d, 0x4c, 0x15, 0x00, 0x47, 0x2c, 0xd1, 0x93, 0x30, 0x7d, 0x79, 0xab, 0xac, + 0xa4, 0x70, 0x91, 0xcd, 0xfe, 0x18, 0xad, 0x82, 0x75, 0x00, 0x5d, 0x61, 0xca, 0x5e, 0x42, 0x6c, + 0x8a, 0xa3, 0xfd, 0xb6, 0xd7, 0xfc, 0xa1, 0xd8, 0xec, 0xee, 0x0b, 0x57, 0x8b, 0x27, 0x12, 0xd8, + 0xa2, 0x1c, 0x2b, 0x0c, 0xf4, 0x32, 0x4c, 0x8b, 0xfd, 0x82, 0xe9, 0xa6, 0xa5, 0xa3, 0xbd, 0x76, + 0xc1, 0x11, 0x09, 0xac, 0xd3, 0x43, 0xcf, 0xc2, 0x74, 0x8b, 0xe5, 0x2a, 0x24, 0x17, 0xdb, 0x8e, + 0x53, 0x3c, 0xc9, 0xf4, 0xa6, 0xba, 0x14, 0xd8, 0x8a, 0x40, 0x58, 0xc7, 0x43, 0x4f, 0xcb, 0x8b, + 0xeb, 0xb7, 0xc4, 0xee, 0x78, 0xd4, 0xc5, 0xb5, 0xb2, 0x72, 0xfb, 0x84, 0x39, 0x9e, 0x7a, 0xc0, + 0x8d, 0xf1, 0x0e, 0x2c, 0x4b, 0x13, 0xab, 0x77, 0x91, 0x14, 0x8b, 0x31, 0x2f, 0xc1, 0xf2, 0xad, + 0xbe, 0x98, 0xf8, 0x10, 0x2a, 0x68, 0x17, 0xf2, 0x96, 0xb3, 0x53, 0x3c, 0x9d, 0x85, 0xad, 0xa8, + 0x3e, 0xde, 0xa4, 0xe5, 0x35, 0xde, 0xa8, 0x60, 0xca, 0xc0, 0xfc, 0x54, 0xe4, 0x84, 0x56, 0x59, + 0xbe, 0x3e, 0xae, 0x4b, 0xb6, 0x91, 0xc5, 0x07, 0x4a, 0x7a, 0xb2, 0xd7, 0xf2, 0x4d, 0x29, 0x55, + 0xae, 0x5b, 0x6a, 0x2d, 0x67, 0xf2, 0xec, 0x3c, 0x9e, 0xc1, 0x8c, 0x9f, 0xe8, 0xe2, 0x2b, 0xd9, + 0xfc, 0xc1, 0x98, 0x72, 0x44, 0x25, 0xee, 0x9e, 0x7d, 0x18, 0xb7, 0x83, 0xd0, 0xf6, 0x32, 0x7c, + 0xc8, 0x92, 0x48, 0xfd, 0xc5, 0x62, 0x08, 0x19, 0x00, 0x73, 0x56, 0x94, 0xa7, 0xdb, 0xb0, 0xdd, + 0x7b, 0xa2, 0xfb, 0xd7, 0x33, 0xbf, 0x54, 0xe6, 0x3c, 0x19, 0x00, 0x73, 0x56, 0xe8, 0x36, 0x97, + 0xb6, 0x6c, 0x3e, 0x46, 0x93, 0xfc, 0xc6, 0x14, 0x8f, 0xc0, 0x91, 0x12, 0x47, 0x79, 0x05, 0x4d, + 0x5b, 0xd8, 0x31, 0x23, 0xf2, 0xaa, 0x6e, 0xae, 0xa7, 0xf1, 0xaa, 0x6e, 0xae, 0x63, 0xca, 0x04, + 0x7d, 0xc6, 0x00, 0xb0, 0xd4, 0xc7, 0x96, 0xb2, 0x49, 0xf5, 0xdc, 0xef, 0xe3, 0x4d, 0x3c, 0xec, + 0x27, 0x82, 0x62, 0x8d, 0xb3, 0xf9, 0xba, 0x01, 0x8b, 0x3d, 0x8d, 0x4d, 0x7e, 0x1a, 0xcb, 0x18, + 0xf0, 0xd3, 0x58, 0x6b, 0xb0, 0x20, 0x92, 0xc3, 0x55, 0x5b, 0x8e, 0x9d, 0xfa, 0x18, 0x6c, 0x3b, + 0x01, 0xc7, 0x3d, 0x35, 0xcc, 0x3f, 0x37, 0x60, 0x5a, 0x8b, 0x5d, 0xa7, 0xf6, 0x35, 0x8b, 0xf1, + 0x17, 0xcd, 0x88, 0xf2, 0xe2, 0x31, 0xdf, 0x1b, 0x87, 0x71, 0x37, 0x70, 0x43, 0x4b, 0x7f, 0x14, + 0xb9, 0x81, 0x69, 0x29, 0x16, 0x50, 0x9e, 0xd8, 0x86, 0xf0, 0xcf, 0x9e, 0xe5, 0xf5, 0xc4, 0x36, + 0xa4, 0x85, 0x19, 0x84, 0xb1, 0xa3, 0x8a, 0x5e, 0xc4, 0xe7, 0x68, 0x69, 0xf8, 0x2c, 0x6a, 0xce, + 0x33, 0x18, 0x3a, 0x03, 0x79, 0xe2, 0xd6, 0x85, 0x55, 0xaa, 0x94, 0xd7, 0x05, 0xb7, 0x8e, 0x69, + 0xb9, 0x79, 0x0d, 0x66, 0xaa, 0xa4, 0xe6, 0x93, 0xf0, 0x45, 0x72, 0x30, 0x70, 0x96, 0xf7, 0x3b, + 0xe4, 0x20, 0x99, 0xe5, 0x9d, 0x56, 0xa7, 0xe5, 0xe6, 0xef, 0x1b, 0x90, 0xc8, 0x8a, 0xa8, 0xb9, + 0x84, 0x8c, 0x7e, 0x2e, 0xa1, 0x98, 0xf3, 0x22, 0x77, 0xa8, 0xf3, 0xe2, 0x0a, 0xa0, 0xa6, 0x15, + 0xd6, 0xf6, 0x62, 0x39, 0x3b, 0xc5, 0x81, 0x20, 0x7a, 0x29, 0xd3, 0x83, 0x81, 0x53, 0x6a, 0x99, + 0xaf, 0x1a, 0xd0, 0xf3, 0xd5, 0x32, 0xba, 0x8d, 0x11, 0x91, 0x40, 0x9b, 0x9f, 0x93, 0xd4, 0x36, + 0x26, 0xf3, 0x66, 0x4b, 0x38, 0x35, 0xa6, 0xa5, 0x3b, 0x46, 0x1e, 0x6e, 0xf9, 0x9b, 0x02, 0x65, + 0x4c, 0xaf, 0xc5, 0xc1, 0x38, 0x89, 0x6f, 0xde, 0x84, 0x82, 0x7c, 0x78, 0xc5, 0x5e, 0x2f, 0xc8, + 0xe3, 0x99, 0xfe, 0x7a, 0x81, 0x9e, 0xce, 0x18, 0x84, 0x0e, 0x53, 0xe0, 0xda, 0x97, 0xbd, 0x20, + 0x94, 0xaf, 0xc5, 0xb8, 0x13, 0xe6, 0xea, 0x3a, 0x2b, 0xc3, 0x0a, 0x6a, 0x2e, 0xc2, 0xbc, 0xf2, + 0xae, 0x70, 0xa1, 0x37, 0xbf, 0x95, 0x87, 0x99, 0xd8, 0x27, 0x4a, 0x1e, 0x3c, 0xd9, 0x83, 0x4f, + 0x4b, 0x8a, 0x97, 0x24, 0x3f, 0xa4, 0x97, 0x44, 0x77, 0x4b, 0x8d, 0x1d, 0xaf, 0x5b, 0x6a, 0x3c, + 0x1b, 0xb7, 0x54, 0x08, 0x93, 0xe2, 0x3b, 0x7d, 0x22, 0xca, 0x73, 0x33, 0xa3, 0x57, 0xd3, 0xe2, + 0xf9, 0x21, 0x0b, 0x6c, 0x95, 0x0a, 0x4c, 0xb2, 0x32, 0xbf, 0x31, 0x0e, 0x73, 0xf1, 0x77, 0xd4, + 0x03, 0xcc, 0xe4, 0x3b, 0x7a, 0x66, 0x72, 0xc8, 0x53, 0x62, 0x7e, 0xd4, 0x53, 0xe2, 0xd8, 0xa8, + 0xa7, 0xc4, 0xf1, 0x23, 0x9c, 0x12, 0x7b, 0xcf, 0x78, 0x13, 0x03, 0x9f, 0xf1, 0xde, 0xa7, 0xae, + 0x38, 0x27, 0x63, 0x77, 0x02, 0xd1, 0x15, 0x27, 0x8a, 0x4f, 0xc3, 0xaa, 0x57, 0x4f, 0xbd, 0x2a, + 0x2e, 0x3c, 0xc0, 0x1a, 0xf6, 0x53, 0x6f, 0x24, 0x87, 0x77, 0x44, 0xbd, 0x65, 0x88, 0xdb, 0xc8, + 0xe8, 0x53, 0x94, 0x6c, 0xf3, 0x83, 0xf8, 0xc6, 0x59, 0x8d, 0x40, 0x58, 0xc7, 0x63, 0x1f, 0xec, + 0x88, 0x7f, 0xa1, 0x84, 0x1d, 0xba, 0xf5, 0x0f, 0x76, 0x24, 0xbe, 0x68, 0x92, 0xc4, 0x37, 0xbf, + 0x9e, 0x87, 0xb9, 0x78, 0xc2, 0x65, 0x74, 0x57, 0x19, 0xac, 0x99, 0xd8, 0xca, 0x9c, 0xac, 0xf6, + 0x92, 0xb8, 0xef, 0x09, 0x94, 0x7f, 0x20, 0x71, 0x47, 0x3d, 0x6b, 0x3e, 0x3e, 0xc6, 0xe2, 0xe8, + 0x27, 0xd8, 0xb1, 0x1c, 0xcd, 0x51, 0x40, 0xa1, 0xb8, 0xd6, 0xcc, 0x9c, 0x7b, 0x14, 0x22, 0xa8, + 0x58, 0x61, 0x8d, 0x2d, 0x55, 0xef, 0xfb, 0xc4, 0xb7, 0x77, 0x6d, 0xf5, 0xb1, 0x08, 0xa6, 0x3c, + 0x6f, 0x8a, 0x32, 0xac, 0xa0, 0xe6, 0xab, 0x39, 0x88, 0x3e, 0x8d, 0xc3, 0x72, 0xbf, 0x06, 0x9a, + 0xd9, 0x20, 0xa6, 0xed, 0xca, 0xa8, 0x09, 0x96, 0x23, 0x8a, 0x22, 0x02, 0x44, 0x2b, 0xc1, 0x31, + 0x8e, 0xff, 0x03, 0x9f, 0xc4, 0xb1, 0x60, 0x3e, 0xf1, 0x00, 0x20, 0xf3, 0x88, 0xb2, 0xaf, 0xe4, + 0x61, 0x4a, 0x3d, 0xa1, 0x40, 0xef, 0x61, 0x69, 0x1b, 0xf7, 0x3c, 0x99, 0x4c, 0xf3, 0xad, 0x5a, + 0x72, 0xc5, 0x3d, 0xaf, 0x7e, 0xbf, 0x53, 0x9a, 0x57, 0xc8, 0xbc, 0x08, 0x8b, 0x0a, 0xd4, 0x48, + 0x6b, 0xfb, 0x4e, 0xd2, 0x48, 0xbb, 0x81, 0x37, 0x30, 0x2d, 0x47, 0xf7, 0x60, 0x72, 0x8f, 0x58, + 0x75, 0xe2, 0xcb, 0x0b, 0xf5, 0xcd, 0x8c, 0x9e, 0x7d, 0x5c, 0x66, 0x54, 0xa3, 0x61, 0xe0, 0xff, + 0x03, 0x2c, 0xd9, 0xd1, 0x8d, 0x6a, 0xc7, 0xab, 0x1f, 0x24, 0x93, 0x31, 0x56, 0xbc, 0xfa, 0x01, + 0x66, 0x10, 0xf4, 0x02, 0xcc, 0x85, 0x76, 0x93, 0xd0, 0xd3, 0xb4, 0xf6, 0xe1, 0x91, 0x7c, 0xe4, + 0x51, 0xdd, 0x8e, 0x41, 0x71, 0x02, 0x9b, 0x6e, 0x74, 0xb7, 0x03, 0xcf, 0x65, 0x49, 0x2b, 0x26, + 0xe2, 0xee, 0x97, 0x2b, 0xd5, 0x6b, 0x57, 0x59, 0xce, 0x0a, 0x85, 0x41, 0xb1, 0x6d, 0x16, 0xa7, + 0xed, 0x13, 0x71, 0xa1, 0xb1, 0x10, 0xbd, 0xa6, 0xe3, 0xe5, 0x58, 0x61, 0x98, 0x37, 0x60, 0x3e, + 0xd1, 0x55, 0x69, 0x0e, 0x1b, 0xe9, 0xe6, 0xf0, 0x60, 0x99, 0x0f, 0xff, 0xd8, 0x80, 0xc5, 0x9e, + 0xc5, 0x3b, 0x68, 0xa8, 0x63, 0x52, 0x93, 0xe7, 0x8e, 0xae, 0xc9, 0xf3, 0xc3, 0x69, 0xf2, 0xca, + 0xca, 0xb7, 0xdf, 0x3c, 0xfb, 0xc8, 0x77, 0xde, 0x3c, 0xfb, 0xc8, 0x77, 0xdf, 0x3c, 0xfb, 0xc8, + 0xab, 0xdd, 0xb3, 0xc6, 0xb7, 0xbb, 0x67, 0x8d, 0xef, 0x74, 0xcf, 0x1a, 0xdf, 0xed, 0x9e, 0x35, + 0x7e, 0xd0, 0x3d, 0x6b, 0xbc, 0xfe, 0xc3, 0xb3, 0x8f, 0xbc, 0x54, 0x90, 0x62, 0xf2, 0xdf, 0x01, + 0x00, 0x00, 0xff, 0xff, 0x1f, 0xc4, 0x47, 0xcd, 0xdf, 0x7c, 0x00, 0x00, +} + +func (m *ALBStatus) 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 *ALBStatus) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ALBStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.StableTargetGroup.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size, err := m.CanaryTargetGroup.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.LoadBalancer.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *ALBTrafficRouting) Marshal() (dAtA []byte, err error) { @@ -2929,6 +3082,18 @@ func (m *ALBTrafficRouting) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.StickinessConfig != nil { + { + size, err := m.StickinessConfig.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } i -= len(m.AnnotationPrefix) copy(dAtA[i:], m.AnnotationPrefix) i = encodeVarintGenerated(dAtA, i, uint64(len(m.AnnotationPrefix))) @@ -3555,6 +3720,39 @@ func (m *ArgumentValueFrom) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *AwsResourceRef) 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 *AwsResourceRef) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AwsResourceRef) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.ARN) + copy(dAtA[i:], m.ARN) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.ARN))) + i-- + dAtA[i] = 0x12 + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *BlueGreenStatus) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -6680,6 +6878,18 @@ func (m *RolloutStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size, err := m.ALB.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xca i -= len(m.WorkloadObservedGeneration) copy(dAtA[i:], m.WorkloadObservedGeneration) i = encodeVarintGenerated(dAtA, i, uint64(len(m.WorkloadObservedGeneration))) @@ -7145,6 +7355,40 @@ func (m *SetCanaryScale) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *StickinessConfig) 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 *StickinessConfig) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StickinessConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i = encodeVarintGenerated(dAtA, i, uint64(m.DurationSeconds)) + i-- + dAtA[i] = 0x10 + i-- + if m.Enabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + return len(dAtA) - i, nil +} + func (m *TLSRoute) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -7645,6 +7889,21 @@ func encodeVarintGenerated(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } +func (m *ALBStatus) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.LoadBalancer.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = m.CanaryTargetGroup.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = m.StableTargetGroup.Size() + n += 1 + l + sovGenerated(uint64(l)) + return n +} + func (m *ALBTrafficRouting) Size() (n int) { if m == nil { return 0 @@ -7658,6 +7917,10 @@ func (m *ALBTrafficRouting) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) l = len(m.AnnotationPrefix) n += 1 + l + sovGenerated(uint64(l)) + if m.StickinessConfig != nil { + l = m.StickinessConfig.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -7889,6 +8152,19 @@ func (m *ArgumentValueFrom) Size() (n int) { return n } +func (m *AwsResourceRef) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.ARN) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + func (m *BlueGreenStatus) Size() (n int) { if m == nil { return 0 @@ -9083,6 +9359,8 @@ func (m *RolloutStatus) Size() (n int) { n += 2 + l + sovGenerated(uint64(l)) l = len(m.WorkloadObservedGeneration) n += 2 + l + sovGenerated(uint64(l)) + l = m.ALB.Size() + n += 2 + l + sovGenerated(uint64(l)) return n } @@ -9192,6 +9470,17 @@ func (m *SetCanaryScale) Size() (n int) { return n } +func (m *StickinessConfig) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += 2 + n += 1 + sovGenerated(uint64(m.DurationSeconds)) + return n +} + func (m *TLSRoute) Size() (n int) { if m == nil { return 0 @@ -9382,6 +9671,18 @@ func sovGenerated(x uint64) (n int) { func sozGenerated(x uint64) (n int) { return sovGenerated(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } +func (this *ALBStatus) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&ALBStatus{`, + `LoadBalancer:` + strings.Replace(strings.Replace(this.LoadBalancer.String(), "AwsResourceRef", "AwsResourceRef", 1), `&`, ``, 1) + `,`, + `CanaryTargetGroup:` + strings.Replace(strings.Replace(this.CanaryTargetGroup.String(), "AwsResourceRef", "AwsResourceRef", 1), `&`, ``, 1) + `,`, + `StableTargetGroup:` + strings.Replace(strings.Replace(this.StableTargetGroup.String(), "AwsResourceRef", "AwsResourceRef", 1), `&`, ``, 1) + `,`, + `}`, + }, "") + return s +} func (this *ALBTrafficRouting) String() string { if this == nil { return "nil" @@ -9391,6 +9692,7 @@ func (this *ALBTrafficRouting) String() string { `ServicePort:` + fmt.Sprintf("%v", this.ServicePort) + `,`, `RootService:` + fmt.Sprintf("%v", this.RootService) + `,`, `AnnotationPrefix:` + fmt.Sprintf("%v", this.AnnotationPrefix) + `,`, + `StickinessConfig:` + strings.Replace(this.StickinessConfig.String(), "StickinessConfig", "StickinessConfig", 1) + `,`, `}`, }, "") return s @@ -9578,6 +9880,17 @@ func (this *ArgumentValueFrom) String() string { }, "") return s } +func (this *AwsResourceRef) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&AwsResourceRef{`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `ARN:` + fmt.Sprintf("%v", this.ARN) + `,`, + `}`, + }, "") + return s +} func (this *BlueGreenStatus) String() string { if this == nil { return "nil" @@ -10462,6 +10775,7 @@ func (this *RolloutStatus) String() string { `Phase:` + fmt.Sprintf("%v", this.Phase) + `,`, `Message:` + fmt.Sprintf("%v", this.Message) + `,`, `WorkloadObservedGeneration:` + fmt.Sprintf("%v", this.WorkloadObservedGeneration) + `,`, + `ALB:` + strings.Replace(strings.Replace(this.ALB.String(), "ALBStatus", "ALBStatus", 1), `&`, ``, 1) + `,`, `}`, }, "") return s @@ -10539,6 +10853,17 @@ func (this *SetCanaryScale) String() string { }, "") return s } +func (this *StickinessConfig) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&StickinessConfig{`, + `Enabled:` + fmt.Sprintf("%v", this.Enabled) + `,`, + `DurationSeconds:` + fmt.Sprintf("%v", this.DurationSeconds) + `,`, + `}`, + }, "") + return s +} func (this *TLSRoute) String() string { if this == nil { return "nil" @@ -10686,6 +11011,155 @@ func valueToStringGenerated(v interface{}) string { pv := reflect.Indirect(rv).Interface() return fmt.Sprintf("*%v", pv) } +func (m *ALBStatus) 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: ALBStatus: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ALBStatus: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LoadBalancer", 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 err := m.LoadBalancer.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CanaryTargetGroup", 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 err := m.CanaryTargetGroup.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StableTargetGroup", 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 err := m.StableTargetGroup.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *ALBTrafficRouting) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -10830,6 +11304,42 @@ func (m *ALBTrafficRouting) Unmarshal(dAtA []byte) error { } m.AnnotationPrefix = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StickinessConfig", 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.StickinessConfig == nil { + m.StickinessConfig = &StickinessConfig{} + } + if err := m.StickinessConfig.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -12504,6 +13014,120 @@ func (m *ArgumentValueFrom) Unmarshal(dAtA []byte) error { } return nil } +func (m *AwsResourceRef) 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: AwsResourceRef: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AwsResourceRef: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ARN", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ARN = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *BlueGreenStatus) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -23116,6 +23740,39 @@ func (m *RolloutStatus) Unmarshal(dAtA []byte) error { } m.WorkloadObservedGeneration = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 25: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ALB", 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 err := m.ALB.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -24024,6 +24681,95 @@ func (m *SetCanaryScale) Unmarshal(dAtA []byte) error { } return nil } +func (m *StickinessConfig) 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: StickinessConfig: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StickinessConfig: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Enabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Enabled = bool(v != 0) + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DurationSeconds", wireType) + } + m.DurationSeconds = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DurationSeconds |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *TLSRoute) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/pkg/apis/rollouts/v1alpha1/generated.proto b/pkg/apis/rollouts/v1alpha1/generated.proto index e787c53ea8..7885f04580 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.proto +++ b/pkg/apis/rollouts/v1alpha1/generated.proto @@ -29,6 +29,14 @@ import "k8s.io/apimachinery/pkg/util/intstr/generated.proto"; // Package-wide variables from generator "generated". option go_package = "v1alpha1"; +message ALBStatus { + optional AwsResourceRef loadBalancer = 1; + + optional AwsResourceRef canaryTargetGroup = 2; + + optional AwsResourceRef stableTargetGroup = 3; +} + // ALBTrafficRouting configuration for ALB ingress controller to control traffic routing message ALBTrafficRouting { // Ingress refers to the name of an `Ingress` resource in the same namespace as the `Rollout` @@ -40,6 +48,10 @@ message ALBTrafficRouting { // RootService references the service in the ingress to the controller should add the action to optional string rootService = 3; + // AdditionalForwardConfig allows to specify further settings on the ForwaredConfig + // +optional + optional StickinessConfig stickinessConfig = 5; + // AnnotationPrefix has to match the configured annotation prefix on the alb ingress controller // +optional optional string annotationPrefix = 4; @@ -194,6 +206,12 @@ message ArgumentValueFrom { optional FieldRef fieldRef = 2; } +message AwsResourceRef { + optional string name = 1; + + optional string arn = 2; +} + // BlueGreenStatus status fields that only pertain to the blueGreen rollout message BlueGreenStatus { // PreviewSelector indicates which replicas set the preview service is serving traffic to @@ -1176,10 +1194,6 @@ message RolloutStatus { // +optional optional string observedGeneration = 13; - // The generation of referenced workload observed by the rollout controller - // +optional - optional string workloadObservedGeneration = 24; - // Conditions a list of conditions a rollout can have. // +optional repeated RolloutCondition conditions = 14; @@ -1215,6 +1229,13 @@ message RolloutStatus { // Message provides details on why the rollout is in its current phase optional string message = 23; + + // The generation of referenced workload observed by the rollout controller + // +optional + optional string workloadObservedGeneration = 24; + + // / ALB keeps information regarding the ALB and TargetGroups + optional ALBStatus alb = 25; } // RolloutStrategy defines strategy to apply during next rollout @@ -1290,6 +1311,12 @@ message SetCanaryScale { optional bool matchTrafficWeight = 3; } +message StickinessConfig { + optional bool enabled = 1; + + optional int64 durationSeconds = 2; +} + // TLSRoute holds the information on the virtual service's TLS/HTTPS routes that are desired to be matched for changing weights. message TLSRoute { // Port number of the TLS Route desired to be matched in the given Istio VirtualService. diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index dcae450417..67a31048bf 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -29,6 +29,7 @@ import ( func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { return map[string]common.OpenAPIDefinition{ + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ALBStatus": schema_pkg_apis_rollouts_v1alpha1_ALBStatus(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ALBTrafficRouting": schema_pkg_apis_rollouts_v1alpha1_ALBTrafficRouting(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AmbassadorTrafficRouting": schema_pkg_apis_rollouts_v1alpha1_AmbassadorTrafficRouting(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisRun": schema_pkg_apis_rollouts_v1alpha1_AnalysisRun(ref), @@ -43,6 +44,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AntiAffinity": schema_pkg_apis_rollouts_v1alpha1_AntiAffinity(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Argument": schema_pkg_apis_rollouts_v1alpha1_Argument(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ArgumentValueFrom": schema_pkg_apis_rollouts_v1alpha1_ArgumentValueFrom(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AwsResourceRef": schema_pkg_apis_rollouts_v1alpha1_AwsResourceRef(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.BlueGreenStatus": schema_pkg_apis_rollouts_v1alpha1_BlueGreenStatus(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.BlueGreenStrategy": schema_pkg_apis_rollouts_v1alpha1_BlueGreenStrategy(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.CanaryStatus": schema_pkg_apis_rollouts_v1alpha1_CanaryStatus(ref), @@ -103,6 +105,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ScopeDetail": schema_pkg_apis_rollouts_v1alpha1_ScopeDetail(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SecretKeyRef": schema_pkg_apis_rollouts_v1alpha1_SecretKeyRef(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetCanaryScale": schema_pkg_apis_rollouts_v1alpha1_SetCanaryScale(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.StickinessConfig": schema_pkg_apis_rollouts_v1alpha1_StickinessConfig(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TLSRoute": schema_pkg_apis_rollouts_v1alpha1_TLSRoute(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TemplateService": schema_pkg_apis_rollouts_v1alpha1_TemplateService(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TemplateSpec": schema_pkg_apis_rollouts_v1alpha1_TemplateSpec(ref), @@ -116,6 +119,38 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA } } +func schema_pkg_apis_rollouts_v1alpha1_ALBStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "loadBalancer": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AwsResourceRef"), + }, + }, + "canaryTargetGroup": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AwsResourceRef"), + }, + }, + "stableTargetGroup": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AwsResourceRef"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AwsResourceRef"}, + } +} + func schema_pkg_apis_rollouts_v1alpha1_ALBTrafficRouting(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -146,6 +181,12 @@ func schema_pkg_apis_rollouts_v1alpha1_ALBTrafficRouting(ref common.ReferenceCal Format: "", }, }, + "stickinessConfig": { + SchemaProps: spec.SchemaProps{ + Description: "AdditionalForwardConfig allows to specify further settings on the ForwaredConfig", + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.StickinessConfig"), + }, + }, "annotationPrefix": { SchemaProps: spec.SchemaProps{ Description: "AnnotationPrefix has to match the configured annotation prefix on the alb ingress controller", @@ -157,6 +198,8 @@ func schema_pkg_apis_rollouts_v1alpha1_ALBTrafficRouting(ref common.ReferenceCal Required: []string{"ingress", "servicePort"}, }, }, + Dependencies: []string{ + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.StickinessConfig"}, } } @@ -701,6 +744,33 @@ func schema_pkg_apis_rollouts_v1alpha1_ArgumentValueFrom(ref common.ReferenceCal } } +func schema_pkg_apis_rollouts_v1alpha1_AwsResourceRef(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "arn": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"name", "arn"}, + }, + }, + } +} + func schema_pkg_apis_rollouts_v1alpha1_BlueGreenStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -3424,13 +3494,6 @@ func schema_pkg_apis_rollouts_v1alpha1_RolloutStatus(ref common.ReferenceCallbac Format: "", }, }, - "workloadObservedGeneration": { - SchemaProps: spec.SchemaProps{ - Description: "The generation of referenced workload observed by the rollout controller", - Type: []string{"string"}, - Format: "", - }, - }, "conditions": { SchemaProps: spec.SchemaProps{ Description: "Conditions a list of conditions a rollout can have.", @@ -3507,11 +3570,25 @@ func schema_pkg_apis_rollouts_v1alpha1_RolloutStatus(ref common.ReferenceCallbac Format: "", }, }, + "workloadObservedGeneration": { + SchemaProps: spec.SchemaProps{ + Description: "The generation of referenced workload observed by the rollout controller", + Type: []string{"string"}, + Format: "", + }, + }, + "alb": { + SchemaProps: spec.SchemaProps{ + Description: "/ ALB keeps information regarding the ALB and TargetGroups", + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ALBStatus"), + }, + }, }, }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.BlueGreenStatus", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.CanaryStatus", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PauseCondition", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutCondition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ALBStatus", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.BlueGreenStatus", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.CanaryStatus", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PauseCondition", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutCondition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } @@ -3723,6 +3800,33 @@ func schema_pkg_apis_rollouts_v1alpha1_SetCanaryScale(ref common.ReferenceCallba } } +func schema_pkg_apis_rollouts_v1alpha1_StickinessConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "enabled": { + SchemaProps: spec.SchemaProps{ + Default: false, + Type: []string{"boolean"}, + Format: "", + }, + }, + "durationSeconds": { + SchemaProps: spec.SchemaProps{ + Default: 0, + Type: []string{"integer"}, + Format: "int64", + }, + }, + }, + Required: []string{"enabled", "durationSeconds"}, + }, + }, + } +} + func schema_pkg_apis_rollouts_v1alpha1_TLSRoute(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/pkg/apis/rollouts/v1alpha1/types.go b/pkg/apis/rollouts/v1alpha1/types.go index 46e5f34082..78b6021929 100644 --- a/pkg/apis/rollouts/v1alpha1/types.go +++ b/pkg/apis/rollouts/v1alpha1/types.go @@ -324,11 +324,19 @@ type ALBTrafficRouting struct { ServicePort int32 `json:"servicePort" protobuf:"varint,2,opt,name=servicePort"` // RootService references the service in the ingress to the controller should add the action to RootService string `json:"rootService,omitempty" protobuf:"bytes,3,opt,name=rootService"` + // AdditionalForwardConfig allows to specify further settings on the ForwaredConfig + // +optional + StickinessConfig *StickinessConfig `json:"stickinessConfig,omitempty" protobuf:"bytes,5,opt,name=stickinessConfig"` // AnnotationPrefix has to match the configured annotation prefix on the alb ingress controller // +optional AnnotationPrefix string `json:"annotationPrefix,omitempty" protobuf:"bytes,4,opt,name=annotationPrefix"` } +type StickinessConfig struct { + Enabled bool `json:"enabled" protobuf:"varint,1,opt,name=enabled"` + DurationSeconds int64 `json:"durationSeconds" protobuf:"varint,2,opt,name=durationSeconds"` +} + // RolloutTrafficRouting hosts all the different configuration for supported service meshes to enable more fine-grained traffic routing type RolloutTrafficRouting struct { // Istio holds Istio specific configuration to route traffic diff --git a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go index 3304117afd..74919abcc4 100644 --- a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go @@ -48,6 +48,11 @@ func (in *ALBStatus) DeepCopy() *ALBStatus { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ALBTrafficRouting) DeepCopyInto(out *ALBTrafficRouting) { *out = *in + if in.StickinessConfig != nil { + in, out := &in.StickinessConfig, &out.StickinessConfig + *out = new(StickinessConfig) + **out = **in + } return } @@ -2008,7 +2013,7 @@ func (in *RolloutTrafficRouting) DeepCopyInto(out *RolloutTrafficRouting) { if in.ALB != nil { in, out := &in.ALB, &out.ALB *out = new(ALBTrafficRouting) - **out = **in + (*in).DeepCopyInto(*out) } if in.SMI != nil { in, out := &in.SMI, &out.SMI @@ -2123,6 +2128,22 @@ func (in *SetCanaryScale) DeepCopy() *SetCanaryScale { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StickinessConfig) DeepCopyInto(out *StickinessConfig) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StickinessConfig. +func (in *StickinessConfig) DeepCopy() *StickinessConfig { + if in == nil { + return nil + } + out := new(StickinessConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TLSRoute) DeepCopyInto(out *TLSRoute) { *out = *in diff --git a/rollout/trafficrouting/alb/alb.go b/rollout/trafficrouting/alb/alb.go index f264d72df0..f3830a9c49 100644 --- a/rollout/trafficrouting/alb/alb.go +++ b/rollout/trafficrouting/alb/alb.go @@ -207,7 +207,7 @@ func (r *Reconciler) VerifyWeight(desiredWeight int32, additionalDestinations .. return pointer.BoolPtr(numVerifiedWeights == 1+len(additionalDestinations)), nil } -func getForwardActionString(r *v1alpha1.Rollout, port int32, desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) string { +func getForwardActionString(r *v1alpha1.Rollout, port int32, desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) (string, error) { stableService := r.Spec.Strategy.Canary.StableService canaryService := r.Spec.Strategy.Canary.CanaryService portStr := strconv.Itoa(int(port)) @@ -245,14 +245,33 @@ func getForwardActionString(r *v1alpha1.Rollout, port int32, desiredWeight int32 TargetGroups: targetGroups, }, } + + var stickinessConfig = r.Spec.Strategy.Canary.TrafficRouting.ALB.StickinessConfig + if stickinessConfig != nil && stickinessConfig.Enabled { + // AWS API valid range + // https://docs.aws.amazon.com/elasticloadbalancing/latest/APIReference/API_TargetGroupStickinessConfig.html + if stickinessConfig.DurationSeconds < 1 || stickinessConfig.DurationSeconds > 604800 { + return "", fmt.Errorf("TargetGroupStickinessConfig's duration must be between 1 and 604800 seconds (7 days)!") + } + newStickyConfig := ingressutil.ALBTargetGroupStickinessConfig{ + Enabled: true, + DurationSeconds: stickinessConfig.DurationSeconds, + } + action.ForwardConfig.TargetGroupStickinessConfig = &newStickyConfig + } + bytes := jsonutil.MustMarshal(action) - return string(bytes) + return string(bytes), nil } func getDesiredAnnotations(current *ingressutil.Ingress, r *v1alpha1.Rollout, port int32, desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) (map[string]string, error) { desired := current.DeepCopy().GetAnnotations() key := ingressutil.ALBActionAnnotationKey(r) - desired[key] = getForwardActionString(r, port, desiredWeight, additionalDestinations...) + value, err := getForwardActionString(r, port, desiredWeight, additionalDestinations...) + if err != nil { + return nil, err + } + desired[key] = value m, err := ingressutil.NewManagedALBActions(desired[ingressutil.ManagedActionsAnnotation]) if err != nil { return nil, err diff --git a/rollout/trafficrouting/alb/alb_test.go b/rollout/trafficrouting/alb/alb_test.go index b3db5beba5..7afb8aa7a6 100644 --- a/rollout/trafficrouting/alb/alb_test.go +++ b/rollout/trafficrouting/alb/alb_test.go @@ -27,6 +27,9 @@ import ( "github.com/argoproj/argo-rollouts/utils/record" ) +const STABLE_SVC = "stable-svc" +const CANARY_SVC = "canary-svc" + func fakeRollout(stableSvc, canarySvc, stableIng string, port int32) *v1alpha1.Rollout { return &v1alpha1.Rollout{ ObjectMeta: metav1.ObjectMeta{ @@ -67,15 +70,39 @@ const actionTemplate = `{ } }` +const actionTemplateWithStickyConfig = `{ + "Type":"forward", + "ForwardConfig":{ + "TargetGroups":[ + { + "ServiceName":"%s", + "ServicePort":"%d", + "Weight":%d + },{ + "ServiceName":"%s", + "ServicePort":"%d", + "Weight":%d + } + ], + "TargetGroupStickinessConfig":{ + "DurationSeconds" : 300, + "Enabled" : true + } + } +}` + const actionTemplateWithExperiments = `{"Type":"forward","ForwardConfig":{"TargetGroups":[{"ServiceName":"%s","ServicePort":"%d","Weight":%d},{"ServiceName":"%s","ServicePort":"%d","Weight":%d},{"ServiceName":"%s","ServicePort":"%d","Weight":%d},{"ServiceName":"%s","ServicePort":"%d","Weight":%d}]}}` func albActionAnnotation(stable string) string { return fmt.Sprintf("%s%s%s", ingressutil.ALBIngressAnnotation, ingressutil.ALBActionPrefix, stable) } -func ingress(name string, stableSvc, canarySvc string, port, weight int32, managedBy string) *extensionsv1beta1.Ingress { +func ingress(name string, stableSvc, canarySvc string, port, weight int32, managedBy string, includeStickyConfig bool) *extensionsv1beta1.Ingress { managedByValue := fmt.Sprintf("%s:%s", managedBy, albActionAnnotation(stableSvc)) action := fmt.Sprintf(actionTemplate, canarySvc, port, weight, stableSvc, port, 100-weight) + if includeStickyConfig { + action = fmt.Sprintf(actionTemplateWithStickyConfig, canarySvc, port, weight, stableSvc, port, 100-weight) + } var a ingressutil.ALBAction err := json.Unmarshal([]byte(action), &a) if err != nil { @@ -149,7 +176,7 @@ func TestIngressNotFound(t *testing.T) { func TestServiceNotFoundInIngress(t *testing.T) { ro := fakeRollout("stable-stable", "canary-service", "ingress", 443) ro.Spec.Strategy.Canary.TrafficRouting.ALB.RootService = "invalid-svc" - i := ingress("ingress", "stable-service", "canary-svc", 443, 50, ro.Name) + i := ingress("ingress", "stable-service", CANARY_SVC, 443, 50, ro.Name, false) client := fake.NewSimpleClientset() k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) @@ -170,8 +197,8 @@ func TestServiceNotFoundInIngress(t *testing.T) { } func TestNoChanges(t *testing.T) { - ro := fakeRollout("stable-svc", "canary-svc", "ingress", 443) - i := ingress("ingress", "stable-svc", "canary-svc", 443, 10, ro.Name) + ro := fakeRollout(STABLE_SVC, CANARY_SVC, "ingress", 443) + i := ingress("ingress", STABLE_SVC, CANARY_SVC, 443, 10, ro.Name, false) client := fake.NewSimpleClientset() k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) @@ -193,8 +220,8 @@ func TestNoChanges(t *testing.T) { } func TestErrorOnInvalidManagedBy(t *testing.T) { - ro := fakeRollout("stable-svc", "canary-svc", "ingress", 443) - i := ingress("ingress", "stable-svc", "canary-svc", 443, 5, ro.Name) + ro := fakeRollout(STABLE_SVC, CANARY_SVC, "ingress", 443) + i := ingress("ingress", STABLE_SVC, CANARY_SVC, 443, 5, ro.Name, false) i.Annotations[ingressutil.ManagedActionsAnnotation] = "test" client := fake.NewSimpleClientset(i) k8sI := kubeinformers.NewSharedInformerFactory(client, 0) @@ -216,8 +243,8 @@ func TestErrorOnInvalidManagedBy(t *testing.T) { } func TestSetInitialDesiredWeight(t *testing.T) { - ro := fakeRollout("stable-svc", "canary-svc", "ingress", 443) - i := ingress("ingress", "stable-svc", "canary-svc", 443, 5, ro.Name) + ro := fakeRollout(STABLE_SVC, CANARY_SVC, "ingress", 443) + i := ingress("ingress", STABLE_SVC, CANARY_SVC, 443, 5, ro.Name, false) i.Annotations = map[string]string{} client := fake.NewSimpleClientset(i) k8sI := kubeinformers.NewSharedInformerFactory(client, 0) @@ -239,9 +266,30 @@ func TestSetInitialDesiredWeight(t *testing.T) { assert.Len(t, client.Actions(), 1) } +func TestUpdateDesiredWeightWithStickyConfig(t *testing.T) { + ro := fakeRollout(STABLE_SVC, CANARY_SVC, "ingress", 443) + i := ingress("ingress", STABLE_SVC, CANARY_SVC, 443, 5, ro.Name, true) + client := fake.NewSimpleClientset(i) + k8sI := kubeinformers.NewSharedInformerFactory(client, 0) + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + assert.Nil(t, err) + r, err := NewReconciler(ReconcilerConfig{ + Rollout: ro, + Client: client, + Recorder: record.NewFakeEventRecorder(), + ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, + IngressWrapper: ingressWrapper, + }) + assert.NoError(t, err) + err = r.SetWeight(10) + assert.Nil(t, err) + assert.Len(t, client.Actions(), 1) +} + func TestUpdateDesiredWeight(t *testing.T) { - ro := fakeRollout("stable-svc", "canary-svc", "ingress", 443) - i := ingress("ingress", "stable-svc", "canary-svc", 443, 5, ro.Name) + ro := fakeRollout(STABLE_SVC, CANARY_SVC, "ingress", 443) + i := ingress("ingress", STABLE_SVC, CANARY_SVC, 443, 5, ro.Name, false) client := fake.NewSimpleClientset(i) k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) @@ -266,13 +314,58 @@ func TestUpdateDesiredWeight(t *testing.T) { // the forward action func TestGetForwardActionStringMarshalsZeroCorrectly(t *testing.T) { r := fakeRollout("stable", "canary", "ingress", 443) - forwardAction := getForwardActionString(r, 443, 0) + forwardAction, err := getForwardActionString(r, 443, 0) + if err != nil { + t.Fatal(err) + } + assert.Contains(t, forwardAction, `"Weight":0`) +} + +func TestGetForwardActionStringMarshalsDisabledStickyConfigCorrectly(t *testing.T) { + r := fakeRollout("stable", "canary", "ingress", 443) + stickinessConfig := v1alpha1.StickinessConfig{ + Enabled: false, + DurationSeconds: 0, + } + r.Spec.Strategy.Canary.TrafficRouting.ALB.StickinessConfig = &stickinessConfig + forwardAction, err := getForwardActionString(r, 443, 0) + if err != nil { + t.Fatal(err) + } assert.Contains(t, forwardAction, `"Weight":0`) } +func TestGetForwardActionStringDetectsNegativeStickyConfigDuration(t *testing.T) { + r := fakeRollout("stable", "canary", "ingress", 443) + stickinessConfig := v1alpha1.StickinessConfig{ + Enabled: true, + DurationSeconds: 0, + } + r.Spec.Strategy.Canary.TrafficRouting.ALB.StickinessConfig = &stickinessConfig + forwardAction, err := getForwardActionString(r, 443, 0) + + assert.NotNilf(t, forwardAction, "There should be no forwardAction being generated: %v", forwardAction) + expectedErrorMsg := "TargetGroupStickinessConfig's duration must be between 1 and 604800 seconds (7 days)!" + assert.EqualErrorf(t, err, expectedErrorMsg, "Error should be: %v, got: %v", expectedErrorMsg, err) +} + +func TestGetForwardActionStringDetectsTooLargeStickyConfigDuration(t *testing.T) { + r := fakeRollout("stable", "canary", "ingress", 443) + stickinessConfig := v1alpha1.StickinessConfig{ + Enabled: true, + DurationSeconds: 604800 + 1, + } + r.Spec.Strategy.Canary.TrafficRouting.ALB.StickinessConfig = &stickinessConfig + forwardAction, err := getForwardActionString(r, 443, 0) + + assert.NotNilf(t, forwardAction, "There should be no forwardAction being generated: %v", forwardAction) + expectedErrorMsg := "TargetGroupStickinessConfig's duration must be between 1 and 604800 seconds (7 days)!" + assert.EqualErrorf(t, err, expectedErrorMsg, "Error should be: %v, got: %v", expectedErrorMsg, err) +} + func TestErrorPatching(t *testing.T) { - ro := fakeRollout("stable-svc", "canary-svc", "ingress", 443) - i := ingress("ingress", "stable-svc", "canary-svc", 443, 5, ro.Name) + ro := fakeRollout(STABLE_SVC, CANARY_SVC, "ingress", 443) + i := ingress("ingress", STABLE_SVC, CANARY_SVC, 443, 5, ro.Name, false) client := fake.NewSimpleClientset(i) client.ReactionChain = nil k8sI := kubeinformers.NewSharedInformerFactory(client, 0) @@ -337,8 +430,8 @@ func (f *fakeAWSClient) getAlbStatus() *v1alpha1.ALBStatus { func TestVerifyWeight(t *testing.T) { newFakeReconciler := func(status *v1alpha1.RolloutStatus) (*Reconciler, *fakeAWSClient) { - ro := fakeRollout("stable-svc", "canary-svc", "ingress", 443) - i := ingress("ingress", "stable-svc", "canary-svc", 443, 5, ro.Name) + ro := fakeRollout(STABLE_SVC, CANARY_SVC, "ingress", 443) + i := ingress("ingress", STABLE_SVC, CANARY_SVC, 443, 5, ro.Name, false) i.Status.LoadBalancer = corev1.LoadBalancerStatus{ Ingress: []corev1.LoadBalancerIngress{ { @@ -455,8 +548,8 @@ func TestVerifyWeight(t *testing.T) { } func TestSetWeightWithMultipleBackends(t *testing.T) { - ro := fakeRollout("stable-svc", "canary-svc", "ingress", 443) - i := ingress("ingress", "stable-svc", "canary-svc", 443, 0, ro.Name) + ro := fakeRollout(STABLE_SVC, CANARY_SVC, "ingress", 443) + i := ingress("ingress", STABLE_SVC, CANARY_SVC, 443, 0, ro.Name, false) client := fake.NewSimpleClientset(i) k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) @@ -497,7 +590,7 @@ func TestSetWeightWithMultipleBackends(t *testing.T) { assert.Nil(t, err) servicePort := 443 - expectedAction := fmt.Sprintf(actionTemplateWithExperiments, "canary-svc", servicePort, 10, weightDestinations[0].ServiceName, servicePort, weightDestinations[0].Weight, weightDestinations[1].ServiceName, servicePort, weightDestinations[1].Weight, "stable-svc", servicePort, 85) + expectedAction := fmt.Sprintf(actionTemplateWithExperiments, CANARY_SVC, servicePort, 10, weightDestinations[0].ServiceName, servicePort, weightDestinations[0].Weight, weightDestinations[1].ServiceName, servicePort, weightDestinations[1].Weight, STABLE_SVC, servicePort, 85) assert.Equal(t, expectedAction, patchedI.Annotations["alb.ingress.kubernetes.io/actions.stable-svc"]) } @@ -515,9 +608,9 @@ func TestVerifyWeightWithAdditionalDestinations(t *testing.T) { }, } newFakeReconciler := func(status *v1alpha1.RolloutStatus) (*Reconciler, *fakeAWSClient) { - ro := fakeRollout("stable-svc", "canary-svc", "ingress", 443) - i := ingress("ingress", "stable-svc", "canary-svc", 443, 0, ro.Name) - i.Annotations["alb.ingress.kubernetes.io/actions.stable-svc"] = fmt.Sprintf(actionTemplateWithExperiments, "canary-svc", 443, 10, weightDestinations[0].ServiceName, 443, weightDestinations[0].Weight, weightDestinations[1].ServiceName, 443, weightDestinations[1].Weight, "stable-svc", 443, 85) + ro := fakeRollout(STABLE_SVC, CANARY_SVC, "ingress", 443) + i := ingress("ingress", STABLE_SVC, CANARY_SVC, 443, 0, ro.Name, false) + i.Annotations["alb.ingress.kubernetes.io/actions.stable-svc"] = fmt.Sprintf(actionTemplateWithExperiments, CANARY_SVC, 443, 10, weightDestinations[0].ServiceName, 443, weightDestinations[0].Weight, weightDestinations[1].ServiceName, 443, weightDestinations[1].Weight, STABLE_SVC, 443, 85) i.Status.LoadBalancer = corev1.LoadBalancerStatus{ Ingress: []corev1.LoadBalancerIngress{ diff --git a/utils/ingress/ingress.go b/utils/ingress/ingress.go index ad9c9ee316..42dc61ca20 100644 --- a/utils/ingress/ingress.go +++ b/utils/ingress/ingress.go @@ -34,7 +34,14 @@ type ALBAction struct { // ALBForwardConfig describes a list of target groups that the ALB should route traffic towards type ALBForwardConfig struct { - TargetGroups []ALBTargetGroup `json:"TargetGroups"` + TargetGroups []ALBTargetGroup `json:"TargetGroups"` + TargetGroupStickinessConfig *ALBTargetGroupStickinessConfig `json:"TargetGroupStickinessConfig,omitempty"` +} + +// ALBTargetGroupStickinessConfig describes settings for the listener to apply to all forwards +type ALBTargetGroupStickinessConfig struct { + Enabled bool `json:"Enabled"` + DurationSeconds int64 `json:"DurationSeconds"` } // ALBTargetGroup holds the weight to send to a specific destination consisting of a K8s service and port or ARN From 6d4174b8e725eb0b27d8f35fad51a70bb7e925b2 Mon Sep 17 00:00:00 2001 From: "Kostis (Codefresh)" <39800303+kostis-codefresh@users.noreply.github.com> Date: Tue, 14 Dec 2021 19:51:47 +0200 Subject: [PATCH 019/175] docs: Clarify application dependencies (#1706) Signed-off-by: Kostis Kapelonis --- docs/FAQ.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index 7d870eddfb..e5dd2e54a5 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -5,7 +5,7 @@ ### Does Argo Rollouts depend on Argo CD or any other Argo project? Argo Rollouts is a standalone project. Even though it works great with Argo CD and other Argo projects, it can be used -on its own for Progressive Delivery scenarios. More specifically, argo Rollouts does **NOT** require that you also have installed Argo CD on the same cluster. +on its own for Progressive Delivery scenarios. More specifically, Argo Rollouts does **NOT** require that you also have installed Argo CD on the same cluster. ### How does Argo Rollouts integrate with Argo CD? Argo CD understands the health of Argo Rollouts resources via Argo CD’s [Lua health check](https://github.com/argoproj/argo-cd/blob/master/docs/operator-manual/health.md). These Health checks understand when the Argo Rollout objects are Progressing, Suspended, Degraded, or Healthy. Additionally, Argo CD has Lua based Resource Actions that can mutate an Argo Rollouts resource (i.e. unpause a Rollout). @@ -55,6 +55,12 @@ A BlueGreen Rollout keeps the old ReplicaSet up and running for 30 seconds or th ### What is the `argo-rollouts.argoproj.io/managed-by-rollouts` annotation? Argo Rollouts adds an `argo-rollouts.argoproj.io/managed-by-rollouts` annotation to Services and Ingresses that the controller modifies. They are used when the Rollout managing these resources is deleted and the controller tries to revert them back into their previous state. +### How can I deploy multiple services in a single step and roll them back according to their dependencies? + +The Rollout specification focuses on a single application/deployment. Argo Rollouts knows nothing about application dependencies. If you want to deploy multiple applications together in a smart way (e.g. automatically rollback a frontend if backend deployment fails) you need to write your own solution +on top of Argo Rollouts. In most cases, you would need one Rollout resource for each application that you +are deploying. Ideally you should also make your services backwards and forwards compatible (i.e. frontend should be able to work with both backend-preview and backend-active). + ## Experiments ### Why doesn't my Experiment end? From 5f6187c99f093bf6aecf0281a79ec6d1d1abfa8d Mon Sep 17 00:00:00 2001 From: Piyush Baderia Date: Tue, 14 Dec 2021 23:22:21 +0530 Subject: [PATCH 020/175] chore(docs): Updated FAQs (#1695) Signed-off-by: Piyush Baderia --- docs/FAQ.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index e5dd2e54a5..62bf91145c 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -47,7 +47,7 @@ Yes. A k8s cluster can run multiple replicas of Argo-rollouts controllers to ach Argo Rollouts supports BlueGreen, Canary, and Rolling Update. Additionally, Progressive Delivery features can be enabled on top of the blue-green/canary update, which further provides advanced deployment such as automated analysis and rollback. ### Does the Rollout object follow the provided strategy when it is first created? -As with Deployments, Rollouts does not follow the strategy parameters on the initial deploy. The controller tries to get the Rollout into a steady state as fast as possible. The controller tries to get the Rollout into a steady state as fast as possible by creating a fully scaled up ReplicaSet from the provided `.spec.template`. Once the Rollout has a stable ReplicaSet to transition from, the controller starts using the provided strategy to transition the previous ReplicaSet to the desired ReplicaSet. +As with Deployments, Rollouts does not follow the strategy parameters on the initial deploy. The controller tries to get the Rollout into a steady state as fast as possible by creating a fully scaled up ReplicaSet from the provided `.spec.template`. Once the Rollout has a stable ReplicaSet to transition from, the controller starts using the provided strategy to transition the previous ReplicaSet to the desired ReplicaSet. ### How does BlueGreen rollback work? A BlueGreen Rollout keeps the old ReplicaSet up and running for 30 seconds or the value of the scaleDownDelaySeconds. The controller tracks the remaining time before scaling down by adding an annotation called `argo-rollouts.argoproj.io/scale-down-deadline` to the old ReplicaSet. If the user applies the old Rollout manifest before the old ReplicaSet scales down, the controller does something called a fast rollback. The controller immediately switches the active service’s selector back to the old ReplicaSet’s rollout-pod-template-hash and removes the scaled down annotation from that ReplicaSet. The controller does not do any of the normal operations when trying to introduce a new version since it is trying to revert as fast as possible. A non-fast-track rollback occurs when the scale down annotation has past and the old ReplicaSet has been scaled down. In this case, the Rollout treats the ReplicaSet like any other new ReplicaSet and follows the usual procedure for deploying a new ReplicaSet. From 15096f3a53718489d83158f2998408e1b453ee6e Mon Sep 17 00:00:00 2001 From: Rohit Agrawal Date: Tue, 14 Dec 2021 12:57:53 -0500 Subject: [PATCH 021/175] feat(experiment): Added DryRun analysis mode functionality for experiments (#1691) Signed-off-by: Rohit Agrawal --- docs/features/analysis.md | 29 +++++++++++ experiments/experiment.go | 18 ++++--- manifests/crds/experiment-crd.yaml | 9 ++++ manifests/install.yaml | 9 ++++ manifests/namespace-install.yaml | 9 ++++ pkg/apiclient/rollout/rollout.swagger.json | 2 +- pkg/apis/api-rules/violation_exceptions.list | 1 + pkg/apis/rollouts/v1alpha1/analysis_types.go | 2 + .../rollouts/v1alpha1/experiment_types.go | 5 ++ pkg/apis/rollouts/v1alpha1/types.go | 1 + .../v1alpha1/zz_generated.deepcopy.go | 5 ++ test/e2e/analysis_test.go | 1 - test/e2e/experiment_test.go | 11 ++++ .../experiment-dry-run-analysis.yaml | 51 +++++++++++++++++++ test/fixtures/then.go | 26 ++++++++++ utils/analysis/helpers.go | 42 --------------- utils/analysis/helpers_test.go | 14 ++--- 17 files changed, 176 insertions(+), 59 deletions(-) create mode 100644 test/e2e/functional/experiment-dry-run-analysis.yaml diff --git a/docs/features/analysis.md b/docs/features/analysis.md index 65e36db179..3800be67ec 100644 --- a/docs/features/analysis.md +++ b/docs/features/analysis.md @@ -650,6 +650,35 @@ spec: - metricName: .* ``` +### Dry-Run Experiments + +If an experiment wants to dry run its analysis, it simply needs to specify the `dryRun` field under its specs. In the +following example, all the metrics from `analyze-job` matching the RegEx rule `test.*` will be executed in the dry-run +mode. + +```yaml hl_lines="20 21" +kind: Experiment +spec: + templates: + - name: baseline + selector: + matchLabels: + app: rollouts-demo + template: + metadata: + labels: + app: rollouts-demo + spec: + containers: + - name: rollouts-demo + image: argoproj/rollouts-demo:blue + analyses: + - name: analyze-job + templateName: analyze-job + dryRun: + - metricName: test.* +``` + ## Inconclusive Runs Analysis runs can also be considered `Inconclusive`, which indicates the run was neither successful, diff --git a/experiments/experiment.go b/experiments/experiment.go index 2c06b7413d..6c24c74091 100644 --- a/experiments/experiment.go +++ b/experiments/experiment.go @@ -100,7 +100,7 @@ func (ec *experimentContext) reconcile() *v1alpha1.ExperimentStatus { } for _, analysis := range ec.ex.Spec.Analyses { - ec.reconcileAnalysisRun(analysis) + ec.reconcileAnalysisRun(analysis, ec.ex.Spec.DryRun) } newStatus := ec.calculateStatus() @@ -371,7 +371,7 @@ func calculateEnqueueDuration(ex *v1alpha1.Experiment, newStatus *v1alpha1.Exper // reconcileAnalysisRun reconciles a single analysis run, creating or terminating it as necessary. // Updates the analysis run statuses, which may subsequently fail the experiment. -func (ec *experimentContext) reconcileAnalysisRun(analysis v1alpha1.ExperimentAnalysisTemplateRef) { +func (ec *experimentContext) reconcileAnalysisRun(analysis v1alpha1.ExperimentAnalysisTemplateRef, dryRunMetrics []v1alpha1.DryRun) { logCtx := ec.log.WithField("analysis", analysis.Name) logCtx.Infof("Reconciling analysis") prevStatus := experimentutil.GetAnalysisRunStatus(ec.ex.Status, analysis.Name) @@ -427,7 +427,7 @@ func (ec *experimentContext) reconcileAnalysisRun(analysis v1alpha1.ExperimentAn logCtx.Warnf("Skipping AnalysisRun creation for analysis %s: experiment is terminating", analysis.Name) return } - run, err := ec.createAnalysisRun(analysis) + run, err := ec.createAnalysisRun(analysis, dryRunMetrics) if err != nil { msg := fmt.Sprintf("Failed to create AnalysisRun for analysis '%s': %v", analysis.Name, err.Error()) newStatus.Phase = v1alpha1.AnalysisPhaseError @@ -474,13 +474,13 @@ func (ec *experimentContext) reconcileAnalysisRun(analysis v1alpha1.ExperimentAn // createAnalysisRun creates the analysis run. If an existing runs exists with same name, is // semantically equal, and is not complete, returns the existing one, otherwise creates a new // run with a collision counter increase. -func (ec *experimentContext) createAnalysisRun(analysis v1alpha1.ExperimentAnalysisTemplateRef) (*v1alpha1.AnalysisRun, error) { +func (ec *experimentContext) createAnalysisRun(analysis v1alpha1.ExperimentAnalysisTemplateRef, dryRunMetrics []v1alpha1.DryRun) (*v1alpha1.AnalysisRun, error) { analysisRunIf := ec.argoProjClientset.ArgoprojV1alpha1().AnalysisRuns(ec.ex.Namespace) args, err := ec.ResolveAnalysisRunArgs(analysis.Args) if err != nil { return nil, err } - run, err := ec.newAnalysisRun(analysis, args) + run, err := ec.newAnalysisRun(analysis, args, dryRunMetrics) if err != nil { return nil, err } @@ -616,7 +616,7 @@ func (ec *experimentContext) assessAnalysisRuns() (v1alpha1.AnalysisPhase, strin } // newAnalysisRun generates an AnalysisRun from the experiment and template -func (ec *experimentContext) newAnalysisRun(analysis v1alpha1.ExperimentAnalysisTemplateRef, args []v1alpha1.Argument) (*v1alpha1.AnalysisRun, error) { +func (ec *experimentContext) newAnalysisRun(analysis v1alpha1.ExperimentAnalysisTemplateRef, args []v1alpha1.Argument, dryRunMetrics []v1alpha1.DryRun) (*v1alpha1.AnalysisRun, error) { if analysis.ClusterScope { clusterTemplate, err := ec.clusterAnalysisTemplateLister.Get(analysis.TemplateName) @@ -625,7 +625,8 @@ func (ec *experimentContext) newAnalysisRun(analysis v1alpha1.ExperimentAnalysis } name := fmt.Sprintf("%s-%s", ec.ex.Name, analysis.Name) - run, err := analysisutil.NewAnalysisRunFromClusterTemplate(clusterTemplate, args, name, "", ec.ex.Namespace) + clusterAnalysisTemplates := []*v1alpha1.ClusterAnalysisTemplate{clusterTemplate} + run, err := analysisutil.NewAnalysisRunFromTemplates(nil, clusterAnalysisTemplates, args, dryRunMetrics, name, "", ec.ex.Namespace) if err != nil { return nil, err } @@ -642,7 +643,8 @@ func (ec *experimentContext) newAnalysisRun(analysis v1alpha1.ExperimentAnalysis } name := fmt.Sprintf("%s-%s", ec.ex.Name, analysis.Name) - run, err := analysisutil.NewAnalysisRunFromTemplate(template, args, name, "", ec.ex.Namespace) + analysisTemplates := []*v1alpha1.AnalysisTemplate{template} + run, err := analysisutil.NewAnalysisRunFromTemplates(analysisTemplates, nil, args, dryRunMetrics, name, "", ec.ex.Namespace) if err != nil { return nil, err } diff --git a/manifests/crds/experiment-crd.yaml b/manifests/crds/experiment-crd.yaml index 2e65d4fe77..90d56c1410 100644 --- a/manifests/crds/experiment-crd.yaml +++ b/manifests/crds/experiment-crd.yaml @@ -84,6 +84,15 @@ spec: - templateName type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array duration: type: string progressDeadlineSeconds: diff --git a/manifests/install.yaml b/manifests/install.yaml index 226370cb5d..ac1f78a792 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -8080,6 +8080,15 @@ spec: - templateName type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array duration: type: string progressDeadlineSeconds: diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 9787a00334..05ff7bc8d7 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -8080,6 +8080,15 @@ spec: - templateName type: object type: array + dryRun: + items: + properties: + metricName: + type: string + required: + - metricName + type: object + type: array duration: type: string progressDeadlineSeconds: diff --git a/pkg/apiclient/rollout/rollout.swagger.json b/pkg/apiclient/rollout/rollout.swagger.json index ce0073d16a..5aa648723a 100644 --- a/pkg/apiclient/rollout/rollout.swagger.json +++ b/pkg/apiclient/rollout/rollout.swagger.json @@ -1038,7 +1038,7 @@ "items": { "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.DryRun" }, - "title": "DryRun object contains the settings for running the analysis in Dry-Run mode\n+patchMergeKey=metricName\n+patchStrategy=merge" + "title": "DryRun object contains the settings for running the analysis in Dry-Run mode\n+patchMergeKey=metricName\n+patchStrategy=merge\n+optional" } }, "title": "RolloutAnalysis defines a template that is used to create a analysisRun" diff --git a/pkg/apis/api-rules/violation_exceptions.list b/pkg/apis/api-rules/violation_exceptions.list index 8865c5cf61..a761bbfaf0 100644 --- a/pkg/apis/api-rules/violation_exceptions.list +++ b/pkg/apis/api-rules/violation_exceptions.list @@ -11,6 +11,7 @@ API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,CloudWatchMetricStatMetric,Dimensions API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,ExperimentAnalysisTemplateRef,Args API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,ExperimentSpec,Analyses +API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,ExperimentSpec,DryRun API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,ExperimentSpec,Templates API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,ExperimentStatus,AnalysisRuns API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,ExperimentStatus,Conditions diff --git a/pkg/apis/rollouts/v1alpha1/analysis_types.go b/pkg/apis/rollouts/v1alpha1/analysis_types.go index 3ecfcbb231..12dd37970d 100644 --- a/pkg/apis/rollouts/v1alpha1/analysis_types.go +++ b/pkg/apis/rollouts/v1alpha1/analysis_types.go @@ -64,6 +64,7 @@ type AnalysisTemplateSpec struct { // DryRun object contains the settings for running the analysis in Dry-Run mode // +patchMergeKey=metricName // +patchStrategy=merge + // +optional DryRun []DryRun `json:"dryRun,omitempty" patchStrategy:"merge" patchMergeKey:"metricName" protobuf:"bytes,3,rep,name=dryRun"` } @@ -289,6 +290,7 @@ type AnalysisRunSpec struct { // DryRun object contains the settings for running the analysis in Dry-Run mode // +patchMergeKey=metricName // +patchStrategy=merge + // +optional DryRun []DryRun `json:"dryRun,omitempty" patchStrategy:"merge" patchMergeKey:"metricName" protobuf:"bytes,4,rep,name=dryRun"` } diff --git a/pkg/apis/rollouts/v1alpha1/experiment_types.go b/pkg/apis/rollouts/v1alpha1/experiment_types.go index 8be63abbb0..c197a23c06 100644 --- a/pkg/apis/rollouts/v1alpha1/experiment_types.go +++ b/pkg/apis/rollouts/v1alpha1/experiment_types.go @@ -55,6 +55,11 @@ type ExperimentSpec struct { // more information // +optional ScaleDownDelaySeconds *int32 `json:"scaleDownDelaySeconds,omitempty" protobuf:"varint,6,opt,name=scaleDownDelaySeconds"` + // DryRun object contains the settings for running the analysis in Dry-Run mode + // +patchMergeKey=metricName + // +patchStrategy=merge + // +optional + DryRun []DryRun `json:"dryRun,omitempty" patchStrategy:"merge" patchMergeKey:"metricName" protobuf:"bytes,7,rep,name=dryRun"` } type TemplateSpec struct { diff --git a/pkg/apis/rollouts/v1alpha1/types.go b/pkg/apis/rollouts/v1alpha1/types.go index 78b6021929..44a2a9c21f 100644 --- a/pkg/apis/rollouts/v1alpha1/types.go +++ b/pkg/apis/rollouts/v1alpha1/types.go @@ -538,6 +538,7 @@ type RolloutAnalysis struct { // DryRun object contains the settings for running the analysis in Dry-Run mode // +patchMergeKey=metricName // +patchStrategy=merge + // +optional DryRun []DryRun `json:"dryRun,omitempty" patchStrategy:"merge" patchMergeKey:"metricName" protobuf:"bytes,3,rep,name=dryRun"` } diff --git a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go index 74919abcc4..0a048cbd5c 100644 --- a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go @@ -1055,6 +1055,11 @@ func (in *ExperimentSpec) DeepCopyInto(out *ExperimentSpec) { *out = new(int32) **out = **in } + if in.DryRun != nil { + in, out := &in.DryRun, &out.DryRun + *out = make([]DryRun, len(*in)) + copy(*out, *in) + } return } diff --git a/test/e2e/analysis_test.go b/test/e2e/analysis_test.go index 13b6d19b60..c5ee4f8e55 100644 --- a/test/e2e/analysis_test.go +++ b/test/e2e/analysis_test.go @@ -1,4 +1,3 @@ -//go:build e2e // +build e2e package e2e diff --git a/test/e2e/experiment_test.go b/test/e2e/experiment_test.go index 2994c35f8a..ac4bf8e29e 100644 --- a/test/e2e/experiment_test.go +++ b/test/e2e/experiment_test.go @@ -16,6 +16,7 @@ import ( type ExperimentSuite struct { fixtures.E2ESuite } + // TestRolloutWithExperimentAndAnalysis this tests the ability for a rollout to launch an experiment, // and use self-referencing features/pass metadata arguments to the experiment and analysis, such as: // * specRef: stable @@ -97,6 +98,16 @@ func (s *ExperimentSuite) TestExperimentWithServiceAndScaleDownDelay() { ExpectExperimentServiceCount("experiment-with-service", 0) } +func (s *ExperimentSuite) TestExperimentWithDryRunMetrics() { + g := s.Given() + g.ApplyManifests("@functional/experiment-dry-run-analysis.yaml") + g.When(). + WaitForExperimentPhase("experiment-with-dry-run", "Successful"). + Sleep(time.Second*3). + Then(). + ExpectExperimentDryRunSummary(1, 0, 1, "experiment-with-dry-run") +} + func TestExperimentSuite(t *testing.T) { suite.Run(t, new(ExperimentSuite)) } diff --git a/test/e2e/functional/experiment-dry-run-analysis.yaml b/test/e2e/functional/experiment-dry-run-analysis.yaml new file mode 100644 index 0000000000..466e38f612 --- /dev/null +++ b/test/e2e/functional/experiment-dry-run-analysis.yaml @@ -0,0 +1,51 @@ +kind: AnalysisTemplate +apiVersion: argoproj.io/v1alpha1 +metadata: + name: dry-run-job +spec: + metrics: + - name: test-1 + provider: + job: + spec: + template: + spec: + containers: + - name: sleep + image: alpine:3.8 + command: [exit, "1"] + restartPolicy: Never + backoffLimit: 0 + +--- +apiVersion: argoproj.io/v1alpha1 +kind: Experiment +metadata: + name: experiment-with-dry-run +spec: + duration: 30s + progressDeadlineSeconds: 30 + templates: + - name: baseline + replicas: 1 + service: {} + selector: + matchLabels: + app: experiment-with-dry-run + template: + metadata: + labels: + app: experiment-with-dry-run + spec: + containers: + - name: experiment-with-dry-run + image: nginx:1.19-alpine + resources: + requests: + memory: 16Mi + cpu: 1m + analyses: + - name: dry-run-job + templateName: dry-run-job + dryRun: + - metricName: test.* diff --git a/test/fixtures/then.go b/test/fixtures/then.go index b99d65347c..fad9177cba 100644 --- a/test/fixtures/then.go +++ b/test/fixtures/then.go @@ -210,6 +210,32 @@ func (t *Then) ExpectExperimentTemplateReplicaSet(expectation string, experiment return t } +func (t *Then) ExpectExperimentDryRunSummary(expectedCount, expectedErrorCount, expectedFailureCount int32, experiment string) *Then { + expectation := v1alpha1.RunSummary{ + Count: expectedCount, + Error: expectedErrorCount, + Failed: expectedFailureCount, + } + t.log.Infof("Expected Dry-Run Summary: Count=%d, Successful=%d, Failed=%d, Error=%d, Inconclusive=%d", expectation.Count, expectation.Successful, expectation.Failed, expectation.Error, expectation.Inconclusive) + ex, err := t.rolloutClient.ArgoprojV1alpha1().Experiments(t.namespace).Get(t.Context, experiment, metav1.GetOptions{}) + t.CheckError(err) + ar := t.GetExperimentAnalysisRun(ex) + dryRunSummary := ar.Status.DryRunSummary + if dryRunSummary != nil { + t.log.Infof("Analysis Dry-Run Summary: Count=%d, Successful=%d, Failed=%d, Error=%d, Inconclusive=%d", dryRunSummary.Count, dryRunSummary.Successful, dryRunSummary.Failed, dryRunSummary.Error, dryRunSummary.Inconclusive) + if expectation == *dryRunSummary { + t.log.Infof("Expectation Matches!") + } else { + t.log.Errorf("Dry-Run Summary of AnalysisRun: '%s' doesn't match the expectations", ar.Name) + t.t.FailNow() + } + } else { + t.log.Errorf("Dry-Run Summary not found in the AnalysisRun: '%s'", ar.Name) + t.t.FailNow() + } + return t +} + func (t *Then) ExpectExperimentTemplateReplicaSetNumReplicas(experiment string, template string, expectedReplicas int) *Then { return t.ExpectExperimentTemplateReplicaSet(fmt.Sprintf("experiment template '%s' num replicas == %d", template, expectedReplicas), experiment, template, func(rs *appsv1.ReplicaSet) bool { return int(rs.Status.Replicas) == expectedReplicas diff --git a/utils/analysis/helpers.go b/utils/analysis/helpers.go index 5d1a79a601..bf9a70e70f 100644 --- a/utils/analysis/helpers.go +++ b/utils/analysis/helpers.go @@ -478,48 +478,6 @@ func NewAnalysisRunFromUnstructured(obj *unstructured.Unstructured, templateArgs return obj, nil } -//TODO(dthomson) remove v0.9.0 -func NewAnalysisRunFromClusterTemplate(template *v1alpha1.ClusterAnalysisTemplate, args []v1alpha1.Argument, name, generateName, namespace string) (*v1alpha1.AnalysisRun, error) { - newArgs, err := MergeArgs(args, template.Spec.Args) - if err != nil { - return nil, err - } - ar := v1alpha1.AnalysisRun{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - GenerateName: generateName, - Namespace: namespace, - }, - Spec: v1alpha1.AnalysisRunSpec{ - Metrics: template.Spec.Metrics, - DryRun: template.Spec.DryRun, - Args: newArgs, - }, - } - return &ar, nil -} - -//TODO(dthomson) remove v0.9.0 -func NewAnalysisRunFromTemplate(template *v1alpha1.AnalysisTemplate, args []v1alpha1.Argument, name, generateName, namespace string) (*v1alpha1.AnalysisRun, error) { - newArgs, err := MergeArgs(args, template.Spec.Args) - if err != nil { - return nil, err - } - ar := v1alpha1.AnalysisRun{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - GenerateName: generateName, - Namespace: namespace, - }, - Spec: v1alpha1.AnalysisRunSpec{ - Metrics: template.Spec.Metrics, - DryRun: template.Spec.DryRun, - Args: newArgs, - }, - } - return &ar, nil -} - // GetInstanceID takes an object and returns the controller instance id if it has one func GetInstanceID(obj runtime.Object) string { objMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) diff --git a/utils/analysis/helpers_test.go b/utils/analysis/helpers_test.go index 1b2ed0df64..5a517afb90 100644 --- a/utils/analysis/helpers_test.go +++ b/utils/analysis/helpers_test.go @@ -728,8 +728,7 @@ func TestNewAnalysisRunFromUnstructured(t *testing.T) { } } -//TODO(dthomson) remove this test in v0.9.0 -func TestNewAnalysisRunFromTemplate(t *testing.T) { +func TestCompatibilityNewAnalysisRunFromTemplate(t *testing.T) { template := v1alpha1.AnalysisTemplate{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", @@ -754,7 +753,8 @@ func TestNewAnalysisRunFromTemplate(t *testing.T) { Value: pointer.StringPtr("my-val"), }, } - run, err := NewAnalysisRunFromTemplate(&template, args, "foo-run", "foo-run-generate-", "my-ns") + analysisTemplates := []*v1alpha1.AnalysisTemplate{&template} + run, err := NewAnalysisRunFromTemplates(analysisTemplates, nil, args, nil, "foo-run", "foo-run-generate-", "my-ns") assert.NoError(t, err) assert.Equal(t, "foo-run", run.Name) assert.Equal(t, "foo-run-generate-", run.GenerateName) @@ -763,9 +763,8 @@ func TestNewAnalysisRunFromTemplate(t *testing.T) { assert.Equal(t, "my-val", *run.Spec.Args[0].Value) } -//TODO(dthomson) remove this test in v0.9.0 -func TestNewAnalysisRunFromClusterTemplate(t *testing.T) { - template := v1alpha1.ClusterAnalysisTemplate{ +func TestCompatibilityNewAnalysisRunFromClusterTemplate(t *testing.T) { + clusterTemplate := v1alpha1.ClusterAnalysisTemplate{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: metav1.NamespaceDefault, @@ -789,7 +788,8 @@ func TestNewAnalysisRunFromClusterTemplate(t *testing.T) { Value: pointer.StringPtr("my-val"), }, } - run, err := NewAnalysisRunFromClusterTemplate(&template, args, "foo-run", "foo-run-generate-", "my-ns") + clusterAnalysisTemplates := []*v1alpha1.ClusterAnalysisTemplate{&clusterTemplate} + run, err := NewAnalysisRunFromTemplates(nil, clusterAnalysisTemplates, args, nil, "foo-run", "foo-run-generate-", "my-ns") assert.NoError(t, err) assert.Equal(t, "foo-run", run.Name) assert.Equal(t, "foo-run-generate-", run.GenerateName) From e243276b10c6094710609871b9f300d0cbbd397b Mon Sep 17 00:00:00 2001 From: cskh Date: Tue, 14 Dec 2021 12:59:12 -0500 Subject: [PATCH 022/175] docs: fix some vague description about analysis arguments (#1672) Signed-off-by: Hui Kang --- docs/features/analysis.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/features/analysis.md b/docs/features/analysis.md index 3800be67ec..c8671fb0cc 100644 --- a/docs/features/analysis.md +++ b/docs/features/analysis.md @@ -356,7 +356,7 @@ templates together. The controller combines the `metrics` and `args` fields of a The controller will error when merging the templates if: * Multiple metrics in the templates have the same name - * Two arguments with the same name both have values + * Two arguments with the same name have different default values no matter the argument value in Rollout ## Analysis Template Arguments @@ -370,11 +370,11 @@ metadata: name: args-example spec: args: - # required + # required in Rollout due to no default value - name: service-name - name: stable-hash - name: latest-hash - # optional + # optional in Rollout given the default value - name: api-url value: http://example/measure # from secret From 918153af73949818dc3c4d97e3ab644bf01797d9 Mon Sep 17 00:00:00 2001 From: "Kostis (Codefresh)" <39800303+kostis-codefresh@users.noreply.github.com> Date: Tue, 14 Dec 2021 19:59:46 +0200 Subject: [PATCH 023/175] docs: Use readthedocs versionining. Closes #1518 (#1671) Signed-off-by: Kostis Kapelonis --- docs/assets/versions.css | 175 +++++++++++++++++++++++++++++++++++++++ docs/assets/versions.js | 35 ++++++++ mkdocs.yml | 4 + 3 files changed, 214 insertions(+) create mode 100644 docs/assets/versions.css create mode 100644 docs/assets/versions.js diff --git a/docs/assets/versions.css b/docs/assets/versions.css new file mode 100644 index 0000000000..b8bb066929 --- /dev/null +++ b/docs/assets/versions.css @@ -0,0 +1,175 @@ +.md-header__title { + display: flex; +} + +.dropdown-caret { + display: inline-block !important; + position: absolute; + right: 4px; +} + +.fa .fa-caret-down { + display: none !important; +} + +.rst-other-versions { + text-align: right; +} + +.rst-other-versions > dl, .rst-other-versions dt, .rst-other-versions small { + display: none; +} + +.rst-other-versions > dl:first-child { + display: flex !important; + flex-direction: column; + line-height: 0px !important; +} + +.rst-versions.shift-up .rst-other-versions { + display: flex !important; +} + +.rst-versions .rst-other-versions { + display: none; +} + +/* Version Warning */ +div[data-md-component=announce] { + background-color: rgb(248, 243, 236); + position: sticky; + top: 0; + z-index: 2; +} +div[data-md-component=announce]>div#announce-msg{ + color: var(--md-code-hl-number-color); + font-size: .8rem; + text-align: center; + margin: 15px; +} +div[data-md-component=announce]>div#announce-msg>a{ + color: var(--md-typeset-a-color); + text-decoration: underline; +} + +/* from https://assets.readthedocs.org/static/css/badge_only.css, +most styles have to be overriden here */ +.rst-versions{ + position: relative !important; + bottom: 0; + left: 0; + width: 100px !important; + background: hsla(173, 100%, 24%, 1) !important; + font-family: inherit !important; + z-index: 0 !important; +} +.rst-versions a{ + color:#2980B9; + text-decoration:none +} +.rst-versions .rst-badge-small{ + display:none +} +.rst-versions .rst-current-version{ + padding:12px; + background: hsla(173, 100%, 24%, 1) !important; + display:block; + text-align:right; + font-size:90%; + cursor:pointer; + color: white !important; + *zoom:1 +} +.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{ + display:table;content:"" +} +.rst-versions .rst-current-version:after{ + clear:both +} +.rst-versions .rst-current-version .fa{ + color:#fcfcfc +} +.rst-versions .rst-current-version .fa-caret-down{ + display: none; +} +.rst-versions.shift-up .rst-other-versions{ + display:block +} +.rst-versions .rst-other-versions{ + font-size:90%; + padding:12px; + color:gray; + display:none +} +.rst-versions .rst-other-versions hr{ + display: none !important; + height: 0px !important; + border: 0px; + margin: 0px !important; + padding: 0px; + border-top: none !important; +} +.rst-versions .rst-other-versions dd{ + display:inline-block; + margin:0 +} +.rst-versions .rst-other-versions dd a{ + display:inline-block; + padding: 1em 0em !important; + color:#fcfcfc; + font-size: .6rem !important; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + width: 80px; +} +.rst-versions .rst-other-versions dd a:hover{ + font-size: .7rem !important; + font-weight: bold; +} +.rst-versions.rst-badge{ + display: block !important; + width: 100px !important; + bottom: 0px !important; + right: 0px !important; + left:auto; + border:none; + text-align: center !important; + line-height: 0; +} +.rst-versions.rst-badge .icon-book{ + display: none; +} +.rst-versions.rst-badge .fa-book{ + display: none !important; +} +.rst-versions.rst-badge.shift-up .rst-current-version{ + text-align: left !important; +} +.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{ + display: none !important; +} +.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{ + display: none !important; +} +.rst-versions.rst-badge .rst-current-version{ + width: 70px !important; + height: 2.4rem !important; + line-height:2.4rem !important; + padding: 0px 5px !important; + display: inline-block !important; + font-size: .6rem !important; + overflow: hidden !important; + text-overflow: ellipsis !important; + white-space: nowrap !important; + text-align: left !important; +} +@media screen and (max-width: 768px){ + .rst-versions{ + width:85%; + display:none + } + .rst-versions.shift{ + display:block + } +} \ No newline at end of file diff --git a/docs/assets/versions.js b/docs/assets/versions.js new file mode 100644 index 0000000000..057ce03158 --- /dev/null +++ b/docs/assets/versions.js @@ -0,0 +1,35 @@ +setTimeout(function() { + const callbackName = 'callback_' + new Date().getTime(); + window[callbackName] = function (response) { + const div = document.createElement('div'); + div.innerHTML = response.html; + document.querySelector(".md-header__inner > .md-header__title").appendChild(div); + const container = div.querySelector('.rst-versions'); + var caret = document.createElement('div'); + caret.innerHTML = "" + caret.classList.add('dropdown-caret') + div.querySelector('.rst-current-version').appendChild(caret); + div.querySelector('.rst-current-version').addEventListener('click', function() { + const classes = container.className.split(' '); + const index = classes.indexOf('shift-up'); + if (index === -1) { + classes.push('shift-up'); + } else { + classes.splice(index, 1); + } + container.className = classes.join(' '); + }); + } + + var CSSLink = document.createElement('link'); + CSSLink.rel='stylesheet'; + CSSLink.href = '/assets/versions.css'; + document.getElementsByTagName('head')[0].appendChild(CSSLink); + + var script = document.createElement('script'); + script.src = 'https://argo-rollouts.readthedocs.io/_/api/v2/footer_html/?'+ + 'callback=' + callbackName + '&project=argo-rollouts&page=&theme=mkdocs&format=jsonp&docroot=docs&source_suffix=.md&version=' + (window['READTHEDOCS_DATA'] || { version: 'latest' }).version; + document.getElementsByTagName('head')[0].appendChild(script); +}, 0); + + diff --git a/mkdocs.yml b/mkdocs.yml index a03f96edf6..87a66197e5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,3 +1,7 @@ +extra_css: +- assets/versions.css +extra_javascript: +- assets/versions.js markdown_extensions: - codehilite - admonition From 294d7a1156cb750a0f44eba567dbd1f77f00acb9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Dec 2021 10:05:40 -0800 Subject: [PATCH 024/175] chore(deps): bump github.com/evanphx/json-patch/v5 from 5.2.0 to 5.6.0 (#1603) Bumps [github.com/evanphx/json-patch/v5](https://github.com/evanphx/json-patch) from 5.2.0 to 5.6.0. - [Release notes](https://github.com/evanphx/json-patch/releases) - [Commits](https://github.com/evanphx/json-patch/compare/v5.2.0...v5.6.0) --- updated-dependencies: - dependency-name: github.com/evanphx/json-patch/v5 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 06cf4f2b64..eb61d90c24 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.5.0 github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.6.1 github.com/blang/semver v3.5.1+incompatible - github.com/evanphx/json-patch/v5 v5.2.0 + github.com/evanphx/json-patch/v5 v5.6.0 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 github.com/go-openapi/spec v0.19.5 github.com/gogo/protobuf v1.3.2 diff --git a/go.sum b/go.sum index 21e8ab6ad8..dd89c3897f 100644 --- a/go.sum +++ b/go.sum @@ -328,8 +328,8 @@ github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdR github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.2.0 h1:8ozOH5xxoMYDt5/u+yMTsVXydVCbTORFnOOoq2lumco= -github.com/evanphx/json-patch/v5 v5.2.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= From 061efd4a527dafe74d42387ad2874ca24448b5c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Dec 2021 10:06:06 -0800 Subject: [PATCH 025/175] chore(deps): bump codecov/codecov-action from 2.0.3 to 2.1.0 (#1508) Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 2.0.3 to 2.1.0. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/master/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v2.0.3...v2.1.0) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/go.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 6ba4e33578..976dee047d 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -55,7 +55,7 @@ jobs: path: coverage.out - name: Upload code coverage information to codecov.io - uses: codecov/codecov-action@v2.0.3 + uses: codecov/codecov-action@v2.1.0 with: file: coverage.out From 5b140c97c569647a4f1e604a44262c9d5281656c Mon Sep 17 00:00:00 2001 From: RaviHari Date: Thu, 16 Dec 2021 00:12:03 +0530 Subject: [PATCH 026/175] fix: Enable default triggers for argo rollouts (#1689) fix: Enable default triggers for argo rollouts (#1689) Signed-off-by: Ravi Hari --- experiments/experiment_test.go | 4 +- go.mod | 2 +- go.sum | 6 ++- mkdocs.yml | 3 ++ utils/record/record.go | 68 ++++++++++++++++++++++++++++------ 5 files changed, 66 insertions(+), 17 deletions(-) diff --git a/experiments/experiment_test.go b/experiments/experiment_test.go index f26ee1038b..48358a1f7b 100644 --- a/experiments/experiment_test.go +++ b/experiments/experiment_test.go @@ -318,7 +318,7 @@ func TestRequeueAfterDuration(t *testing.T) { // ensures we are enqueued around ~20 seconds twentySeconds := time.Second * time.Duration(20) delta := math.Abs(float64(twentySeconds - duration)) - assert.True(t, delta < float64(100*time.Millisecond), "") + assert.True(t, delta < float64(150*time.Millisecond), "") } exCtx.reconcile() assert.True(t, enqueueCalled) @@ -345,7 +345,7 @@ func TestRequeueAfterProgressDeadlineSeconds(t *testing.T) { // ensures we are enqueued around 10 minutes tenMinutes := time.Second * time.Duration(600) delta := math.Abs(float64(tenMinutes - duration)) - assert.True(t, delta < float64(100*time.Millisecond)) + assert.True(t, delta < float64(150*time.Millisecond)) } exCtx.reconcile() assert.True(t, enqueueCalled) diff --git a/go.mod b/go.mod index eb61d90c24..8e580b61b9 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.16 require ( github.com/antonmedv/expr v1.8.9 - github.com/argoproj/notifications-engine v0.2.1-0.20210525191332-e8e293898477 + github.com/argoproj/notifications-engine v0.3.0 github.com/argoproj/pkg v0.9.0 github.com/aws/aws-sdk-go-v2/config v1.8.1 github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.5.0 diff --git a/go.sum b/go.sum index dd89c3897f..80a4c87956 100644 --- a/go.sum +++ b/go.sum @@ -154,8 +154,8 @@ github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDw github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= github.com/appscode/go v0.0.0-20190808133642-1d4ef1f1c1e0/go.mod h1:iy07dV61Z7QQdCKJCIvUoDL21u6AIceRhZzyleh2ymc= -github.com/argoproj/notifications-engine v0.2.1-0.20210525191332-e8e293898477 h1:mcfUn59PKafSlbkZ39+aQAIzoAsYzjVR61O6Ns/Dfzo= -github.com/argoproj/notifications-engine v0.2.1-0.20210525191332-e8e293898477/go.mod h1:rKhm9LtebGKgLA/UtPtBeRUrrS/CT0U5az1jSfUiipw= +github.com/argoproj/notifications-engine v0.3.0 h1:1KMVYwXlg7SGzX00eg/bU0YupXDVdfpm8FlpNbrkUxM= +github.com/argoproj/notifications-engine v0.3.0/go.mod h1:0TEB4QbOsNN8URcsUJpAFuuG6aw8KS8ZY/YCzsss9JQ= github.com/argoproj/pkg v0.9.0 h1:PfWWYykfcEQdN0g41XLbVh/aonTjD+dPkvDp3hwpLYM= github.com/argoproj/pkg v0.9.0/go.mod h1:ra+bQPmbVAoEL+gYSKesuigt4m49i3Qa3mE/xQcjCiA= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -605,6 +605,8 @@ github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.m github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= github.com/gostaticanalysis/analysisutil v0.1.0/go.mod h1:dMhHRU9KTiDcuLGdy87/2gTR8WruwYZrKdRq9m1O6uw= github.com/gostaticanalysis/comment v1.3.0/go.mod h1:xMicKDx7XRXYdVwY9f9wQpDJVnqWxw9wCauCMKp+IBI= +github.com/gregdel/pushover v1.1.0 h1:dwHyvrcpZCOS9V1fAnKPaGRRI5OC55cVaKhMybqNsKQ= +github.com/gregdel/pushover v1.1.0/go.mod h1:EcaO66Nn1StkpEm1iKtBTV3d2A16SoMsVER1PthX7to= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= diff --git a/mkdocs.yml b/mkdocs.yml index 87a66197e5..c94e257094 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -57,12 +57,15 @@ nav: - Notifications: - Overview: features/notifications.md - Services: + - generated/notification-services/alertmanager.md - generated/notification-services/email.md - generated/notification-services/github.md + - generated/notification-services/googlechat.md - generated/notification-services/grafana.md - generated/notification-services/mattermost.md - generated/notification-services/opsgenie.md - generated/notification-services/overview.md + - generated/notification-services/pushover.md - generated/notification-services/rocketchat.md - generated/notification-services/slack.md - generated/notification-services/teams.md diff --git a/utils/record/record.go b/utils/record/record.go index 23c19a0f5d..0b6d063a54 100644 --- a/utils/record/record.go +++ b/utils/record/record.go @@ -1,11 +1,18 @@ package record import ( + "context" "encoding/json" + + "github.com/argoproj/notifications-engine/pkg/services" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/client-go/tools/cache" + "regexp" "strings" + "time" - "github.com/argoproj/notifications-engine/pkg/services" + k8sinformers "k8s.io/client-go/informers" "github.com/argoproj/notifications-engine/pkg/api" "github.com/argoproj/notifications-engine/pkg/subscriptions" @@ -89,6 +96,39 @@ type FakeEventRecorder struct { Events []string } +func NewFakeApiFactory() api.Factory { + var ( + settings = api.Settings{ConfigMapName: "my-config-map", SecretName: "my-secret", InitGetVars: func(cfg *api.Config, configMap *corev1.ConfigMap, secret *corev1.Secret) (api.GetVars, error) { + return func(obj map[string]interface{}, dest services.Destination) map[string]interface{} { + return map[string]interface{}{"obj": obj} + }, nil + }} + ) + + cm := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{Name: "my-config-map", Namespace: "default"}, + Data: map[string]string{ + "service.slack": `{"token": "abc"}`, + }, + } + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "my-secret", Namespace: "default"}, + } + + clientset := k8sfake.NewSimpleClientset(cm, secret) + informerFactory := k8sinformers.NewSharedInformerFactory(clientset, time.Minute) + + secrets := informerFactory.Core().V1().Secrets().Informer() + configMaps := informerFactory.Core().V1().ConfigMaps().Informer() + apiFactory := api.NewFactory(settings, "default", secrets, configMaps) + go informerFactory.Start(context.Background().Done()) + if !cache.WaitForCacheSync(context.Background().Done(), configMaps.HasSynced, secrets.HasSynced) { + log.Info("failed to sync informers") + } + + return apiFactory +} + func NewFakeEventRecorder() *FakeEventRecorder { recorder := NewEventRecorder( k8sfake.NewSimpleClientset(), @@ -98,7 +138,7 @@ func NewFakeEventRecorder() *FakeEventRecorder { }, []string{"name", "namespace", "type", "reason"}, ), - nil, + NewFakeApiFactory(), ).(*EventRecorderAdapter) recorder.Recorder = record.NewFakeRecorder(1000) fakeRecorder := &FakeEventRecorder{} @@ -168,24 +208,28 @@ func NewAPIFactorySettings() api.Settings { // Send notifications for triggered event if user is subscribed func (e *EventRecorderAdapter) sendNotifications(object runtime.Object, opts EventOptions) error { logCtx := logutil.WithObject(object) - subsFromAnnotations := subscriptions.Annotations(object.(metav1.Object).GetAnnotations()) - destByTrigger := subsFromAnnotations.GetDestinations(nil, map[string][]string{}) - + notificationsAPI, err := e.apiFactory.GetAPI() + if err != nil { + // don't return error if notifications are not configured and rollout has no subscribers + subsFromAnnotations := subscriptions.Annotations(object.(metav1.Object).GetAnnotations()) + logCtx.Infof("subsFromAnnotations: %s", subsFromAnnotations) + if errors.IsNotFound(err) && len(subsFromAnnotations.GetDestinations(nil, map[string][]string{})) == 0 { + return nil + } + return err + } + cfg := notificationsAPI.GetConfig() + destByTrigger := cfg.GetGlobalDestinations(object.(metav1.Object).GetLabels()) + destByTrigger.Merge(subscriptions.NewAnnotations(object.(metav1.Object).GetAnnotations()).GetDestinations(cfg.DefaultTriggers, cfg.ServiceDefaultTriggers)) trigger := translateReasonToTrigger(opts.EventReason) - destinations := destByTrigger[trigger] if len(destinations) == 0 { logCtx.Debugf("No configured destinations for trigger: %s", trigger) return nil } - notificationsAPI, err := e.apiFactory.GetAPI() - if err != nil { - return err - } - // Creates config for notifications for built-in triggers - triggerActions, ok := notificationsAPI.GetConfig().Triggers[trigger] + triggerActions, ok := cfg.Triggers[trigger] if !ok { logCtx.Debugf("No configured template for trigger: %s", trigger) return nil From a3477cfbb85b40b0d5722a1f661d4dd261550fa4 Mon Sep 17 00:00:00 2001 From: cskh Date: Tue, 21 Dec 2021 14:13:05 -0500 Subject: [PATCH 027/175] fix: leaderelection uses the lock in the same ns as the controller (#1717) Signed-off-by: Hui Kang --- .github/workflows/e2e.yaml | 1 + cmd/rollouts-controller/main.go | 1 - controller/controller.go | 5 +---- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index d59956ceb7..1854019cc7 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -29,6 +29,7 @@ jobs: sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config sudo chmod 755 ~/.kube/config kubectl version + kubectl create ns argo-rollouts - uses: actions/cache@v2 with: path: ~/go/pkg/mod diff --git a/cmd/rollouts-controller/main.go b/cmd/rollouts-controller/main.go index 6a3942e1c6..a55e1f5f2c 100644 --- a/cmd/rollouts-controller/main.go +++ b/cmd/rollouts-controller/main.go @@ -235,7 +235,6 @@ func newCommand() *cobra.Command { command.Flags().BoolVar(&awsVerifyTargetGroup, "aws-verify-target-group", false, "Verify ALB target group before progressing through steps (requires AWS privileges)") command.Flags().BoolVar(&printVersion, "version", false, "Print version") command.Flags().BoolVar(&electOpts.LeaderElect, "leader-elect", controller.DefaultLeaderElect, "If true, controller will perform leader election between instances to ensure no more than one instance of controller operates at a time") - command.Flags().StringVar(&electOpts.LeaderElectionNamespace, "leader-election-namespace", controller.DefaultLeaderElectionNamespace, "Namespace used to perform leader election. Only used if leader election is enabled") command.Flags().DurationVar(&electOpts.LeaderElectionLeaseDuration, "leader-election-lease-duration", controller.DefaultLeaderElectionLeaseDuration, "The duration that non-leader candidates will wait after observing a leadership renewal until attempting to acquire leadership of a led but unrenewed leader slot. This is effectively the maximum duration that a leader can be stopped before it is replaced by another candidate. This is only applicable if leader election is enabled.") command.Flags().DurationVar(&electOpts.LeaderElectionRenewDeadline, "leader-election-renew-deadline", controller.DefaultLeaderElectionRenewDeadline, "The interval between attempts by the acting master to renew a leadership slot before it stops leading. This must be less than or equal to the lease duration. This is only applicable if leader election is enabled.") command.Flags().DurationVar(&electOpts.LeaderElectionRetryPeriod, "leader-election-retry-period", controller.DefaultLeaderElectionRetryPeriod, "The duration the clients should wait between attempting acquisition and renewal of a leadership. This is only applicable if leader election is enabled.") diff --git a/controller/controller.go b/controller/controller.go index fb4b2b068f..171f62d5fc 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -76,9 +76,6 @@ const ( // DefaultLeaderElect is the default true leader election should be enabled DefaultLeaderElect = true - // DefaultLeaderElectionNamespace is the default namespace used to perform leader election. Only used if leader election is enabled - DefaultLeaderElectionNamespace = "kube-system" - // DefaultLeaderElectionLeaseDuration is the default time in seconds that non-leader candidates will wait to force acquire leadership DefaultLeaderElectionLeaseDuration = 15 * time.Second @@ -103,7 +100,7 @@ type LeaderElectionOptions struct { func NewLeaderElectionOptions() *LeaderElectionOptions { return &LeaderElectionOptions{ LeaderElect: DefaultLeaderElect, - LeaderElectionNamespace: DefaultLeaderElectionNamespace, + LeaderElectionNamespace: defaults.Namespace(), LeaderElectionLeaseDuration: DefaultLeaderElectionLeaseDuration, LeaderElectionRenewDeadline: DefaultLeaderElectionRenewDeadline, LeaderElectionRetryPeriod: DefaultLeaderElectionRetryPeriod, From 97444e8f65ff266fc8db1848a7546beab55b3631 Mon Sep 17 00:00:00 2001 From: Shlomo Sanders Date: Wed, 29 Dec 2021 17:25:19 +0200 Subject: [PATCH 028/175] update rollout-crd.yaml --- manifests/crds/rollout-crd.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/manifests/crds/rollout-crd.yaml b/manifests/crds/rollout-crd.yaml index 7881a6b8d5..ebbc6677de 100644 --- a/manifests/crds/rollout-crd.yaml +++ b/manifests/crds/rollout-crd.yaml @@ -321,6 +321,9 @@ spec: - type: integer - type: string x-kubernetes-int-or-string: true + minPodsPerRS: + format: int32 + type: integer scaleDownDelayRevisionLimit: format: int32 type: integer From 442482856653364f49b4fa170c953f8c461cc3db Mon Sep 17 00:00:00 2001 From: Shlomo Sanders Date: Sun, 2 Jan 2022 17:44:05 +0200 Subject: [PATCH 029/175] fix test --- utils/replicaset/canary_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/utils/replicaset/canary_test.go b/utils/replicaset/canary_test.go index c1e4ed0c44..ecf305e122 100644 --- a/utils/replicaset/canary_test.go +++ b/utils/replicaset/canary_test.go @@ -654,6 +654,9 @@ func TestCalculateReplicaCountsForCanary(t *testing.T) { stableRS := newRS("stable", test.stableSpecReplica, test.stableAvailableReplica) canaryRS := newRS("canary", test.canarySpecReplica, test.canaryAvailableReplica) rollout.Spec.Strategy.Canary.AbortScaleDownDelaySeconds = test.abortScaleDownDelaySeconds + if test.minPodsPerRS != nil { + rollout.Spec.Strategy.Canary.MinPodsPerRS = test.minPodsPerRS + } var newRSReplicaCount, stableRSReplicaCount int32 if test.trafficRouting != nil { newRSReplicaCount, stableRSReplicaCount = CalculateReplicaCountsForTrafficRoutedCanary(rollout, nil) From c291d2de762790a43df66257d87046131b4fc7a4 Mon Sep 17 00:00:00 2001 From: Ben Poland <24273909+bpoland@users.noreply.github.com> Date: Mon, 3 Jan 2022 19:12:22 -0500 Subject: [PATCH 030/175] fix: dashboard promote buttons disabled during deploy (#1669) - keep promote and abort buttons enabled while deploying - disable them at all other times - also, only enable retry button when Rollout is degraded Fixes https://github.com/argoproj/argo-rollouts/issues/1581 Signed-off-by: Ben Poland --- .../app/components/rollout-actions/rollout-actions.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ui/src/app/components/rollout-actions/rollout-actions.tsx b/ui/src/app/components/rollout-actions/rollout-actions.tsx index fb7c8321e0..283af8c4ca 100644 --- a/ui/src/app/components/rollout-actions/rollout-actions.tsx +++ b/ui/src/app/components/rollout-actions/rollout-actions.tsx @@ -18,6 +18,7 @@ export const RolloutActionButton = (props: {action: RolloutAction; rollout: Roll const namespaceCtx = React.useContext(NamespaceContext); const restartedAt = formatTimestamp(props.rollout.restartedAt || ''); + const isDeploying = props.rollout.status === RolloutStatus.Progressing || props.rollout.status === RolloutStatus.Paused const actionMap = new Map([ [ @@ -36,6 +37,7 @@ export const RolloutActionButton = (props: {action: RolloutAction; rollout: Roll label: 'RETRY', icon: 'fa-redo-alt', action: api.rolloutServiceRetryRollout, + disabled: props.rollout.status !== RolloutStatus.Degraded, shouldConfirm: true, }, ], @@ -45,6 +47,7 @@ export const RolloutActionButton = (props: {action: RolloutAction; rollout: Roll label: 'ABORT', icon: 'fa-exclamation-circle', action: api.rolloutServiceAbortRollout, + disabled: !isDeploying, shouldConfirm: true, }, ], @@ -55,7 +58,7 @@ export const RolloutActionButton = (props: {action: RolloutAction; rollout: Roll icon: 'fa-chevron-circle-up', action: api.rolloutServicePromoteRollout, body: {full: false}, - disabled: props.rollout.status !== RolloutStatus.Paused, + disabled: !isDeploying, shouldConfirm: true, }, ], @@ -64,9 +67,9 @@ export const RolloutActionButton = (props: {action: RolloutAction; rollout: Roll { label: 'PROMOTE-FULL', icon: 'fa-arrow-circle-up', - body: {full: true}, action: api.rolloutServicePromoteRollout, - disabled: props.rollout.status !== RolloutStatus.Paused, + body: {full: true}, + disabled: !isDeploying, shouldConfirm: true, }, ], From 04494ef6d2fb6d56f09c56273a7bf6c11d6c23e8 Mon Sep 17 00:00:00 2001 From: cskh Date: Tue, 4 Jan 2022 12:03:14 -0500 Subject: [PATCH 031/175] fix: e2e istio crd; deprecated apiextensions/v1beta1 (#1740) Signed-off-by: Hui Kang --- .../rollout-alb-experiment-no-setweight.yaml | 9 +- test/e2e/alb/rollout-alb-experiment.yaml | 9 +- test/e2e/crds/istio.yaml | 8327 +++++++++++------ test/e2e/crds/split.yaml | 258 +- .../e2e/functional/alb-bluegreen-rollout.yaml | 9 +- test/e2e/functional/alb-canary-rollout.yaml | 9 +- .../canary-dynamic-stable-scale.yaml | 9 +- .../e2e/functional/canary-scaledowndelay.yaml | 9 +- .../functional/canary-scaledownonabort.yaml | 9 +- .../functional/canary-unscaledownonabort.yaml | 9 +- test/e2e/functional/nginx-template.yaml | 9 +- test/e2e/smi/rollout-smi-experiment.yaml | 9 +- .../rollout-smi-ingress-canary.yaml | 9 +- test/fixtures/common.go | 14 +- test/kustomize/rollout/expected.yaml | 8 +- test/kustomize/rollout/rollout.yaml | 8 +- 16 files changed, 5742 insertions(+), 2972 deletions(-) diff --git a/test/e2e/alb/rollout-alb-experiment-no-setweight.yaml b/test/e2e/alb/rollout-alb-experiment-no-setweight.yaml index cb80c86468..544da2799d 100644 --- a/test/e2e/alb/rollout-alb-experiment-no-setweight.yaml +++ b/test/e2e/alb/rollout-alb-experiment-no-setweight.yaml @@ -40,7 +40,7 @@ spec: selector: app: alb-rollout --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: alb-rollout-ingress @@ -51,9 +51,12 @@ spec: - http: paths: - path: /* + pathType: ImplementationSpecific backend: - serviceName: alb-rollout-root - servicePort: use-annotation + service: + name: alb-rollout-root + port: + name: use-annotation --- apiVersion: argoproj.io/v1alpha1 kind: Rollout diff --git a/test/e2e/alb/rollout-alb-experiment.yaml b/test/e2e/alb/rollout-alb-experiment.yaml index e7b975701c..c718e11069 100644 --- a/test/e2e/alb/rollout-alb-experiment.yaml +++ b/test/e2e/alb/rollout-alb-experiment.yaml @@ -40,7 +40,7 @@ spec: selector: app: alb-rollout --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: alb-rollout-ingress @@ -51,9 +51,12 @@ spec: - http: paths: - path: /* + pathType: ImplementationSpecific backend: - serviceName: alb-rollout-root - servicePort: use-annotation + service: + name: alb-rollout-root + port: + name: use-annotation --- apiVersion: argoproj.io/v1alpha1 kind: Rollout diff --git a/test/e2e/crds/istio.yaml b/test/e2e/crds/istio.yaml index 7491f5b3d5..c2999ea163 100644 --- a/test/e2e/crds/istio.yaml +++ b/test/e2e/crds/istio.yaml @@ -1,5 +1,102 @@ # DO NOT EDIT - Generated by Cue OpenAPI generator based on Istio APIs. -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: wasmplugins.extensions.istio.io +spec: + group: extensions.istio.io + names: + categories: + - istio-io + - extensions-istio-io + kind: WasmPlugin + listKind: WasmPluginList + plural: wasmplugins + singular: wasmplugin + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Extend the functionality provided by the Istio proxy through + WebAssembly filters. See more details at: https://istio.io/docs/reference/config/proxy_extensions/wasm-plugin.html' + properties: + imagePullPolicy: + description: The pull behaviour to be applied when fetching an OCI + image. + enum: + - UNSPECIFIED_POLICY + - IfNotPresent + - Always + type: string + imagePullSecret: + description: Credentials to use for OCI image pulling. + type: string + phase: + description: Determines where in the filter chain this `WasmPlugin` + is to be injected. + enum: + - UNSPECIFIED_PHASE + - AUTHN + - AUTHZ + - STATS + type: string + pluginConfig: + description: The configuration that will be passed on to the plugin. + type: object + x-kubernetes-preserve-unknown-fields: true + pluginName: + type: string + priority: + description: Determines ordering of `WasmPlugins` in the same `phase`. + nullable: true + type: integer + selector: + properties: + matchLabels: + additionalProperties: + type: string + type: object + type: object + sha256: + description: SHA256 checksum that will be used to verify Wasm module + or OCI container. + type: string + url: + description: URL of a Wasm module or OCI container. + type: string + verificationKey: + type: string + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} + +--- +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: @@ -11,19 +108,6 @@ metadata: release: istio name: destinationrules.networking.istio.io spec: - additionalPrinterColumns: - - JSONPath: .spec.host - description: The name of a service from the service registry - name: Host - type: string - - JSONPath: .metadata.creationTimestamp - description: 'CreationTimestamp is a timestamp representing the server time when - this object was created. It is not guaranteed to be set in happens-before order - across separate operations. Clients may not set this value. It is represented - in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for - lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' - name: Age - type: date group: networking.istio.io names: categories: @@ -35,376 +119,122 @@ spec: shortNames: - dr singular: destinationrule - preserveUnknownFields: false scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: 'Configuration affecting load balancing, outlier detection, - etc. See more details at: https://istio.io/docs/reference/config/networking/destination-rule.html' - properties: - exportTo: - description: A list of namespaces to which this destination rule is - exported. - items: - format: string + versions: + - additionalPrinterColumns: + - description: The name of a service from the service registry + jsonPath: .spec.host + name: Host + type: string + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha3 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting load balancing, outlier detection, + etc. See more details at: https://istio.io/docs/reference/config/networking/destination-rule.html' + properties: + exportTo: + description: A list of namespaces to which this destination rule is + exported. + items: + type: string + type: array + host: + description: The name of a service from the service registry. type: string - type: array - host: - description: The name of a service from the service registry. - format: string - type: string - subsets: - items: - properties: - labels: - additionalProperties: - format: string + subsets: + items: + properties: + labels: + additionalProperties: + type: string + type: object + name: + description: Name of the subset. type: string - type: object - name: - description: Name of the subset. - format: string - type: string - trafficPolicy: - description: Traffic policies that apply to this subset. - properties: - connectionPool: - properties: - http: - description: HTTP connection pool settings. - properties: - h2UpgradePolicy: - description: Specify if http1.1 connection should - be upgraded to http2 for the associated destination. - enum: - - DEFAULT - - DO_NOT_UPGRADE - - UPGRADE - type: string - http1MaxPendingRequests: - description: Maximum number of pending HTTP requests - to a destination. - format: int32 - type: integer - http2MaxRequests: - description: Maximum number of requests to a backend. - format: int32 - type: integer - idleTimeout: - description: The idle timeout for upstream connection - pool connections. - type: string - maxRequestsPerConnection: - description: Maximum number of requests per connection - to a backend. - format: int32 - type: integer - maxRetries: - format: int32 - type: integer - useClientProtocol: - description: If set to true, client protocol will - be preserved while initiating connection to backend. - type: boolean - type: object - tcp: - description: Settings common to both HTTP and TCP upstream - connections. - properties: - connectTimeout: - description: TCP connection timeout. - type: string - maxConnections: - description: Maximum number of HTTP1 /TCP connections - to a destination host. - format: int32 - type: integer - tcpKeepalive: - description: If set then set SO_KEEPALIVE on the socket - to enable TCP Keepalives. - properties: - interval: - description: The time duration between keep-alive - probes. - type: string - probes: - type: integer - time: - type: string - type: object - type: object - type: object - loadBalancer: - description: Settings controlling the load balancer algorithms. - oneOf: - - not: - anyOf: - - required: - - simple - - properties: - consistentHash: - oneOf: - - not: - anyOf: - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - required: - - consistentHash - - required: - - simple - - properties: - consistentHash: - oneOf: - - not: - anyOf: - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - required: - - consistentHash - properties: - consistentHash: - properties: - httpCookie: - description: Hash based on HTTP cookie. - properties: - name: - description: Name of the cookie. - format: string - type: string - path: - description: Path to set for the cookie. - format: string - type: string - ttl: - description: Lifetime of the cookie. - type: string - type: object - httpHeaderName: - description: Hash based on a specific HTTP header. - format: string - type: string - httpQueryParameterName: - description: Hash based on a specific HTTP query parameter. - format: string - type: string - minimumRingSize: - type: integer - useSourceIp: - description: Hash based on the source IP address. - type: boolean - type: object - localityLbSetting: - properties: - distribute: - description: 'Optional: only one of distribute or - failover can be set.' - items: - properties: - from: - description: Originating locality, '/' separated, - e.g. - format: string - type: string - to: - additionalProperties: - type: integer - description: Map of upstream localities to traffic - distribution weights. - type: object - type: object - type: array - enabled: - description: enable locality load balancing, this - is DestinationRule-level and will override mesh - wide settings in entirety. - nullable: true - type: boolean - failover: - description: 'Optional: only failover or distribute - can be set.' - items: - properties: - from: - description: Originating region. - format: string - type: string - to: - format: string - type: string - type: object - type: array - type: object - simple: - enum: - - ROUND_ROBIN - - LEAST_CONN - - RANDOM - - PASSTHROUGH - type: string - type: object - outlierDetection: - properties: - baseEjectionTime: - description: Minimum ejection duration. - type: string - consecutive5xxErrors: - description: Number of 5xx errors before a host is ejected - from the connection pool. - nullable: true - type: integer - consecutiveErrors: - format: int32 - type: integer - consecutiveGatewayErrors: - description: Number of gateway errors before a host is - ejected from the connection pool. - nullable: true - type: integer - interval: - description: Time interval between ejection sweep analysis. - type: string - maxEjectionPercent: - format: int32 - type: integer - minHealthPercent: - format: int32 - type: integer - type: object - portLevelSettings: - description: Traffic policies specific to individual ports. - items: + trafficPolicy: + description: Traffic policies that apply to this subset. + properties: + connectionPool: properties: - connectionPool: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should + be upgraded to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP requests + to a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection + pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per connection + to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + useClientProtocol: + description: If set to true, client protocol will + be preserved while initiating connection to backend. + type: boolean + type: object + tcp: + description: Settings common to both HTTP and TCP upstream + connections. properties: - http: - description: HTTP connection pool settings. + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections + to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on the + socket to enable TCP Keepalives. properties: - h2UpgradePolicy: - description: Specify if http1.1 connection should - be upgraded to http2 for the associated destination. - enum: - - DEFAULT - - DO_NOT_UPGRADE - - UPGRADE - type: string - http1MaxPendingRequests: - description: Maximum number of pending HTTP - requests to a destination. - format: int32 - type: integer - http2MaxRequests: - description: Maximum number of requests to a - backend. - format: int32 - type: integer - idleTimeout: - description: The idle timeout for upstream connection - pool connections. + interval: + description: The time duration between keep-alive + probes. type: string - maxRequestsPerConnection: - description: Maximum number of requests per - connection to a backend. - format: int32 + probes: type: integer - maxRetries: - format: int32 - type: integer - useClientProtocol: - description: If set to true, client protocol - will be preserved while initiating connection - to backend. - type: boolean - type: object - tcp: - description: Settings common to both HTTP and TCP - upstream connections. - properties: - connectTimeout: - description: TCP connection timeout. + time: type: string - maxConnections: - description: Maximum number of HTTP1 /TCP connections - to a destination host. - format: int32 - type: integer - tcpKeepalive: - description: If set then set SO_KEEPALIVE on - the socket to enable TCP Keepalives. - properties: - interval: - description: The time duration between keep-alive - probes. - type: string - probes: - type: integer - time: - type: string - type: object type: object type: object - loadBalancer: - description: Settings controlling the load balancer - algorithms. - oneOf: - - not: - anyOf: - - required: - - simple - - properties: - consistentHash: - oneOf: - - not: - anyOf: - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - required: - - consistentHash + type: object + loadBalancer: + description: Settings controlling the load balancer algorithms. + oneOf: + - not: + anyOf: - required: - simple - properties: @@ -430,510 +260,267 @@ spec: - httpQueryParameterName required: - consistentHash + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + properties: + consistentHash: properties: - consistentHash: + httpCookie: + description: Hash based on HTTP cookie. properties: - httpCookie: - description: Hash based on HTTP cookie. - properties: - name: - description: Name of the cookie. - format: string - type: string - path: - description: Path to set for the cookie. - format: string - type: string - ttl: - description: Lifetime of the cookie. - type: string - type: object - httpHeaderName: - description: Hash based on a specific HTTP header. - format: string + name: + description: Name of the cookie. type: string - httpQueryParameterName: - description: Hash based on a specific HTTP query - parameter. - format: string + path: + description: Path to set for the cookie. + type: string + ttl: + description: Lifetime of the cookie. type: string - minimumRingSize: - type: integer - useSourceIp: - description: Hash based on the source IP address. - type: boolean - type: object - localityLbSetting: - properties: - distribute: - description: 'Optional: only one of distribute - or failover can be set.' - items: - properties: - from: - description: Originating locality, '/' - separated, e.g. - format: string - type: string - to: - additionalProperties: - type: integer - description: Map of upstream localities - to traffic distribution weights. - type: object - type: object - type: array - enabled: - description: enable locality load balancing, - this is DestinationRule-level and will override - mesh wide settings in entirety. - nullable: true - type: boolean - failover: - description: 'Optional: only failover or distribute - can be set.' - items: - properties: - from: - description: Originating region. - format: string - type: string - to: - format: string - type: string - type: object - type: array type: object - simple: - enum: - - ROUND_ROBIN - - LEAST_CONN - - RANDOM - - PASSTHROUGH + httpHeaderName: + description: Hash based on a specific HTTP header. type: string - type: object - outlierDetection: - properties: - baseEjectionTime: - description: Minimum ejection duration. - type: string - consecutive5xxErrors: - description: Number of 5xx errors before a host - is ejected from the connection pool. - nullable: true - type: integer - consecutiveErrors: - format: int32 - type: integer - consecutiveGatewayErrors: - description: Number of gateway errors before a host - is ejected from the connection pool. - nullable: true - type: integer - interval: - description: Time interval between ejection sweep - analysis. + httpQueryParameterName: + description: Hash based on a specific HTTP query + parameter. type: string - maxEjectionPercent: - format: int32 - type: integer - minHealthPercent: - format: int32 + minimumRingSize: type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean type: object - port: + localityLbSetting: properties: - number: - type: integer - type: object - tls: - description: TLS related settings for connections to - the upstream service. - properties: - caCertificates: - format: string - type: string - clientCertificate: - description: REQUIRED if mode is `MUTUAL`. - format: string - type: string - credentialName: - format: string - type: string - mode: - enum: - - DISABLE - - SIMPLE - - MUTUAL - - ISTIO_MUTUAL - type: string - privateKey: - description: REQUIRED if mode is `MUTUAL`. - format: string - type: string - sni: - description: SNI string to present to the server - during TLS handshake. - format: string - type: string - subjectAltNames: + distribute: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating locality, '/' separated, + e.g. + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities to + traffic distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, this + is DestinationRule-level and will override mesh + wide settings in entirety. + nullable: true + type: boolean + failover: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating region. + type: string + to: + type: string + type: object + type: array + failoverPriority: + description: failoverPriority is an ordered list + of labels used to sort endpoints to do priority + based load balancing. items: - format: string type: string type: array type: object - type: object - type: array - tls: - description: TLS related settings for connections to the upstream - service. - properties: - caCertificates: - format: string - type: string - clientCertificate: - description: REQUIRED if mode is `MUTUAL`. - format: string - type: string - credentialName: - format: string - type: string - mode: - enum: - - DISABLE - - SIMPLE - - MUTUAL - - ISTIO_MUTUAL - type: string - privateKey: - description: REQUIRED if mode is `MUTUAL`. - format: string - type: string - sni: - description: SNI string to present to the server during - TLS handshake. - format: string - type: string - subjectAltNames: - items: - format: string - type: string - type: array - type: object - type: object - type: object - type: array - trafficPolicy: - properties: - connectionPool: - properties: - http: - description: HTTP connection pool settings. - properties: - h2UpgradePolicy: - description: Specify if http1.1 connection should be upgraded - to http2 for the associated destination. - enum: - - DEFAULT - - DO_NOT_UPGRADE - - UPGRADE - type: string - http1MaxPendingRequests: - description: Maximum number of pending HTTP requests to - a destination. - format: int32 - type: integer - http2MaxRequests: - description: Maximum number of requests to a backend. - format: int32 - type: integer - idleTimeout: - description: The idle timeout for upstream connection pool - connections. - type: string - maxRequestsPerConnection: - description: Maximum number of requests per connection to - a backend. - format: int32 - type: integer - maxRetries: - format: int32 - type: integer - useClientProtocol: - description: If set to true, client protocol will be preserved - while initiating connection to backend. - type: boolean - type: object - tcp: - description: Settings common to both HTTP and TCP upstream connections. - properties: - connectTimeout: - description: TCP connection timeout. - type: string - maxConnections: - description: Maximum number of HTTP1 /TCP connections to - a destination host. - format: int32 - type: integer - tcpKeepalive: - description: If set then set SO_KEEPALIVE on the socket - to enable TCP Keepalives. - properties: - interval: - description: The time duration between keep-alive probes. - type: string - probes: - type: integer - time: + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH type: string type: object - type: object - type: object - loadBalancer: - description: Settings controlling the load balancer algorithms. - oneOf: - - not: - anyOf: - - required: - - simple - - properties: - consistentHash: - oneOf: - - not: - anyOf: - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - required: - - consistentHash - - required: - - simple - - properties: - consistentHash: - oneOf: - - not: - anyOf: - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - required: - - consistentHash - properties: - consistentHash: - properties: - httpCookie: - description: Hash based on HTTP cookie. + outlierDetection: properties: - name: - description: Name of the cookie. - format: string - type: string - path: - description: Path to set for the cookie. - format: string + baseEjectionTime: + description: Minimum ejection duration. type: string - ttl: - description: Lifetime of the cookie. + consecutive5xxErrors: + description: Number of 5xx errors before a host is ejected + from the connection pool. + nullable: true + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host + is ejected from the connection pool. + nullable: true + type: integer + consecutiveLocalOriginFailures: + nullable: true + type: integer + interval: + description: Time interval between ejection sweep analysis. type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + splitExternalLocalOriginErrors: + description: Determines whether to distinguish local + origin failures from external errors. + type: boolean type: object - httpHeaderName: - description: Hash based on a specific HTTP header. - format: string - type: string - httpQueryParameterName: - description: Hash based on a specific HTTP query parameter. - format: string - type: string - minimumRingSize: - type: integer - useSourceIp: - description: Hash based on the source IP address. - type: boolean - type: object - localityLbSetting: - properties: - distribute: - description: 'Optional: only one of distribute or failover - can be set.' - items: - properties: - from: - description: Originating locality, '/' separated, - e.g. - format: string - type: string - to: - additionalProperties: - type: integer - description: Map of upstream localities to traffic - distribution weights. - type: object - type: object - type: array - enabled: - description: enable locality load balancing, this is DestinationRule-level - and will override mesh wide settings in entirety. - nullable: true - type: boolean - failover: - description: 'Optional: only failover or distribute can - be set.' + portLevelSettings: + description: Traffic policies specific to individual ports. items: properties: - from: - description: Originating region. - format: string - type: string - to: - format: string - type: string - type: object - type: array - type: object - simple: - enum: - - ROUND_ROBIN - - LEAST_CONN - - RANDOM - - PASSTHROUGH - type: string - type: object - outlierDetection: - properties: - baseEjectionTime: - description: Minimum ejection duration. - type: string - consecutive5xxErrors: - description: Number of 5xx errors before a host is ejected from - the connection pool. - nullable: true - type: integer - consecutiveErrors: - format: int32 - type: integer - consecutiveGatewayErrors: - description: Number of gateway errors before a host is ejected - from the connection pool. - nullable: true - type: integer - interval: - description: Time interval between ejection sweep analysis. - type: string - maxEjectionPercent: - format: int32 - type: integer - minHealthPercent: - format: int32 - type: integer - type: object - portLevelSettings: - description: Traffic policies specific to individual ports. - items: - properties: - connectionPool: - properties: - http: - description: HTTP connection pool settings. - properties: - h2UpgradePolicy: - description: Specify if http1.1 connection should - be upgraded to http2 for the associated destination. - enum: - - DEFAULT - - DO_NOT_UPGRADE - - UPGRADE - type: string - http1MaxPendingRequests: - description: Maximum number of pending HTTP requests - to a destination. - format: int32 - type: integer - http2MaxRequests: - description: Maximum number of requests to a backend. - format: int32 - type: integer - idleTimeout: - description: The idle timeout for upstream connection - pool connections. - type: string - maxRequestsPerConnection: - description: Maximum number of requests per connection - to a backend. - format: int32 - type: integer - maxRetries: - format: int32 - type: integer - useClientProtocol: - description: If set to true, client protocol will - be preserved while initiating connection to backend. - type: boolean - type: object - tcp: - description: Settings common to both HTTP and TCP upstream - connections. - properties: - connectTimeout: - description: TCP connection timeout. - type: string - maxConnections: - description: Maximum number of HTTP1 /TCP connections - to a destination host. - format: int32 - type: integer - tcpKeepalive: - description: If set then set SO_KEEPALIVE on the socket - to enable TCP Keepalives. + connectionPool: properties: - interval: - description: The time duration between keep-alive - probes. - type: string - probes: - type: integer - time: - type: string + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection + should be upgraded to http2 for the associated + destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP + requests to a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to + a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream + connection pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per + connection to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + useClientProtocol: + description: If set to true, client protocol + will be preserved while initiating connection + to backend. + type: boolean + type: object + tcp: + description: Settings common to both HTTP and + TCP upstream connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP + connections to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE + on the socket to enable TCP Keepalives. + properties: + interval: + description: The time duration between + keep-alive probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object type: object - type: object - type: object - loadBalancer: - description: Settings controlling the load balancer algorithms. - oneOf: - - not: - anyOf: - - required: - - simple - - properties: - consistentHash: - oneOf: - - not: - anyOf: + loadBalancer: + description: Settings controlling the load balancer + algorithms. + oneOf: + - not: + anyOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName - required: - httpHeaderName - required: @@ -942,976 +529,2957 @@ spec: - useSourceIp - required: - httpQueryParameterName - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - required: - - consistentHash - - required: - - simple - - properties: - consistentHash: - oneOf: - - not: - anyOf: - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - - required: - - httpHeaderName - - required: - - httpCookie - - required: - - useSourceIp - - required: - - httpQueryParameterName - required: - - consistentHash - properties: - consistentHash: - properties: - httpCookie: - description: Hash based on HTTP cookie. + required: + - consistentHash properties: - name: - description: Name of the cookie. - format: string + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + type: string + path: + description: Path to set for the cookie. + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP + header. + type: string + httpQueryParameterName: + description: Hash based on a specific HTTP + query parameter. + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating locality, '/' + separated, e.g. + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities + to traffic distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, + this is DestinationRule-level and will override + mesh wide settings in entirety. + nullable: true + type: boolean + failover: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating region. + type: string + to: + type: string + type: object + type: array + failoverPriority: + description: failoverPriority is an ordered + list of labels used to sort endpoints to + do priority based load balancing. + items: + type: string + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH type: string - path: - description: Path to set for the cookie. - format: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. type: string - ttl: - description: Lifetime of the cookie. + consecutive5xxErrors: + description: Number of 5xx errors before a host + is ejected from the connection pool. + nullable: true + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a + host is ejected from the connection pool. + nullable: true + type: integer + consecutiveLocalOriginFailures: + nullable: true + type: integer + interval: + description: Time interval between ejection sweep + analysis. type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + splitExternalLocalOriginErrors: + description: Determines whether to distinguish + local origin failures from external errors. + type: boolean type: object - httpHeaderName: - description: Hash based on a specific HTTP header. - format: string - type: string - httpQueryParameterName: - description: Hash based on a specific HTTP query parameter. - format: string - type: string - minimumRingSize: - type: integer - useSourceIp: - description: Hash based on the source IP address. - type: boolean - type: object - localityLbSetting: - properties: - distribute: - description: 'Optional: only one of distribute or - failover can be set.' - items: - properties: - from: - description: Originating locality, '/' separated, - e.g. - format: string - type: string - to: - additionalProperties: - type: integer - description: Map of upstream localities to traffic - distribution weights. - type: object - type: object - type: array - enabled: - description: enable locality load balancing, this - is DestinationRule-level and will override mesh - wide settings in entirety. - nullable: true - type: boolean - failover: - description: 'Optional: only failover or distribute - can be set.' - items: - properties: - from: - description: Originating region. - format: string - type: string - to: - format: string + port: + properties: + number: + type: integer + type: object + tls: + description: TLS related settings for connections + to the upstream service. + properties: + caCertificates: + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + type: string + credentialName: + type: string + insecureSkipVerify: + nullable: true + type: boolean + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + type: string + sni: + description: SNI string to present to the server + during TLS handshake. + type: string + subjectAltNames: + items: type: string - type: object - type: array + type: array + type: object type: object - simple: - enum: - - ROUND_ROBIN - - LEAST_CONN - - RANDOM - - PASSTHROUGH - type: string - type: object - outlierDetection: + type: array + tls: + description: TLS related settings for connections to the + upstream service. + properties: + caCertificates: + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + type: string + credentialName: + type: string + insecureSkipVerify: + nullable: true + type: boolean + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + type: string + sni: + description: SNI string to present to the server during + TLS handshake. + type: string + subjectAltNames: + items: + type: string + type: array + type: object + type: object + type: object + type: array + trafficPolicy: + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. properties: - baseEjectionTime: - description: Minimum ejection duration. + h2UpgradePolicy: + description: Specify if http1.1 connection should be upgraded + to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE type: string - consecutive5xxErrors: - description: Number of 5xx errors before a host is ejected - from the connection pool. - nullable: true - type: integer - consecutiveErrors: + http1MaxPendingRequests: + description: Maximum number of pending HTTP requests to + a destination. format: int32 type: integer - consecutiveGatewayErrors: - description: Number of gateway errors before a host is - ejected from the connection pool. - nullable: true + http2MaxRequests: + description: Maximum number of requests to a backend. + format: int32 type: integer - interval: - description: Time interval between ejection sweep analysis. + idleTimeout: + description: The idle timeout for upstream connection + pool connections. type: string - maxEjectionPercent: + maxRequestsPerConnection: + description: Maximum number of requests per connection + to a backend. format: int32 type: integer - minHealthPercent: + maxRetries: format: int32 type: integer + useClientProtocol: + description: If set to true, client protocol will be preserved + while initiating connection to backend. + type: boolean type: object - port: - properties: - number: - type: integer - type: object - tls: - description: TLS related settings for connections to the upstream - service. + tcp: + description: Settings common to both HTTP and TCP upstream + connections. properties: - caCertificates: - format: string + connectTimeout: + description: TCP connection timeout. type: string - clientCertificate: - description: REQUIRED if mode is `MUTUAL`. - format: string - type: string - credentialName: - format: string - type: string - mode: - enum: - - DISABLE - - SIMPLE - - MUTUAL - - ISTIO_MUTUAL - type: string - privateKey: - description: REQUIRED if mode is `MUTUAL`. - format: string - type: string - sni: - description: SNI string to present to the server during - TLS handshake. - format: string - type: string - subjectAltNames: - items: - format: string - type: string - type: array + maxConnections: + description: Maximum number of HTTP1 /TCP connections + to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on the socket + to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive + probes. + type: string + probes: + type: integer + time: + type: string + type: object type: object type: object - type: array - tls: - description: TLS related settings for connections to the upstream - service. - properties: - caCertificates: - format: string - type: string - clientCertificate: - description: REQUIRED if mode is `MUTUAL`. - format: string - type: string - credentialName: - format: string - type: string - mode: - enum: - - DISABLE - - SIMPLE - - MUTUAL - - ISTIO_MUTUAL - type: string - privateKey: - description: REQUIRED if mode is `MUTUAL`. - format: string - type: string - sni: - description: SNI string to present to the server during TLS - handshake. - format: string - type: string - subjectAltNames: - items: - format: string - type: string - type: array - type: object - type: object - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - versions: - - name: v1alpha3 - served: true - storage: true - - name: v1beta1 - served: true - storage: false - ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - annotations: - "helm.sh/resource-policy": keep - labels: - app: istio-pilot - chart: istio - heritage: Tiller - release: istio - name: envoyfilters.networking.istio.io -spec: - group: networking.istio.io - names: - categories: - - istio-io - - networking-istio-io - kind: EnvoyFilter - listKind: EnvoyFilterList - plural: envoyfilters - singular: envoyfilter - preserveUnknownFields: true - scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: 'Customizing Envoy configuration generated by Istio. See more - details at: https://istio.io/docs/reference/config/networking/envoy-filter.html' - properties: - configPatches: - description: One or more patches with match conditions. - items: - properties: - applyTo: - enum: - - INVALID - - LISTENER - - FILTER_CHAIN - - NETWORK_FILTER - - HTTP_FILTER - - ROUTE_CONFIGURATION - - VIRTUAL_HOST - - HTTP_ROUTE - - CLUSTER - - EXTENSION_CONFIG - type: string - match: - description: Match on listener/route configuration/cluster. + loadBalancer: + description: Settings controlling the load balancer algorithms. oneOf: - not: anyOf: - required: - - listener - - required: - - routeConfiguration - - required: - - cluster - - required: - - listener - - required: - - routeConfiguration + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash - required: - - cluster + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash properties: - cluster: - description: Match on envoy cluster attributes. - properties: - name: - description: The exact name of the cluster to match. - format: string - type: string - portNumber: - description: The service port for which this cluster was - generated. - type: integer - service: - description: The fully qualified service name for this - cluster. - format: string - type: string - subset: - description: The subset associated with the service. - format: string - type: string - type: object - context: - description: The specific config generation context to match - on. - enum: - - ANY - - SIDECAR_INBOUND - - SIDECAR_OUTBOUND - - GATEWAY - type: string - listener: - description: Match on envoy listener attributes. + consistentHash: properties: - filterChain: - description: Match a specific filter chain in a listener. + httpCookie: + description: Hash based on HTTP cookie. properties: - applicationProtocols: - description: Applies only to sidecars. - format: string - type: string - destinationPort: - description: The destination_port value used by a - filter chain's match condition. - type: integer - filter: - description: The name of a specific filter to apply - the patch to. - properties: - name: - description: The filter name to match on. - format: string - type: string - subFilter: - properties: - name: - description: The filter name to match on. - format: string - type: string - type: object - type: object name: - description: The name assigned to the filter chain. - format: string + description: Name of the cookie. type: string - sni: - description: The SNI value used by a filter chain's - match condition. - format: string + path: + description: Path to set for the cookie. type: string - transportProtocol: - description: Applies only to `SIDECAR_INBOUND` context. - format: string + ttl: + description: Lifetime of the cookie. type: string type: object - name: - description: Match a specific listener by its name. - format: string + httpHeaderName: + description: Hash based on a specific HTTP header. type: string - portName: - format: string + httpQueryParameterName: + description: Hash based on a specific HTTP query parameter. type: string - portNumber: + minimumRingSize: type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean type: object - proxy: - description: Match on properties associated with a proxy. + localityLbSetting: properties: - metadata: - additionalProperties: - format: string + distribute: + description: 'Optional: only one of distribute, failover + or failoverPriority can be set.' + items: + properties: + from: + description: Originating locality, '/' separated, + e.g. + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities to traffic + distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, this is DestinationRule-level + and will override mesh wide settings in entirety. + nullable: true + type: boolean + failover: + description: 'Optional: only one of distribute, failover + or failoverPriority can be set.' + items: + properties: + from: + description: Originating region. + type: string + to: + type: string + type: object + type: array + failoverPriority: + description: failoverPriority is an ordered list of labels + used to sort endpoints to do priority based load balancing. + items: type: string - type: object - proxyVersion: - format: string - type: string - type: object - routeConfiguration: - description: Match on envoy HTTP route configuration attributes. - properties: - gateway: - format: string - type: string - name: - description: Route configuration name to match on. - format: string - type: string - portName: - description: Applicable only for GATEWAY context. - format: string - type: string - portNumber: - type: integer - vhost: - properties: - name: - format: string - type: string - route: - description: Match a specific route within the virtual - host. - properties: - action: - description: Match a route with specific action - type. - enum: - - ANY - - ROUTE - - REDIRECT - - DIRECT_RESPONSE - type: string - name: - format: string - type: string - type: object - type: object + type: array type: object - type: object - patch: - description: The patch to apply along with the operation. - properties: - filterClass: - description: Determines the filter insertion order. - enum: - - UNSPECIFIED - - AUTHN - - AUTHZ - - STATS - type: string - operation: - description: Determines how the patch should be applied. + simple: enum: - - INVALID - - MERGE - - ADD - - REMOVE - - INSERT_BEFORE - - INSERT_AFTER - - INSERT_FIRST - - REPLACE + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH type: string - value: - description: The JSON config of the object being patched. - type: object type: object - type: object - type: array - workloadSelector: - properties: - labels: - additionalProperties: - format: string - type: string - type: object - type: object - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - versions: - - name: v1alpha3 - served: true - storage: true - ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - annotations: - "helm.sh/resource-policy": keep - labels: - app: istio-pilot - chart: istio - heritage: Tiller - release: istio - name: gateways.networking.istio.io -spec: - group: networking.istio.io - names: - categories: - - istio-io - - networking-istio-io - kind: Gateway - listKind: GatewayList - plural: gateways - shortNames: - - gw - singular: gateway - preserveUnknownFields: false - scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: 'Configuration affecting edge load balancer. See more details - at: https://istio.io/docs/reference/config/networking/gateway.html' - properties: - selector: - additionalProperties: - format: string - type: string - type: object - servers: - description: A list of server specifications. - items: - properties: - bind: - format: string - type: string - defaultEndpoint: - format: string - type: string - hosts: - description: One or more hosts exposed by this gateway. - items: - format: string - type: string - type: array - name: - description: An optional name of the server, when set must be - unique across all servers. - format: string - type: string - port: + outlierDetection: properties: - name: - description: Label assigned to the port. - format: string + baseEjectionTime: + description: Minimum ejection duration. type: string - number: - description: A valid non-negative integer port number. + consecutive5xxErrors: + description: Number of 5xx errors before a host is ejected + from the connection pool. + nullable: true + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host is ejected + from the connection pool. + nullable: true + type: integer + consecutiveLocalOriginFailures: + nullable: true type: integer - protocol: - description: The protocol exposed on the port. - format: string + interval: + description: Time interval between ejection sweep analysis. type: string - targetPort: + maxEjectionPercent: + format: int32 type: integer + minHealthPercent: + format: int32 + type: integer + splitExternalLocalOriginErrors: + description: Determines whether to distinguish local origin + failures from external errors. + type: boolean type: object - tls: - description: Set of TLS related options that govern the server's - behavior. - properties: - caCertificates: - description: REQUIRED if mode is `MUTUAL`. - format: string - type: string - cipherSuites: - description: 'Optional: If specified, only support the specified - cipher list.' - items: - format: string - type: string - type: array - credentialName: - format: string + portLevelSettings: + description: Traffic policies specific to individual ports. + items: + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should + be upgraded to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP requests + to a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection + pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per connection + to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + useClientProtocol: + description: If set to true, client protocol will + be preserved while initiating connection to backend. + type: boolean + type: object + tcp: + description: Settings common to both HTTP and TCP upstream + connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections + to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on the + socket to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive + probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer algorithms. + oneOf: + - not: + anyOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + type: string + path: + description: Path to set for the cookie. + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP header. + type: string + httpQueryParameterName: + description: Hash based on a specific HTTP query + parameter. + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating locality, '/' separated, + e.g. + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities to + traffic distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, this + is DestinationRule-level and will override mesh + wide settings in entirety. + nullable: true + type: boolean + failover: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating region. + type: string + to: + type: string + type: object + type: array + failoverPriority: + description: failoverPriority is an ordered list + of labels used to sort endpoints to do priority + based load balancing. + items: + type: string + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host is ejected + from the connection pool. + nullable: true + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host + is ejected from the connection pool. + nullable: true + type: integer + consecutiveLocalOriginFailures: + nullable: true + type: integer + interval: + description: Time interval between ejection sweep analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + splitExternalLocalOriginErrors: + description: Determines whether to distinguish local + origin failures from external errors. + type: boolean + type: object + port: + properties: + number: + type: integer + type: object + tls: + description: TLS related settings for connections to the + upstream service. + properties: + caCertificates: + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + type: string + credentialName: + type: string + insecureSkipVerify: + nullable: true + type: boolean + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + type: string + sni: + description: SNI string to present to the server during + TLS handshake. + type: string + subjectAltNames: + items: + type: string + type: array + type: object + type: object + type: array + tls: + description: TLS related settings for connections to the upstream + service. + properties: + caCertificates: type: string - httpsRedirect: - type: boolean - maxProtocolVersion: - description: 'Optional: Maximum TLS protocol version.' - enum: - - TLS_AUTO - - TLSV1_0 - - TLSV1_1 - - TLSV1_2 - - TLSV1_3 + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. type: string - minProtocolVersion: - description: 'Optional: Minimum TLS protocol version.' - enum: - - TLS_AUTO - - TLSV1_0 - - TLSV1_1 - - TLSV1_2 - - TLSV1_3 + credentialName: type: string + insecureSkipVerify: + nullable: true + type: boolean mode: enum: - - PASSTHROUGH + - DISABLE - SIMPLE - MUTUAL - - AUTO_PASSTHROUGH - ISTIO_MUTUAL type: string privateKey: - description: REQUIRED if mode is `SIMPLE` or `MUTUAL`. - format: string + description: REQUIRED if mode is `MUTUAL`. type: string - serverCertificate: - description: REQUIRED if mode is `SIMPLE` or `MUTUAL`. - format: string + sni: + description: SNI string to present to the server during TLS + handshake. type: string subjectAltNames: items: - format: string - type: string - type: array - verifyCertificateHash: - items: - format: string - type: string - type: array - verifyCertificateSpki: - items: - format: string type: string type: array type: object type: object - type: array - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - versions: - - name: v1alpha3 + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object served: true storage: true - - name: v1beta1 - served: true - storage: false - ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - annotations: - "helm.sh/resource-policy": keep - labels: - app: istio-pilot - chart: istio - heritage: Tiller - release: istio - name: serviceentries.networking.istio.io -spec: - additionalPrinterColumns: - - JSONPath: .spec.hosts - description: The hosts associated with the ServiceEntry - name: Hosts - type: string - - JSONPath: .spec.location - description: Whether the service is external to the mesh or part of the mesh (MESH_EXTERNAL - or MESH_INTERNAL) - name: Location - type: string - - JSONPath: .spec.resolution - description: Service discovery mode for the hosts (NONE, STATIC, or DNS) - name: Resolution - type: string - - JSONPath: .metadata.creationTimestamp - description: 'CreationTimestamp is a timestamp representing the server time when - this object was created. It is not guaranteed to be set in happens-before order - across separate operations. Clients may not set this value. It is represented - in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for - lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' - name: Age - type: date - group: networking.istio.io - names: - categories: - - istio-io - - networking-istio-io - kind: ServiceEntry - listKind: ServiceEntryList - plural: serviceentries - shortNames: - - se - singular: serviceentry - preserveUnknownFields: false - scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: 'Configuration affecting service registry. See more details - at: https://istio.io/docs/reference/config/networking/service-entry.html' - properties: - addresses: - description: The virtual IP addresses associated with the service. - items: - format: string + subresources: + status: {} + - additionalPrinterColumns: + - description: The name of a service from the service registry + jsonPath: .spec.host + name: Host + type: string + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting load balancing, outlier detection, + etc. See more details at: https://istio.io/docs/reference/config/networking/destination-rule.html' + properties: + exportTo: + description: A list of namespaces to which this destination rule is + exported. + items: + type: string + type: array + host: + description: The name of a service from the service registry. type: string - type: array - endpoints: - description: One or more endpoints associated with the service. - items: - properties: - address: - format: string - type: string - labels: - additionalProperties: - format: string + subsets: + items: + properties: + labels: + additionalProperties: + type: string + type: object + name: + description: Name of the subset. type: string - description: One or more labels associated with the endpoint. - type: object - locality: - description: The locality associated with the endpoint. - format: string - type: string - network: - format: string - type: string - ports: - additionalProperties: - type: integer - description: Set of ports associated with the endpoint. - type: object - serviceAccount: - format: string - type: string - weight: - description: The load balancing weight associated with the endpoint. - type: integer - type: object - type: array - exportTo: - description: A list of namespaces to which this service is exported. - items: - format: string - type: string - type: array - hosts: - description: The hosts associated with the ServiceEntry. - items: - format: string - type: string - type: array - location: - enum: - - MESH_EXTERNAL - - MESH_INTERNAL - type: string - ports: - description: The ports associated with the external service. - items: - properties: - name: - description: Label assigned to the port. - format: string - type: string - number: - description: A valid non-negative integer port number. - type: integer - protocol: - description: The protocol exposed on the port. - format: string - type: string - targetPort: - type: integer - type: object - type: array - resolution: - description: Service discovery mode for the hosts. - enum: - - NONE - - STATIC - - DNS - type: string - subjectAltNames: - items: - format: string - type: string - type: array - workloadSelector: - description: Applicable only for MESH_INTERNAL services. - properties: - labels: - additionalProperties: - format: string - type: string - type: object - type: object - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - versions: - - name: v1alpha3 - served: true - storage: true - - name: v1beta1 - served: true - storage: false - ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - annotations: - "helm.sh/resource-policy": keep - labels: - app: istio-pilot - chart: istio - heritage: Tiller - release: istio - name: sidecars.networking.istio.io -spec: - group: networking.istio.io - names: - categories: - - istio-io - - networking-istio-io - kind: Sidecar - listKind: SidecarList - plural: sidecars - singular: sidecar - preserveUnknownFields: false - scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: 'Configuration affecting network reachability of a sidecar. - See more details at: https://istio.io/docs/reference/config/networking/sidecar.html' - properties: - egress: - items: - properties: - bind: - format: string - type: string - captureMode: - enum: - - DEFAULT - - IPTABLES - - NONE - type: string - hosts: + trafficPolicy: + description: Traffic policies that apply to this subset. + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should + be upgraded to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP requests + to a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection + pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per connection + to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + useClientProtocol: + description: If set to true, client protocol will + be preserved while initiating connection to backend. + type: boolean + type: object + tcp: + description: Settings common to both HTTP and TCP upstream + connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections + to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on the + socket to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive + probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer algorithms. + oneOf: + - not: + anyOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + type: string + path: + description: Path to set for the cookie. + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP header. + type: string + httpQueryParameterName: + description: Hash based on a specific HTTP query + parameter. + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating locality, '/' separated, + e.g. + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities to + traffic distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, this + is DestinationRule-level and will override mesh + wide settings in entirety. + nullable: true + type: boolean + failover: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating region. + type: string + to: + type: string + type: object + type: array + failoverPriority: + description: failoverPriority is an ordered list + of labels used to sort endpoints to do priority + based load balancing. + items: + type: string + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host is ejected + from the connection pool. + nullable: true + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host + is ejected from the connection pool. + nullable: true + type: integer + consecutiveLocalOriginFailures: + nullable: true + type: integer + interval: + description: Time interval between ejection sweep analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + splitExternalLocalOriginErrors: + description: Determines whether to distinguish local + origin failures from external errors. + type: boolean + type: object + portLevelSettings: + description: Traffic policies specific to individual ports. + items: + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection + should be upgraded to http2 for the associated + destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP + requests to a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to + a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream + connection pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per + connection to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + useClientProtocol: + description: If set to true, client protocol + will be preserved while initiating connection + to backend. + type: boolean + type: object + tcp: + description: Settings common to both HTTP and + TCP upstream connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP + connections to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE + on the socket to enable TCP Keepalives. + properties: + interval: + description: The time duration between + keep-alive probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer + algorithms. + oneOf: + - not: + anyOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + type: string + path: + description: Path to set for the cookie. + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP + header. + type: string + httpQueryParameterName: + description: Hash based on a specific HTTP + query parameter. + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating locality, '/' + separated, e.g. + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities + to traffic distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, + this is DestinationRule-level and will override + mesh wide settings in entirety. + nullable: true + type: boolean + failover: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating region. + type: string + to: + type: string + type: object + type: array + failoverPriority: + description: failoverPriority is an ordered + list of labels used to sort endpoints to + do priority based load balancing. + items: + type: string + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host + is ejected from the connection pool. + nullable: true + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a + host is ejected from the connection pool. + nullable: true + type: integer + consecutiveLocalOriginFailures: + nullable: true + type: integer + interval: + description: Time interval between ejection sweep + analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + splitExternalLocalOriginErrors: + description: Determines whether to distinguish + local origin failures from external errors. + type: boolean + type: object + port: + properties: + number: + type: integer + type: object + tls: + description: TLS related settings for connections + to the upstream service. + properties: + caCertificates: + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + type: string + credentialName: + type: string + insecureSkipVerify: + nullable: true + type: boolean + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + type: string + sni: + description: SNI string to present to the server + during TLS handshake. + type: string + subjectAltNames: + items: + type: string + type: array + type: object + type: object + type: array + tls: + description: TLS related settings for connections to the + upstream service. + properties: + caCertificates: + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + type: string + credentialName: + type: string + insecureSkipVerify: + nullable: true + type: boolean + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + type: string + sni: + description: SNI string to present to the server during + TLS handshake. + type: string + subjectAltNames: + items: + type: string + type: array + type: object + type: object + type: object + type: array + trafficPolicy: + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should be upgraded + to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP requests to + a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection + pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per connection + to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + useClientProtocol: + description: If set to true, client protocol will be preserved + while initiating connection to backend. + type: boolean + type: object + tcp: + description: Settings common to both HTTP and TCP upstream + connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections + to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on the socket + to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive + probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer algorithms. + oneOf: + - not: + anyOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + type: string + path: + description: Path to set for the cookie. + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP header. + type: string + httpQueryParameterName: + description: Hash based on a specific HTTP query parameter. + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute, failover + or failoverPriority can be set.' + items: + properties: + from: + description: Originating locality, '/' separated, + e.g. + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities to traffic + distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, this is DestinationRule-level + and will override mesh wide settings in entirety. + nullable: true + type: boolean + failover: + description: 'Optional: only one of distribute, failover + or failoverPriority can be set.' + items: + properties: + from: + description: Originating region. + type: string + to: + type: string + type: object + type: array + failoverPriority: + description: failoverPriority is an ordered list of labels + used to sort endpoints to do priority based load balancing. + items: + type: string + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host is ejected + from the connection pool. + nullable: true + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host is ejected + from the connection pool. + nullable: true + type: integer + consecutiveLocalOriginFailures: + nullable: true + type: integer + interval: + description: Time interval between ejection sweep analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + splitExternalLocalOriginErrors: + description: Determines whether to distinguish local origin + failures from external errors. + type: boolean + type: object + portLevelSettings: + description: Traffic policies specific to individual ports. items: - format: string + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should + be upgraded to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP requests + to a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection + pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per connection + to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + useClientProtocol: + description: If set to true, client protocol will + be preserved while initiating connection to backend. + type: boolean + type: object + tcp: + description: Settings common to both HTTP and TCP upstream + connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections + to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on the + socket to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive + probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer algorithms. + oneOf: + - not: + anyOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + - required: + - simple + - properties: + consistentHash: + oneOf: + - not: + anyOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + - required: + - httpQueryParameterName + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + type: string + path: + description: Path to set for the cookie. + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP header. + type: string + httpQueryParameterName: + description: Hash based on a specific HTTP query + parameter. + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating locality, '/' separated, + e.g. + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities to + traffic distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, this + is DestinationRule-level and will override mesh + wide settings in entirety. + nullable: true + type: boolean + failover: + description: 'Optional: only one of distribute, + failover or failoverPriority can be set.' + items: + properties: + from: + description: Originating region. + type: string + to: + type: string + type: object + type: array + failoverPriority: + description: failoverPriority is an ordered list + of labels used to sort endpoints to do priority + based load balancing. + items: + type: string + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host is ejected + from the connection pool. + nullable: true + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host + is ejected from the connection pool. + nullable: true + type: integer + consecutiveLocalOriginFailures: + nullable: true + type: integer + interval: + description: Time interval between ejection sweep analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + splitExternalLocalOriginErrors: + description: Determines whether to distinguish local + origin failures from external errors. + type: boolean + type: object + port: + properties: + number: + type: integer + type: object + tls: + description: TLS related settings for connections to the + upstream service. + properties: + caCertificates: + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + type: string + credentialName: + type: string + insecureSkipVerify: + nullable: true + type: boolean + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + type: string + sni: + description: SNI string to present to the server during + TLS handshake. + type: string + subjectAltNames: + items: + type: string + type: array + type: object + type: object + type: array + tls: + description: TLS related settings for connections to the upstream + service. + properties: + caCertificates: + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + type: string + credentialName: + type: string + insecureSkipVerify: + nullable: true + type: boolean + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + type: string + sni: + description: SNI string to present to the server during TLS + handshake. + type: string + subjectAltNames: + items: + type: string + type: array + type: object + type: object + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: envoyfilters.networking.istio.io +spec: + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: EnvoyFilter + listKind: EnvoyFilterList + plural: envoyfilters + singular: envoyfilter + scope: Namespaced + versions: + - name: v1alpha3 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Customizing Envoy configuration generated by Istio. See + more details at: https://istio.io/docs/reference/config/networking/envoy-filter.html' + properties: + configPatches: + description: One or more patches with match conditions. + items: + properties: + applyTo: + enum: + - INVALID + - LISTENER + - FILTER_CHAIN + - NETWORK_FILTER + - HTTP_FILTER + - ROUTE_CONFIGURATION + - VIRTUAL_HOST + - HTTP_ROUTE + - CLUSTER + - EXTENSION_CONFIG + - BOOTSTRAP + type: string + match: + description: Match on listener/route configuration/cluster. + oneOf: + - not: + anyOf: + - required: + - listener + - required: + - routeConfiguration + - required: + - cluster + - required: + - listener + - required: + - routeConfiguration + - required: + - cluster + properties: + cluster: + description: Match on envoy cluster attributes. + properties: + name: + description: The exact name of the cluster to match. + type: string + portNumber: + description: The service port for which this cluster + was generated. + type: integer + service: + description: The fully qualified service name for this + cluster. + type: string + subset: + description: The subset associated with the service. + type: string + type: object + context: + description: The specific config generation context to match + on. + enum: + - ANY + - SIDECAR_INBOUND + - SIDECAR_OUTBOUND + - GATEWAY + type: string + listener: + description: Match on envoy listener attributes. + properties: + filterChain: + description: Match a specific filter chain in a listener. + properties: + applicationProtocols: + description: Applies only to sidecars. + type: string + destinationPort: + description: The destination_port value used by + a filter chain's match condition. + type: integer + filter: + description: The name of a specific filter to apply + the patch to. + properties: + name: + description: The filter name to match on. + type: string + subFilter: + properties: + name: + description: The filter name to match on. + type: string + type: object + type: object + name: + description: The name assigned to the filter chain. + type: string + sni: + description: The SNI value used by a filter chain's + match condition. + type: string + transportProtocol: + description: Applies only to `SIDECAR_INBOUND` context. + type: string + type: object + name: + description: Match a specific listener by its name. + type: string + portName: + type: string + portNumber: + type: integer + type: object + proxy: + description: Match on properties associated with a proxy. + properties: + metadata: + additionalProperties: + type: string + type: object + proxyVersion: + type: string + type: object + routeConfiguration: + description: Match on envoy HTTP route configuration attributes. + properties: + gateway: + type: string + name: + description: Route configuration name to match on. + type: string + portName: + description: Applicable only for GATEWAY context. + type: string + portNumber: + type: integer + vhost: + properties: + name: + type: string + route: + description: Match a specific route within the virtual + host. + properties: + action: + description: Match a route with specific action + type. + enum: + - ANY + - ROUTE + - REDIRECT + - DIRECT_RESPONSE + type: string + name: + type: string + type: object + type: object + type: object + type: object + patch: + description: The patch to apply along with the operation. + properties: + filterClass: + description: Determines the filter insertion order. + enum: + - UNSPECIFIED + - AUTHN + - AUTHZ + - STATS + type: string + operation: + description: Determines how the patch should be applied. + enum: + - INVALID + - MERGE + - ADD + - REMOVE + - INSERT_BEFORE + - INSERT_AFTER + - INSERT_FIRST + - REPLACE + type: string + value: + description: The JSON config of the object being patched. + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + type: array + priority: + description: Priority defines the order in which patch sets are applied + within a context. + format: int32 + type: integer + workloadSelector: + properties: + labels: + additionalProperties: + type: string + type: object + type: object + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: gateways.networking.istio.io +spec: + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: Gateway + listKind: GatewayList + plural: gateways + shortNames: + - gw + singular: gateway + scope: Namespaced + versions: + - name: v1alpha3 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting edge load balancer. See more details + at: https://istio.io/docs/reference/config/networking/gateway.html' + properties: + selector: + additionalProperties: + type: string + type: object + servers: + description: A list of server specifications. + items: + properties: + bind: + type: string + defaultEndpoint: + type: string + hosts: + description: One or more hosts exposed by this gateway. + items: + type: string + type: array + name: + description: An optional name of the server, when set must be + unique across all servers. + type: string + port: + properties: + name: + description: Label assigned to the port. + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + type: string + targetPort: + type: integer + type: object + tls: + description: Set of TLS related options that govern the server's + behavior. + properties: + caCertificates: + description: REQUIRED if mode is `MUTUAL`. + type: string + cipherSuites: + description: 'Optional: If specified, only support the specified + cipher list.' + items: + type: string + type: array + credentialName: + type: string + httpsRedirect: + type: boolean + maxProtocolVersion: + description: 'Optional: Maximum TLS protocol version.' + enum: + - TLS_AUTO + - TLSV1_0 + - TLSV1_1 + - TLSV1_2 + - TLSV1_3 + type: string + minProtocolVersion: + description: 'Optional: Minimum TLS protocol version.' + enum: + - TLS_AUTO + - TLSV1_0 + - TLSV1_1 + - TLSV1_2 + - TLSV1_3 + type: string + mode: + enum: + - PASSTHROUGH + - SIMPLE + - MUTUAL + - AUTO_PASSTHROUGH + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `SIMPLE` or `MUTUAL`. + type: string + serverCertificate: + description: REQUIRED if mode is `SIMPLE` or `MUTUAL`. + type: string + subjectAltNames: + items: + type: string + type: array + verifyCertificateHash: + items: + type: string + type: array + verifyCertificateSpki: + items: + type: string + type: array + type: object + type: object + type: array + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} + - name: v1beta1 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting edge load balancer. See more details + at: https://istio.io/docs/reference/config/networking/gateway.html' + properties: + selector: + additionalProperties: + type: string + type: object + servers: + description: A list of server specifications. + items: + properties: + bind: + type: string + defaultEndpoint: + type: string + hosts: + description: One or more hosts exposed by this gateway. + items: + type: string + type: array + name: + description: An optional name of the server, when set must be + unique across all servers. + type: string + port: + properties: + name: + description: Label assigned to the port. + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + type: string + targetPort: + type: integer + type: object + tls: + description: Set of TLS related options that govern the server's + behavior. + properties: + caCertificates: + description: REQUIRED if mode is `MUTUAL`. + type: string + cipherSuites: + description: 'Optional: If specified, only support the specified + cipher list.' + items: + type: string + type: array + credentialName: + type: string + httpsRedirect: + type: boolean + maxProtocolVersion: + description: 'Optional: Maximum TLS protocol version.' + enum: + - TLS_AUTO + - TLSV1_0 + - TLSV1_1 + - TLSV1_2 + - TLSV1_3 + type: string + minProtocolVersion: + description: 'Optional: Minimum TLS protocol version.' + enum: + - TLS_AUTO + - TLSV1_0 + - TLSV1_1 + - TLSV1_2 + - TLSV1_3 + type: string + mode: + enum: + - PASSTHROUGH + - SIMPLE + - MUTUAL + - AUTO_PASSTHROUGH + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `SIMPLE` or `MUTUAL`. + type: string + serverCertificate: + description: REQUIRED if mode is `SIMPLE` or `MUTUAL`. + type: string + subjectAltNames: + items: + type: string + type: array + verifyCertificateHash: + items: + type: string + type: array + verifyCertificateSpki: + items: + type: string + type: array + type: object + type: object + type: array + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: serviceentries.networking.istio.io +spec: + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: ServiceEntry + listKind: ServiceEntryList + plural: serviceentries + shortNames: + - se + singular: serviceentry + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The hosts associated with the ServiceEntry + jsonPath: .spec.hosts + name: Hosts + type: string + - description: Whether the service is external to the mesh or part of the mesh + (MESH_EXTERNAL or MESH_INTERNAL) + jsonPath: .spec.location + name: Location + type: string + - description: Service discovery mode for the hosts (NONE, STATIC, or DNS) + jsonPath: .spec.resolution + name: Resolution + type: string + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha3 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting service registry. See more details + at: https://istio.io/docs/reference/config/networking/service-entry.html' + properties: + addresses: + description: The virtual IP addresses associated with the service. + items: + type: string + type: array + endpoints: + description: One or more endpoints associated with the service. + items: + properties: + address: + type: string + labels: + additionalProperties: + type: string + description: One or more labels associated with the endpoint. + type: object + locality: + description: The locality associated with the endpoint. + type: string + network: + type: string + ports: + additionalProperties: + type: integer + description: Set of ports associated with the endpoint. + type: object + serviceAccount: + type: string + weight: + description: The load balancing weight associated with the endpoint. + type: integer + type: object + type: array + exportTo: + description: A list of namespaces to which this service is exported. + items: + type: string + type: array + hosts: + description: The hosts associated with the ServiceEntry. + items: + type: string + type: array + location: + enum: + - MESH_EXTERNAL + - MESH_INTERNAL + type: string + ports: + description: The ports associated with the external service. + items: + properties: + name: + description: Label assigned to the port. + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + type: string + targetPort: + type: integer + type: object + type: array + resolution: + description: Service discovery mode for the hosts. + enum: + - NONE + - STATIC + - DNS + - DNS_ROUND_ROBIN + type: string + subjectAltNames: + items: + type: string + type: array + workloadSelector: + description: Applicable only for MESH_INTERNAL services. + properties: + labels: + additionalProperties: + type: string + type: object + type: object + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - description: The hosts associated with the ServiceEntry + jsonPath: .spec.hosts + name: Hosts + type: string + - description: Whether the service is external to the mesh or part of the mesh + (MESH_EXTERNAL or MESH_INTERNAL) + jsonPath: .spec.location + name: Location + type: string + - description: Service discovery mode for the hosts (NONE, STATIC, or DNS) + jsonPath: .spec.resolution + name: Resolution + type: string + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting service registry. See more details + at: https://istio.io/docs/reference/config/networking/service-entry.html' + properties: + addresses: + description: The virtual IP addresses associated with the service. + items: + type: string + type: array + endpoints: + description: One or more endpoints associated with the service. + items: + properties: + address: + type: string + labels: + additionalProperties: + type: string + description: One or more labels associated with the endpoint. + type: object + locality: + description: The locality associated with the endpoint. + type: string + network: + type: string + ports: + additionalProperties: + type: integer + description: Set of ports associated with the endpoint. + type: object + serviceAccount: + type: string + weight: + description: The load balancing weight associated with the endpoint. + type: integer + type: object + type: array + exportTo: + description: A list of namespaces to which this service is exported. + items: + type: string + type: array + hosts: + description: The hosts associated with the ServiceEntry. + items: + type: string + type: array + location: + enum: + - MESH_EXTERNAL + - MESH_INTERNAL + type: string + ports: + description: The ports associated with the external service. + items: + properties: + name: + description: Label assigned to the port. + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + type: string + targetPort: + type: integer + type: object + type: array + resolution: + description: Service discovery mode for the hosts. + enum: + - NONE + - STATIC + - DNS + - DNS_ROUND_ROBIN + type: string + subjectAltNames: + items: + type: string + type: array + workloadSelector: + description: Applicable only for MESH_INTERNAL services. + properties: + labels: + additionalProperties: + type: string + type: object + type: object + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: sidecars.networking.istio.io +spec: + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: Sidecar + listKind: SidecarList + plural: sidecars + singular: sidecar + scope: Namespaced + versions: + - name: v1alpha3 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting network reachability of a sidecar. + See more details at: https://istio.io/docs/reference/config/networking/sidecar.html' + properties: + egress: + items: + properties: + bind: type: string - type: array - port: - description: The port associated with the listener. + captureMode: + enum: + - DEFAULT + - IPTABLES + - NONE + type: string + hosts: + items: + type: string + type: array + port: + description: The port associated with the listener. + properties: + name: + description: Label assigned to the port. + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + type: string + targetPort: + type: integer + type: object + type: object + type: array + ingress: + items: + properties: + bind: + description: The IP to which the listener should be bound. + type: string + captureMode: + enum: + - DEFAULT + - IPTABLES + - NONE + type: string + defaultEndpoint: + type: string + port: + description: The port associated with the listener. + properties: + name: + description: Label assigned to the port. + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + type: string + targetPort: + type: integer + type: object + type: object + type: array + outboundTrafficPolicy: + description: Configuration for the outbound traffic policy. + properties: + egressProxy: properties: - name: - description: Label assigned to the port. - format: string + host: + description: The name of a service from the service registry. type: string - number: - description: A valid non-negative integer port number. - type: integer - protocol: - description: The protocol exposed on the port. - format: string + port: + description: Specifies the port on the host that is being + addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. type: string - targetPort: - type: integer type: object - type: object - type: array - ingress: - items: - properties: - bind: - description: The IP to which the listener should be bound. - format: string - type: string - captureMode: + mode: enum: - - DEFAULT - - IPTABLES - - NONE + - REGISTRY_ONLY + - ALLOW_ANY type: string - defaultEndpoint: - format: string - type: string - port: - description: The port associated with the listener. - properties: - name: - description: Label assigned to the port. - format: string - type: string - number: - description: A valid non-negative integer port number. - type: integer - protocol: - description: The protocol exposed on the port. - format: string - type: string - targetPort: - type: integer + type: object + workloadSelector: + properties: + labels: + additionalProperties: + type: string type: object type: object - type: array - outboundTrafficPolicy: - description: Configuration for the outbound traffic policy. - properties: - egressProxy: + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} + - name: v1beta1 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting network reachability of a sidecar. + See more details at: https://istio.io/docs/reference/config/networking/sidecar.html' + properties: + egress: + items: properties: - host: - description: The name of a service from the service registry. - format: string + bind: type: string + captureMode: + enum: + - DEFAULT + - IPTABLES + - NONE + type: string + hosts: + items: + type: string + type: array port: - description: Specifies the port on the host that is being addressed. + description: The port associated with the listener. properties: + name: + description: Label assigned to the port. + type: string number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + type: string + targetPort: type: integer type: object - subset: - description: The name of a subset within the service. - format: string + type: object + type: array + ingress: + items: + properties: + bind: + description: The IP to which the listener should be bound. + type: string + captureMode: + enum: + - DEFAULT + - IPTABLES + - NONE + type: string + defaultEndpoint: type: string + port: + description: The port associated with the listener. + properties: + name: + description: Label assigned to the port. + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + type: string + targetPort: + type: integer + type: object type: object - mode: - enum: - - REGISTRY_ONLY - - ALLOW_ANY - type: string - type: object - workloadSelector: - properties: - labels: - additionalProperties: - format: string + type: array + outboundTrafficPolicy: + description: Configuration for the outbound traffic policy. + properties: + egressProxy: + properties: + host: + description: The name of a service from the service registry. + type: string + port: + description: Specifies the port on the host that is being + addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + type: string + type: object + mode: + enum: + - REGISTRY_ONLY + - ALLOW_ANY type: string - type: object - type: object - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - versions: - - name: v1alpha3 - served: true - storage: true - - name: v1beta1 + type: object + workloadSelector: + properties: + labels: + additionalProperties: + type: string + type: object + type: object + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object served: true storage: false + subresources: + status: {} --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: @@ -1923,23 +3491,6 @@ metadata: release: istio name: virtualservices.networking.istio.io spec: - additionalPrinterColumns: - - JSONPath: .spec.gateways - description: The names of gateways and sidecars that should apply these routes - name: Gateways - type: string - - JSONPath: .spec.hosts - description: The destination hosts to which traffic is being sent - name: Hosts - type: string - - JSONPath: .metadata.creationTimestamp - description: 'CreationTimestamp is a timestamp representing the server time when - this object was created. It is not guaranteed to be set in happens-before order - across separate operations. Clients may not set this value. It is represented - in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for - lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' - name: Age - type: date group: networking.istio.io names: categories: @@ -1951,268 +3502,974 @@ spec: shortNames: - vs singular: virtualservice - preserveUnknownFields: false scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: 'Configuration affecting label/content routing, sni routing, - etc. See more details at: https://istio.io/docs/reference/config/networking/virtual-service.html' - properties: - exportTo: - description: A list of namespaces to which this virtual service is exported. - items: - format: string - type: string - type: array - gateways: - description: The names of gateways and sidecars that should apply these - routes. - items: - format: string - type: string - type: array - hosts: - description: The destination hosts to which traffic is being sent. - items: - format: string - type: string - type: array - http: - description: An ordered list of route rules for HTTP traffic. - items: - properties: - corsPolicy: - description: Cross-Origin Resource Sharing policy (CORS). - properties: - allowCredentials: - nullable: true - type: boolean - allowHeaders: - items: - format: string + versions: + - additionalPrinterColumns: + - description: The names of gateways and sidecars that should apply these routes + jsonPath: .spec.gateways + name: Gateways + type: string + - description: The destination hosts to which traffic is being sent + jsonPath: .spec.hosts + name: Hosts + type: string + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha3 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting label/content routing, sni routing, + etc. See more details at: https://istio.io/docs/reference/config/networking/virtual-service.html' + properties: + exportTo: + description: A list of namespaces to which this virtual service is + exported. + items: + type: string + type: array + gateways: + description: The names of gateways and sidecars that should apply + these routes. + items: + type: string + type: array + hosts: + description: The destination hosts to which traffic is being sent. + items: + type: string + type: array + http: + description: An ordered list of route rules for HTTP traffic. + items: + properties: + corsPolicy: + description: Cross-Origin Resource Sharing policy (CORS). + properties: + allowCredentials: + nullable: true + type: boolean + allowHeaders: + items: + type: string + type: array + allowMethods: + description: List of HTTP methods allowed to access the + resource. + items: + type: string + type: array + allowOrigin: + description: The list of origins that are allowed to perform + CORS requests. + items: + type: string + type: array + allowOrigins: + description: String patterns that match allowed origins. + items: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + type: array + exposeHeaders: + items: + type: string + type: array + maxAge: type: string - type: array - allowMethods: - description: List of HTTP methods allowed to access the resource. - items: - format: string + type: object + delegate: + properties: + name: + description: Name specifies the name of the delegate VirtualService. type: string - type: array - allowOrigin: - description: The list of origins that are allowed to perform - CORS requests. - items: - format: string + namespace: + description: Namespace specifies the namespace where the + delegate VirtualService resides. type: string - type: array - allowOrigins: - description: String patterns that match allowed origins. - items: + type: object + fault: + description: Fault injection policy to apply on HTTP traffic + at the client side. + properties: + abort: + oneOf: + - not: + anyOf: + - required: + - httpStatus + - required: + - grpcStatus + - required: + - http2Error + - required: + - httpStatus + - required: + - grpcStatus + - required: + - http2Error + properties: + grpcStatus: + type: string + http2Error: + type: string + httpStatus: + description: HTTP status code to use to abort the Http + request. + format: int32 + type: integer + percentage: + description: Percentage of requests to be aborted with + the error code provided. + properties: + value: + format: double + type: number + type: object + type: object + delay: oneOf: - not: anyOf: + - required: + - fixedDelay + - required: + - exponentialDelay + - required: + - fixedDelay + - required: + - exponentialDelay + properties: + exponentialDelay: + type: string + fixedDelay: + description: Add a fixed delay before forwarding the + request. + type: string + percent: + description: Percentage of requests on which the delay + will be injected (0-100). + format: int32 + type: integer + percentage: + description: Percentage of requests on which the delay + will be injected. + properties: + value: + format: double + type: number + type: object + type: object + type: object + headers: + properties: + request: + properties: + add: + additionalProperties: + type: string + type: object + remove: + items: + type: string + type: array + set: + additionalProperties: + type: string + type: object + type: object + response: + properties: + add: + additionalProperties: + type: string + type: object + remove: + items: + type: string + type: array + set: + additionalProperties: + type: string + type: object + type: object + type: object + match: + items: + properties: + authority: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + gateways: + description: Names of gateways where the rule should be + applied. + items: + type: string + type: array + headers: + additionalProperties: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex - required: - exact - required: - prefix - required: - regex - - required: - - exact - - required: - - prefix - - required: - - regex - properties: - exact: - format: string - type: string - prefix: - format: string - type: string - regex: - description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). - format: string - type: string - type: object - type: array - exposeHeaders: - items: - format: string - type: string - type: array - maxAge: - type: string - type: object - delegate: - properties: - name: - description: Name specifies the name of the delegate VirtualService. - format: string - type: string - namespace: - description: Namespace specifies the namespace where the delegate - VirtualService resides. - format: string - type: string - type: object - fault: - description: Fault injection policy to apply on HTTP traffic at - the client side. - properties: - abort: - oneOf: - - not: - anyOf: + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + type: object + ignoreUriCase: + description: Flag to specify whether the URI matching + should be case-insensitive. + type: boolean + method: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex - required: - - httpStatus + - exact - required: - - grpcStatus + - prefix - required: - - http2Error - - required: - - httpStatus - - required: - - grpcStatus - - required: - - http2Error - properties: - grpcStatus: - format: string - type: string - http2Error: - format: string + - regex + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + name: + description: The name assigned to a match. type: string - httpStatus: - description: HTTP status code to use to abort the Http - request. - format: int32 + port: + description: Specifies the ports on the host that is being + addressed. type: integer - percentage: - description: Percentage of requests to be aborted with - the error code provided. + queryParams: + additionalProperties: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + description: Query parameters for matching. + type: object + scheme: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex + - required: + - exact + - required: + - prefix + - required: + - regex properties: - value: - format: double - type: number + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + sourceLabels: + additionalProperties: + type: string + type: object + sourceNamespace: + description: Source namespace constraining the applicability + of a rule to workloads in that namespace. + type: string + uri: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + withoutHeaders: + additionalProperties: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + description: withoutHeader has the same syntax with the + header, but has opposite meaning. + type: object + type: object + type: array + mirror: + properties: + host: + description: The name of a service from the service registry. + type: string + port: + description: Specifies the port on the host that is being + addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + type: string + type: object + mirror_percent: + description: Percentage of the traffic to be mirrored by the + `mirror` field. + nullable: true + type: integer + mirrorPercent: + description: Percentage of the traffic to be mirrored by the + `mirror` field. + nullable: true + type: integer + mirrorPercentage: + description: Percentage of the traffic to be mirrored by the + `mirror` field. + properties: + value: + format: double + type: number + type: object + name: + description: The name assigned to the route for debugging purposes. + type: string + redirect: + description: A HTTP rule can either redirect or forward (default) + traffic. + oneOf: + - not: + anyOf: + - required: + - port + - required: + - derivePort + - required: + - port + - required: + - derivePort + properties: + authority: + type: string + derivePort: + enum: + - FROM_PROTOCOL_DEFAULT + - FROM_REQUEST_PORT + type: string + port: + description: On a redirect, overwrite the port portion of + the URL with this value. + type: integer + redirectCode: + type: integer + scheme: + description: On a redirect, overwrite the scheme portion + of the URL with this value. + type: string + uri: + type: string + type: object + retries: + description: Retry policy for HTTP requests. + properties: + attempts: + description: Number of retries to be allowed for a given + request. + format: int32 + type: integer + perTryTimeout: + description: Timeout per attempt for a given request, including + the initial call and any retries. + type: string + retryOn: + description: Specifies the conditions under which retry + takes place. + type: string + retryRemoteLocalities: + description: Flag to specify whether the retries should + retry to other localities. + nullable: true + type: boolean + type: object + rewrite: + description: Rewrite HTTP URIs and Authority headers. + properties: + authority: + description: rewrite the Authority/Host header with this + value. + type: string + uri: + type: string + type: object + route: + description: A HTTP rule can either redirect or forward (default) + traffic. + items: + properties: + destination: + properties: + host: + description: The name of a service from the service + registry. + type: string + port: + description: Specifies the port on the host that is + being addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + type: string + type: object + headers: + properties: + request: + properties: + add: + additionalProperties: + type: string + type: object + remove: + items: + type: string + type: array + set: + additionalProperties: + type: string + type: object + type: object + response: + properties: + add: + additionalProperties: + type: string + type: object + remove: + items: + type: string + type: array + set: + additionalProperties: + type: string + type: object + type: object type: object - type: object - delay: - oneOf: - - not: - anyOf: - - required: - - fixedDelay - - required: - - exponentialDelay - - required: - - fixedDelay - - required: - - exponentialDelay - properties: - exponentialDelay: - type: string - fixedDelay: - description: Add a fixed delay before forwarding the request. - type: string - percent: - description: Percentage of requests on which the delay - will be injected (0-100). + weight: format: int32 type: integer - percentage: - description: Percentage of requests on which the delay - will be injected. - properties: - value: - format: double - type: number - type: object type: object - type: object - headers: - properties: - request: + type: array + timeout: + description: Timeout for HTTP requests, default is disabled. + type: string + type: object + type: array + tcp: + description: An ordered list of route rules for opaque TCP traffic. + items: + properties: + match: + items: properties: - add: - additionalProperties: - format: string + destinationSubnets: + description: IPv4 or IPv6 ip addresses of destination + with optional subnet. + items: type: string - type: object - remove: + type: array + gateways: + description: Names of gateways where the rule should be + applied. items: - format: string type: string type: array - set: + port: + description: Specifies the port on the host that is being + addressed. + type: integer + sourceLabels: additionalProperties: - format: string type: string type: object + sourceNamespace: + description: Source namespace constraining the applicability + of a rule to workloads in that namespace. + type: string + sourceSubnet: + description: IPv4 or IPv6 ip address of source with optional + subnet. + type: string type: object - response: + type: array + route: + description: The destination to which the connection should + be forwarded to. + items: properties: - add: - additionalProperties: - format: string - type: string + destination: + properties: + host: + description: The name of a service from the service + registry. + type: string + port: + description: Specifies the port on the host that is + being addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + type: string type: object - remove: + weight: + format: int32 + type: integer + type: object + type: array + type: object + type: array + tls: + items: + properties: + match: + items: + properties: + destinationSubnets: + description: IPv4 or IPv6 ip addresses of destination + with optional subnet. + items: + type: string + type: array + gateways: + description: Names of gateways where the rule should be + applied. + items: + type: string + type: array + port: + description: Specifies the port on the host that is being + addressed. + type: integer + sniHosts: + description: SNI (server name indicator) to match on. items: - format: string type: string type: array - set: + sourceLabels: additionalProperties: - format: string type: string type: object + sourceNamespace: + description: Source namespace constraining the applicability + of a rule to workloads in that namespace. + type: string type: object - type: object - match: - items: + type: array + route: + description: The destination to which the connection should + be forwarded to. + items: + properties: + destination: + properties: + host: + description: The name of a service from the service + registry. + type: string + port: + description: Specifies the port on the host that is + being addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + type: string + type: object + weight: + format: int32 + type: integer + type: object + type: array + type: object + type: array + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - description: The names of gateways and sidecars that should apply these routes + jsonPath: .spec.gateways + name: Gateways + type: string + - description: The destination hosts to which traffic is being sent + jsonPath: .spec.hosts + name: Hosts + type: string + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting label/content routing, sni routing, + etc. See more details at: https://istio.io/docs/reference/config/networking/virtual-service.html' + properties: + exportTo: + description: A list of namespaces to which this virtual service is + exported. + items: + type: string + type: array + gateways: + description: The names of gateways and sidecars that should apply + these routes. + items: + type: string + type: array + hosts: + description: The destination hosts to which traffic is being sent. + items: + type: string + type: array + http: + description: An ordered list of route rules for HTTP traffic. + items: + properties: + corsPolicy: + description: Cross-Origin Resource Sharing policy (CORS). properties: - authority: + allowCredentials: + nullable: true + type: boolean + allowHeaders: + items: + type: string + type: array + allowMethods: + description: List of HTTP methods allowed to access the + resource. + items: + type: string + type: array + allowOrigin: + description: The list of origins that are allowed to perform + CORS requests. + items: + type: string + type: array + allowOrigins: + description: String patterns that match allowed origins. + items: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + type: array + exposeHeaders: + items: + type: string + type: array + maxAge: + type: string + type: object + delegate: + properties: + name: + description: Name specifies the name of the delegate VirtualService. + type: string + namespace: + description: Namespace specifies the namespace where the + delegate VirtualService resides. + type: string + type: object + fault: + description: Fault injection policy to apply on HTTP traffic + at the client side. + properties: + abort: oneOf: - not: anyOf: - required: - - exact + - httpStatus - required: - - prefix + - grpcStatus - required: - - regex + - http2Error - required: - - exact + - httpStatus - required: - - prefix + - grpcStatus - required: - - regex + - http2Error properties: - exact: - format: string + grpcStatus: + type: string + http2Error: type: string - prefix: - format: string + httpStatus: + description: HTTP status code to use to abort the Http + request. + format: int32 + type: integer + percentage: + description: Percentage of requests to be aborted with + the error code provided. + properties: + value: + format: double + type: number + type: object + type: object + delay: + oneOf: + - not: + anyOf: + - required: + - fixedDelay + - required: + - exponentialDelay + - required: + - fixedDelay + - required: + - exponentialDelay + properties: + exponentialDelay: type: string - regex: - description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). - format: string + fixedDelay: + description: Add a fixed delay before forwarding the + request. type: string + percent: + description: Percentage of requests on which the delay + will be injected (0-100). + format: int32 + type: integer + percentage: + description: Percentage of requests on which the delay + will be injected. + properties: + value: + format: double + type: number + type: object type: object - gateways: - description: Names of gateways where the rule should be - applied. - items: - format: string - type: string - type: array - headers: - additionalProperties: + type: object + headers: + properties: + request: + properties: + add: + additionalProperties: + type: string + type: object + remove: + items: + type: string + type: array + set: + additionalProperties: + type: string + type: object + type: object + response: + properties: + add: + additionalProperties: + type: string + type: object + remove: + items: + type: string + type: array + set: + additionalProperties: + type: string + type: object + type: object + type: object + match: + items: + properties: + authority: oneOf: - not: anyOf: @@ -2230,59 +4487,51 @@ spec: - regex properties: exact: - format: string type: string prefix: - format: string type: string regex: description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). - format: string type: string type: object - type: object - ignoreUriCase: - description: Flag to specify whether the URI matching should - be case-insensitive. - type: boolean - method: - oneOf: - - not: - anyOf: + gateways: + description: Names of gateways where the rule should be + applied. + items: + type: string + type: array + headers: + additionalProperties: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex - required: - exact - required: - prefix - required: - regex - - required: - - exact - - required: - - prefix - - required: - - regex - properties: - exact: - format: string - type: string - prefix: - format: string - type: string - regex: - description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). - format: string - type: string - type: object - name: - description: The name assigned to a match. - format: string - type: string - port: - description: Specifies the ports on the host that is being - addressed. - type: integer - queryParams: - additionalProperties: + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + type: object + ignoreUriCase: + description: Flag to specify whether the URI matching + should be case-insensitive. + type: boolean + method: oneOf: - not: anyOf: @@ -2300,86 +4549,82 @@ spec: - regex properties: exact: - format: string type: string prefix: - format: string type: string regex: description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). - format: string type: string type: object - description: Query parameters for matching. - type: object - scheme: - oneOf: - - not: - anyOf: + name: + description: The name assigned to a match. + type: string + port: + description: Specifies the ports on the host that is being + addressed. + type: integer + queryParams: + additionalProperties: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex - required: - exact - required: - prefix - required: - regex - - required: - - exact - - required: - - prefix - - required: - - regex - properties: - exact: - format: string - type: string - prefix: - format: string - type: string - regex: - description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). - format: string + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + description: Query parameters for matching. + type: object + scheme: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string + type: object + sourceLabels: + additionalProperties: type: string - type: object - sourceLabels: - additionalProperties: - format: string + type: object + sourceNamespace: + description: Source namespace constraining the applicability + of a rule to workloads in that namespace. type: string - type: object - sourceNamespace: - description: Source namespace constraining the applicability - of a rule to workloads in that namespace. - format: string - type: string - uri: - oneOf: - - not: - anyOf: - - required: - - exact - - required: - - prefix - - required: - - regex - - required: - - exact - - required: - - prefix - - required: - - regex - properties: - exact: - format: string - type: string - prefix: - format: string - type: string - regex: - description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). - format: string - type: string - type: object - withoutHeaders: - additionalProperties: + uri: oneOf: - not: anyOf: @@ -2397,340 +4642,357 @@ spec: - regex properties: exact: - format: string type: string prefix: - format: string type: string regex: description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). - format: string type: string type: object - description: withoutHeader has the same syntax with the - header, but has opposite meaning. - type: object - type: object - type: array - mirror: - properties: - host: - description: The name of a service from the service registry. - format: string - type: string - port: - description: Specifies the port on the host that is being - addressed. - properties: - number: - type: integer - type: object - subset: - description: The name of a subset within the service. - format: string - type: string - type: object - mirror_percent: - description: Percentage of the traffic to be mirrored by the `mirror` - field. - nullable: true - type: integer - mirrorPercent: - description: Percentage of the traffic to be mirrored by the `mirror` - field. - nullable: true - type: integer - mirrorPercentage: - description: Percentage of the traffic to be mirrored by the `mirror` - field. - properties: - value: - format: double - type: number - type: object - name: - description: The name assigned to the route for debugging purposes. - format: string - type: string - redirect: - description: A HTTP rule can either redirect or forward (default) - traffic. - properties: - authority: - format: string - type: string - redirectCode: - type: integer - uri: - format: string - type: string - type: object - retries: - description: Retry policy for HTTP requests. - properties: - attempts: - description: Number of retries to be allowed for a given request. - format: int32 - type: integer - perTryTimeout: - description: Timeout per retry attempt for a given request. - type: string - retryOn: - description: Specifies the conditions under which retry takes - place. - format: string - type: string - retryRemoteLocalities: - description: Flag to specify whether the retries should retry - to other localities. - nullable: true - type: boolean - type: object - rewrite: - description: Rewrite HTTP URIs and Authority headers. - properties: - authority: - description: rewrite the Authority/Host header with this value. - format: string - type: string - uri: - format: string - type: string - type: object - route: - description: A HTTP rule can either redirect or forward (default) - traffic. - items: - properties: - destination: - properties: - host: - description: The name of a service from the service - registry. - format: string - type: string - port: - description: Specifies the port on the host that is - being addressed. + withoutHeaders: + additionalProperties: + oneOf: + - not: + anyOf: + - required: + - exact + - required: + - prefix + - required: + - regex + - required: + - exact + - required: + - prefix + - required: + - regex properties: - number: - type: integer + exact: + type: string + prefix: + type: string + regex: + description: RE2 style regex-based match (https://github.com/google/re2/wiki/Syntax). + type: string type: object - subset: - description: The name of a subset within the service. - format: string - type: string - type: object - headers: + description: withoutHeader has the same syntax with the + header, but has opposite meaning. + type: object + type: object + type: array + mirror: + properties: + host: + description: The name of a service from the service registry. + type: string + port: + description: Specifies the port on the host that is being + addressed. properties: - request: - properties: - add: - additionalProperties: - format: string - type: string - type: object - remove: - items: - format: string - type: string - type: array - set: - additionalProperties: - format: string - type: string - type: object - type: object - response: - properties: - add: - additionalProperties: - format: string - type: string - type: object - remove: - items: - format: string - type: string - type: array - set: - additionalProperties: - format: string - type: string - type: object - type: object + number: + type: integer type: object - weight: - format: int32 - type: integer + subset: + description: The name of a subset within the service. + type: string type: object - type: array - timeout: - description: Timeout for HTTP requests, default is disabled. - type: string - type: object - type: array - tcp: - description: An ordered list of route rules for opaque TCP traffic. - items: - properties: - match: - items: + mirror_percent: + description: Percentage of the traffic to be mirrored by the + `mirror` field. + nullable: true + type: integer + mirrorPercent: + description: Percentage of the traffic to be mirrored by the + `mirror` field. + nullable: true + type: integer + mirrorPercentage: + description: Percentage of the traffic to be mirrored by the + `mirror` field. properties: - destinationSubnets: - description: IPv4 or IPv6 ip addresses of destination with - optional subnet. - items: - format: string - type: string - type: array - gateways: - description: Names of gateways where the rule should be - applied. - items: - format: string - type: string - type: array + value: + format: double + type: number + type: object + name: + description: The name assigned to the route for debugging purposes. + type: string + redirect: + description: A HTTP rule can either redirect or forward (default) + traffic. + oneOf: + - not: + anyOf: + - required: + - port + - required: + - derivePort + - required: + - port + - required: + - derivePort + properties: + authority: + type: string + derivePort: + enum: + - FROM_PROTOCOL_DEFAULT + - FROM_REQUEST_PORT + type: string port: - description: Specifies the port on the host that is being - addressed. + description: On a redirect, overwrite the port portion of + the URL with this value. type: integer - sourceLabels: - additionalProperties: - format: string - type: string - type: object - sourceNamespace: - description: Source namespace constraining the applicability - of a rule to workloads in that namespace. - format: string + redirectCode: + type: integer + scheme: + description: On a redirect, overwrite the scheme portion + of the URL with this value. type: string - sourceSubnet: - description: IPv4 or IPv6 ip address of source with optional - subnet. - format: string + uri: type: string type: object - type: array - route: - description: The destination to which the connection should be - forwarded to. - items: + retries: + description: Retry policy for HTTP requests. properties: - destination: - properties: - host: - description: The name of a service from the service - registry. - format: string - type: string - port: - description: Specifies the port on the host that is - being addressed. - properties: - number: - type: integer - type: object - subset: - description: The name of a subset within the service. - format: string - type: string - type: object - weight: + attempts: + description: Number of retries to be allowed for a given + request. format: int32 type: integer + perTryTimeout: + description: Timeout per attempt for a given request, including + the initial call and any retries. + type: string + retryOn: + description: Specifies the conditions under which retry + takes place. + type: string + retryRemoteLocalities: + description: Flag to specify whether the retries should + retry to other localities. + nullable: true + type: boolean type: object - type: array - type: object - type: array - tls: - items: - properties: - match: - items: + rewrite: + description: Rewrite HTTP URIs and Authority headers. properties: - destinationSubnets: - description: IPv4 or IPv6 ip addresses of destination with - optional subnet. - items: - format: string - type: string - type: array - gateways: - description: Names of gateways where the rule should be - applied. - items: - format: string - type: string - type: array - port: - description: Specifies the port on the host that is being - addressed. - type: integer - sniHosts: - description: SNI (server name indicator) to match on. - items: - format: string - type: string - type: array - sourceLabels: - additionalProperties: - format: string - type: string - type: object - sourceNamespace: - description: Source namespace constraining the applicability - of a rule to workloads in that namespace. - format: string + authority: + description: rewrite the Authority/Host header with this + value. + type: string + uri: type: string type: object - type: array - route: - description: The destination to which the connection should be - forwarded to. - items: - properties: - destination: - properties: - host: - description: The name of a service from the service - registry. - format: string - type: string - port: - description: Specifies the port on the host that is - being addressed. - properties: - number: - type: integer - type: object - subset: - description: The name of a subset within the service. - format: string + route: + description: A HTTP rule can either redirect or forward (default) + traffic. + items: + properties: + destination: + properties: + host: + description: The name of a service from the service + registry. + type: string + port: + description: Specifies the port on the host that is + being addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + type: string + type: object + headers: + properties: + request: + properties: + add: + additionalProperties: + type: string + type: object + remove: + items: + type: string + type: array + set: + additionalProperties: + type: string + type: object + type: object + response: + properties: + add: + additionalProperties: + type: string + type: object + remove: + items: + type: string + type: array + set: + additionalProperties: + type: string + type: object + type: object + type: object + weight: + format: int32 + type: integer + type: object + type: array + timeout: + description: Timeout for HTTP requests, default is disabled. + type: string + type: object + type: array + tcp: + description: An ordered list of route rules for opaque TCP traffic. + items: + properties: + match: + items: + properties: + destinationSubnets: + description: IPv4 or IPv6 ip addresses of destination + with optional subnet. + items: + type: string + type: array + gateways: + description: Names of gateways where the rule should be + applied. + items: + type: string + type: array + port: + description: Specifies the port on the host that is being + addressed. + type: integer + sourceLabels: + additionalProperties: + type: string + type: object + sourceNamespace: + description: Source namespace constraining the applicability + of a rule to workloads in that namespace. + type: string + sourceSubnet: + description: IPv4 or IPv6 ip address of source with optional + subnet. + type: string + type: object + type: array + route: + description: The destination to which the connection should + be forwarded to. + items: + properties: + destination: + properties: + host: + description: The name of a service from the service + registry. + type: string + port: + description: Specifies the port on the host that is + being addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + type: string + type: object + weight: + format: int32 + type: integer + type: object + type: array + type: object + type: array + tls: + items: + properties: + match: + items: + properties: + destinationSubnets: + description: IPv4 or IPv6 ip addresses of destination + with optional subnet. + items: type: string - type: object - weight: - format: int32 - type: integer - type: object - type: array - type: object - type: array - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - versions: - - name: v1alpha3 - served: true - storage: true - - name: v1beta1 + type: array + gateways: + description: Names of gateways where the rule should be + applied. + items: + type: string + type: array + port: + description: Specifies the port on the host that is being + addressed. + type: integer + sniHosts: + description: SNI (server name indicator) to match on. + items: + type: string + type: array + sourceLabels: + additionalProperties: + type: string + type: object + sourceNamespace: + description: Source namespace constraining the applicability + of a rule to workloads in that namespace. + type: string + type: object + type: array + route: + description: The destination to which the connection should + be forwarded to. + items: + properties: + destination: + properties: + host: + description: The name of a service from the service + registry. + type: string + port: + description: Specifies the port on the host that is + being addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + type: string + type: object + weight: + format: int32 + type: integer + type: object + type: array + type: object + type: array + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object served: true storage: false + subresources: + status: {} --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: @@ -2742,19 +5004,6 @@ metadata: release: istio name: workloadentries.networking.istio.io spec: - additionalPrinterColumns: - - JSONPath: .metadata.creationTimestamp - description: 'CreationTimestamp is a timestamp representing the server time when - this object was created. It is not guaranteed to be set in happens-before order - across separate operations. Clients may not set this value. It is represented - in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for - lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' - name: Age - type: date - - JSONPath: .spec.address - description: Address associated with the network endpoint. - name: Address - type: string group: networking.istio.io names: categories: @@ -2766,59 +5015,115 @@ spec: shortNames: - we singular: workloadentry - preserveUnknownFields: false scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: 'Configuration affecting VMs onboarded into the mesh. See more - details at: https://istio.io/docs/reference/config/networking/workload-entry.html' - properties: - address: - format: string - type: string - labels: - additionalProperties: - format: string + versions: + - additionalPrinterColumns: + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Address associated with the network endpoint. + jsonPath: .spec.address + name: Address + type: string + name: v1alpha3 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting VMs onboarded into the mesh. See + more details at: https://istio.io/docs/reference/config/networking/workload-entry.html' + properties: + address: + type: string + labels: + additionalProperties: + type: string + description: One or more labels associated with the endpoint. + type: object + locality: + description: The locality associated with the endpoint. + type: string + network: + type: string + ports: + additionalProperties: + type: integer + description: Set of ports associated with the endpoint. + type: object + serviceAccount: type: string - description: One or more labels associated with the endpoint. - type: object - locality: - description: The locality associated with the endpoint. - format: string - type: string - network: - format: string - type: string - ports: - additionalProperties: + weight: + description: The load balancing weight associated with the endpoint. type: integer - description: Set of ports associated with the endpoint. - type: object - serviceAccount: - format: string - type: string - weight: - description: The load balancing weight associated with the endpoint. - type: integer - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - versions: - - name: v1alpha3 + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object served: true storage: true - - name: v1beta1 + subresources: + status: {} + - additionalPrinterColumns: + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Address associated with the network endpoint. + jsonPath: .spec.address + name: Address + type: string + name: v1beta1 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting VMs onboarded into the mesh. See + more details at: https://istio.io/docs/reference/config/networking/workload-entry.html' + properties: + address: + type: string + labels: + additionalProperties: + type: string + description: One or more labels associated with the endpoint. + type: object + locality: + description: The locality associated with the endpoint. + type: string + network: + type: string + ports: + additionalProperties: + type: integer + description: Set of ports associated with the endpoint. + type: object + serviceAccount: + type: string + weight: + description: The load balancing weight associated with the endpoint. + type: integer + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object served: true storage: false + subresources: + status: {} --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: labels: @@ -2828,15 +5133,6 @@ metadata: release: istio name: workloadgroups.networking.istio.io spec: - additionalPrinterColumns: - - JSONPath: .metadata.creationTimestamp - description: 'CreationTimestamp is a timestamp representing the server time when - this object was created. It is not guaranteed to be set in happens-before order - across separate operations. Clients may not set this value. It is represented - in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for - lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' - name: Age - type: date group: networking.istio.io names: categories: @@ -2848,167 +5144,162 @@ spec: shortNames: - wg singular: workloadgroup - preserveUnknownFields: false scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: 'Describes a collection of workload instances. See more details - at: https://istio.io/docs/reference/config/networking/workload-group.html' - properties: - metadata: - description: Metadata that will be used for all corresponding `WorkloadEntries`. - properties: - annotations: - additionalProperties: - format: string - type: string - type: object - labels: - additionalProperties: - format: string - type: string - type: object - type: object - probe: - description: '`ReadinessProbe` describes the configuration the user - must provide for healthchecking on their workload.' - oneOf: - - not: - anyOf: - - required: - - httpGet - - required: - - tcpSocket - - required: - - exec - - required: - - httpGet - - required: - - tcpSocket - - required: - - exec - properties: - exec: - description: Health is determined by how the command that is executed - exited. - properties: - command: - description: Command to run. - items: - format: string - type: string - type: array - type: object - failureThreshold: - description: Minimum consecutive failures for the probe to be considered - failed after having succeeded. - format: int32 - type: integer - httpGet: - properties: - host: - description: Host name to connect to, defaults to the pod IP. - format: string - type: string - httpHeaders: - description: Headers the proxy will pass on to make the request. - items: - properties: - name: - format: string - type: string - value: - format: string - type: string - type: object - type: array - path: - description: Path to access on the HTTP server. - format: string + versions: + - additionalPrinterColumns: + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha3 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Describes a collection of workload instances. See more details + at: https://istio.io/docs/reference/config/networking/workload-group.html' + properties: + metadata: + description: Metadata that will be used for all corresponding `WorkloadEntries`. + properties: + annotations: + additionalProperties: type: string - port: - description: Port on which the endpoint lives. - type: integer - scheme: - format: string + type: object + labels: + additionalProperties: type: string - type: object - initialDelaySeconds: - description: Number of seconds after the container has started before - readiness probes are initiated. - format: int32 - type: integer - periodSeconds: - description: How often (in seconds) to perform the probe. - format: int32 - type: integer - successThreshold: - description: Minimum consecutive successes for the probe to be considered - successful after having failed. - format: int32 - type: integer - tcpSocket: - description: Health is determined by if the proxy is able to connect. - properties: - host: - format: string + type: object + type: object + probe: + description: '`ReadinessProbe` describes the configuration the user + must provide for healthchecking on their workload.' + oneOf: + - not: + anyOf: + - required: + - httpGet + - required: + - tcpSocket + - required: + - exec + - required: + - httpGet + - required: + - tcpSocket + - required: + - exec + properties: + exec: + description: Health is determined by how the command that is executed + exited. + properties: + command: + description: Command to run. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the probe to be + considered failed after having succeeded. + format: int32 + type: integer + httpGet: + properties: + host: + description: Host name to connect to, defaults to the pod + IP. + type: string + httpHeaders: + description: Headers the proxy will pass on to make the request. + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + description: Port on which the endpoint lives. + type: integer + scheme: + type: string + type: object + initialDelaySeconds: + description: Number of seconds after the container has started + before readiness probes are initiated. + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the probe. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the probe to be + considered successful after having failed. + format: int32 + type: integer + tcpSocket: + description: Health is determined by if the proxy is able to connect. + properties: + host: + type: string + port: + type: integer + type: object + timeoutSeconds: + description: Number of seconds after which the probe times out. + format: int32 + type: integer + type: object + template: + description: Template to be used for the generation of `WorkloadEntry` + resources that belong to this `WorkloadGroup`. + properties: + address: + type: string + labels: + additionalProperties: type: string - port: + description: One or more labels associated with the endpoint. + type: object + locality: + description: The locality associated with the endpoint. + type: string + network: + type: string + ports: + additionalProperties: type: integer - type: object - timeoutSeconds: - description: Number of seconds after which the probe times out. - format: int32 - type: integer - type: object - template: - description: Template to be used for the generation of `WorkloadEntry` - resources that belong to this `WorkloadGroup`. - properties: - address: - format: string - type: string - labels: - additionalProperties: - format: string + description: Set of ports associated with the endpoint. + type: object + serviceAccount: type: string - description: One or more labels associated with the endpoint. - type: object - locality: - description: The locality associated with the endpoint. - format: string - type: string - network: - format: string - type: string - ports: - additionalProperties: + weight: + description: The load balancing weight associated with the endpoint. type: integer - description: Set of ports associated with the endpoint. - type: object - serviceAccount: - format: string - type: string - weight: - description: The load balancing weight associated with the endpoint. - type: integer - type: object - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - versions: - - name: v1alpha3 + type: object + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object served: true storage: true + subresources: + status: {} --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: @@ -3026,221 +5317,197 @@ spec: categories: - istio-io - security-istio-io - kind: AuthorizationPolicy - listKind: AuthorizationPolicyList - plural: authorizationpolicies - singular: authorizationpolicy - preserveUnknownFields: false - scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: 'Configuration for access control on workloads. See more details - at: https://istio.io/docs/reference/config/security/authorization-policy.html' - oneOf: - - not: - anyOf: - - required: - - provider - - required: - - provider - properties: - action: - description: Optional. - enum: - - ALLOW - - DENY - - AUDIT - - CUSTOM - type: string - provider: - description: Specifies detailed configuration of the CUSTOM action. - properties: - name: - description: Specifies the name of the extension provider. - format: string - type: string - type: object - rules: - description: Optional. - items: - properties: - from: - description: Optional. - items: - properties: - source: - description: Source specifies the source of a request. - properties: - ipBlocks: - description: Optional. - items: - format: string - type: string - type: array - namespaces: - description: Optional. - items: - format: string - type: string - type: array - notIpBlocks: - description: Optional. - items: - format: string - type: string - type: array - notNamespaces: - description: Optional. - items: - format: string - type: string - type: array - notPrincipals: - description: Optional. - items: - format: string - type: string - type: array - notRemoteIpBlocks: - description: Optional. - items: - format: string - type: string - type: array - notRequestPrincipals: - description: Optional. - items: - format: string - type: string - type: array - principals: - description: Optional. - items: - format: string - type: string - type: array - remoteIpBlocks: - description: Optional. - items: - format: string - type: string - type: array - requestPrincipals: - description: Optional. - items: - format: string - type: string - type: array - type: object - type: object - type: array - to: - description: Optional. - items: - properties: - operation: - description: Operation specifies the operation of a request. - properties: - hosts: - description: Optional. - items: - format: string - type: string - type: array - methods: - description: Optional. - items: - format: string - type: string - type: array - notHosts: - description: Optional. - items: - format: string - type: string - type: array - notMethods: - description: Optional. - items: - format: string - type: string - type: array - notPaths: - description: Optional. - items: - format: string - type: string - type: array - notPorts: - description: Optional. - items: - format: string - type: string - type: array - paths: - description: Optional. - items: - format: string - type: string - type: array - ports: - description: Optional. - items: - format: string - type: string - type: array - type: object - type: object - type: array - when: - description: Optional. - items: - properties: - key: - description: The name of an Istio attribute. - format: string - type: string - notValues: - description: Optional. - items: - format: string - type: string - type: array - values: - description: Optional. - items: - format: string - type: string - type: array - type: object - type: array - type: object - type: array - selector: - description: Optional. - properties: - matchLabels: - additionalProperties: - format: string - type: string - type: object - type: object - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object + kind: AuthorizationPolicy + listKind: AuthorizationPolicyList + plural: authorizationpolicies + singular: authorizationpolicy + scope: Namespaced versions: - name: v1beta1 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Configuration for access control on workloads. See more + details at: https://istio.io/docs/reference/config/security/authorization-policy.html' + oneOf: + - not: + anyOf: + - required: + - provider + - required: + - provider + properties: + action: + description: Optional. + enum: + - ALLOW + - DENY + - AUDIT + - CUSTOM + type: string + provider: + description: Specifies detailed configuration of the CUSTOM action. + properties: + name: + description: Specifies the name of the extension provider. + type: string + type: object + rules: + description: Optional. + items: + properties: + from: + description: Optional. + items: + properties: + source: + description: Source specifies the source of a request. + properties: + ipBlocks: + description: Optional. + items: + type: string + type: array + namespaces: + description: Optional. + items: + type: string + type: array + notIpBlocks: + description: Optional. + items: + type: string + type: array + notNamespaces: + description: Optional. + items: + type: string + type: array + notPrincipals: + description: Optional. + items: + type: string + type: array + notRemoteIpBlocks: + description: Optional. + items: + type: string + type: array + notRequestPrincipals: + description: Optional. + items: + type: string + type: array + principals: + description: Optional. + items: + type: string + type: array + remoteIpBlocks: + description: Optional. + items: + type: string + type: array + requestPrincipals: + description: Optional. + items: + type: string + type: array + type: object + type: object + type: array + to: + description: Optional. + items: + properties: + operation: + description: Operation specifies the operation of a request. + properties: + hosts: + description: Optional. + items: + type: string + type: array + methods: + description: Optional. + items: + type: string + type: array + notHosts: + description: Optional. + items: + type: string + type: array + notMethods: + description: Optional. + items: + type: string + type: array + notPaths: + description: Optional. + items: + type: string + type: array + notPorts: + description: Optional. + items: + type: string + type: array + paths: + description: Optional. + items: + type: string + type: array + ports: + description: Optional. + items: + type: string + type: array + type: object + type: object + type: array + when: + description: Optional. + items: + properties: + key: + description: The name of an Istio attribute. + type: string + notValues: + description: Optional. + items: + type: string + type: array + values: + description: Optional. + items: + type: string + type: array + type: object + type: array + type: object + type: array + selector: + description: Optional. + properties: + matchLabels: + additionalProperties: + type: string + type: object + type: object + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object served: true storage: true + subresources: + status: {} --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: @@ -3253,19 +5520,6 @@ metadata: release: istio name: peerauthentications.security.istio.io spec: - additionalPrinterColumns: - - JSONPath: .spec.mtls.mode - description: Defines the mTLS mode used for peer authentication. - name: Mode - type: string - - JSONPath: .metadata.creationTimestamp - description: 'CreationTimestamp is a timestamp representing the server time when - this object was created. It is not guaranteed to be set in happens-before order - across separate operations. Clients may not set this value. It is represented - in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for - lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' - name: Age - type: date group: security.istio.io names: categories: @@ -3277,31 +5531,31 @@ spec: shortNames: - pa singular: peerauthentication - preserveUnknownFields: false scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: PeerAuthentication defines how traffic will be tunneled (or - not) to the sidecar. - properties: - mtls: - description: Mutual TLS settings for workload. - properties: - mode: - description: Defines the mTLS mode used for peer authentication. - enum: - - UNSET - - DISABLE - - PERMISSIVE - - STRICT - type: string - type: object - portLevelMtls: - additionalProperties: + versions: + - additionalPrinterColumns: + - description: Defines the mTLS mode used for peer authentication. + jsonPath: .spec.mtls.mode + name: Mode + type: string + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + properties: + spec: + description: PeerAuthentication defines how traffic will be tunneled (or + not) to the sidecar. + properties: + mtls: + description: Mutual TLS settings for workload. properties: mode: description: Defines the mTLS mode used for peer authentication. @@ -3312,30 +5566,41 @@ spec: - STRICT type: string type: object - description: Port specific mutual TLS settings. - type: object - selector: - description: The selector determines the workloads to apply the ChannelAuthentication - on. - properties: - matchLabels: - additionalProperties: - format: string - type: string + portLevelMtls: + additionalProperties: + properties: + mode: + description: Defines the mTLS mode used for peer authentication. + enum: + - UNSET + - DISABLE + - PERMISSIVE + - STRICT + type: string type: object - type: object - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - versions: - - name: v1beta1 + description: Port specific mutual TLS settings. + type: object + selector: + description: The selector determines the workloads to apply the ChannelAuthentication + on. + properties: + matchLabels: + additionalProperties: + type: string + type: object + type: object + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object served: true storage: true + subresources: + status: {} --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: @@ -3359,90 +5624,318 @@ spec: shortNames: - ra singular: requestauthentication - preserveUnknownFields: false scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - properties: - spec: - description: RequestAuthentication defines what request authentication methods - are supported by a workload. - properties: - jwtRules: - description: Define the list of JWTs that can be validated at the selected - workloads' proxy. - items: + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + properties: + spec: + description: RequestAuthentication defines what request authentication + methods are supported by a workload. + properties: + jwtRules: + description: Define the list of JWTs that can be validated at the + selected workloads' proxy. + items: + properties: + audiences: + items: + type: string + type: array + forwardOriginalToken: + description: If set to true, the original token will be kept + for the upstream request. + type: boolean + fromHeaders: + description: List of header locations from which JWT is expected. + items: + properties: + name: + description: The HTTP header name. + type: string + prefix: + description: The prefix that should be stripped before + decoding the token. + type: string + type: object + type: array + fromParams: + description: List of query parameters from which JWT is expected. + items: + type: string + type: array + issuer: + description: Identifies the issuer that issued the JWT. + type: string + jwks: + description: JSON Web Key Set of public keys to validate signature + of the JWT. + type: string + jwks_uri: + type: string + jwksUri: + type: string + outputPayloadToHeader: + type: string + type: object + type: array + selector: + description: Optional. properties: - audiences: - items: - format: string + matchLabels: + additionalProperties: type: string - type: array - forwardOriginalToken: - description: If set to true, the orginal token will be kept for - the ustream request. - type: boolean - fromHeaders: - description: List of header locations from which JWT is expected. - items: - properties: - name: - description: The HTTP header name. - format: string - type: string - prefix: - description: The prefix that should be stripped before decoding - the token. - format: string - type: string - type: object - type: array - fromParams: - description: List of query parameters from which JWT is expected. - items: - format: string + type: object + type: object + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + istio: telemetry + release: istio + name: telemetries.telemetry.istio.io +spec: + group: telemetry.istio.io + names: + categories: + - istio-io + - telemetry-istio-io + kind: Telemetry + listKind: TelemetryList + plural: telemetries + shortNames: + - telemetry + singular: telemetry + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: 'CreationTimestamp is a timestamp representing the server time + when this object was created. It is not guaranteed to be set in happens-before + order across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + spec: + description: 'Telemetry configuration for workloads. See more details + at: https://istio.io/docs/reference/config/telemetry.html' + properties: + accessLogging: + description: Optional. + items: + properties: + disabled: + description: Controls logging. + nullable: true + type: boolean + providers: + description: Optional. + items: + properties: + name: + description: Required. + type: string + type: object + type: array + type: object + type: array + metrics: + description: Optional. + items: + properties: + overrides: + description: Optional. + items: + properties: + disabled: + description: Optional. + nullable: true + type: boolean + match: + description: Match allows provides the scope of the override. + oneOf: + - not: + anyOf: + - required: + - metric + - required: + - customMetric + - required: + - metric + - required: + - customMetric + properties: + customMetric: + description: Allows free-form specification of a metric. + type: string + metric: + description: One of the well-known Istio Standard + Metrics. + enum: + - ALL_METRICS + - REQUEST_COUNT + - REQUEST_DURATION + - REQUEST_SIZE + - RESPONSE_SIZE + - TCP_OPENED_CONNECTIONS + - TCP_CLOSED_CONNECTIONS + - TCP_SENT_BYTES + - TCP_RECEIVED_BYTES + - GRPC_REQUEST_MESSAGES + - GRPC_RESPONSE_MESSAGES + type: string + mode: + description: 'Controls which mode of metrics generation + is selected: CLIENT and/or SERVER.' + enum: + - CLIENT_AND_SERVER + - CLIENT + - SERVER + type: string + type: object + tagOverrides: + additionalProperties: + properties: + operation: + description: Operation controls whether or not to + update/add a tag, or to remove it. + enum: + - UPSERT + - REMOVE + type: string + value: + description: Value is only considered if the operation + is `UPSERT`. + type: string + type: object + description: Optional. + type: object + type: object + type: array + providers: + description: Optional. + items: + properties: + name: + description: Required. + type: string + type: object + type: array + type: object + type: array + selector: + description: Optional. + properties: + matchLabels: + additionalProperties: type: string - type: array - issuer: - description: Identifies the issuer that issued the JWT. - format: string - type: string - jwks: - description: JSON Web Key Set of public keys to validate signature - of the JWT. - format: string - type: string - jwks_uri: - format: string - type: string - jwksUri: - format: string - type: string - outputPayloadToHeader: - format: string - type: string + type: object type: object - type: array - selector: - description: The selector determines the workloads to apply the RequestAuthentication - on. - properties: - matchLabels: - additionalProperties: - format: string - type: string + tracing: + description: Optional. + items: + properties: + customTags: + additionalProperties: + oneOf: + - not: + anyOf: + - required: + - literal + - required: + - environment + - required: + - header + - required: + - literal + - required: + - environment + - required: + - header + properties: + environment: + description: Environment adds the value of an environment + variable to each span. + properties: + defaultValue: + description: Optional. + type: string + name: + description: Name of the environment variable from + which to extract the tag value. + type: string + type: object + header: + description: RequestHeader adds the value of an header + from the request to each span. + properties: + defaultValue: + description: Optional. + type: string + name: + description: Name of the header from which to extract + the tag value. + type: string + type: object + literal: + description: Literal adds the same, hard-coded value to + each span. + properties: + value: + description: The tag value to use. + type: string + type: object + type: object + description: Optional. + type: object + disableSpanReporting: + description: Controls span reporting. + nullable: true + type: boolean + providers: + description: Optional. + items: + properties: + name: + description: Required. + type: string + type: object + type: array + randomSamplingPercentage: + nullable: true + type: number type: object - type: object - type: object - status: - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - versions: - - name: v1beta1 + type: array + type: object + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object served: true storage: true + subresources: + status: {} ---- \ No newline at end of file +--- diff --git a/test/e2e/crds/split.yaml b/test/e2e/crds/split.yaml index 04aa266b71..716b8552b9 100644 --- a/test/e2e/crds/split.yaml +++ b/test/e2e/crds/split.yaml @@ -1,25 +1,265 @@ --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: trafficsplits.split.smi-spec.io spec: group: split.smi-spec.io - version: v1alpha1 - scope: Namespaced names: kind: TrafficSplit listKind: TrafficSplitList + plural: trafficsplits shortNames: - ts - plural: trafficsplits singular: trafficsplit + scope: Namespaced versions: - name: v1alpha1 + schema: + openAPIV3Schema: + description: TrafficSplit is the Schema for the trafficsplits API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: TrafficSplitSpec defines the desired state of TrafficSplit + properties: + backends: + items: + description: TrafficSplitBackend defines a backend + properties: + service: + type: string + weight: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: array + service: + type: string + type: object + status: + description: TrafficSplitStatus defines the observed state of TrafficSplit + type: object + type: object + served: true + storage: false + subresources: + status: {} + - name: v1alpha2 + schema: + openAPIV3Schema: + description: TrafficSplit is the Schema for the trafficsplits API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: TrafficSplitSpec defines the desired state of TrafficSplit + properties: + backends: + items: + description: TrafficSplitBackend defines a backend + properties: + service: + type: string + weight: + type: integer + required: + - service + - weight + type: object + type: array + service: + type: string + type: object + status: + description: TrafficSplitStatus defines the observed state of TrafficSplit + type: object + type: object + served: true + storage: false + subresources: + status: {} + - name: v1alpha3 + schema: + openAPIV3Schema: + description: TrafficSplit is the Schema for the trafficsplits API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: TrafficSplitSpec defines the desired state of TrafficSplit + properties: + backends: + description: Backends defines a list of Kubernetes services used as + the traffic split destination + items: + description: TrafficSplitBackend defines a backend + properties: + service: + description: Service is the name of a Kubernetes service + type: string + weight: + description: Weight defines the traffic split percentage + type: integer + required: + - service + - weight + type: object + type: array + matches: + description: Matches allows defining a list of HTTP route groups that + this traffic split object should match + items: + description: TypedLocalObjectReference contains enough information + to let you locate the typed referenced object inside the same + namespace. + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + type: array + service: + description: Service represents the apex service + type: string + required: + - backends + - service + type: object + status: + description: TrafficSplitStatus defines the observed state of TrafficSplit + type: object + type: object + served: true + storage: false + subresources: + status: {} + - name: v1alpha4 + schema: + openAPIV3Schema: + description: TrafficSplit is the Schema for the trafficsplits API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: TrafficSplitSpec defines the desired state of TrafficSplit + properties: + backends: + description: Backends defines a list of Kubernetes services used as + the traffic split destination + items: + description: TrafficSplitBackend defines a backend + properties: + service: + description: Service is the name of a Kubernetes service + type: string + weight: + description: Weight defines the traffic split percentage + type: integer + required: + - service + - weight + type: object + type: array + matches: + description: Matches allows defining a list of HTTP route groups that + this traffic split object should match + items: + description: TypedLocalObjectReference contains enough information + to let you locate the typed referenced object inside the same + namespace. + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + type: array + service: + description: Service represents the apex service + type: string + required: + - backends + - service + type: object + status: + description: TrafficSplitStatus defines the observed state of TrafficSplit + type: object + type: object served: true storage: true - additionalPrinterColumns: - - name: Service - type: string - description: The apex service of this split. - JSONPath: .spec.service + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/test/e2e/functional/alb-bluegreen-rollout.yaml b/test/e2e/functional/alb-bluegreen-rollout.yaml index e06c2b5bea..3eedb62a8d 100644 --- a/test/e2e/functional/alb-bluegreen-rollout.yaml +++ b/test/e2e/functional/alb-bluegreen-rollout.yaml @@ -26,7 +26,7 @@ spec: selector: app: alb-bluegreen --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: alb-bluegreen-ingress @@ -37,9 +37,12 @@ spec: - http: paths: - path: /* + pathType: Prefix backend: - serviceName: alb-bluegreen-stable - servicePort: 80 + service: + name: alb-bluegreen-stable + port: + number: 80 --- apiVersion: argoproj.io/v1alpha1 kind: Rollout diff --git a/test/e2e/functional/alb-canary-rollout.yaml b/test/e2e/functional/alb-canary-rollout.yaml index df90ecc3cd..e05f73d2c2 100644 --- a/test/e2e/functional/alb-canary-rollout.yaml +++ b/test/e2e/functional/alb-canary-rollout.yaml @@ -40,7 +40,7 @@ spec: selector: app: alb-canary --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: alb-canary-ingress @@ -51,9 +51,12 @@ spec: - http: paths: - path: /* + pathType: Prefix backend: - serviceName: alb-canary-root - servicePort: use-annotation + service: + name: alb-canary-root + port: + name: use-annotation --- apiVersion: argoproj.io/v1alpha1 kind: Rollout diff --git a/test/e2e/functional/canary-dynamic-stable-scale.yaml b/test/e2e/functional/canary-dynamic-stable-scale.yaml index 612f684dea..aae5e8c324 100644 --- a/test/e2e/functional/canary-dynamic-stable-scale.yaml +++ b/test/e2e/functional/canary-dynamic-stable-scale.yaml @@ -38,7 +38,7 @@ spec: selector: app: dynamic-stable-scale --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: dynamic-stable-scale-ingress @@ -49,9 +49,12 @@ spec: - http: paths: - path: /* + pathType: Prefix backend: - serviceName: dynamic-stable-scale-root - servicePort: use-annotation + service: + name: dynamic-stable-scale-root + port: + name: use-annotation --- apiVersion: argoproj.io/v1alpha1 kind: Rollout diff --git a/test/e2e/functional/canary-scaledowndelay.yaml b/test/e2e/functional/canary-scaledowndelay.yaml index 21fc6a4d42..7d469fe929 100644 --- a/test/e2e/functional/canary-scaledowndelay.yaml +++ b/test/e2e/functional/canary-scaledowndelay.yaml @@ -40,7 +40,7 @@ spec: selector: app: canary-scaledowndelay --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: canary-scaledowndelay-ingress @@ -51,9 +51,12 @@ spec: - http: paths: - path: /* + pathType: Prefix backend: - serviceName: canary-scaledowndelay-root - servicePort: use-annotation + service: + name: canary-scaledowndelay-root + port: + name: use-annotation --- apiVersion: argoproj.io/v1alpha1 kind: Rollout diff --git a/test/e2e/functional/canary-scaledownonabort.yaml b/test/e2e/functional/canary-scaledownonabort.yaml index 8d5d05aff3..308becf609 100644 --- a/test/e2e/functional/canary-scaledownonabort.yaml +++ b/test/e2e/functional/canary-scaledownonabort.yaml @@ -40,7 +40,7 @@ spec: selector: app: canary-scaledowndelay --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: canary-scaledowndelay-ingress @@ -51,9 +51,12 @@ spec: - http: paths: - path: /* + pathType: Prefix backend: - serviceName: canary-scaledowndelay-root - servicePort: use-annotation + service: + name: canary-scaledowndelay-root + port: + name: use-annotation --- apiVersion: argoproj.io/v1alpha1 kind: Rollout diff --git a/test/e2e/functional/canary-unscaledownonabort.yaml b/test/e2e/functional/canary-unscaledownonabort.yaml index cf9ce26438..a4b4955988 100644 --- a/test/e2e/functional/canary-unscaledownonabort.yaml +++ b/test/e2e/functional/canary-unscaledownonabort.yaml @@ -40,7 +40,7 @@ spec: selector: app: canary-scaledowndelay --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: canary-scaledowndelay-ingress @@ -51,9 +51,12 @@ spec: - http: paths: - path: /* + pathType: Prefix backend: - serviceName: canary-scaledowndelay-root - servicePort: use-annotation + service: + name: canary-scaledowndelay-root + port: + name: use-annotation --- apiVersion: argoproj.io/v1alpha1 kind: Rollout diff --git a/test/e2e/functional/nginx-template.yaml b/test/e2e/functional/nginx-template.yaml index 85058636f7..9fa3335af1 100644 --- a/test/e2e/functional/nginx-template.yaml +++ b/test/e2e/functional/nginx-template.yaml @@ -26,7 +26,7 @@ spec: selector: app: REPLACEME --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: REPLACEME-ingress @@ -37,9 +37,12 @@ spec: - http: paths: - path: /* + pathType: Prefix backend: - serviceName: REPLACEME-stable - servicePort: 80 + service: + name: REPLACEME-stable + port: + number: 80 --- apiVersion: argoproj.io/v1alpha1 kind: Rollout diff --git a/test/e2e/smi/rollout-smi-experiment.yaml b/test/e2e/smi/rollout-smi-experiment.yaml index 88e5a529e4..a71a759805 100644 --- a/test/e2e/smi/rollout-smi-experiment.yaml +++ b/test/e2e/smi/rollout-smi-experiment.yaml @@ -28,7 +28,7 @@ spec: # This selector will be updated with the pod-template-hash of the stable ReplicaSet. e.g.: # rollouts-pod-template-hash: 789746c88d --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: rollout-smi-experiment-stable @@ -40,10 +40,13 @@ spec: http: paths: - path: / + pathType: ImplementationSpecific backend: # Reference to a Service name, also specified in the Rollout spec.strategy.canary.stableService field - serviceName: rollout-smi-experiment-stable - servicePort: 80 + service: + name: rollout-smi-experiment-stable + port: + number: 80 --- apiVersion: argoproj.io/v1alpha1 kind: Rollout diff --git a/test/e2e/smi_ingress/rollout-smi-ingress-canary.yaml b/test/e2e/smi_ingress/rollout-smi-ingress-canary.yaml index 024203b9f3..c9b71c5fcc 100644 --- a/test/e2e/smi_ingress/rollout-smi-ingress-canary.yaml +++ b/test/e2e/smi_ingress/rollout-smi-ingress-canary.yaml @@ -28,7 +28,7 @@ spec: # This selector will be updated with the pod-template-hash of the stable ReplicaSet. e.g.: # rollouts-pod-template-hash: 789746c88d --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: rollout-smi-ingress-canary-stable @@ -40,10 +40,13 @@ spec: http: paths: - path: / + pathType: Prefix backend: # Reference to a Service name, also specified in the Rollout spec.strategy.canary.stableService field - serviceName: rollout-smi-ingress-canary-stable - servicePort: 80 + service: + name: rollout-smi-ingress-canary-stable + port: + number: 80 --- apiVersion: argoproj.io/v1alpha1 kind: Rollout diff --git a/test/fixtures/common.go b/test/fixtures/common.go index fa0c5b7def..9d73f21447 100644 --- a/test/fixtures/common.go +++ b/test/fixtures/common.go @@ -21,7 +21,7 @@ import ( appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" - extensionsv1beta1 "k8s.io/api/extensions/v1beta1" + networkingv1 "k8s.io/api/networking/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -527,26 +527,26 @@ func (c *Common) GetServices() (*corev1.Service, *corev1.Service) { return desiredSvc, stableSvc } -func (c *Common) GetALBIngress() *extensionsv1beta1.Ingress { +func (c *Common) GetALBIngress() *networkingv1.Ingress { ro := c.Rollout() name := ro.Spec.Strategy.Canary.TrafficRouting.ALB.Ingress - ingress, err := c.kubeClient.ExtensionsV1beta1().Ingresses(c.namespace).Get(c.Context, name, metav1.GetOptions{}) + ingress, err := c.kubeClient.NetworkingV1().Ingresses(c.namespace).Get(c.Context, name, metav1.GetOptions{}) c.CheckError(err) return ingress } -func (c *Common) GetNginxIngressStable() *extensionsv1beta1.Ingress { +func (c *Common) GetNginxIngressStable() *networkingv1.Ingress { ro := c.Rollout() name := ro.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress - ingress, err := c.kubeClient.ExtensionsV1beta1().Ingresses(c.namespace).Get(c.Context, name, metav1.GetOptions{}) + ingress, err := c.kubeClient.NetworkingV1().Ingresses(c.namespace).Get(c.Context, name, metav1.GetOptions{}) c.CheckError(err) return ingress } -func (c *Common) GetNginxIngressCanary() *extensionsv1beta1.Ingress { +func (c *Common) GetNginxIngressCanary() *networkingv1.Ingress { ro := c.Rollout() name := ro.Name + "-" + ro.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress + "-canary" - ingress, err := c.kubeClient.ExtensionsV1beta1().Ingresses(c.namespace).Get(c.Context, name, metav1.GetOptions{}) + ingress, err := c.kubeClient.NetworkingV1().Ingresses(c.namespace).Get(c.Context, name, metav1.GetOptions{}) c.CheckError(err) return ingress } diff --git a/test/kustomize/rollout/expected.yaml b/test/kustomize/rollout/expected.yaml index eebed46dc9..e9dee28f1c 100644 --- a/test/kustomize/rollout/expected.yaml +++ b/test/kustomize/rollout/expected.yaml @@ -351,7 +351,7 @@ spec: host: guestbook-canary-svc weight: 0 --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: @@ -365,5 +365,7 @@ spec: http: paths: - backend: - serviceName: website - servicePort: 80 + service: + name: website + port: + number: 80 diff --git a/test/kustomize/rollout/rollout.yaml b/test/kustomize/rollout/rollout.yaml index 5a0db90149..03b78371a3 100644 --- a/test/kustomize/rollout/rollout.yaml +++ b/test/kustomize/rollout/rollout.yaml @@ -182,7 +182,7 @@ spec: targetPort: 8080 --- -apiVersion: networking.k8s.io/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: networking-ingress @@ -192,8 +192,10 @@ spec: http: paths: - backend: - serviceName: website - servicePort: 80 + service: + name: website + port: + number: 80 --- apiVersion: extensions/v1beta1 From 0bc05926a38b7c0512860b7fe0d06c1d4866ad94 Mon Sep 17 00:00:00 2001 From: Charles Guertin Date: Tue, 4 Jan 2022 13:17:29 -0500 Subject: [PATCH 032/175] fix(plugin): Fixes arm64 compatibility to plugin docker image. Fixes #1728 (#1732) Signed-off-by: Charles Guertin --- .github/workflows/release.yaml | 12 ++++++------ Dockerfile | 4 ++-- Makefile | 1 + hack/build-release-plugins.sh | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 677476ed8f..0dfc96f945 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,12 +1,11 @@ name: Release on: - workflow_dispatch: - inputs: - tag: - description: Git tag to build release from - required: true - + workflow_dispatch: + inputs: + tag: + description: Git tag to build release from + required: true jobs: release-images: runs-on: ubuntu-latest @@ -128,6 +127,7 @@ jobs: draft: true files: | dist/kubectl-argo-rollouts-linux-amd64 + dist/kubectl-argo-rollouts-linux-arm64 dist/kubectl-argo-rollouts-darwin-amd64 dist/kubectl-argo-rollouts-windows-amd64 manifests/dashboard-install.yaml diff --git a/Dockerfile b/Dockerfile index 7212a9c8df..fd78e01c1a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -63,7 +63,7 @@ RUN touch ui/dist/node_modules.marker && \ touch ui/dist/app/index.html && \ find ui/dist -ARG MAKE_TARGET="controller plugin-linux plugin-darwin plugin-windows" +ARG MAKE_TARGET="controller plugin plugin-linux plugin-darwin plugin-windows" RUN make ${MAKE_TARGET} #################################################################################################### @@ -71,7 +71,7 @@ RUN make ${MAKE_TARGET} #################################################################################################### FROM docker.io/library/ubuntu:20.10 as kubectl-argo-rollouts -COPY --from=argo-rollouts-build /go/src/github.com/argoproj/argo-rollouts/dist/kubectl-argo-rollouts-linux-amd64 /bin/kubectl-argo-rollouts +COPY --from=argo-rollouts-build /go/src/github.com/argoproj/argo-rollouts/dist/kubectl-argo-rollouts /bin/kubectl-argo-rollouts USER 999 diff --git a/Makefile b/Makefile index e29d6912e9..644cbe1784 100644 --- a/Makefile +++ b/Makefile @@ -191,6 +191,7 @@ ui/dist: plugin-linux: ui/dist cp -r ui/dist/app/* server/static CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -v -i -ldflags '${LDFLAGS}' -o ${DIST_DIR}/${PLUGIN_CLI_NAME}-linux-amd64 ./cmd/kubectl-argo-rollouts + CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -v -i -ldflags '${LDFLAGS}' -o ${DIST_DIR}/${PLUGIN_CLI_NAME}-linux-arm64 ./cmd/kubectl-argo-rollouts .PHONY: plugin-darwin plugin-darwin: ui/dist diff --git a/hack/build-release-plugins.sh b/hack/build-release-plugins.sh index 07f9b66ddc..25c4091dd7 100755 --- a/hack/build-release-plugins.sh +++ b/hack/build-release-plugins.sh @@ -10,7 +10,7 @@ docker build --iidfile ${rollout_iid_file} --target argo-rollouts-build . rollout_iid=$(cat ${rollout_iid_file}) container_id=$(docker create ${rollout_iid}) -for plat in linux-amd64 darwin-amd64 windows-amd64; do +for plat in linux-amd64 linux-arm64 darwin-amd64 windows-amd64; do docker cp ${container_id}:/go/src/github.com/argoproj/argo-rollouts/dist/kubectl-argo-rollouts-${plat} ${SRCROOT}/dist done docker rm -v ${container_id} From 200b045320b7202a07f727c558f2c0f2f703f8af Mon Sep 17 00:00:00 2001 From: Michael Crenshaw Date: Wed, 5 Jan 2022 16:52:42 -0500 Subject: [PATCH 033/175] chore: update docs for minikube 1.19 (#1746) Signed-off-by: Michael Crenshaw --- docs/getting-started/setup/index.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/getting-started/setup/index.md b/docs/getting-started/setup/index.md index 8066de72a1..7b72bbc14b 100644 --- a/docs/getting-started/setup/index.md +++ b/docs/getting-started/setup/index.md @@ -27,7 +27,7 @@ minikube addons enable ingress Optionally, Prometheus and Grafana can be installed to utilize progressive delivery functionality: -``` +```shell # Install Prometheus kubectl create ns monitoring helm install prometheus prometheus-community/prometheus -n monitoring -f docs/getting-started/setup/values-prometheus.yaml @@ -35,8 +35,14 @@ helm install prometheus prometheus-community/prometheus -n monitoring -f docs/ge # Patch the ingress-nginx-controller pod so that it has the required # prometheus annotations. This allows the pod to be scraped by the # prometheus server. -kubectl patch deploy ingress-nginx-controller -n kube-system -p "$(cat docs/getting-started/setup/ingress-nginx-controller-metrics-scrape.yaml)" +kubectl patch deploy ingress-nginx-controller -n ingress-nginx -p "$(cat docs/getting-started/setup/ingress-nginx-controller-metrics-scrape.yaml)" +``` +!!! note + [For Minikube version 1.18.1 or earlier](https://kubernetes.io/docs/tasks/access-application-cluster/ingress-minikube/#enable-the-ingress-controller), + change the `-n` parameter value (namespace) to `kube-system`. + +```shell # Install grafana along with nginx ingress dashboards helm install grafana grafana/grafana -n monitoring -f docs/getting-started/setup/values-grafana-nginx.yaml From e2201d0e4e911412e367b0634dcac3931e99e0c3 Mon Sep 17 00:00:00 2001 From: Mubarak Jama <83465122+mubarak-j@users.noreply.github.com> Date: Tue, 11 Jan 2022 10:54:36 -0700 Subject: [PATCH 034/175] docs(controller): remove duplicate sentence. (#1756) Signed-off-by: Mubarak Jama --- docs/features/analysis.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/features/analysis.md b/docs/features/analysis.md index c8671fb0cc..7d037a2f07 100644 --- a/docs/features/analysis.md +++ b/docs/features/analysis.md @@ -633,8 +633,7 @@ Metric Results: ### Dry-Run Rollouts -If a rollout wants to dry run its analysis, it simply needs to specify the `dryRun` field to its `analysis` stanza. If a -rollout wants to dry run its analysis, it simply needs to specify the `dryRun` field to its `analysis` stanza. In the +If a rollout wants to dry run its analysis, it simply needs to specify the `dryRun` field to its `analysis` stanza. In the following example, all the metrics from `random-fail` and `always-pass` get merged and executed in the dry-run mode. ```yaml hl_lines="9 10" From 03e75f950b9413acc714e1245fdcc678685ecb2f Mon Sep 17 00:00:00 2001 From: Andrii Perenesenko Date: Wed, 12 Jan 2022 11:57:43 -0800 Subject: [PATCH 035/175] fix: traffic routed canary would flap traffic to stable after last step (#1757) Signed-off-by: Andrii Perenesenko --- rollout/trafficrouting.go | 10 +++---- rollout/trafficrouting_test.go | 50 ++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/rollout/trafficrouting.go b/rollout/trafficrouting.go index 62d698074e..2f3b549f31 100644 --- a/rollout/trafficrouting.go +++ b/rollout/trafficrouting.go @@ -140,16 +140,16 @@ func (c *rolloutContext) reconcileTrafficRouting() error { break } } + weightDestinations = append(weightDestinations, c.calculateWeightDestinationsFromExperiment()...) } else if *index != int32(len(c.rollout.Spec.Strategy.Canary.Steps)) { - // This if statement prevents the desiredWeight from being set to 100 - // when the rollout has progressed through all the steps. The rollout - // should send all traffic to the stable service by using a weight of - // 0. If the rollout is progressing through the steps, the desired + // If the rollout is progressing through the steps, the desired // weight of the traffic routing service should be at the value of the // last setWeight step, which is set by GetCurrentSetWeight. desiredWeight = replicasetutil.GetCurrentSetWeight(c.rollout) + weightDestinations = append(weightDestinations, c.calculateWeightDestinationsFromExperiment()...) + } else { + desiredWeight = 100 } - weightDestinations = append(weightDestinations, c.calculateWeightDestinationsFromExperiment()...) } err = reconciler.UpdateHash(canaryHash, stableHash, weightDestinations...) diff --git a/rollout/trafficrouting_test.go b/rollout/trafficrouting_test.go index d825342f97..1328276a55 100644 --- a/rollout/trafficrouting_test.go +++ b/rollout/trafficrouting_test.go @@ -192,6 +192,56 @@ func TestRolloutUseDesiredWeight(t *testing.T) { f.run(getKey(r2, t)) } +func TestRolloutUseDesiredWeight100(t *testing.T) { + f := newFixture(t) + defer f.Close() + + steps := []v1alpha1.CanaryStep{ + { + SetWeight: pointer.Int32Ptr(10), + }, + { + Pause: &v1alpha1.RolloutPause{}, + }, + } + r1 := newCanaryRollout("foo", 10, nil, steps, pointer.Int32Ptr(2), intstr.FromInt(1), intstr.FromInt(0)) + r2 := bumpVersion(r1) + r2.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{} + r2.Spec.Strategy.Canary.CanaryService = "canary" + r2.Spec.Strategy.Canary.StableService = "stable" + + rs1 := newReplicaSetWithStatus(r1, 10, 10) + rs2 := newReplicaSetWithStatus(r2, 10, 10) + + rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] + rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] + canarySelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash} + stableSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs1PodHash} + canarySvc := newService("canary", 80, canarySelector, r2) + stableSvc := newService("stable", 80, stableSelector, r2) + + f.kubeobjects = append(f.kubeobjects, rs1, rs2, canarySvc, stableSvc) + f.replicaSetLister = append(f.replicaSetLister, rs1, rs2) + + r2 = updateCanaryRolloutStatus(r2, rs1PodHash, 10, 0, 10, false) + f.rolloutLister = append(f.rolloutLister, r2) + f.objects = append(f.objects, r2) + + f.expectPatchRolloutAction(r2) + + f.fakeTrafficRouting = *newUnmockedFakeTrafficRoutingReconciler() + for _, fakeTrafficRouting := range f.fakeTrafficRouting { + fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) + fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { + // make sure SetWeight was called with correct value + assert.Equal(t, int32(100), desiredWeight) + return nil + }) + fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(true, nil) + } + f.run(getKey(r2, t)) +} + func TestRolloutWithExperimentStep(t *testing.T) { f := newFixture(t) defer f.Close() From d1eef41f92e66e30506829dbdbd4a7a1015351df Mon Sep 17 00:00:00 2001 From: cskh Date: Wed, 12 Jan 2022 14:59:27 -0500 Subject: [PATCH 036/175] docs: clarify the setCanaryScale of dynamic canary scale (#1703) Signed-off-by: Hui Kang --- docs/features/canary.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/features/canary.md b/docs/features/canary.md index 5cc4fd11b8..de1053a101 100644 --- a/docs/features/canary.md +++ b/docs/features/canary.md @@ -86,12 +86,12 @@ match the traffic weight. Some use cases for this: Setting canary scale is only available when using the canary strategy with a traffic router, since the basic canary needs to control canary scale in order to approximate canary weight. -To control canary weights during steps, use the `setCanaryScale` step and indicate which scale the +To control canary scales and weights during steps, use the `setCanaryScale` step and indicate which scale the the canary should use: -* explicit replica count -* explicit weight percentage of total spec.replicas -* to match current canary setWeight +* explicit replica count without changing traffic weight (`replicas`) +* explicit weight percentage of total spec.replicas without changing traffic weight(`weight`) +* to or not to match current canary's `setWeight` step (`matchTrafficWeight: true or false`) ```yaml spec: @@ -120,12 +120,16 @@ spec: strategy: canary: steps: + # 1 canary pod (10% of spec.replicas) - setCanaryScale: weight: 10 + # 90% of traffic to the 1 canary pod - setWeight: 90 - pause: {} ``` +The above situation is caused by the changed behvaior of `setWeight` after `setCanaryScale`. To reset, set `matchTrafficWeight: true` and the `setWeight` behavior will be restored, i.e., subsequent `setWeight` will create canary replicas matching the traffic weight. + ## Dynamic Stable Scale (with Traffic Routing) !!! important From 75c2861eecf5acb7e596701882473d25a07b263c Mon Sep 17 00:00:00 2001 From: Rohit Agrawal Date: Thu, 13 Jan 2022 01:30:51 +0530 Subject: [PATCH 037/175] feat(analysis): Add Measurements Retention Limit Option for Metrics (#1729) Signed-off-by: Rohit Agrawal --- analysis/analysis.go | 25 ++++- analysis/analysis_test.go | 71 +++++++++++++- docs/features/analysis.md | 73 ++++++++++++++ manifests/crds/analysis-run-crd.yaml | 12 +++ manifests/crds/analysis-template-crd.yaml | 12 +++ .../crds/cluster-analysis-template-crd.yaml | 12 +++ manifests/install.yaml | 36 +++++++ manifests/namespace-install.yaml | 36 +++++++ pkg/apis/api-rules/violation_exceptions.list | 2 + pkg/apis/rollouts/v1alpha1/analysis_types.go | 18 ++++ .../v1alpha1/zz_generated.deepcopy.go | 26 +++++ utils/analysis/helpers.go | 22 +++++ utils/analysis/helpers_test.go | 94 ++++++++++++++++++- 13 files changed, 428 insertions(+), 11 deletions(-) diff --git a/analysis/analysis.go b/analysis/analysis.go index 7d9793182d..3afc481635 100644 --- a/analysis/analysis.go +++ b/analysis/analysis.go @@ -80,6 +80,16 @@ func (c *Controller) reconcileAnalysisRun(origRun *v1alpha1.AnalysisRun) *v1alph return run } + measurementRetentionMetricsMap, err := analysisutil.GetMeasurementRetentionMetrics(run.Spec.MeasurementRetention, resolvedMetrics) + if err != nil { + message := fmt.Sprintf("Analysis spec invalid: %v", err) + logger.Warn(message) + run.Status.Phase = v1alpha1.AnalysisPhaseError + run.Status.Message = message + c.recordAnalysisRunCompletionEvent(run) + return run + } + tasks := generateMetricTasks(run, resolvedMetrics) logger.Infof("Taking %d Measurement(s)...", len(tasks)) err = c.runMeasurements(run, tasks, dryRunMetricsMap) @@ -101,7 +111,7 @@ func (c *Controller) reconcileAnalysisRun(origRun *v1alpha1.AnalysisRun) *v1alph } } - err = c.garbageCollectMeasurements(run, DefaultMeasurementHistoryLimit) + err = c.garbageCollectMeasurements(run, measurementRetentionMetricsMap, DefaultMeasurementHistoryLimit) if err != nil { // TODO(jessesuen): surface errors to controller so they can be retried logger.Warnf("Failed to garbage collect measurements: %v", err) @@ -693,7 +703,7 @@ func calculateNextReconcileTime(run *v1alpha1.AnalysisRun, metrics []v1alpha1.Me } // garbageCollectMeasurements trims the measurement history to the specified limit and GCs old measurements -func (c *Controller) garbageCollectMeasurements(run *v1alpha1.AnalysisRun, limit int) error { +func (c *Controller) garbageCollectMeasurements(run *v1alpha1.AnalysisRun, measurementRetentionMetricNamesMap map[string]*v1alpha1.MeasurementRetention, limit int) error { var errors []error metricsByName := make(map[string]v1alpha1.Metric) @@ -703,7 +713,12 @@ func (c *Controller) garbageCollectMeasurements(run *v1alpha1.AnalysisRun, limit for i, result := range run.Status.MetricResults { length := len(result.Measurements) - if length > limit { + measurementRetentionObject := measurementRetentionMetricNamesMap[result.Name] + measurementsLimit := limit + if measurementRetentionObject != nil && measurementRetentionObject.Limit > 0 { + measurementsLimit = measurementRetentionObject.Limit + } + if length > measurementsLimit { metric, ok := metricsByName[result.Name] if !ok { continue @@ -714,11 +729,11 @@ func (c *Controller) garbageCollectMeasurements(run *v1alpha1.AnalysisRun, limit errors = append(errors, err) continue } - err = provider.GarbageCollect(run, metric, limit) + err = provider.GarbageCollect(run, metric, measurementsLimit) if err != nil { return err } - result.Measurements = result.Measurements[length-limit : length] + result.Measurements = result.Measurements[length-measurementsLimit : length] } run.Status.MetricResults[i] = result } diff --git a/analysis/analysis_test.go b/analysis/analysis_test.go index 6533565e47..031e8f78eb 100644 --- a/analysis/analysis_test.go +++ b/analysis/analysis_test.go @@ -1055,7 +1055,8 @@ func TestTrimMeasurementHistory(t *testing.T) { { run := newRun() - c.garbageCollectMeasurements(run, 2) + err := c.garbageCollectMeasurements(run, map[string]*v1alpha1.MeasurementRetention{}, 2) + assert.Nil(t, err) assert.Len(t, run.Status.MetricResults[0].Measurements, 1) assert.Equal(t, "1", run.Status.MetricResults[0].Measurements[0].Value) assert.Len(t, run.Status.MetricResults[1].Measurements, 2) @@ -1064,12 +1065,37 @@ func TestTrimMeasurementHistory(t *testing.T) { } { run := newRun() - c.garbageCollectMeasurements(run, 1) + err := c.garbageCollectMeasurements(run, map[string]*v1alpha1.MeasurementRetention{}, 1) + assert.Nil(t, err) assert.Len(t, run.Status.MetricResults[0].Measurements, 1) assert.Equal(t, "1", run.Status.MetricResults[0].Measurements[0].Value) assert.Len(t, run.Status.MetricResults[1].Measurements, 1) assert.Equal(t, "3", run.Status.MetricResults[1].Measurements[0].Value) } + { + run := newRun() + var measurementRetentionMetricsMap = map[string]*v1alpha1.MeasurementRetention{} + measurementRetentionMetricsMap["metric2"] = &v1alpha1.MeasurementRetention{MetricName: "*", Limit: 2} + err := c.garbageCollectMeasurements(run, measurementRetentionMetricsMap, 1) + assert.Nil(t, err) + assert.Len(t, run.Status.MetricResults[0].Measurements, 1) + assert.Equal(t, "1", run.Status.MetricResults[0].Measurements[0].Value) + assert.Len(t, run.Status.MetricResults[1].Measurements, 2) + assert.Equal(t, "2", run.Status.MetricResults[1].Measurements[0].Value) + assert.Equal(t, "3", run.Status.MetricResults[1].Measurements[1].Value) + } + { + run := newRun() + var measurementRetentionMetricsMap = map[string]*v1alpha1.MeasurementRetention{} + measurementRetentionMetricsMap["metric2"] = &v1alpha1.MeasurementRetention{MetricName: "metric2", Limit: 2} + err := c.garbageCollectMeasurements(run, measurementRetentionMetricsMap, 1) + assert.Nil(t, err) + assert.Len(t, run.Status.MetricResults[0].Measurements, 1) + assert.Equal(t, "1", run.Status.MetricResults[0].Measurements[0].Value) + assert.Len(t, run.Status.MetricResults[1].Measurements, 2) + assert.Equal(t, "2", run.Status.MetricResults[1].Measurements[0].Value) + assert.Equal(t, "3", run.Status.MetricResults[1].Measurements[1].Value) + } } func TestResolveMetricArgsUnableToSubstitute(t *testing.T) { @@ -1675,3 +1701,44 @@ func TestInvalidDryRunConfigThrowsError(t *testing.T) { assert.Equal(t, v1alpha1.AnalysisPhaseError, newRun.Status.Phase) assert.Equal(t, "Analysis spec invalid: dryRun[0]: Rule didn't match any metric name(s)", newRun.Status.Message) } + +func TestInvalidMeasurementsRetentionConfigThrowsError(t *testing.T) { + f := newFixture(t) + defer f.Close() + c, _, _ := f.newController(noResyncPeriodFunc) + + // Mocks terminate to cancel the in-progress measurement + f.provider.On("Terminate", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(newMeasurement(v1alpha1.AnalysisPhaseSuccessful), nil) + + var measurementsRetentionArray []v1alpha1.MeasurementRetention + measurementsRetentionArray = append(measurementsRetentionArray, v1alpha1.MeasurementRetention{MetricName: "error-rate"}) + now := metav1.Now() + run := &v1alpha1.AnalysisRun{ + Spec: v1alpha1.AnalysisRunSpec{ + Terminate: true, + Args: []v1alpha1.Argument{ + { + Name: "service", + Value: pointer.StringPtr("rollouts-demo-canary.default.svc.cluster.local"), + }, + }, + Metrics: []v1alpha1.Metric{{ + Name: "success-rate", + InitialDelay: "20s", + Interval: "20s", + SuccessCondition: "result[0] > 0.90", + Provider: v1alpha1.MetricProvider{ + Web: &v1alpha1.WebMetric{}, + }, + }}, + MeasurementRetention: measurementsRetentionArray, + }, + Status: v1alpha1.AnalysisRunStatus{ + StartedAt: &now, + Phase: v1alpha1.AnalysisPhaseRunning, + }, + } + newRun := c.reconcileAnalysisRun(run) + assert.Equal(t, v1alpha1.AnalysisPhaseError, newRun.Status.Phase) + assert.Equal(t, "Analysis spec invalid: measurementRetention[0]: Rule didn't match any metric name(s)", newRun.Status.Message) +} diff --git a/docs/features/analysis.md b/docs/features/analysis.md index 7d037a2f07..6456c70415 100644 --- a/docs/features/analysis.md +++ b/docs/features/analysis.md @@ -678,6 +678,79 @@ spec: - metricName: test.* ``` +## Measurements Retention + +!!! important +Available since v1.2 + +`measurementRetention` can be used to retain other than the latest ten results for the metrics running in any mode +(dry/non-dry). Setting this option to `0` would disable it and, the controller will revert to the existing behavior of +retaining the latest ten measurements. + +The following example queries Prometheus every 5 minutes to get the total number of 4XX and 5XX errors and retains the +latest twenty measurements for the 5XX metric run results instead of the default ten. + +```yaml hl_lines="1 2 3" + measurementRetention: + - metricName: total-5xx-errors + limit: 20 + metrics: + - name: total-5xx-errors + interval: 5m + failureCondition: result[0] >= 10 + failureLimit: 3 + provider: + prometheus: + address: http://prometheus.example.com:9090 + query: | + sum(irate( + istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code~"5.*"}[5m] + )) + - name: total-4xx-errors + interval: 5m + failureCondition: result[0] >= 10 + failureLimit: 3 + provider: + prometheus: + address: http://prometheus.example.com:9090 + query: | + sum(irate( + istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code~"4.*"}[5m] + )) +``` + +RegEx matches are also supported. `.*` can be used to apply the same retention rule to all the metrics. In the following +example, the controller will retain the latest twenty run results for all the metrics instead of the default ten results. + +```yaml hl_lines="1 2 3" + measurementRetention: + - metricName: .* + limit: 20 + metrics: + - name: total-5xx-errors + interval: 5m + failureCondition: result[0] >= 10 + failureLimit: 3 + provider: + prometheus: + address: http://prometheus.example.com:9090 + query: | + sum(irate( + istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code~"5.*"}[5m] + )) + - name: total-4xx-errors + interval: 5m + failureCondition: result[0] >= 10 + failureLimit: 3 + provider: + prometheus: + address: http://prometheus.example.com:9090 + query: | + sum(irate( + istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code~"4.*"}[5m] + )) +``` + ## Inconclusive Runs Analysis runs can also be considered `Inconclusive`, which indicates the run was neither successful, diff --git a/manifests/crds/analysis-run-crd.yaml b/manifests/crds/analysis-run-crd.yaml index 6d399679a3..c01f11145e 100644 --- a/manifests/crds/analysis-run-crd.yaml +++ b/manifests/crds/analysis-run-crd.yaml @@ -77,6 +77,18 @@ spec: - metricName type: object type: array + measurementRetention: + items: + properties: + limit: + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array metrics: items: properties: diff --git a/manifests/crds/analysis-template-crd.yaml b/manifests/crds/analysis-template-crd.yaml index 0d61a67203..b439a780d1 100644 --- a/manifests/crds/analysis-template-crd.yaml +++ b/manifests/crds/analysis-template-crd.yaml @@ -73,6 +73,18 @@ spec: - metricName type: object type: array + measurementRetention: + items: + properties: + limit: + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array metrics: items: properties: diff --git a/manifests/crds/cluster-analysis-template-crd.yaml b/manifests/crds/cluster-analysis-template-crd.yaml index e5cd0d29ba..91acef74e1 100644 --- a/manifests/crds/cluster-analysis-template-crd.yaml +++ b/manifests/crds/cluster-analysis-template-crd.yaml @@ -73,6 +73,18 @@ spec: - metricName type: object type: array + measurementRetention: + items: + properties: + limit: + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array metrics: items: properties: diff --git a/manifests/install.yaml b/manifests/install.yaml index ac1f78a792..96985377db 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -78,6 +78,18 @@ spec: - metricName type: object type: array + measurementRetention: + items: + properties: + limit: + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array metrics: items: properties: @@ -2815,6 +2827,18 @@ spec: - metricName type: object type: array + measurementRetention: + items: + properties: + limit: + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array metrics: items: properties: @@ -5442,6 +5466,18 @@ spec: - metricName type: object type: array + measurementRetention: + items: + properties: + limit: + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array metrics: items: properties: diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 05ff7bc8d7..aab81d4eec 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -78,6 +78,18 @@ spec: - metricName type: object type: array + measurementRetention: + items: + properties: + limit: + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array metrics: items: properties: @@ -2815,6 +2827,18 @@ spec: - metricName type: object type: array + measurementRetention: + items: + properties: + limit: + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array metrics: items: properties: @@ -5442,6 +5466,18 @@ spec: - metricName type: object type: array + measurementRetention: + items: + properties: + limit: + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array metrics: items: properties: diff --git a/pkg/apis/api-rules/violation_exceptions.list b/pkg/apis/api-rules/violation_exceptions.list index a761bbfaf0..a4930858ab 100644 --- a/pkg/apis/api-rules/violation_exceptions.list +++ b/pkg/apis/api-rules/violation_exceptions.list @@ -1,10 +1,12 @@ API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AmbassadorTrafficRouting,Mappings API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AnalysisRunSpec,Args API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AnalysisRunSpec,DryRun +API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AnalysisRunSpec,MeasurementRetention API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AnalysisRunSpec,Metrics API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AnalysisRunStatus,MetricResults API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AnalysisTemplateSpec,Args API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AnalysisTemplateSpec,DryRun +API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AnalysisTemplateSpec,MeasurementRetention API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AnalysisTemplateSpec,Metrics API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,CanaryStrategy,Steps API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,CloudWatchMetric,MetricDataQueries diff --git a/pkg/apis/rollouts/v1alpha1/analysis_types.go b/pkg/apis/rollouts/v1alpha1/analysis_types.go index 12dd37970d..0094571c5d 100644 --- a/pkg/apis/rollouts/v1alpha1/analysis_types.go +++ b/pkg/apis/rollouts/v1alpha1/analysis_types.go @@ -66,6 +66,11 @@ type AnalysisTemplateSpec struct { // +patchStrategy=merge // +optional DryRun []DryRun `json:"dryRun,omitempty" patchStrategy:"merge" patchMergeKey:"metricName" protobuf:"bytes,3,rep,name=dryRun"` + // MeasurementRetention object contains the settings for retaining the number of measurements during the analysis + // +patchMergeKey=metricName + // +patchStrategy=merge + // +optional + MeasurementRetention []MeasurementRetention `json:"measurementRetention,omitempty" patchStrategy:"merge" patchMergeKey:"metricName" protobuf:"bytes,4,rep,name=measurementRetention"` } // DurationString is a string representing a duration (e.g. 30s, 5m, 1h) @@ -120,6 +125,14 @@ type DryRun struct { MetricName string `json:"metricName" protobuf:"bytes,1,opt,name=metricName"` } +// MeasurementRetention defines the settings for retaining the number of measurements during the analysis. +type MeasurementRetention struct { + // MetricName is the name of the metric on which this retention policy should be applied. + MetricName string `json:"metricName" protobuf:"bytes,1,opt,name=metricName"` + // Limit is the maximum number of measurements to be retained for this given metric. + Limit int `json:"limit" protobuf:"varint,2,opt,name=limit"` +} + // EffectiveCount is the effective count based on whether or not count/interval is specified // If neither count or interval is specified, the effective count is 1 // If only interval is specified, metric runs indefinitely and there is no effective count (nil) @@ -292,6 +305,11 @@ type AnalysisRunSpec struct { // +patchStrategy=merge // +optional DryRun []DryRun `json:"dryRun,omitempty" patchStrategy:"merge" patchMergeKey:"metricName" protobuf:"bytes,4,rep,name=dryRun"` + // MeasurementRetention object contains the settings for retaining the number of measurements during the analysis + // +patchMergeKey=metricName + // +patchStrategy=merge + // +optional + MeasurementRetention []MeasurementRetention `json:"measurementRetention,omitempty" patchStrategy:"merge" patchMergeKey:"metricName" protobuf:"bytes,5,rep,name=measurementRetention"` } // Argument is an argument to an AnalysisRun diff --git a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go index 0a048cbd5c..e7ff0ab8d5 100644 --- a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go @@ -191,6 +191,11 @@ func (in *AnalysisRunSpec) DeepCopyInto(out *AnalysisRunSpec) { *out = make([]DryRun, len(*in)) copy(*out, *in) } + if in.MeasurementRetention != nil { + in, out := &in.MeasurementRetention, &out.MeasurementRetention + *out = make([]MeasurementRetention, len(*in)) + copy(*out, *in) + } return } @@ -345,6 +350,11 @@ func (in *AnalysisTemplateSpec) DeepCopyInto(out *AnalysisTemplateSpec) { *out = make([]DryRun, len(*in)) copy(*out, *in) } + if in.MeasurementRetention != nil { + in, out := &in.MeasurementRetention, &out.MeasurementRetention + *out = make([]MeasurementRetention, len(*in)) + copy(*out, *in) + } return } @@ -1330,6 +1340,22 @@ func (in *Measurement) DeepCopy() *Measurement { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MeasurementRetention) DeepCopyInto(out *MeasurementRetention) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MeasurementRetention. +func (in *MeasurementRetention) DeepCopy() *MeasurementRetention { + if in == nil { + return nil + } + out := new(MeasurementRetention) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Metric) DeepCopyInto(out *Metric) { *out = *in diff --git a/utils/analysis/helpers.go b/utils/analysis/helpers.go index bf9a70e70f..cb25dabcac 100644 --- a/utils/analysis/helpers.go +++ b/utils/analysis/helpers.go @@ -93,6 +93,28 @@ func IsTerminating(run *v1alpha1.AnalysisRun) bool { return false } +// GetMeasurementRetentionMetrics returns an array of metric names matching the RegEx rules from the MeasurementRetention rules. +func GetMeasurementRetentionMetrics(measurementRetentionMetrics []v1alpha1.MeasurementRetention, metrics []v1alpha1.Metric) (map[string]*v1alpha1.MeasurementRetention, error) { + metricsMap := make(map[string]*v1alpha1.MeasurementRetention) + if len(measurementRetentionMetrics) == 0 { + return metricsMap, nil + } + // Iterate all the rules in `measurementRetentionMetrics` and try to match the `metrics` one by one + for index, measurementRetentionObject := range measurementRetentionMetrics { + matchCount := 0 + for _, metric := range metrics { + if matched, _ := regexp.MatchString(measurementRetentionObject.MetricName, metric.Name); matched { + metricsMap[metric.Name] = &measurementRetentionObject + matchCount++ + } + } + if matchCount < 1 { + return metricsMap, fmt.Errorf("measurementRetention[%d]: Rule didn't match any metric name(s)", index) + } + } + return metricsMap, nil +} + // GetDryRunMetrics returns an array of metric names matching the RegEx rules from the Dry-Run metrics. func GetDryRunMetrics(dryRunMetrics []v1alpha1.DryRun, metrics []v1alpha1.Metric) (map[string]bool, error) { metricsMap := make(map[string]bool) diff --git a/utils/analysis/helpers_test.go b/utils/analysis/helpers_test.go index 5a517afb90..3d73dcb061 100644 --- a/utils/analysis/helpers_test.go +++ b/utils/analysis/helpers_test.go @@ -530,7 +530,7 @@ func TestNewAnalysisRunFromTemplates(t *testing.T) { }, }} - clustertemplates := []*v1alpha1.ClusterAnalysisTemplate{} + var clusterTemplates []*v1alpha1.ClusterAnalysisTemplate arg := v1alpha1.Argument{ Name: "my-arg", @@ -547,7 +547,7 @@ func TestNewAnalysisRunFromTemplates(t *testing.T) { } args := []v1alpha1.Argument{arg, secretArg} - run, err := NewAnalysisRunFromTemplates(templates, clustertemplates, args, []v1alpha1.DryRun{}, "foo-run", "foo-run-generate-", "my-ns") + run, err := NewAnalysisRunFromTemplates(templates, clusterTemplates, args, []v1alpha1.DryRun{}, "foo-run", "foo-run-generate-", "my-ns") assert.NoError(t, err) assert.Equal(t, "foo-run", run.Name) assert.Equal(t, "foo-run-generate-", run.GenerateName) @@ -560,7 +560,7 @@ func TestNewAnalysisRunFromTemplates(t *testing.T) { // Fail Merge Args unresolvedArg := v1alpha1.Argument{Name: "unresolved"} templates[0].Spec.Args = append(templates[0].Spec.Args, unresolvedArg) - run, err = NewAnalysisRunFromTemplates(templates, clustertemplates, args, []v1alpha1.DryRun{}, "foo-run", "foo-run-generate-", "my-ns") + run, err = NewAnalysisRunFromTemplates(templates, clusterTemplates, args, []v1alpha1.DryRun{}, "foo-run", "foo-run-generate-", "my-ns") assert.Nil(t, run) assert.Equal(t, fmt.Errorf("args.unresolved was not resolved"), err) // Fail flatten metric @@ -573,7 +573,7 @@ func TestNewAnalysisRunFromTemplates(t *testing.T) { } // Fail Flatten Templates templates = append(templates, matchingMetric) - run, err = NewAnalysisRunFromTemplates(templates, clustertemplates, args, []v1alpha1.DryRun{}, "foo-run", "foo-run-generate-", "my-ns") + run, err = NewAnalysisRunFromTemplates(templates, clusterTemplates, args, []v1alpha1.DryRun{}, "foo-run", "foo-run-generate-", "my-ns") assert.Nil(t, run) assert.Equal(t, fmt.Errorf("two metrics have the same name 'success-rate'"), err) } @@ -897,3 +897,89 @@ func TestGetDryRunMetrics(t *testing.T) { assert.Equal(t, len(dryRunMetricNamesMap), 0) }) } + +func TestGetMeasurementRetentionMetrics(t *testing.T) { + t.Run("GetMeasurementRetentionMetrics returns the metric names map", func(t *testing.T) { + failureLimit := intstr.FromInt(2) + count := intstr.FromInt(1) + spec := v1alpha1.AnalysisTemplateSpec{ + Metrics: []v1alpha1.Metric{ + { + Name: "success-rate", + Count: &count, + FailureLimit: &failureLimit, + Provider: v1alpha1.MetricProvider{ + Prometheus: &v1alpha1.PrometheusMetric{}, + }, + }, + }, + MeasurementRetention: []v1alpha1.MeasurementRetention{ + { + MetricName: "success-rate", + Limit: 10, + }, + }, + } + measurementRetentionMetricNamesMap, err := GetMeasurementRetentionMetrics(spec.MeasurementRetention, spec.Metrics) + assert.Nil(t, err) + assert.NotNil(t, measurementRetentionMetricNamesMap["success-rate"]) + }) + t.Run("GetMeasurementRetentionMetrics handles the RegEx rules", func(t *testing.T) { + failureLimit := intstr.FromInt(2) + count := intstr.FromInt(1) + spec := v1alpha1.AnalysisTemplateSpec{ + Metrics: []v1alpha1.Metric{ + { + Name: "success-rate", + Count: &count, + FailureLimit: &failureLimit, + Provider: v1alpha1.MetricProvider{ + Prometheus: &v1alpha1.PrometheusMetric{}, + }, + }, + { + Name: "error-rate", + Count: &count, + FailureLimit: &failureLimit, + Provider: v1alpha1.MetricProvider{ + Prometheus: &v1alpha1.PrometheusMetric{}, + }, + }, + }, + MeasurementRetention: []v1alpha1.MeasurementRetention{ + { + MetricName: ".*", + Limit: 15, + }, + }, + } + measurementRetentionMetricNamesMap, err := GetMeasurementRetentionMetrics(spec.MeasurementRetention, spec.Metrics) + assert.Nil(t, err) + assert.Equal(t, len(measurementRetentionMetricNamesMap), 2) + }) + t.Run("GetMeasurementRetentionMetrics throw error when a rule doesn't get matched", func(t *testing.T) { + failureLimit := intstr.FromInt(2) + count := intstr.FromInt(1) + spec := v1alpha1.AnalysisTemplateSpec{ + Metrics: []v1alpha1.Metric{ + { + Name: "success-rate", + Count: &count, + FailureLimit: &failureLimit, + Provider: v1alpha1.MetricProvider{ + Prometheus: &v1alpha1.PrometheusMetric{}, + }, + }, + }, + MeasurementRetention: []v1alpha1.MeasurementRetention{ + { + MetricName: "error-rate", + Limit: 11, + }, + }, + } + measurementRetentionMetricNamesMap, err := GetMeasurementRetentionMetrics(spec.MeasurementRetention, spec.Metrics) + assert.EqualError(t, err, "measurementRetention[0]: Rule didn't match any metric name(s)") + assert.Equal(t, len(measurementRetentionMetricNamesMap), 0) + }) +} From 649aa555fe5dcbe1da6f154105e023f025bc95c7 Mon Sep 17 00:00:00 2001 From: cskh Date: Wed, 12 Jan 2022 15:05:12 -0500 Subject: [PATCH 038/175] fix: missing array type in the CRD rollout's spec volumes (#1737) Signed-off-by: Hui Kang --- docs/features/kustomize/rollout_cr_schema.json | 7 +++++-- hack/gen-crd-spec/main.go | 2 +- manifests/crds/rollout-crd.yaml | 4 +++- manifests/install.yaml | 4 +++- manifests/namespace-install.yaml | 4 +++- test/e2e/bluegreen_test.go | 3 +++ 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/docs/features/kustomize/rollout_cr_schema.json b/docs/features/kustomize/rollout_cr_schema.json index c228c79733..0578824a9d 100644 --- a/docs/features/kustomize/rollout_cr_schema.json +++ b/docs/features/kustomize/rollout_cr_schema.json @@ -2834,9 +2834,12 @@ "x-kubernetes-patch-strategy": "merge" }, "volumes": { + "items": { + "x-kubernetes-preserve-unknown-fields": true + }, + "type": "array", "x-kubernetes-patch-merge-key": "name", - "x-kubernetes-patch-strategy": "merge,retainKeys", - "x-kubernetes-preserve-unknown-fields": true + "x-kubernetes-patch-strategy": "merge,retainKeys" } }, "required": [ diff --git a/hack/gen-crd-spec/main.go b/hack/gen-crd-spec/main.go index 42f611d009..8ed5f46ede 100644 --- a/hack/gen-crd-spec/main.go +++ b/hack/gen-crd-spec/main.go @@ -244,7 +244,7 @@ func removeK8S118Fields(un *unstructured.Unstructured) { setValidationOverride(un, preserveUnknownFields, "spec.template.spec.ephemeralContainers[].resources.requests") // Replace this with "spec.template.spec.volumes[].ephemeral.volumeClaimTemplate.spec.resources.{limits/requests}" // when it's ok to only support k8s 1.17+ - setValidationOverride(un, preserveUnknownFields, "spec.template.spec.volumes") + setValidationOverride(un, preserveUnknownFields, "spec.template.spec.volumes[]") case "Experiment": setValidationOverride(un, preserveUnknownFields, "spec.templates[].template.spec.containers[].resources.limits") setValidationOverride(un, preserveUnknownFields, "spec.templates[].template.spec.containers[].resources.requests") diff --git a/manifests/crds/rollout-crd.yaml b/manifests/crds/rollout-crd.yaml index 22a475b1c4..8c258e1405 100644 --- a/manifests/crds/rollout-crd.yaml +++ b/manifests/crds/rollout-crd.yaml @@ -2882,7 +2882,9 @@ spec: - whenUnsatisfiable x-kubernetes-list-type: map volumes: - x-kubernetes-preserve-unknown-fields: true + items: + x-kubernetes-preserve-unknown-fields: true + type: array required: - containers type: object diff --git a/manifests/install.yaml b/manifests/install.yaml index 96985377db..bee89265c9 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -13390,7 +13390,9 @@ spec: - whenUnsatisfiable x-kubernetes-list-type: map volumes: - x-kubernetes-preserve-unknown-fields: true + items: + x-kubernetes-preserve-unknown-fields: true + type: array required: - containers type: object diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index aab81d4eec..ea598cc1b0 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -13390,7 +13390,9 @@ spec: - whenUnsatisfiable x-kubernetes-list-type: map volumes: - x-kubernetes-preserve-unknown-fields: true + items: + x-kubernetes-preserve-unknown-fields: true + type: array required: - containers type: object diff --git a/test/e2e/bluegreen_test.go b/test/e2e/bluegreen_test.go index 0d1e38bf5d..a7c263acb3 100644 --- a/test/e2e/bluegreen_test.go +++ b/test/e2e/bluegreen_test.go @@ -111,6 +111,9 @@ spec: requests: memory: 16Mi cpu: 1m + volumes: + - name: cache-volume + emptyDir: {} `). When(). ApplyManifests(). From b83307370d461a2e63c75810d1b74f29c4c55112 Mon Sep 17 00:00:00 2001 From: RaviHari Date: Thu, 13 Jan 2022 02:09:58 +0530 Subject: [PATCH 039/175] docs: Add notiication templates for rollouts and analysis (#1753) * docs: Add notiication templates for rollouts and analysis Signed-off-by: Ravi Hari * docs: update installation files Signed-off-by: Ravi Hari --- manifests/notifications-install.yaml | 140 ++++++++++++++++++ manifests/notifications/kustomization.yaml | 7 +- .../notifications/on-analysis-run-error.yaml | 33 +++++ .../notifications/on-analysis-run-failed.yaml | 33 +++++ .../on-analysis-run-running.yaml | 33 +++++ .../notifications/on-rollout-aborted.yaml | 33 +++++ .../notifications/on-rollout-paused.yaml | 33 +++++ 7 files changed, 311 insertions(+), 1 deletion(-) create mode 100644 manifests/notifications/on-analysis-run-error.yaml create mode 100644 manifests/notifications/on-analysis-run-failed.yaml create mode 100644 manifests/notifications/on-analysis-run-running.yaml create mode 100644 manifests/notifications/on-rollout-aborted.yaml create mode 100644 manifests/notifications/on-rollout-paused.yaml diff --git a/manifests/notifications-install.yaml b/manifests/notifications-install.yaml index f7d8a4436e..c0f6b2aa59 100644 --- a/manifests/notifications-install.yaml +++ b/manifests/notifications-install.yaml @@ -1,6 +1,110 @@ # This is an auto-generated file. DO NOT EDIT apiVersion: v1 data: + template.analysis-run-error: | + message: Rollout {{.rollout.metadata.name}}'s analysis run is in error state. + email: + subject: Rollout {{.rollout.metadata.name}}'s analysis run is in error state. + slack: + attachments: | + [{ + "title": "{{ .rollout.metadata.name}}", + "color": "#ECB22E", + "fields": [ + { + "title": "Strategy", + "value": "{{if .rollout.spec.strategy.blueGreen}}BlueGreen{{end}}{{if .rollout.spec.strategy.canary}}Canary{{end}}", + "short": true + } + {{range $index, $c := .rollout.spec.template.spec.containers}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.name}}", + "value": "{{$c.image}}", + "short": true + } + {{end}} + ] + }] + template.analysis-run-failed: | + message: Rollout {{.rollout.metadata.name}}'s analysis run failed. + email: + subject: Rollout {{.rollout.metadata.name}}'s analysis run failed. + slack: + attachments: | + [{ + "title": "{{ .rollout.metadata.name}}", + "color": "#E01E5A", + "fields": [ + { + "title": "Strategy", + "value": "{{if .rollout.spec.strategy.blueGreen}}BlueGreen{{end}}{{if .rollout.spec.strategy.canary}}Canary{{end}}", + "short": true + } + {{range $index, $c := .rollout.spec.template.spec.containers}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.name}}", + "value": "{{$c.image}}", + "short": true + } + {{end}} + ] + }] + template.analysis-run-running: | + message: Rollout {{.rollout.metadata.name}}'s analysis run is running. + email: + subject: Rollout {{.rollout.metadata.name}}'s analysis run is running. + slack: + attachments: | + [{ + "title": "{{ .rollout.metadata.name}}", + "color": "#18be52", + "fields": [ + { + "title": "Strategy", + "value": "{{if .rollout.spec.strategy.blueGreen}}BlueGreen{{end}}{{if .rollout.spec.strategy.canary}}Canary{{end}}", + "short": true + } + {{range $index, $c := .rollout.spec.template.spec.containers}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.name}}", + "value": "{{$c.image}}", + "short": true + } + {{end}} + ] + }] + template.rollout-aborted: | + message: Rollout {{.rollout.metadata.name}} has been aborted. + email: + subject: Rollout {{.rollout.metadata.name}} has been aborted. + slack: + attachments: | + [{ + "title": "{{ .rollout.metadata.name}}", + "color": "#E01E5A", + "fields": [ + { + "title": "Strategy", + "value": "{{if .rollout.spec.strategy.blueGreen}}BlueGreen{{end}}{{if .rollout.spec.strategy.canary}}Canary{{end}}", + "short": true + } + {{range $index, $c := .rollout.spec.template.spec.containers}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.name}}", + "value": "{{$c.image}}", + "short": true + } + {{end}} + ] + }] template.rollout-completed: | message: Rollout {{.rollout.metadata.name}} has been completed. email: @@ -27,6 +131,32 @@ data: {{end}} ] }] + template.rollout-paused: | + message: Rollout {{.rollout.metadata.name}} has been paused. + email: + subject: Rollout {{.rollout.metadata.name}} has been paused. + slack: + attachments: | + [{ + "title": "{{ .rollout.metadata.name}}", + "color": "#18be52", + "fields": [ + { + "title": "Strategy", + "value": "{{if .rollout.spec.strategy.blueGreen}}BlueGreen{{end}}{{if .rollout.spec.strategy.canary}}Canary{{end}}", + "short": true + } + {{range $index, $c := .rollout.spec.template.spec.containers}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.name}}", + "value": "{{$c.image}}", + "short": true + } + {{end}} + ] + }] template.rollout-step-completed: | message: Rollout {{.rollout.metadata.name}} step number {{ add .rollout.status.currentStepIndex 1}}/{{len .rollout.spec.strategy.canary.steps}} has been completed. email: @@ -120,8 +250,18 @@ data: {{end}} ] }] + trigger.on-analysis-run-error: | + - send: [analysis-run-error] + trigger.on-analysis-run-failed: | + - send: [analysis-run-failed] + trigger.on-analysis-run-running: | + - send: [analysis-run-running] + trigger.on-rollout-aborted: | + - send: [rollout-aborted] trigger.on-rollout-completed: | - send: [rollout-completed] + trigger.on-rollout-paused: | + - send: [rollout-paused] trigger.on-rollout-step-completed: | - send: [rollout-step-completed] trigger.on-rollout-updated: | diff --git a/manifests/notifications/kustomization.yaml b/manifests/notifications/kustomization.yaml index d63cbca662..e8b7beeed9 100644 --- a/manifests/notifications/kustomization.yaml +++ b/manifests/notifications/kustomization.yaml @@ -8,4 +8,9 @@ patchesStrategicMerge: - on-rollout-completed.yaml - on-scaling-replica-set.yaml - on-rollout-step-completed.yaml - - on-rollout-updated.yaml \ No newline at end of file + - on-rollout-updated.yaml + - on-rollout-aborted.yaml + - on-rollout-paused.yaml + - on-analysis-run-running.yaml + - on-analysis-run-error.yaml + - on-analysis-run-failed.yaml diff --git a/manifests/notifications/on-analysis-run-error.yaml b/manifests/notifications/on-analysis-run-error.yaml new file mode 100644 index 0000000000..e92aff4487 --- /dev/null +++ b/manifests/notifications/on-analysis-run-error.yaml @@ -0,0 +1,33 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: argo-rollouts-notification-configmap +data: + trigger.on-analysis-run-error: | + - send: [analysis-run-error] + template.analysis-run-error: | + message: Rollout {{.rollout.metadata.name}}'s analysis run is in error state. + email: + subject: Rollout {{.rollout.metadata.name}}'s analysis run is in error state. + slack: + attachments: | + [{ + "title": "{{ .rollout.metadata.name}}", + "color": "#ECB22E", + "fields": [ + { + "title": "Strategy", + "value": "{{if .rollout.spec.strategy.blueGreen}}BlueGreen{{end}}{{if .rollout.spec.strategy.canary}}Canary{{end}}", + "short": true + } + {{range $index, $c := .rollout.spec.template.spec.containers}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.name}}", + "value": "{{$c.image}}", + "short": true + } + {{end}} + ] + }] diff --git a/manifests/notifications/on-analysis-run-failed.yaml b/manifests/notifications/on-analysis-run-failed.yaml new file mode 100644 index 0000000000..822fde16c9 --- /dev/null +++ b/manifests/notifications/on-analysis-run-failed.yaml @@ -0,0 +1,33 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: argo-rollouts-notification-configmap +data: + trigger.on-analysis-run-failed: | + - send: [analysis-run-failed] + template.analysis-run-failed: | + message: Rollout {{.rollout.metadata.name}}'s analysis run failed. + email: + subject: Rollout {{.rollout.metadata.name}}'s analysis run failed. + slack: + attachments: | + [{ + "title": "{{ .rollout.metadata.name}}", + "color": "#E01E5A", + "fields": [ + { + "title": "Strategy", + "value": "{{if .rollout.spec.strategy.blueGreen}}BlueGreen{{end}}{{if .rollout.spec.strategy.canary}}Canary{{end}}", + "short": true + } + {{range $index, $c := .rollout.spec.template.spec.containers}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.name}}", + "value": "{{$c.image}}", + "short": true + } + {{end}} + ] + }] diff --git a/manifests/notifications/on-analysis-run-running.yaml b/manifests/notifications/on-analysis-run-running.yaml new file mode 100644 index 0000000000..c7cbd6ac07 --- /dev/null +++ b/manifests/notifications/on-analysis-run-running.yaml @@ -0,0 +1,33 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: argo-rollouts-notification-configmap +data: + trigger.on-analysis-run-running: | + - send: [analysis-run-running] + template.analysis-run-running: | + message: Rollout {{.rollout.metadata.name}}'s analysis run is running. + email: + subject: Rollout {{.rollout.metadata.name}}'s analysis run is running. + slack: + attachments: | + [{ + "title": "{{ .rollout.metadata.name}}", + "color": "#18be52", + "fields": [ + { + "title": "Strategy", + "value": "{{if .rollout.spec.strategy.blueGreen}}BlueGreen{{end}}{{if .rollout.spec.strategy.canary}}Canary{{end}}", + "short": true + } + {{range $index, $c := .rollout.spec.template.spec.containers}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.name}}", + "value": "{{$c.image}}", + "short": true + } + {{end}} + ] + }] diff --git a/manifests/notifications/on-rollout-aborted.yaml b/manifests/notifications/on-rollout-aborted.yaml new file mode 100644 index 0000000000..6ad3448ce5 --- /dev/null +++ b/manifests/notifications/on-rollout-aborted.yaml @@ -0,0 +1,33 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: argo-rollouts-notification-configmap +data: + trigger.on-rollout-aborted: | + - send: [rollout-aborted] + template.rollout-aborted: | + message: Rollout {{.rollout.metadata.name}} has been aborted. + email: + subject: Rollout {{.rollout.metadata.name}} has been aborted. + slack: + attachments: | + [{ + "title": "{{ .rollout.metadata.name}}", + "color": "#E01E5A", + "fields": [ + { + "title": "Strategy", + "value": "{{if .rollout.spec.strategy.blueGreen}}BlueGreen{{end}}{{if .rollout.spec.strategy.canary}}Canary{{end}}", + "short": true + } + {{range $index, $c := .rollout.spec.template.spec.containers}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.name}}", + "value": "{{$c.image}}", + "short": true + } + {{end}} + ] + }] diff --git a/manifests/notifications/on-rollout-paused.yaml b/manifests/notifications/on-rollout-paused.yaml new file mode 100644 index 0000000000..48085f67b8 --- /dev/null +++ b/manifests/notifications/on-rollout-paused.yaml @@ -0,0 +1,33 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: argo-rollouts-notification-configmap +data: + trigger.on-rollout-paused: | + - send: [rollout-paused] + template.rollout-paused: | + message: Rollout {{.rollout.metadata.name}} has been paused. + email: + subject: Rollout {{.rollout.metadata.name}} has been paused. + slack: + attachments: | + [{ + "title": "{{ .rollout.metadata.name}}", + "color": "#18be52", + "fields": [ + { + "title": "Strategy", + "value": "{{if .rollout.spec.strategy.blueGreen}}BlueGreen{{end}}{{if .rollout.spec.strategy.canary}}Canary{{end}}", + "short": true + } + {{range $index, $c := .rollout.spec.template.spec.containers}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.name}}", + "value": "{{$c.image}}", + "short": true + } + {{end}} + ] + }] From 7f65b2baa9e26c496104b530310cdb733b3f3124 Mon Sep 17 00:00:00 2001 From: "Kostis (Codefresh)" <39800303+kostis-codefresh@users.noreply.github.com> Date: Wed, 12 Jan 2022 22:40:16 +0200 Subject: [PATCH 040/175] docs: mention default notification templates (#1725) Signed-off-by: Kostis Kapelonis --- docs/features/notifications.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/features/notifications.md b/docs/features/notifications.md index b0a14187ff..1556345734 100644 --- a/docs/features/notifications.md +++ b/docs/features/notifications.md @@ -50,6 +50,15 @@ stringData: Learn more about supported services and configuration settings in services [documentation](../generated/notification-services/overview.md). +## Default Trigger templates + +Currently the following triggers have [built-in templates](https://github.com/argoproj/argo-rollouts/tree/master/manifests/notifications). + +* `on-rollout-completed` when a rollout is finished and all its steps are completed +* `on-rollout-step-completed` when an individual step inside a rollout definition is completed +* `on-rollout-updated` when a rollout definition is changed +* `on-scaling-replica-set` when the number of replicas in a rollout is changed + ## Subscriptions The end-users can start leveraging notifications using `notifications.argoproj.io/subscribe..: ` annotation. From 4739bcd2d9b4910805fd9529d5afd385dbe51bbd Mon Sep 17 00:00:00 2001 From: Noam Gal Date: Wed, 12 Jan 2022 22:40:37 +0200 Subject: [PATCH 041/175] feat(analysis): Allow analysis arguments to get valueFrom Rollout status (#1242) (#1629) * use objx to read value from Rollout manifest Signed-off-by: Noam Gal * handle `[]` annotation correcly in BuildArgumentsForRolloutAnalysisRun Signed-off-by: Noam Gal * validate valueFrom correctly Signed-off-by: Noam Gal * use jsonpath instead of objx return err if path is inavlid in runtime (don't check in validation time) Signed-off-by: Noam Gal * parse path in code, instead of using jsonPath Signed-off-by: Noam Gal * fixed test Signed-off-by: Noam Gal * updated documentation Signed-off-by: Noam Gal * added tests for coverage Signed-off-by: Noam Gal * fixed lint Signed-off-by: Noam Gal * added another test case Signed-off-by: Noam Gal * fixed case when path ends with "]" Signed-off-by: Noam Gal * removed objx dependency Signed-off-by: Noam Gal --- docs/features/analysis.md | 9 +- pkg/apis/rollouts/validation/validation.go | 3 +- .../validation/validation_references.go | 3 +- rollout/analysis.go | 6 +- rollout/experiment.go | 6 +- utils/analysis/factory.go | 65 +++++++++-- utils/analysis/factory_test.go | 110 ++++++++++++++++-- 7 files changed, 181 insertions(+), 21 deletions(-) diff --git a/docs/features/analysis.md b/docs/features/analysis.md index 6456c70415..acffd7f04f 100644 --- a/docs/features/analysis.md +++ b/docs/features/analysis.md @@ -426,8 +426,9 @@ spec: valueFrom: podTemplateHashValue: Latest ``` -Analysis arguments also support valueFrom for reading metadata fields and passing them as arguments to AnalysisTemplate. -An example would be to reference metadata labels like env and region and passing them along to AnalysisTemplate. +Analysis arguments also support valueFrom for reading any Rollout fields and passing them as arguments to AnalysisTemplate. +An example would be to reference metadata labels like env and region and passing them along to AnalysisTemplate, or any field +from the Rollout status ```yaml apiVersion: argoproj.io/v1alpha1 kind: Rollout @@ -457,6 +458,10 @@ spec: valueFrom: fieldRef: fieldPath: metadata.labels['region'] + - name: canary-hash + valueFrom: + fieldRef: + fieldPath: status.canary.weights.canary.podTemplateHash ``` ## BlueGreen Pre Promotion Analysis diff --git a/pkg/apis/rollouts/validation/validation.go b/pkg/apis/rollouts/validation/validation.go index 5afb080ddc..da03a1fd95 100644 --- a/pkg/apis/rollouts/validation/validation.go +++ b/pkg/apis/rollouts/validation/validation.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "strconv" + "strings" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -278,7 +279,7 @@ func ValidateRolloutStrategyCanary(rollout *v1alpha1.Rollout, fldPath *field.Pat for _, arg := range analysisRunArgs { if arg.ValueFrom != nil { - if arg.ValueFrom.FieldRef != nil { + if arg.ValueFrom.FieldRef != nil && strings.HasPrefix(arg.ValueFrom.FieldRef.FieldPath, "metadata") { _, err := fieldpath.ExtractFieldPathAsString(rollout, arg.ValueFrom.FieldRef.FieldPath) if err != nil { allErrs = append(allErrs, field.Invalid(stepFldPath.Child("analyses"), analysisRunArgs, InvalidAnalysisArgsMessage)) diff --git a/pkg/apis/rollouts/validation/validation_references.go b/pkg/apis/rollouts/validation/validation_references.go index 98efefd9f2..e570bc7c03 100644 --- a/pkg/apis/rollouts/validation/validation_references.go +++ b/pkg/apis/rollouts/validation/validation_references.go @@ -382,7 +382,8 @@ func buildAnalysisArgs(args []v1alpha1.AnalysisRunArgument, r *v1alpha1.Rollout) }, }, } - return analysisutil.BuildArgumentsForRolloutAnalysisRun(args, &stableRSDummy, &newRSDummy, r) + res, _ := analysisutil.BuildArgumentsForRolloutAnalysisRun(args, &stableRSDummy, &newRSDummy, r) + return res } // validateAnalysisMetrics validates the metrics of an Analysis object diff --git a/rollout/analysis.go b/rollout/analysis.go index ce4bb78719..cc2e66b07d 100644 --- a/rollout/analysis.go +++ b/rollout/analysis.go @@ -347,7 +347,11 @@ func (c *rolloutContext) reconcileBackgroundAnalysisRun() (*v1alpha1.AnalysisRun } func (c *rolloutContext) createAnalysisRun(rolloutAnalysis *v1alpha1.RolloutAnalysis, infix string, labels map[string]string) (*v1alpha1.AnalysisRun, error) { - args := analysisutil.BuildArgumentsForRolloutAnalysisRun(rolloutAnalysis.Args, c.stableRS, c.newRS, c.rollout) + args, err := analysisutil.BuildArgumentsForRolloutAnalysisRun(rolloutAnalysis.Args, c.stableRS, c.newRS, c.rollout) + if err != nil { + return nil, err + } + podHash := replicasetutil.GetPodTemplateHash(c.newRS) if podHash == "" { return nil, fmt.Errorf("Latest ReplicaSet '%s' has no pod hash in the labels", c.newRS.Name) diff --git a/rollout/experiment.go b/rollout/experiment.go index a000fe014e..67b7e534b4 100644 --- a/rollout/experiment.go +++ b/rollout/experiment.go @@ -106,7 +106,11 @@ func GetExperimentFromTemplate(r *v1alpha1.Rollout, stableRS, newRS *appsv1.Repl } for i := range step.Analyses { analysis := step.Analyses[i] - args := analysisutil.BuildArgumentsForRolloutAnalysisRun(analysis.Args, stableRS, newRS, r) + args, err := analysisutil.BuildArgumentsForRolloutAnalysisRun(analysis.Args, stableRS, newRS, r) + if err != nil { + return nil, err + } + analysisTemplate := v1alpha1.ExperimentAnalysisTemplateRef{ Name: analysis.Name, TemplateName: analysis.TemplateName, diff --git a/utils/analysis/factory.go b/utils/analysis/factory.go index e00ddc7e95..b500bfd30d 100644 --- a/utils/analysis/factory.go +++ b/utils/analysis/factory.go @@ -3,17 +3,20 @@ package analysis import ( "encoding/json" "fmt" + "regexp" "strconv" + "strings" + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" templateutil "github.com/argoproj/argo-rollouts/utils/template" - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" appsv1 "k8s.io/api/apps/v1" "k8s.io/kubernetes/pkg/fieldpath" ) // BuildArgumentsForRolloutAnalysisRun builds the arguments for a analysis base created by a rollout -func BuildArgumentsForRolloutAnalysisRun(args []v1alpha1.AnalysisRunArgument, stableRS, newRS *appsv1.ReplicaSet, r *v1alpha1.Rollout) []v1alpha1.Argument { +func BuildArgumentsForRolloutAnalysisRun(args []v1alpha1.AnalysisRunArgument, stableRS, newRS *appsv1.ReplicaSet, r *v1alpha1.Rollout) ([]v1alpha1.Argument, error) { + var err error arguments := []v1alpha1.Argument{} for i := range args { arg := args[i] @@ -26,21 +29,28 @@ func BuildArgumentsForRolloutAnalysisRun(args []v1alpha1.AnalysisRunArgument, st case v1alpha1.Stable: value = stableRS.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] } - } else { - if arg.ValueFrom.FieldRef != nil { - value, _ = fieldpath.ExtractFieldPathAsString(r, arg.ValueFrom.FieldRef.FieldPath) + } else if arg.ValueFrom.FieldRef != nil { + if strings.HasPrefix(arg.ValueFrom.FieldRef.FieldPath, "metadata") { + value, err = fieldpath.ExtractFieldPathAsString(r, arg.ValueFrom.FieldRef.FieldPath) + if err != nil { + return nil, err + } + } else { + // in case of error - return empty value for Validation stage, so it will pass validation + // returned error will only be used in Analysis stage + value, err = extractValueFromRollout(r, arg.ValueFrom.FieldRef.FieldPath) } } - } + analysisArg := v1alpha1.Argument{ Name: arg.Name, Value: &value, } arguments = append(arguments, analysisArg) - } - return arguments + + return arguments, err } // PostPromotionLabels returns a map[string]string of common labels for the post promotion analysis @@ -217,3 +227,42 @@ func ValidateMetric(metric v1alpha1.Metric) error { } return nil } + +func extractValueFromRollout(r *v1alpha1.Rollout, path string) (string, error) { + j, _ := json.Marshal(r) + m := interface{}(nil) + json.Unmarshal(j, &m) + sections := regexp.MustCompile("[\\.\\[\\]]+").Split(path, -1) + for _, section := range sections { + if section == "" { + continue // if path ends with a separator char, Split returns an empty last section + } + + if asArray, ok := m.([]interface{}); ok { + if i, err := strconv.Atoi(section); err != nil { + return "", fmt.Errorf("invalid index '%s'", section) + } else if i >= len(asArray) { + return "", fmt.Errorf("index %d out of range", i) + } else { + m = asArray[i] + } + } else if asMap, ok := m.(map[string]interface{}); ok { + m = asMap[section] + } else { + return "", fmt.Errorf("invalid path %s in rollout", path) + } + } + + if m == nil { + return "", fmt.Errorf("invalid path %s in rollout", path) + } + + var isArray, isMap bool + _, isArray = m.([]interface{}) + _, isMap = m.(map[string]interface{}) + if isArray || isMap { + return "", fmt.Errorf("path %s in rollout must terminate in a primitive value", path) + } + + return fmt.Sprintf("%v", m), nil +} diff --git a/utils/analysis/factory_test.go b/utils/analysis/factory_test.go index 08ed88359e..21b55fb592 100644 --- a/utils/analysis/factory_test.go +++ b/utils/analysis/factory_test.go @@ -4,22 +4,21 @@ import ( "fmt" "testing" - "k8s.io/apimachinery/pkg/util/intstr" - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/annotations" "github.com/stretchr/testify/assert" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/uuid" "k8s.io/utils/pointer" ) func TestBuildArgumentsForRolloutAnalysisRun(t *testing.T) { - new := v1alpha1.Latest stable := v1alpha1.Stable + annotationPath := fmt.Sprintf("metadata.annotations['%s']", annotations.RevisionAnnotation) rolloutAnalysis := &v1alpha1.RolloutAnalysis{ Args: []v1alpha1.AnalysisRunArgument{ { @@ -50,6 +49,18 @@ func TestBuildArgumentsForRolloutAnalysisRun(t *testing.T) { FieldRef: &v1alpha1.FieldRef{FieldPath: "metadata.labels['env']"}, }, }, + { + Name: annotationPath, + ValueFrom: &v1alpha1.ArgumentValueFrom{ + FieldRef: &v1alpha1.FieldRef{FieldPath: annotationPath}, + }, + }, + { + Name: "status.pauseConditions[0].reason", + ValueFrom: &v1alpha1.ArgumentValueFrom{ + FieldRef: &v1alpha1.FieldRef{FieldPath: "status.pauseConditions[0].reason"}, + }, + }, }, } stableRS := &appsv1.ReplicaSet{ @@ -64,7 +75,6 @@ func TestBuildArgumentsForRolloutAnalysisRun(t *testing.T) { Labels: map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: "123456"}, }, } - ro := &v1alpha1.Rollout{ ObjectMeta: metav1.ObjectMeta{ UID: uuid.NewUUID(), @@ -102,16 +112,24 @@ func TestBuildArgumentsForRolloutAnalysisRun(t *testing.T) { "env": "test", }}, }, - Status: v1alpha1.RolloutStatus{}, + Status: v1alpha1.RolloutStatus{ + PauseConditions: []v1alpha1.PauseCondition{ + { + Reason: "test-reason", + }, + }, + }, } - args := BuildArgumentsForRolloutAnalysisRun(rolloutAnalysis.Args, stableRS, newRS, ro) + args, err := BuildArgumentsForRolloutAnalysisRun(rolloutAnalysis.Args, stableRS, newRS, ro) + assert.NoError(t, err) assert.Contains(t, args, v1alpha1.Argument{Name: "hard-coded-value-key", Value: pointer.StringPtr("hard-coded-value")}) assert.Contains(t, args, v1alpha1.Argument{Name: "stable-key", Value: pointer.StringPtr("abcdef")}) assert.Contains(t, args, v1alpha1.Argument{Name: "new-key", Value: pointer.StringPtr("123456")}) assert.Contains(t, args, v1alpha1.Argument{Name: "metadata.labels['app']", Value: pointer.StringPtr("app")}) assert.Contains(t, args, v1alpha1.Argument{Name: "metadata.labels['env']", Value: pointer.StringPtr("test")}) - + assert.Contains(t, args, v1alpha1.Argument{Name: annotationPath, Value: pointer.StringPtr("1")}) + assert.Contains(t, args, v1alpha1.Argument{Name: "status.pauseConditions[0].reason", Value: pointer.StringPtr("test-reason")}) } func TestPrePromotionLabels(t *testing.T) { @@ -426,3 +444,81 @@ func TestResolveMetricArgsWithQuotes(t *testing.T) { assert.NoError(t, err) assert.Equal(t, fmt.Sprintf(arg), newMetric.SuccessCondition) } + +func Test_extractValueFromRollout(t *testing.T) { + ro := &v1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{ + "app": "app", + }, + }, + Status: v1alpha1.RolloutStatus{ + PauseConditions: []v1alpha1.PauseCondition{ + { + Reason: "test-reason", + }, + }, + }, + } + tests := map[string]struct { + path string + want string + wantErr string + }{ + "should return a simple metadata value": { + path: "metadata.name", + want: "test", + }, + "should return a label using dot notation": { + path: "metadata.labels.app", + want: "app", + }, + "should fail returning a label using accessor notation": { + path: "metadata.labels['app']", + wantErr: "invalid path metadata.labels['app'] in rollout", + }, + "should return a status value": { + path: "status.pauseConditions[0].reason", + want: "test-reason", + }, + "should fail when array indexer is not an int": { + path: "status.pauseConditions[blah].reason", + wantErr: "invalid index 'blah'", + }, + "should fail when array indexer is out of range": { + path: "status.pauseConditions[12].reason", + wantErr: "index 12 out of range", + }, + "should fail when path references an empty field": { + path: "status.pauseConditions[0].startTime", + wantErr: "invalid path status.pauseConditions[0].startTime in rollout", + }, + "should fail when path is inavlid": { + path: "some.invalid[2].non.existing.path", + wantErr: "invalid path some.invalid[2].non.existing.path in rollout", + }, + "should fail when path references a non-primitive value": { + path: "status.pauseConditions[0]", + wantErr: "path status.pauseConditions[0] in rollout must terminate in a primitive value", + }, + } + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + got, err := extractValueFromRollout(ro, tt.path) + if err != nil { + if tt.wantErr != "" { + assert.EqualError(t, err, tt.wantErr) + } else { + t.Errorf("extractValueFromRollout() error = %v", err) + } + + return + } + + if got != tt.want { + t.Errorf("extractValueFromRollout() = %v, want %v", got, tt.want) + } + }) + } +} From a4bf576b74226387be07d37db41846e941081ffb Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Thu, 13 Jan 2022 14:36:27 -0800 Subject: [PATCH 042/175] chore: make ci/local codegen consistent (#1772) Signed-off-by: Jesse Suen --- .github/workflows/go.yml | 35 +- Makefile | 66 +- analysis/analysis.go | 2 +- .../features/kustomize/rollout_cr_schema.json | 48 + hack/installers/install-codegen-go-tools.sh | 57 + hack/installers/install-protoc.sh | 44 + hack/tools.go | 1 + manifests/crds/analysis-run-crd.yaml | 1 + manifests/crds/analysis-template-crd.yaml | 1 + .../crds/cluster-analysis-template-crd.yaml | 1 + manifests/install.yaml | 3 + manifests/namespace-install.yaml | 3 + pkg/apis/rollouts/v1alpha1/analysis_types.go | 2 +- pkg/apis/rollouts/v1alpha1/generated.pb.go | 2716 ++++++++++++----- pkg/apis/rollouts/v1alpha1/generated.proto | 83 +- .../rollouts/v1alpha1/openapi_generated.go | 277 +- 16 files changed, 2566 insertions(+), 774 deletions(-) create mode 100755 hack/installers/install-codegen-go-tools.sh create mode 100755 hack/installers/install-protoc.sh diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 976dee047d..e7472b3c38 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -64,7 +64,6 @@ jobs: runs-on: ubuntu-latest env: GOPATH: /home/runner/go - PROTOC_ZIP: protoc-3.12.3-linux-x86_64.zip steps: - name: Checkout code uses: actions/checkout@v2 @@ -84,53 +83,23 @@ jobs: with: path: /home/runner/go/bin key: go-bin-v1-${{ hashFiles('**/go.mod') }} - - uses: actions/cache@v2 - with: - path: protoc-3.12.3-linux-x86_64.zip - key: protoc-3.12.3-linux-x86_64.zip - name: Install protoc run: | - set -eux -o pipefail - curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v3.12.3/$PROTOC_ZIP - sudo unzip -o $PROTOC_ZIP -d /usr/local bin/protoc - sudo unzip -o $PROTOC_ZIP -d /usr/local 'include/*' - sudo chmod +x /usr/local/bin/protoc - sudo find /usr/local/include -type f | xargs sudo chmod a+r - sudo find /usr/local/include -type d | xargs sudo chmod a+rx - ls /usr/local/include/google/protobuf/ - + make install-toolchain - name: Add ~/go/bin to PATH run: | echo "/home/runner/go/bin" >> $GITHUB_PATH - name: Add /usr/local/bin to PATH run: | echo "/usr/local/bin" >> $GITHUB_PATH - - name: Create links run: | mkdir -p ~/go/src/github.com/argoproj cp -a ../argo-rollouts ~/go/src/github.com/argoproj - - name: Vendor and Download - run: | - go mod vendor -v - go mod download - - - name: Install UI code generator - run: | - wget https://repo1.maven.org/maven2/io/swagger/codegen/v3/swagger-codegen-cli/3.0.25/swagger-codegen-cli-3.0.25.jar -O swagger-codegen-cli.jar - echo "#!/usr/bin/java -jar" > swagger-codegen - cat swagger-codegen-cli.jar >> swagger-codegen - chmod +x swagger-codegen - sudo mv swagger-codegen /usr/local/bin/swagger-codegen - rm swagger-codegen-cli.jar - - - uses: actions/setup-java@v1 - with: - java-version: "9.0.4" - - name: Run codegen run: | + make go-mod-vendor make codegen make manifests make docs diff --git a/Makefile b/Makefile index 644cbe1784..686a0a136b 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,7 @@ define protoc # protoc $(1) PATH=${DIST_DIR}:$$PATH protoc \ -I /usr/local/include \ + -I ${DIST_DIR}/protoc-include \ -I . \ -I ./vendor \ -I ${GOPATH}/src \ @@ -69,63 +70,27 @@ go-mod-vendor: go mod tidy go mod vendor -# go_get,path -# use go_get to install a toolchain binary for a package which is *not* vendored in go.mod -define go_get - cd /tmp && GOBIN=${DIST_DIR} go get $(1) -endef - -# go_install,path -# use go_install to install a toolchain binary for a package which *is* vendored in go.mod -define go_install - GOBIN=${DIST_DIR} go install -mod=vendor ./vendor/$(1) -endef - -.PHONY: $(DIST_DIR)/controller-gen -$(DIST_DIR)/controller-gen: - $(call go_get,sigs.k8s.io/controller-tools/cmd/controller-gen@v0.5.0) - -.PHONY: $(DIST_DIR)/bin/goimports -$(DIST_DIR)/bin/goimports: - $(call go_get,golang.org/x/tools/cmd/goimports) - -.PHONY: $(DIST_DIR)/go-to-protobuf -$(DIST_DIR)/go-to-protobuf: go-mod-vendor - $(call go_install,k8s.io/code-generator/cmd/go-to-protobuf) - -.PHONY: $(DIST_DIR)/protoc-gen-gogo -$(DIST_DIR)/protoc-gen-gogo: go-mod-vendor - $(call go_install,github.com/gogo/protobuf/protoc-gen-gogo) - -.PHONY: $(DIST_DIR)/protoc-gen-gogofast -$(DIST_DIR)/protoc-gen-gogofast: - $(call go_install,github.com/gogo/protobuf/protoc-gen-gogofast) - -.PHONY: $(DIST_DIR)/protoc-gen-grpc-gateway -$(DIST_DIR)/protoc-gen-grpc-gateway: go-mod-vendor - $(call go_install,github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway) - -.PHONY: $(DIST_DIR)/protoc-gen-swagger -$(DIST_DIR)/protoc-gen-swagger: go-mod-vendor - $(call go_install,github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger) +.PHONY: install-go-tools-local +install-go-tools-local: go-mod-vendor + ./hack/installers/install-codegen-go-tools.sh -.PHONY: $(DIST_DIR)/openapi-gen -$(DIST_DIR)/openapi-gen: go-mod-vendor - $(call go_install,k8s.io/kube-openapi/cmd/openapi-gen) +.PHONY: install-protoc-local +install-protoc-local: + ./hack/installers/install-protoc.sh -.PHONY: $(DIST_DIR)/mockery -$(DIST_DIR)/mockery: - $(call go_get,github.com/vektra/mockery/v2@v2.6.0) +# Installs all tools required to build and test locally +.PHONY: install-tools-local +install-tools-local: install-go-tools-local install-protoc-local TYPES := $(shell find pkg/apis/rollouts/v1alpha1 -type f -name '*.go' -not -name openapi_generated.go -not -name '*generated*' -not -name '*test.go') APIMACHINERY_PKGS=k8s.io/apimachinery/pkg/util/intstr,+k8s.io/apimachinery/pkg/api/resource,+k8s.io/apimachinery/pkg/runtime/schema,+k8s.io/apimachinery/pkg/runtime,k8s.io/apimachinery/pkg/apis/meta/v1,k8s.io/api/core/v1,k8s.io/api/batch/v1 .PHONY: install-toolchain -install-toolchain: go-mod-vendor $(DIST_DIR)/controller-gen $(DIST_DIR)/bin/goimports $(DIST_DIR)/go-to-protobuf $(DIST_DIR)/protoc-gen-gogo $(DIST_DIR)/protoc-gen-gogofast $(DIST_DIR)/protoc-gen-grpc-gateway $(DIST_DIR)/protoc-gen-swagger $(DIST_DIR)/openapi-gen $(DIST_DIR)/mockery +install-toolchain: install-go-tools-local install-protoc-local # generates all auto-generated code .PHONY: codegen -codegen: gen-proto gen-k8scodegen gen-openapi gen-mocks gen-crd manifests +codegen: go-mod-vendor gen-proto gen-k8scodegen gen-openapi gen-mocks gen-crd manifests # generates all files related to proto files .PHONY: gen-proto @@ -133,17 +98,18 @@ gen-proto: k8s-proto api-proto ui-proto # generates the .proto files affected by changes to types.go .PHONY: k8s-proto -k8s-proto: go-mod-vendor install-toolchain $(TYPES) +k8s-proto: go-mod-vendor $(TYPES) PATH=${DIST_DIR}:$$PATH go-to-protobuf \ --go-header-file=./hack/custom-boilerplate.go.txt \ --packages=github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1 \ --apimachinery-packages=${APIMACHINERY_PKGS} \ - --proto-import $(CURDIR)/vendor + --proto-import $(CURDIR)/vendor \ + --proto-import=${DIST_DIR}/protoc-include touch pkg/apis/rollouts/v1alpha1/generated.proto # generates *.pb.go, *.pb.gw.go, swagger from .proto files .PHONY: api-proto -api-proto: go-mod-vendor install-toolchain k8s-proto +api-proto: go-mod-vendor k8s-proto $(call protoc,pkg/apiclient/rollout/rollout.proto) # generates ui related proto files diff --git a/analysis/analysis.go b/analysis/analysis.go index 3afc481635..77a2081920 100644 --- a/analysis/analysis.go +++ b/analysis/analysis.go @@ -716,7 +716,7 @@ func (c *Controller) garbageCollectMeasurements(run *v1alpha1.AnalysisRun, measu measurementRetentionObject := measurementRetentionMetricNamesMap[result.Name] measurementsLimit := limit if measurementRetentionObject != nil && measurementRetentionObject.Limit > 0 { - measurementsLimit = measurementRetentionObject.Limit + measurementsLimit = int(measurementRetentionObject.Limit) } if length > measurementsLimit { metric, ok := metricsByName[result.Name] diff --git a/docs/features/kustomize/rollout_cr_schema.json b/docs/features/kustomize/rollout_cr_schema.json index 0578824a9d..2f27f6f557 100644 --- a/docs/features/kustomize/rollout_cr_schema.json +++ b/docs/features/kustomize/rollout_cr_schema.json @@ -47,6 +47,22 @@ "type": "array", "x-kubernetes-patch-merge-key": "name", "x-kubernetes-patch-strategy": "merge" + }, + "dryRun": { + "items": { + "properties": { + "metricName": { + "type": "string" + } + }, + "required": [ + "metricName" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge" } }, "type": "object" @@ -90,6 +106,22 @@ "type": "array", "x-kubernetes-patch-merge-key": "name", "x-kubernetes-patch-strategy": "merge" + }, + "dryRun": { + "items": { + "properties": { + "metricName": { + "type": "string" + } + }, + "required": [ + "metricName" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge" } }, "type": "object" @@ -141,6 +173,22 @@ "type": "array", "x-kubernetes-patch-merge-key": "name", "x-kubernetes-patch-strategy": "merge" + }, + "dryRun": { + "items": { + "properties": { + "metricName": { + "type": "string" + } + }, + "required": [ + "metricName" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge" } }, "type": "object" diff --git a/hack/installers/install-codegen-go-tools.sh b/hack/installers/install-codegen-go-tools.sh new file mode 100755 index 0000000000..b74ef32753 --- /dev/null +++ b/hack/installers/install-codegen-go-tools.sh @@ -0,0 +1,57 @@ +#!/bin/bash +set -eux -o pipefail + +SRCROOT="$( CDPATH='' cd -- "$(dirname "$0")/../.." && pwd -P )" + +# This script installs all our golang-based codegen utility CLIs necessary for codegen. +# Some dependencies are vendored in go.mod (ones which are actually imported in our codebase). +# Other dependencies are only used as a CLI and do not need vendoring in go.mod (doing so adds +# unecessary dependencies to go.mod). We want to maintain a single source of truth for versioning +# our binaries (either go.mod or go install @), so we use two techniques to install +# our CLIs: +# 1. For CLIs which are NOT vendored in go.mod, we can run `go install @` with an explicit version +# 2. For packages which we *do* vendor in go.mod, we determine version from go.mod followed by `go install` with that version +go_mod_install() { + module=$(go list -f '{{.Module}}' $1 | awk '{print $1}') + module_version=$(go list -m $module | awk '{print $NF}' | head -1) + go install $1@$module_version +} + +# All binaries are compiled into the argo-cd/dist directory, which is added to the PATH during codegen +export GOBIN="${SRCROOT}/dist" +mkdir -p $GOBIN + +# protoc-gen-go* is used to generate .pb.go from .proto files +#go_mod_install github.com/golang/protobuf/protoc-gen-go +#go_mod_install github.com/gogo/protobuf/protoc-gen-gogo +go_mod_install github.com/gogo/protobuf/protoc-gen-gogofast + +# protoc-gen-grpc-gateway is used to build .pb.gw.go files from from .proto files +go_mod_install github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway + +# # protoc-gen-swagger is used to build swagger.json +go_mod_install github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger + +# k8s tools to codegen .proto files, client libraries, and helpers from types.go +go_mod_install k8s.io/code-generator/cmd/go-to-protobuf +go_mod_install k8s.io/code-generator/cmd/go-to-protobuf/protoc-gen-gogo +go_mod_install k8s.io/code-generator/cmd/client-gen +go_mod_install k8s.io/code-generator/cmd/deepcopy-gen +go_mod_install k8s.io/code-generator/cmd/defaulter-gen +go_mod_install k8s.io/code-generator/cmd/informer-gen +go_mod_install k8s.io/code-generator/cmd/lister-gen + +# We still install openapi-gen from go.mod since upstream does not utilize release tags +go_mod_install k8s.io/kube-openapi/cmd/openapi-gen + +# controller-gen is run by ./hack/gen-crd-spec to generate the CRDs +go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.5.0 + +# swagger cli is used to generate swagger docs +go install github.com/go-swagger/go-swagger/cmd/swagger@v0.28.0 + +# goimports is used to auto-format generated code +go install golang.org/x/tools/cmd/goimports@v0.1.8 + +# mockery is used for generating mock +go install github.com/vektra/mockery/v2@v2.6.0 diff --git a/hack/installers/install-protoc.sh b/hack/installers/install-protoc.sh new file mode 100755 index 0000000000..1f3dd8e7bc --- /dev/null +++ b/hack/installers/install-protoc.sh @@ -0,0 +1,44 @@ +#!/bin/bash +set -eux -o pipefail + +PROJECT_ROOT=$(cd $(dirname ${BASH_SOURCE})/../..; pwd) +DIST_PATH="${PROJECT_ROOT}/dist" +PATH="${DIST_PATH}:${PATH}" + +protoc_version=3.17.3 + +OS=$(go env GOOS) +ARCH=$(go env GOARCH) +case $OS in + darwin) + # For macOS, the x86_64 binary is used even on Apple Silicon (it is run through rosetta), so + # we download and install the x86_64 version. See: https://github.com/protocolbuffers/protobuf/pull/8557 + protoc_os=osx + protoc_arch=x86_64 + ;; + *) + protoc_os=linux + case $ARCH in + arm64|arm) + protoc_arch=aarch_64 + ;; + *) + protoc_arch=x86_64 + ;; + esac + ;; +esac + +export TARGET_FILE=protoc_${protoc_version}_${OS}_${ARCH}.zip +temp_path="/tmp/${TARGET_FILE}" +url=https://github.com/protocolbuffers/protobuf/releases/download/v${protoc_version}/protoc-${protoc_version}-${protoc_os}-${protoc_arch}.zip +[ -e ${temp_path} ] || curl -sLf --retry 3 -o ${temp_path} ${url} + +mkdir -p /tmp/protoc-${protoc_version} +unzip -o ${temp_path} -d /tmp/protoc-${protoc_version} +mkdir -p ${DIST_PATH}/protoc-include +cp /tmp/protoc-${protoc_version}/bin/protoc ${DIST_PATH}/protoc +chmod +x ${DIST_PATH}/protoc +cp -a /tmp/protoc-${protoc_version}/include/* ${DIST_PATH}/protoc-include +chmod -R +rx ${DIST_PATH}/protoc-include +protoc --version diff --git a/hack/tools.go b/hack/tools.go index 22abdb37c9..be7401da62 100644 --- a/hack/tools.go +++ b/hack/tools.go @@ -8,6 +8,7 @@ import ( _ "k8s.io/code-generator/cmd/deepcopy-gen" _ "k8s.io/code-generator/cmd/defaulter-gen" _ "k8s.io/code-generator/cmd/go-to-protobuf" + _ "k8s.io/code-generator/cmd/go-to-protobuf/protoc-gen-gogo" _ "k8s.io/code-generator/cmd/informer-gen" _ "k8s.io/code-generator/cmd/lister-gen" _ "k8s.io/code-generator/pkg/util" diff --git a/manifests/crds/analysis-run-crd.yaml b/manifests/crds/analysis-run-crd.yaml index c01f11145e..51d86d0e51 100644 --- a/manifests/crds/analysis-run-crd.yaml +++ b/manifests/crds/analysis-run-crd.yaml @@ -81,6 +81,7 @@ spec: items: properties: limit: + format: int32 type: integer metricName: type: string diff --git a/manifests/crds/analysis-template-crd.yaml b/manifests/crds/analysis-template-crd.yaml index b439a780d1..0677555741 100644 --- a/manifests/crds/analysis-template-crd.yaml +++ b/manifests/crds/analysis-template-crd.yaml @@ -77,6 +77,7 @@ spec: items: properties: limit: + format: int32 type: integer metricName: type: string diff --git a/manifests/crds/cluster-analysis-template-crd.yaml b/manifests/crds/cluster-analysis-template-crd.yaml index 91acef74e1..6a25750124 100644 --- a/manifests/crds/cluster-analysis-template-crd.yaml +++ b/manifests/crds/cluster-analysis-template-crd.yaml @@ -77,6 +77,7 @@ spec: items: properties: limit: + format: int32 type: integer metricName: type: string diff --git a/manifests/install.yaml b/manifests/install.yaml index bee89265c9..89f4621d96 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -82,6 +82,7 @@ spec: items: properties: limit: + format: int32 type: integer metricName: type: string @@ -2831,6 +2832,7 @@ spec: items: properties: limit: + format: int32 type: integer metricName: type: string @@ -5470,6 +5472,7 @@ spec: items: properties: limit: + format: int32 type: integer metricName: type: string diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index ea598cc1b0..7b74516558 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -82,6 +82,7 @@ spec: items: properties: limit: + format: int32 type: integer metricName: type: string @@ -2831,6 +2832,7 @@ spec: items: properties: limit: + format: int32 type: integer metricName: type: string @@ -5470,6 +5472,7 @@ spec: items: properties: limit: + format: int32 type: integer metricName: type: string diff --git a/pkg/apis/rollouts/v1alpha1/analysis_types.go b/pkg/apis/rollouts/v1alpha1/analysis_types.go index 0094571c5d..82d461cdcc 100644 --- a/pkg/apis/rollouts/v1alpha1/analysis_types.go +++ b/pkg/apis/rollouts/v1alpha1/analysis_types.go @@ -130,7 +130,7 @@ type MeasurementRetention struct { // MetricName is the name of the metric on which this retention policy should be applied. MetricName string `json:"metricName" protobuf:"bytes,1,opt,name=metricName"` // Limit is the maximum number of measurements to be retained for this given metric. - Limit int `json:"limit" protobuf:"varint,2,opt,name=limit"` + Limit int32 `json:"limit" protobuf:"varint,2,opt,name=limit"` } // EffectiveCount is the effective count based on whether or not count/interval is specified diff --git a/pkg/apis/rollouts/v1alpha1/generated.pb.go b/pkg/apis/rollouts/v1alpha1/generated.pb.go index 5ff91102e2..3f052727e0 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.pb.go +++ b/pkg/apis/rollouts/v1alpha1/generated.pb.go @@ -1,5 +1,5 @@ /* -Copyright 2021 The Kubernetes sample-controller Authors. +Copyright 2022 The Kubernetes sample-controller Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -860,10 +860,38 @@ func (m *DatadogMetric) XXX_DiscardUnknown() { var xxx_messageInfo_DatadogMetric proto.InternalMessageInfo +func (m *DryRun) Reset() { *m = DryRun{} } +func (*DryRun) ProtoMessage() {} +func (*DryRun) Descriptor() ([]byte, []int) { + return fileDescriptor_e0e705f843545fab, []int{29} +} +func (m *DryRun) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DryRun) 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 *DryRun) XXX_Merge(src proto.Message) { + xxx_messageInfo_DryRun.Merge(m, src) +} +func (m *DryRun) XXX_Size() int { + return m.Size() +} +func (m *DryRun) XXX_DiscardUnknown() { + xxx_messageInfo_DryRun.DiscardUnknown(m) +} + +var xxx_messageInfo_DryRun proto.InternalMessageInfo + func (m *Experiment) Reset() { *m = Experiment{} } func (*Experiment) ProtoMessage() {} func (*Experiment) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{29} + return fileDescriptor_e0e705f843545fab, []int{30} } func (m *Experiment) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -891,7 +919,7 @@ var xxx_messageInfo_Experiment proto.InternalMessageInfo func (m *ExperimentAnalysisRunStatus) Reset() { *m = ExperimentAnalysisRunStatus{} } func (*ExperimentAnalysisRunStatus) ProtoMessage() {} func (*ExperimentAnalysisRunStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{30} + return fileDescriptor_e0e705f843545fab, []int{31} } func (m *ExperimentAnalysisRunStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -919,7 +947,7 @@ var xxx_messageInfo_ExperimentAnalysisRunStatus proto.InternalMessageInfo func (m *ExperimentAnalysisTemplateRef) Reset() { *m = ExperimentAnalysisTemplateRef{} } func (*ExperimentAnalysisTemplateRef) ProtoMessage() {} func (*ExperimentAnalysisTemplateRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{31} + return fileDescriptor_e0e705f843545fab, []int{32} } func (m *ExperimentAnalysisTemplateRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -947,7 +975,7 @@ var xxx_messageInfo_ExperimentAnalysisTemplateRef proto.InternalMessageInfo func (m *ExperimentCondition) Reset() { *m = ExperimentCondition{} } func (*ExperimentCondition) ProtoMessage() {} func (*ExperimentCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{32} + return fileDescriptor_e0e705f843545fab, []int{33} } func (m *ExperimentCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -975,7 +1003,7 @@ var xxx_messageInfo_ExperimentCondition proto.InternalMessageInfo func (m *ExperimentList) Reset() { *m = ExperimentList{} } func (*ExperimentList) ProtoMessage() {} func (*ExperimentList) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{33} + return fileDescriptor_e0e705f843545fab, []int{34} } func (m *ExperimentList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1003,7 +1031,7 @@ var xxx_messageInfo_ExperimentList proto.InternalMessageInfo func (m *ExperimentSpec) Reset() { *m = ExperimentSpec{} } func (*ExperimentSpec) ProtoMessage() {} func (*ExperimentSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{34} + return fileDescriptor_e0e705f843545fab, []int{35} } func (m *ExperimentSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1031,7 +1059,7 @@ var xxx_messageInfo_ExperimentSpec proto.InternalMessageInfo func (m *ExperimentStatus) Reset() { *m = ExperimentStatus{} } func (*ExperimentStatus) ProtoMessage() {} func (*ExperimentStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{35} + return fileDescriptor_e0e705f843545fab, []int{36} } func (m *ExperimentStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1059,7 +1087,7 @@ var xxx_messageInfo_ExperimentStatus proto.InternalMessageInfo func (m *FieldRef) Reset() { *m = FieldRef{} } func (*FieldRef) ProtoMessage() {} func (*FieldRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{36} + return fileDescriptor_e0e705f843545fab, []int{37} } func (m *FieldRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1087,7 +1115,7 @@ var xxx_messageInfo_FieldRef proto.InternalMessageInfo func (m *GraphiteMetric) Reset() { *m = GraphiteMetric{} } func (*GraphiteMetric) ProtoMessage() {} func (*GraphiteMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{37} + return fileDescriptor_e0e705f843545fab, []int{38} } func (m *GraphiteMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1115,7 +1143,7 @@ var xxx_messageInfo_GraphiteMetric proto.InternalMessageInfo func (m *IstioDestinationRule) Reset() { *m = IstioDestinationRule{} } func (*IstioDestinationRule) ProtoMessage() {} func (*IstioDestinationRule) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{38} + return fileDescriptor_e0e705f843545fab, []int{39} } func (m *IstioDestinationRule) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1143,7 +1171,7 @@ var xxx_messageInfo_IstioDestinationRule proto.InternalMessageInfo func (m *IstioTrafficRouting) Reset() { *m = IstioTrafficRouting{} } func (*IstioTrafficRouting) ProtoMessage() {} func (*IstioTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{39} + return fileDescriptor_e0e705f843545fab, []int{40} } func (m *IstioTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1171,7 +1199,7 @@ var xxx_messageInfo_IstioTrafficRouting proto.InternalMessageInfo func (m *IstioVirtualService) Reset() { *m = IstioVirtualService{} } func (*IstioVirtualService) ProtoMessage() {} func (*IstioVirtualService) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{40} + return fileDescriptor_e0e705f843545fab, []int{41} } func (m *IstioVirtualService) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1199,7 +1227,7 @@ var xxx_messageInfo_IstioVirtualService proto.InternalMessageInfo func (m *JobMetric) Reset() { *m = JobMetric{} } func (*JobMetric) ProtoMessage() {} func (*JobMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{41} + return fileDescriptor_e0e705f843545fab, []int{42} } func (m *JobMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1227,7 +1255,7 @@ var xxx_messageInfo_JobMetric proto.InternalMessageInfo func (m *KayentaMetric) Reset() { *m = KayentaMetric{} } func (*KayentaMetric) ProtoMessage() {} func (*KayentaMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{42} + return fileDescriptor_e0e705f843545fab, []int{43} } func (m *KayentaMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1255,7 +1283,7 @@ var xxx_messageInfo_KayentaMetric proto.InternalMessageInfo func (m *KayentaScope) Reset() { *m = KayentaScope{} } func (*KayentaScope) ProtoMessage() {} func (*KayentaScope) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{43} + return fileDescriptor_e0e705f843545fab, []int{44} } func (m *KayentaScope) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1283,7 +1311,7 @@ var xxx_messageInfo_KayentaScope proto.InternalMessageInfo func (m *KayentaThreshold) Reset() { *m = KayentaThreshold{} } func (*KayentaThreshold) ProtoMessage() {} func (*KayentaThreshold) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{44} + return fileDescriptor_e0e705f843545fab, []int{45} } func (m *KayentaThreshold) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1311,7 +1339,7 @@ var xxx_messageInfo_KayentaThreshold proto.InternalMessageInfo func (m *Measurement) Reset() { *m = Measurement{} } func (*Measurement) ProtoMessage() {} func (*Measurement) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{45} + return fileDescriptor_e0e705f843545fab, []int{46} } func (m *Measurement) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1336,10 +1364,38 @@ func (m *Measurement) XXX_DiscardUnknown() { var xxx_messageInfo_Measurement proto.InternalMessageInfo +func (m *MeasurementRetention) Reset() { *m = MeasurementRetention{} } +func (*MeasurementRetention) ProtoMessage() {} +func (*MeasurementRetention) Descriptor() ([]byte, []int) { + return fileDescriptor_e0e705f843545fab, []int{47} +} +func (m *MeasurementRetention) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MeasurementRetention) 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 *MeasurementRetention) XXX_Merge(src proto.Message) { + xxx_messageInfo_MeasurementRetention.Merge(m, src) +} +func (m *MeasurementRetention) XXX_Size() int { + return m.Size() +} +func (m *MeasurementRetention) XXX_DiscardUnknown() { + xxx_messageInfo_MeasurementRetention.DiscardUnknown(m) +} + +var xxx_messageInfo_MeasurementRetention proto.InternalMessageInfo + func (m *Metric) Reset() { *m = Metric{} } func (*Metric) ProtoMessage() {} func (*Metric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{46} + return fileDescriptor_e0e705f843545fab, []int{48} } func (m *Metric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1367,7 +1423,7 @@ var xxx_messageInfo_Metric proto.InternalMessageInfo func (m *MetricProvider) Reset() { *m = MetricProvider{} } func (*MetricProvider) ProtoMessage() {} func (*MetricProvider) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{47} + return fileDescriptor_e0e705f843545fab, []int{49} } func (m *MetricProvider) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1395,7 +1451,7 @@ var xxx_messageInfo_MetricProvider proto.InternalMessageInfo func (m *MetricResult) Reset() { *m = MetricResult{} } func (*MetricResult) ProtoMessage() {} func (*MetricResult) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{48} + return fileDescriptor_e0e705f843545fab, []int{50} } func (m *MetricResult) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1423,7 +1479,7 @@ var xxx_messageInfo_MetricResult proto.InternalMessageInfo func (m *NewRelicMetric) Reset() { *m = NewRelicMetric{} } func (*NewRelicMetric) ProtoMessage() {} func (*NewRelicMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{49} + return fileDescriptor_e0e705f843545fab, []int{51} } func (m *NewRelicMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1451,7 +1507,7 @@ var xxx_messageInfo_NewRelicMetric proto.InternalMessageInfo func (m *NginxTrafficRouting) Reset() { *m = NginxTrafficRouting{} } func (*NginxTrafficRouting) ProtoMessage() {} func (*NginxTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{50} + return fileDescriptor_e0e705f843545fab, []int{52} } func (m *NginxTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1479,7 +1535,7 @@ var xxx_messageInfo_NginxTrafficRouting proto.InternalMessageInfo func (m *ObjectRef) Reset() { *m = ObjectRef{} } func (*ObjectRef) ProtoMessage() {} func (*ObjectRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{51} + return fileDescriptor_e0e705f843545fab, []int{53} } func (m *ObjectRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1507,7 +1563,7 @@ var xxx_messageInfo_ObjectRef proto.InternalMessageInfo func (m *PauseCondition) Reset() { *m = PauseCondition{} } func (*PauseCondition) ProtoMessage() {} func (*PauseCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{52} + return fileDescriptor_e0e705f843545fab, []int{54} } func (m *PauseCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1535,7 +1591,7 @@ var xxx_messageInfo_PauseCondition proto.InternalMessageInfo func (m *PodTemplateMetadata) Reset() { *m = PodTemplateMetadata{} } func (*PodTemplateMetadata) ProtoMessage() {} func (*PodTemplateMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{53} + return fileDescriptor_e0e705f843545fab, []int{55} } func (m *PodTemplateMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1565,7 +1621,7 @@ func (m *PreferredDuringSchedulingIgnoredDuringExecution) Reset() { } func (*PreferredDuringSchedulingIgnoredDuringExecution) ProtoMessage() {} func (*PreferredDuringSchedulingIgnoredDuringExecution) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{54} + return fileDescriptor_e0e705f843545fab, []int{56} } func (m *PreferredDuringSchedulingIgnoredDuringExecution) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1593,7 +1649,7 @@ var xxx_messageInfo_PreferredDuringSchedulingIgnoredDuringExecution proto.Intern func (m *PrometheusMetric) Reset() { *m = PrometheusMetric{} } func (*PrometheusMetric) ProtoMessage() {} func (*PrometheusMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{55} + return fileDescriptor_e0e705f843545fab, []int{57} } func (m *PrometheusMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1623,7 +1679,7 @@ func (m *RequiredDuringSchedulingIgnoredDuringExecution) Reset() { } func (*RequiredDuringSchedulingIgnoredDuringExecution) ProtoMessage() {} func (*RequiredDuringSchedulingIgnoredDuringExecution) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{56} + return fileDescriptor_e0e705f843545fab, []int{58} } func (m *RequiredDuringSchedulingIgnoredDuringExecution) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1651,7 +1707,7 @@ var xxx_messageInfo_RequiredDuringSchedulingIgnoredDuringExecution proto.Interna func (m *Rollout) Reset() { *m = Rollout{} } func (*Rollout) ProtoMessage() {} func (*Rollout) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{57} + return fileDescriptor_e0e705f843545fab, []int{59} } func (m *Rollout) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1679,7 +1735,7 @@ var xxx_messageInfo_Rollout proto.InternalMessageInfo func (m *RolloutAnalysis) Reset() { *m = RolloutAnalysis{} } func (*RolloutAnalysis) ProtoMessage() {} func (*RolloutAnalysis) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{58} + return fileDescriptor_e0e705f843545fab, []int{60} } func (m *RolloutAnalysis) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1707,7 +1763,7 @@ var xxx_messageInfo_RolloutAnalysis proto.InternalMessageInfo func (m *RolloutAnalysisBackground) Reset() { *m = RolloutAnalysisBackground{} } func (*RolloutAnalysisBackground) ProtoMessage() {} func (*RolloutAnalysisBackground) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{59} + return fileDescriptor_e0e705f843545fab, []int{61} } func (m *RolloutAnalysisBackground) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1735,7 +1791,7 @@ var xxx_messageInfo_RolloutAnalysisBackground proto.InternalMessageInfo func (m *RolloutAnalysisRunStatus) Reset() { *m = RolloutAnalysisRunStatus{} } func (*RolloutAnalysisRunStatus) ProtoMessage() {} func (*RolloutAnalysisRunStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{60} + return fileDescriptor_e0e705f843545fab, []int{62} } func (m *RolloutAnalysisRunStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1763,7 +1819,7 @@ var xxx_messageInfo_RolloutAnalysisRunStatus proto.InternalMessageInfo func (m *RolloutAnalysisTemplate) Reset() { *m = RolloutAnalysisTemplate{} } func (*RolloutAnalysisTemplate) ProtoMessage() {} func (*RolloutAnalysisTemplate) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{61} + return fileDescriptor_e0e705f843545fab, []int{63} } func (m *RolloutAnalysisTemplate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1791,7 +1847,7 @@ var xxx_messageInfo_RolloutAnalysisTemplate proto.InternalMessageInfo func (m *RolloutCondition) Reset() { *m = RolloutCondition{} } func (*RolloutCondition) ProtoMessage() {} func (*RolloutCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{62} + return fileDescriptor_e0e705f843545fab, []int{64} } func (m *RolloutCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1819,7 +1875,7 @@ var xxx_messageInfo_RolloutCondition proto.InternalMessageInfo func (m *RolloutExperimentStep) Reset() { *m = RolloutExperimentStep{} } func (*RolloutExperimentStep) ProtoMessage() {} func (*RolloutExperimentStep) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{63} + return fileDescriptor_e0e705f843545fab, []int{65} } func (m *RolloutExperimentStep) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1849,7 +1905,7 @@ func (m *RolloutExperimentStepAnalysisTemplateRef) Reset() { } func (*RolloutExperimentStepAnalysisTemplateRef) ProtoMessage() {} func (*RolloutExperimentStepAnalysisTemplateRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{64} + return fileDescriptor_e0e705f843545fab, []int{66} } func (m *RolloutExperimentStepAnalysisTemplateRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1877,7 +1933,7 @@ var xxx_messageInfo_RolloutExperimentStepAnalysisTemplateRef proto.InternalMessa func (m *RolloutExperimentTemplate) Reset() { *m = RolloutExperimentTemplate{} } func (*RolloutExperimentTemplate) ProtoMessage() {} func (*RolloutExperimentTemplate) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{65} + return fileDescriptor_e0e705f843545fab, []int{67} } func (m *RolloutExperimentTemplate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1905,7 +1961,7 @@ var xxx_messageInfo_RolloutExperimentTemplate proto.InternalMessageInfo func (m *RolloutList) Reset() { *m = RolloutList{} } func (*RolloutList) ProtoMessage() {} func (*RolloutList) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{66} + return fileDescriptor_e0e705f843545fab, []int{68} } func (m *RolloutList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1933,7 +1989,7 @@ var xxx_messageInfo_RolloutList proto.InternalMessageInfo func (m *RolloutPause) Reset() { *m = RolloutPause{} } func (*RolloutPause) ProtoMessage() {} func (*RolloutPause) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{67} + return fileDescriptor_e0e705f843545fab, []int{69} } func (m *RolloutPause) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1961,7 +2017,7 @@ var xxx_messageInfo_RolloutPause proto.InternalMessageInfo func (m *RolloutSpec) Reset() { *m = RolloutSpec{} } func (*RolloutSpec) ProtoMessage() {} func (*RolloutSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{68} + return fileDescriptor_e0e705f843545fab, []int{70} } func (m *RolloutSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1989,7 +2045,7 @@ var xxx_messageInfo_RolloutSpec proto.InternalMessageInfo func (m *RolloutStatus) Reset() { *m = RolloutStatus{} } func (*RolloutStatus) ProtoMessage() {} func (*RolloutStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{69} + return fileDescriptor_e0e705f843545fab, []int{71} } func (m *RolloutStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2017,7 +2073,7 @@ var xxx_messageInfo_RolloutStatus proto.InternalMessageInfo func (m *RolloutStrategy) Reset() { *m = RolloutStrategy{} } func (*RolloutStrategy) ProtoMessage() {} func (*RolloutStrategy) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{70} + return fileDescriptor_e0e705f843545fab, []int{72} } func (m *RolloutStrategy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2045,7 +2101,7 @@ var xxx_messageInfo_RolloutStrategy proto.InternalMessageInfo func (m *RolloutTrafficRouting) Reset() { *m = RolloutTrafficRouting{} } func (*RolloutTrafficRouting) ProtoMessage() {} func (*RolloutTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{71} + return fileDescriptor_e0e705f843545fab, []int{73} } func (m *RolloutTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2070,10 +2126,38 @@ func (m *RolloutTrafficRouting) XXX_DiscardUnknown() { var xxx_messageInfo_RolloutTrafficRouting proto.InternalMessageInfo +func (m *RunSummary) Reset() { *m = RunSummary{} } +func (*RunSummary) ProtoMessage() {} +func (*RunSummary) Descriptor() ([]byte, []int) { + return fileDescriptor_e0e705f843545fab, []int{74} +} +func (m *RunSummary) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RunSummary) 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 *RunSummary) XXX_Merge(src proto.Message) { + xxx_messageInfo_RunSummary.Merge(m, src) +} +func (m *RunSummary) XXX_Size() int { + return m.Size() +} +func (m *RunSummary) XXX_DiscardUnknown() { + xxx_messageInfo_RunSummary.DiscardUnknown(m) +} + +var xxx_messageInfo_RunSummary proto.InternalMessageInfo + func (m *SMITrafficRouting) Reset() { *m = SMITrafficRouting{} } func (*SMITrafficRouting) ProtoMessage() {} func (*SMITrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{72} + return fileDescriptor_e0e705f843545fab, []int{75} } func (m *SMITrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2101,7 +2185,7 @@ var xxx_messageInfo_SMITrafficRouting proto.InternalMessageInfo func (m *ScopeDetail) Reset() { *m = ScopeDetail{} } func (*ScopeDetail) ProtoMessage() {} func (*ScopeDetail) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{73} + return fileDescriptor_e0e705f843545fab, []int{76} } func (m *ScopeDetail) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2129,7 +2213,7 @@ var xxx_messageInfo_ScopeDetail proto.InternalMessageInfo func (m *SecretKeyRef) Reset() { *m = SecretKeyRef{} } func (*SecretKeyRef) ProtoMessage() {} func (*SecretKeyRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{74} + return fileDescriptor_e0e705f843545fab, []int{77} } func (m *SecretKeyRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2157,7 +2241,7 @@ var xxx_messageInfo_SecretKeyRef proto.InternalMessageInfo func (m *SetCanaryScale) Reset() { *m = SetCanaryScale{} } func (*SetCanaryScale) ProtoMessage() {} func (*SetCanaryScale) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{75} + return fileDescriptor_e0e705f843545fab, []int{78} } func (m *SetCanaryScale) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2185,7 +2269,7 @@ var xxx_messageInfo_SetCanaryScale proto.InternalMessageInfo func (m *StickinessConfig) Reset() { *m = StickinessConfig{} } func (*StickinessConfig) ProtoMessage() {} func (*StickinessConfig) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{76} + return fileDescriptor_e0e705f843545fab, []int{79} } func (m *StickinessConfig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2213,7 +2297,7 @@ var xxx_messageInfo_StickinessConfig proto.InternalMessageInfo func (m *TLSRoute) Reset() { *m = TLSRoute{} } func (*TLSRoute) ProtoMessage() {} func (*TLSRoute) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{77} + return fileDescriptor_e0e705f843545fab, []int{80} } func (m *TLSRoute) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2241,7 +2325,7 @@ var xxx_messageInfo_TLSRoute proto.InternalMessageInfo func (m *TemplateService) Reset() { *m = TemplateService{} } func (*TemplateService) ProtoMessage() {} func (*TemplateService) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{78} + return fileDescriptor_e0e705f843545fab, []int{81} } func (m *TemplateService) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2269,7 +2353,7 @@ var xxx_messageInfo_TemplateService proto.InternalMessageInfo func (m *TemplateSpec) Reset() { *m = TemplateSpec{} } func (*TemplateSpec) ProtoMessage() {} func (*TemplateSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{79} + return fileDescriptor_e0e705f843545fab, []int{82} } func (m *TemplateSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2297,7 +2381,7 @@ var xxx_messageInfo_TemplateSpec proto.InternalMessageInfo func (m *TemplateStatus) Reset() { *m = TemplateStatus{} } func (*TemplateStatus) ProtoMessage() {} func (*TemplateStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{80} + return fileDescriptor_e0e705f843545fab, []int{83} } func (m *TemplateStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2325,7 +2409,7 @@ var xxx_messageInfo_TemplateStatus proto.InternalMessageInfo func (m *TrafficWeights) Reset() { *m = TrafficWeights{} } func (*TrafficWeights) ProtoMessage() {} func (*TrafficWeights) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{81} + return fileDescriptor_e0e705f843545fab, []int{84} } func (m *TrafficWeights) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2353,7 +2437,7 @@ var xxx_messageInfo_TrafficWeights proto.InternalMessageInfo func (m *ValueFrom) Reset() { *m = ValueFrom{} } func (*ValueFrom) ProtoMessage() {} func (*ValueFrom) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{82} + return fileDescriptor_e0e705f843545fab, []int{85} } func (m *ValueFrom) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2381,7 +2465,7 @@ var xxx_messageInfo_ValueFrom proto.InternalMessageInfo func (m *WavefrontMetric) Reset() { *m = WavefrontMetric{} } func (*WavefrontMetric) ProtoMessage() {} func (*WavefrontMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{83} + return fileDescriptor_e0e705f843545fab, []int{86} } func (m *WavefrontMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2409,7 +2493,7 @@ var xxx_messageInfo_WavefrontMetric proto.InternalMessageInfo func (m *WebMetric) Reset() { *m = WebMetric{} } func (*WebMetric) ProtoMessage() {} func (*WebMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{84} + return fileDescriptor_e0e705f843545fab, []int{87} } func (m *WebMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2437,7 +2521,7 @@ var xxx_messageInfo_WebMetric proto.InternalMessageInfo func (m *WebMetricHeader) Reset() { *m = WebMetricHeader{} } func (*WebMetricHeader) ProtoMessage() {} func (*WebMetricHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{85} + return fileDescriptor_e0e705f843545fab, []int{88} } func (m *WebMetricHeader) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2465,7 +2549,7 @@ var xxx_messageInfo_WebMetricHeader proto.InternalMessageInfo func (m *WeightDestination) Reset() { *m = WeightDestination{} } func (*WeightDestination) ProtoMessage() {} func (*WeightDestination) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{86} + return fileDescriptor_e0e705f843545fab, []int{89} } func (m *WeightDestination) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2520,6 +2604,7 @@ func init() { proto.RegisterType((*ClusterAnalysisTemplate)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ClusterAnalysisTemplate") proto.RegisterType((*ClusterAnalysisTemplateList)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ClusterAnalysisTemplateList") proto.RegisterType((*DatadogMetric)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.DatadogMetric") + proto.RegisterType((*DryRun)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.DryRun") proto.RegisterType((*Experiment)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.Experiment") proto.RegisterType((*ExperimentAnalysisRunStatus)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ExperimentAnalysisRunStatus") proto.RegisterType((*ExperimentAnalysisTemplateRef)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ExperimentAnalysisTemplateRef") @@ -2538,6 +2623,7 @@ func init() { proto.RegisterType((*KayentaThreshold)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.KayentaThreshold") proto.RegisterType((*Measurement)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.Measurement") proto.RegisterMapType((map[string]string)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.Measurement.MetadataEntry") + proto.RegisterType((*MeasurementRetention)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MeasurementRetention") proto.RegisterType((*Metric)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.Metric") proto.RegisterType((*MetricProvider)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MetricProvider") proto.RegisterType((*MetricResult)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MetricResult") @@ -2567,6 +2653,7 @@ func init() { proto.RegisterType((*RolloutStatus)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.RolloutStatus") proto.RegisterType((*RolloutStrategy)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.RolloutStrategy") proto.RegisterType((*RolloutTrafficRouting)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.RolloutTrafficRouting") + proto.RegisterType((*RunSummary)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.RunSummary") proto.RegisterType((*SMITrafficRouting)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SMITrafficRouting") proto.RegisterType((*ScopeDetail)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ScopeDetail") proto.RegisterType((*SecretKeyRef)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SecretKeyRef") @@ -2589,424 +2676,436 @@ func init() { } var fileDescriptor_e0e705f843545fab = []byte{ - // 6668 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3d, 0x5b, 0x8c, 0x24, 0xc9, - 0x51, 0x57, 0xdd, 0xf3, 0xe8, 0x89, 0x79, 0xe7, 0xce, 0x7a, 0x7b, 0xe7, 0x6e, 0xb7, 0xcf, 0x75, - 0xd6, 0x71, 0x06, 0x7b, 0xd6, 0xde, 0xbb, 0x83, 0xb3, 0xcf, 0x3a, 0xd1, 0x3d, 0xb3, 0x8f, 0xd9, - 0x9b, 0xd9, 0x9d, 0xcd, 0x9e, 0xdd, 0xb5, 0xcf, 0x3e, 0xe3, 0x9a, 0xee, 0x9c, 0x9e, 0xda, 0xad, - 0xae, 0x6a, 0x57, 0x55, 0xcf, 0xee, 0x9c, 0x2d, 0xfb, 0x8c, 0x75, 0xc6, 0x20, 0x5b, 0x3e, 0xb0, - 0xfd, 0x81, 0x90, 0x91, 0x85, 0xf8, 0x40, 0x98, 0x0f, 0x64, 0x81, 0xf8, 0x31, 0x02, 0x81, 0x2d, - 0x99, 0x0f, 0x90, 0x91, 0x80, 0x33, 0xc8, 0x6e, 0x7c, 0x6d, 0xf8, 0x80, 0x1f, 0x64, 0xc9, 0x08, - 0x79, 0xbf, 0x50, 0x3e, 0x2b, 0xab, 0xba, 0x7a, 0xb6, 0x7b, 0xba, 0x66, 0xb1, 0x80, 0xbf, 0xee, - 0x8c, 0xc8, 0x88, 0x7c, 0x44, 0x46, 0x46, 0x46, 0x46, 0x46, 0xc1, 0x46, 0xc3, 0x0e, 0xf7, 0xda, - 0x3b, 0x2b, 0x35, 0xaf, 0x79, 0xce, 0xf2, 0x1b, 0x5e, 0xcb, 0xf7, 0x6e, 0xb3, 0x1f, 0xef, 0xf4, - 0x3d, 0xc7, 0xf1, 0xda, 0x61, 0x70, 0xae, 0x75, 0xa7, 0x71, 0xce, 0x6a, 0xd9, 0xc1, 0x39, 0x55, - 0xb2, 0xff, 0x6e, 0xcb, 0x69, 0xed, 0x59, 0xef, 0x3e, 0xd7, 0x20, 0x2e, 0xf1, 0xad, 0x90, 0xd4, - 0x57, 0x5a, 0xbe, 0x17, 0x7a, 0xe8, 0x7d, 0x11, 0xb5, 0x15, 0x49, 0x8d, 0xfd, 0xf8, 0x25, 0x59, - 0x77, 0xa5, 0x75, 0xa7, 0xb1, 0x42, 0xa9, 0xad, 0xa8, 0x12, 0x49, 0x6d, 0xf9, 0x9d, 0x5a, 0x5b, - 0x1a, 0x5e, 0xc3, 0x3b, 0xc7, 0x88, 0xee, 0xb4, 0x77, 0xd9, 0x3f, 0xf6, 0x87, 0xfd, 0xe2, 0xcc, - 0x96, 0x9f, 0xb8, 0xf3, 0x5c, 0xb0, 0x62, 0x7b, 0xb4, 0x6d, 0xe7, 0x76, 0xac, 0xb0, 0xb6, 0x77, - 0x6e, 0xbf, 0xa7, 0x45, 0xcb, 0xa6, 0x86, 0x54, 0xf3, 0x7c, 0x92, 0x86, 0xf3, 0x4c, 0x84, 0xd3, - 0xb4, 0x6a, 0x7b, 0xb6, 0x4b, 0xfc, 0x83, 0xa8, 0xd7, 0x4d, 0x12, 0x5a, 0x69, 0xb5, 0xce, 0xf5, - 0xab, 0xe5, 0xb7, 0xdd, 0xd0, 0x6e, 0x92, 0x9e, 0x0a, 0x3f, 0xff, 0xa0, 0x0a, 0x41, 0x6d, 0x8f, - 0x34, 0xad, 0x9e, 0x7a, 0x4f, 0xf7, 0xab, 0xd7, 0x0e, 0x6d, 0xe7, 0x9c, 0xed, 0x86, 0x41, 0xe8, - 0x27, 0x2b, 0x99, 0xdf, 0xcc, 0xc3, 0x54, 0x79, 0xa3, 0x52, 0x0d, 0xad, 0xb0, 0x1d, 0xa0, 0xcf, - 0x18, 0x30, 0xe3, 0x78, 0x56, 0xbd, 0x62, 0x39, 0x96, 0x5b, 0x23, 0x7e, 0xd1, 0x78, 0xdc, 0x78, - 0x6a, 0xfa, 0xfc, 0xc6, 0xca, 0x28, 0xf3, 0xb5, 0x52, 0xbe, 0x1b, 0x60, 0x12, 0x78, 0x6d, 0xbf, - 0x46, 0x30, 0xd9, 0xad, 0x2c, 0x7d, 0xbb, 0x53, 0x7a, 0xa4, 0xdb, 0x29, 0xcd, 0x6c, 0x68, 0x9c, - 0x70, 0x8c, 0x2f, 0xfa, 0xb2, 0x01, 0x8b, 0x35, 0xcb, 0xb5, 0xfc, 0x83, 0x6d, 0xcb, 0x6f, 0x90, - 0xf0, 0x92, 0xef, 0xb5, 0x5b, 0xc5, 0xdc, 0x31, 0xb4, 0xe6, 0xb4, 0x68, 0xcd, 0xe2, 0x6a, 0x92, - 0x1d, 0xee, 0x6d, 0x01, 0x6b, 0x57, 0x10, 0x5a, 0x3b, 0x0e, 0xd1, 0xdb, 0x95, 0x3f, 0xce, 0x76, - 0x55, 0x93, 0xec, 0x70, 0x6f, 0x0b, 0xcc, 0xd7, 0xf2, 0xb0, 0x58, 0xde, 0xa8, 0x6c, 0xfb, 0xd6, - 0xee, 0xae, 0x5d, 0xc3, 0x5e, 0x3b, 0xb4, 0xdd, 0x06, 0x7a, 0x3b, 0x4c, 0xda, 0x6e, 0xc3, 0x27, - 0x41, 0xc0, 0x26, 0x72, 0xaa, 0x32, 0x2f, 0x88, 0x4e, 0xae, 0xf3, 0x62, 0x2c, 0xe1, 0xe8, 0x59, - 0x98, 0x0e, 0x88, 0xbf, 0x6f, 0xd7, 0xc8, 0x96, 0xe7, 0x87, 0x6c, 0xa4, 0xc7, 0x2b, 0x27, 0x04, - 0xfa, 0x74, 0x35, 0x02, 0x61, 0x1d, 0x8f, 0x56, 0xf3, 0x3d, 0x2f, 0x14, 0x70, 0x36, 0x10, 0x53, - 0x51, 0x35, 0x1c, 0x81, 0xb0, 0x8e, 0x87, 0x5e, 0x37, 0x60, 0x21, 0x08, 0xed, 0xda, 0x1d, 0xdb, - 0x25, 0x41, 0xb0, 0xea, 0xb9, 0xbb, 0x76, 0xa3, 0x38, 0xce, 0x46, 0xf1, 0xea, 0x68, 0xa3, 0x58, - 0x4d, 0x50, 0xad, 0x2c, 0x75, 0x3b, 0xa5, 0x85, 0x64, 0x29, 0xee, 0xe1, 0x8e, 0xd6, 0x60, 0xc1, - 0x72, 0x5d, 0x2f, 0xb4, 0x42, 0xdb, 0x73, 0xb7, 0x7c, 0xb2, 0x6b, 0xdf, 0x2b, 0x8e, 0xb1, 0xee, - 0x14, 0x45, 0x77, 0x16, 0xca, 0x09, 0x38, 0xee, 0xa9, 0x61, 0xae, 0x41, 0xb1, 0xdc, 0xdc, 0xb1, - 0x82, 0xc0, 0xaa, 0x7b, 0x7e, 0x62, 0x36, 0x9e, 0x82, 0x42, 0xd3, 0x6a, 0xb5, 0x6c, 0xb7, 0x41, - 0xa7, 0x23, 0xff, 0xd4, 0x54, 0x65, 0xa6, 0xdb, 0x29, 0x15, 0x36, 0x45, 0x19, 0x56, 0x50, 0xf3, - 0x1f, 0x73, 0x30, 0x5d, 0x76, 0x2d, 0xe7, 0x20, 0xb0, 0x03, 0xdc, 0x76, 0xd1, 0x47, 0xa0, 0x40, - 0xb5, 0x4b, 0xdd, 0x0a, 0x2d, 0xb1, 0x22, 0xdf, 0xb5, 0xc2, 0x17, 0xfb, 0x8a, 0xbe, 0xd8, 0xa3, - 0x71, 0xa1, 0xd8, 0x2b, 0xfb, 0xef, 0x5e, 0xb9, 0xb6, 0x73, 0x9b, 0xd4, 0xc2, 0x4d, 0x12, 0x5a, - 0x15, 0x24, 0x7a, 0x01, 0x51, 0x19, 0x56, 0x54, 0x91, 0x07, 0x63, 0x41, 0x8b, 0xd4, 0xc4, 0x0a, - 0xdb, 0x1c, 0x51, 0x92, 0xa3, 0xa6, 0x57, 0x5b, 0xa4, 0x56, 0x99, 0x11, 0xac, 0xc7, 0xe8, 0x3f, - 0xcc, 0x18, 0xa1, 0xbb, 0x30, 0x11, 0x30, 0x9d, 0x23, 0x16, 0xcf, 0xb5, 0xec, 0x58, 0x32, 0xb2, - 0x95, 0x39, 0xc1, 0x74, 0x82, 0xff, 0xc7, 0x82, 0x9d, 0xf9, 0x4f, 0x06, 0x9c, 0xd0, 0xb0, 0xcb, - 0x7e, 0xa3, 0xdd, 0x24, 0x6e, 0x88, 0x1e, 0x87, 0x31, 0xd7, 0x6a, 0x12, 0xb1, 0x50, 0x54, 0x93, - 0xaf, 0x5a, 0x4d, 0x82, 0x19, 0x04, 0x3d, 0x01, 0xe3, 0xfb, 0x96, 0xd3, 0x26, 0x6c, 0x90, 0xa6, - 0x2a, 0xb3, 0x02, 0x65, 0xfc, 0x26, 0x2d, 0xc4, 0x1c, 0x86, 0x3e, 0x0e, 0x53, 0xec, 0xc7, 0x45, - 0xdf, 0x6b, 0x66, 0xd4, 0x35, 0xd1, 0xc2, 0x9b, 0x92, 0x6c, 0x65, 0xb6, 0xdb, 0x29, 0x4d, 0xa9, - 0xbf, 0x38, 0x62, 0x68, 0xfe, 0xb3, 0x01, 0xf3, 0x5a, 0xe7, 0x36, 0xec, 0x20, 0x44, 0x1f, 0xea, - 0x11, 0x9e, 0x95, 0xc1, 0x84, 0x87, 0xd6, 0x66, 0xa2, 0xb3, 0x20, 0x7a, 0x5a, 0x90, 0x25, 0x9a, - 0xe0, 0xb8, 0x30, 0x6e, 0x87, 0xa4, 0x19, 0x14, 0x73, 0x8f, 0xe7, 0x9f, 0x9a, 0x3e, 0xbf, 0x9e, - 0xd9, 0x34, 0x46, 0xe3, 0xbb, 0x4e, 0xe9, 0x63, 0xce, 0xc6, 0xfc, 0x4a, 0x2e, 0xd6, 0x43, 0x2a, - 0x51, 0xc8, 0x83, 0xc9, 0x26, 0x09, 0x7d, 0xbb, 0xc6, 0xd7, 0xd5, 0xf4, 0xf9, 0xb5, 0xd1, 0x5a, - 0xb1, 0xc9, 0x88, 0x45, 0xca, 0x92, 0xff, 0x0f, 0xb0, 0xe4, 0x82, 0xf6, 0x60, 0xcc, 0xf2, 0x1b, - 0xb2, 0xcf, 0x17, 0xb3, 0x99, 0xdf, 0x48, 0xe6, 0xca, 0x7e, 0x23, 0xc0, 0x8c, 0x03, 0x3a, 0x07, - 0x53, 0x21, 0xf1, 0x9b, 0xb6, 0x6b, 0x85, 0x5c, 0xbb, 0x16, 0x2a, 0x8b, 0x02, 0x6d, 0x6a, 0x5b, - 0x02, 0x70, 0x84, 0x63, 0xbe, 0x91, 0x83, 0xc5, 0x9e, 0xc5, 0x80, 0x9e, 0x81, 0xf1, 0xd6, 0x9e, - 0x15, 0x48, 0xe9, 0x3e, 0x2b, 0x87, 0x76, 0x8b, 0x16, 0xde, 0xef, 0x94, 0x66, 0x65, 0x15, 0x56, - 0x80, 0x39, 0x32, 0xdd, 0x3e, 0x9a, 0x24, 0x08, 0xac, 0x86, 0x14, 0x79, 0x6d, 0x44, 0x58, 0x31, - 0x96, 0x70, 0xf4, 0x2b, 0x06, 0xcc, 0xf2, 0xd1, 0xc1, 0x24, 0x68, 0x3b, 0x21, 0x5d, 0xd6, 0x74, - 0x6c, 0xae, 0x64, 0x31, 0x13, 0x9c, 0x64, 0xe5, 0xa4, 0xe0, 0x3e, 0xab, 0x97, 0x06, 0x38, 0xce, - 0x17, 0xdd, 0x82, 0xa9, 0x20, 0xb4, 0xfc, 0x90, 0xd4, 0xcb, 0x21, 0x53, 0xe0, 0xd3, 0xe7, 0x7f, - 0x76, 0x30, 0x79, 0xdf, 0xb6, 0x9b, 0x84, 0xaf, 0xad, 0xaa, 0x24, 0x80, 0x23, 0x5a, 0xe6, 0xdf, - 0xc7, 0x15, 0x47, 0x35, 0xa4, 0x66, 0x54, 0xe3, 0x00, 0x7d, 0x10, 0x4e, 0x07, 0xed, 0x5a, 0x8d, - 0x04, 0xc1, 0x6e, 0xdb, 0xc1, 0x6d, 0xf7, 0xb2, 0x1d, 0x84, 0x9e, 0x7f, 0xb0, 0x61, 0x37, 0xed, - 0x90, 0x8d, 0xf7, 0x78, 0xe5, 0x4c, 0xb7, 0x53, 0x3a, 0x5d, 0xed, 0x87, 0x84, 0xfb, 0xd7, 0x47, - 0x16, 0x3c, 0xda, 0x76, 0xfb, 0x93, 0xe7, 0xdb, 0x74, 0xa9, 0xdb, 0x29, 0x3d, 0x7a, 0xa3, 0x3f, - 0x1a, 0x3e, 0x8c, 0x86, 0xf9, 0xef, 0x06, 0x2c, 0xc8, 0x7e, 0x6d, 0x93, 0x66, 0xcb, 0xb1, 0x42, - 0xf2, 0x10, 0x76, 0x9c, 0x30, 0xb6, 0xe3, 0xe0, 0x6c, 0xf4, 0x86, 0x6c, 0x7f, 0xbf, 0x6d, 0xc7, - 0xfc, 0x37, 0x03, 0x96, 0x92, 0xc8, 0x0f, 0x41, 0x4b, 0x06, 0x71, 0x2d, 0x79, 0x35, 0xdb, 0xde, - 0xf6, 0x51, 0x95, 0x3f, 0x4a, 0xe9, 0xeb, 0xff, 0x72, 0x7d, 0x69, 0xfe, 0xde, 0x18, 0xcc, 0x94, - 0xdd, 0xd0, 0x2e, 0xef, 0xee, 0xda, 0xae, 0x1d, 0x1e, 0xa0, 0xcf, 0xe5, 0xe0, 0x5c, 0xcb, 0x27, - 0xbb, 0xc4, 0xf7, 0x49, 0x7d, 0xad, 0xed, 0xdb, 0x6e, 0xa3, 0x5a, 0xdb, 0x23, 0xf5, 0xb6, 0x63, - 0xbb, 0x8d, 0xf5, 0x86, 0xeb, 0xa9, 0xe2, 0x0b, 0xf7, 0x48, 0xad, 0x4d, 0x4d, 0x39, 0x31, 0xff, - 0xcd, 0xd1, 0x9a, 0xb9, 0x35, 0x1c, 0xd3, 0xca, 0xd3, 0xdd, 0x4e, 0xe9, 0xdc, 0x90, 0x95, 0xf0, - 0xb0, 0x5d, 0x43, 0x9f, 0xcd, 0xc1, 0x8a, 0x4f, 0x3e, 0xda, 0xb6, 0x07, 0x1f, 0x0d, 0xbe, 0x40, - 0x9d, 0xd1, 0x46, 0x03, 0x0f, 0xc5, 0xb3, 0x72, 0xbe, 0xdb, 0x29, 0x0d, 0x59, 0x07, 0x0f, 0xd9, - 0x2f, 0xf3, 0x2f, 0x0d, 0x28, 0x0c, 0x61, 0xfd, 0x95, 0xe2, 0xd6, 0xdf, 0x54, 0x8f, 0xe5, 0x17, - 0xf6, 0x5a, 0x7e, 0x97, 0x46, 0x1b, 0xb4, 0x41, 0x2c, 0xbe, 0xff, 0x30, 0x60, 0xb1, 0xc7, 0x42, - 0x44, 0x7b, 0xb0, 0xd4, 0xf2, 0xea, 0x72, 0xd1, 0x5f, 0xb6, 0x82, 0x3d, 0x06, 0x13, 0xdd, 0x7b, - 0xa6, 0xdb, 0x29, 0x2d, 0x6d, 0xa5, 0xc0, 0xef, 0x77, 0x4a, 0x45, 0x45, 0x24, 0x81, 0x80, 0x53, - 0x29, 0xa2, 0x16, 0x14, 0x76, 0x6d, 0xe2, 0xd4, 0x31, 0xd9, 0x15, 0x92, 0x32, 0xe2, 0xf2, 0xbe, - 0x28, 0xa8, 0xf1, 0xc3, 0x91, 0xfc, 0x87, 0x15, 0x17, 0xf3, 0x3a, 0xcc, 0xc5, 0x8f, 0xca, 0x03, - 0x4c, 0xde, 0x19, 0xc8, 0x5b, 0xbe, 0x2b, 0xa6, 0x6e, 0x5a, 0x20, 0xe4, 0xcb, 0xf8, 0x2a, 0xa6, - 0xe5, 0xe6, 0x4f, 0xc6, 0x60, 0xbe, 0xe2, 0xb4, 0xc9, 0x25, 0x9f, 0x10, 0x69, 0x32, 0x95, 0x61, - 0xbe, 0xe5, 0x93, 0x7d, 0x9b, 0xdc, 0xad, 0x12, 0x87, 0xd4, 0x42, 0xcf, 0x17, 0xf4, 0x4f, 0x89, - 0xea, 0xf3, 0x5b, 0x71, 0x30, 0x4e, 0xe2, 0xa3, 0x17, 0x60, 0xce, 0xaa, 0x85, 0xf6, 0x3e, 0x51, - 0x14, 0x78, 0x03, 0xde, 0x22, 0x28, 0xcc, 0x95, 0x63, 0x50, 0x9c, 0xc0, 0x46, 0x1f, 0x82, 0x62, - 0x50, 0xb3, 0x1c, 0x72, 0xa3, 0x25, 0x58, 0xad, 0xee, 0x91, 0xda, 0x9d, 0x2d, 0xcf, 0x76, 0x43, - 0x61, 0x0b, 0x3e, 0x2e, 0x28, 0x15, 0xab, 0x7d, 0xf0, 0x70, 0x5f, 0x0a, 0xe8, 0xcf, 0x0c, 0x38, - 0xd3, 0xf2, 0xc9, 0x96, 0xef, 0x35, 0x3d, 0xba, 0x20, 0x7a, 0xac, 0x46, 0x61, 0x3d, 0xdd, 0x1c, - 0x71, 0xe5, 0xf3, 0x92, 0xde, 0x03, 0xda, 0x5b, 0xbb, 0x9d, 0xd2, 0x99, 0xad, 0xc3, 0x1a, 0x80, - 0x0f, 0x6f, 0x1f, 0xfa, 0x0b, 0x03, 0xce, 0xb6, 0xbc, 0x20, 0x3c, 0xa4, 0x0b, 0xe3, 0xc7, 0xda, - 0x05, 0xb3, 0xdb, 0x29, 0x9d, 0xdd, 0x3a, 0xb4, 0x05, 0xf8, 0x01, 0x2d, 0x34, 0xbb, 0xd3, 0xb0, - 0xa8, 0xc9, 0x9e, 0x30, 0x2a, 0x9f, 0x87, 0x59, 0x29, 0x0c, 0xdc, 0xb3, 0xc2, 0x65, 0x4f, 0x99, - 0xc0, 0x65, 0x1d, 0x88, 0xe3, 0xb8, 0x54, 0xee, 0x94, 0x28, 0xf2, 0xda, 0x09, 0xb9, 0xdb, 0x8a, - 0x41, 0x71, 0x02, 0x1b, 0xad, 0xc3, 0x09, 0x51, 0x82, 0x49, 0xcb, 0xb1, 0x6b, 0xd6, 0xaa, 0xd7, - 0x16, 0x22, 0x37, 0x5e, 0x39, 0xd5, 0xed, 0x94, 0x4e, 0x6c, 0xf5, 0x82, 0x71, 0x5a, 0x1d, 0xb4, - 0x01, 0x4b, 0x56, 0x3b, 0xf4, 0x54, 0xff, 0x2f, 0xb8, 0xd6, 0x8e, 0x43, 0xea, 0x4c, 0xb4, 0x0a, - 0x95, 0x22, 0x55, 0x44, 0xe5, 0x14, 0x38, 0x4e, 0xad, 0x85, 0xb6, 0x12, 0xd4, 0xaa, 0xa4, 0xe6, - 0xb9, 0x75, 0x3e, 0xcb, 0xe3, 0x95, 0xc7, 0x44, 0xf7, 0xe2, 0x14, 0x05, 0x0e, 0x4e, 0xad, 0x89, - 0x1c, 0x98, 0x6b, 0x5a, 0xf7, 0x6e, 0xb8, 0xd6, 0xbe, 0x65, 0x3b, 0x94, 0x49, 0x71, 0xe2, 0x01, - 0xd6, 0x6e, 0x3b, 0xb4, 0x9d, 0x15, 0xee, 0x4c, 0x5d, 0x59, 0x77, 0xc3, 0x6b, 0x7e, 0x35, 0xa4, - 0xfb, 0x4a, 0x05, 0xd1, 0x81, 0xdd, 0x8c, 0xd1, 0xc2, 0x09, 0xda, 0xe8, 0x1a, 0x9c, 0x64, 0xcb, - 0x71, 0xcd, 0xbb, 0xeb, 0xae, 0x11, 0xc7, 0x3a, 0x90, 0x1d, 0x98, 0x64, 0x1d, 0x38, 0xdd, 0xed, - 0x94, 0x4e, 0x56, 0xd3, 0x10, 0x70, 0x7a, 0x3d, 0x7a, 0x3c, 0x88, 0x03, 0x30, 0xd9, 0xb7, 0x03, - 0xdb, 0x73, 0xf9, 0xf1, 0xa0, 0x10, 0x1d, 0x0f, 0xaa, 0xfd, 0xd1, 0xf0, 0x61, 0x34, 0xd0, 0x6f, - 0x19, 0xb0, 0x94, 0xb6, 0x0c, 0x8b, 0x53, 0x59, 0xb8, 0x8a, 0x12, 0x4b, 0x8b, 0x4b, 0x44, 0xaa, - 0x52, 0x48, 0x6d, 0x04, 0x7a, 0xd5, 0x80, 0x19, 0x4b, 0xb3, 0xf7, 0x8a, 0xc0, 0x5a, 0x75, 0x65, - 0x54, 0x03, 0x3b, 0xa2, 0x58, 0x59, 0xe8, 0x76, 0x4a, 0x31, 0x9b, 0x12, 0xc7, 0x38, 0xa2, 0xdf, - 0x36, 0xe0, 0x64, 0xea, 0x1a, 0x2f, 0x4e, 0x1f, 0xc7, 0x08, 0x31, 0x21, 0x49, 0xd7, 0x39, 0xe9, - 0xcd, 0x40, 0xaf, 0x1b, 0x6a, 0x2b, 0xdb, 0x94, 0x47, 0x9c, 0x19, 0xd6, 0xb4, 0xeb, 0x23, 0x9a, - 0xb8, 0x91, 0x41, 0x20, 0x09, 0x57, 0x4e, 0x68, 0x3b, 0xa3, 0x2c, 0xc4, 0x49, 0xf6, 0xe8, 0xf3, - 0x86, 0xdc, 0x1a, 0x55, 0x8b, 0x66, 0x8f, 0xab, 0x45, 0x28, 0xda, 0x69, 0x55, 0x83, 0x12, 0xcc, - 0xd1, 0x87, 0x61, 0xd9, 0xda, 0xf1, 0xfc, 0x30, 0x75, 0xf1, 0x15, 0xe7, 0xd8, 0x32, 0x3a, 0xdb, - 0xed, 0x94, 0x96, 0xcb, 0x7d, 0xb1, 0xf0, 0x21, 0x14, 0xcc, 0xef, 0x8d, 0xc1, 0x0c, 0xbf, 0x5f, - 0x10, 0x5b, 0xd7, 0x37, 0x0c, 0x78, 0xac, 0xd6, 0xf6, 0x7d, 0xe2, 0x86, 0xd5, 0x90, 0xb4, 0x7a, - 0x37, 0x2e, 0xe3, 0x58, 0x37, 0xae, 0xc7, 0xbb, 0x9d, 0xd2, 0x63, 0xab, 0x87, 0xf0, 0xc7, 0x87, - 0xb6, 0x0e, 0xfd, 0x8d, 0x01, 0xa6, 0x40, 0xa8, 0x58, 0xb5, 0x3b, 0x0d, 0xdf, 0x6b, 0xbb, 0xf5, - 0xde, 0x4e, 0xe4, 0x8e, 0xb5, 0x13, 0x4f, 0x76, 0x3b, 0x25, 0x73, 0xf5, 0x81, 0xad, 0xc0, 0x03, - 0xb4, 0x14, 0x5d, 0x82, 0x45, 0x81, 0x75, 0xe1, 0x5e, 0x8b, 0xf8, 0x36, 0x35, 0xa7, 0xc5, 0x6d, - 0x46, 0x74, 0x41, 0x94, 0x44, 0xc0, 0xbd, 0x75, 0x50, 0x00, 0x93, 0x77, 0x89, 0xdd, 0xd8, 0x0b, - 0xa5, 0xf9, 0x34, 0xe2, 0xad, 0x90, 0xb8, 0x43, 0xb8, 0xc5, 0x69, 0x56, 0xa6, 0xe9, 0xf9, 0x5a, - 0xfc, 0xc1, 0x92, 0x93, 0xf9, 0x87, 0x63, 0x00, 0x52, 0xbc, 0x48, 0x0b, 0xfd, 0x1c, 0x4c, 0x05, - 0x24, 0xe4, 0x58, 0xc2, 0x03, 0xc5, 0xdd, 0x5a, 0xb2, 0x10, 0x47, 0x70, 0x74, 0x07, 0xc6, 0x5b, - 0x56, 0x3b, 0x20, 0x62, 0xb2, 0xae, 0x64, 0x32, 0x59, 0x5b, 0x94, 0x22, 0x3f, 0x23, 0xb1, 0x9f, - 0x98, 0xf3, 0x40, 0x9f, 0x36, 0x00, 0x48, 0x7c, 0x80, 0xa7, 0xcf, 0x57, 0x33, 0x61, 0x19, 0xcd, - 0x01, 0x1d, 0x83, 0xca, 0x5c, 0xb7, 0x53, 0x02, 0x6d, 0xaa, 0x34, 0xb6, 0xe8, 0x2e, 0x14, 0x2c, - 0xa9, 0xa3, 0xc7, 0x8e, 0x43, 0x47, 0xb3, 0xa3, 0x8b, 0x12, 0x32, 0xc5, 0x0c, 0x7d, 0xd6, 0x80, - 0xb9, 0x80, 0x84, 0x62, 0xaa, 0xa8, 0xa6, 0x10, 0x06, 0xea, 0x88, 0x42, 0x52, 0x8d, 0xd1, 0xe4, - 0x1a, 0x2f, 0x5e, 0x86, 0x13, 0x7c, 0xcd, 0xef, 0x4d, 0xc3, 0x9c, 0x14, 0x99, 0xc8, 0xe6, 0xe4, - 0x17, 0x9e, 0x7d, 0x6c, 0xce, 0x55, 0x1d, 0x88, 0xe3, 0xb8, 0xb4, 0x32, 0xbf, 0x95, 0x8c, 0x9b, - 0x9c, 0xaa, 0x72, 0x55, 0x07, 0xe2, 0x38, 0x2e, 0x6a, 0xc2, 0x78, 0x10, 0x92, 0x96, 0x74, 0x1a, - 0x5f, 0x1e, 0x6d, 0x34, 0xa2, 0x95, 0x10, 0x39, 0xc6, 0xe8, 0xbf, 0x00, 0x73, 0x2e, 0xe8, 0x0b, - 0x06, 0xcc, 0x85, 0xb1, 0xbb, 0x39, 0x21, 0x06, 0xd9, 0x48, 0x62, 0xfc, 0xda, 0x8f, 0xcf, 0x46, - 0xbc, 0x0c, 0x27, 0xd8, 0xa7, 0x98, 0xa1, 0xe3, 0xc7, 0x68, 0x86, 0xbe, 0x04, 0x85, 0xa6, 0x75, - 0xaf, 0xda, 0xf6, 0x1b, 0x47, 0x37, 0x77, 0xc5, 0xd5, 0x25, 0xa7, 0x82, 0x15, 0x3d, 0xf4, 0x29, - 0x43, 0x5b, 0x5c, 0x93, 0x8c, 0xf8, 0xad, 0x6c, 0x17, 0x97, 0xd2, 0xe2, 0x7d, 0x97, 0x59, 0x8f, - 0x51, 0x58, 0x78, 0xe8, 0x46, 0x21, 0x35, 0x70, 0xf8, 0x02, 0x51, 0x06, 0xce, 0xd4, 0xb1, 0x1a, - 0x38, 0xab, 0x31, 0x66, 0x38, 0xc1, 0x9c, 0xb5, 0x87, 0xaf, 0x39, 0xd5, 0x1e, 0x38, 0xd6, 0xf6, - 0x54, 0x63, 0xcc, 0x70, 0x82, 0x79, 0xff, 0x93, 0xd0, 0xf4, 0xf1, 0x9c, 0x84, 0x66, 0x32, 0x38, - 0x09, 0x1d, 0x6e, 0x24, 0xce, 0x8e, 0x6a, 0x24, 0xa2, 0x2b, 0x80, 0xea, 0x07, 0xae, 0xd5, 0xb4, - 0x6b, 0x42, 0x59, 0xb2, 0x0d, 0x62, 0x8e, 0x9d, 0x94, 0x97, 0x85, 0x22, 0x43, 0x6b, 0x3d, 0x18, - 0x38, 0xa5, 0x96, 0xf9, 0x9f, 0x06, 0x2c, 0xac, 0x3a, 0x5e, 0xbb, 0x7e, 0xcb, 0x0a, 0x6b, 0x7b, - 0xdc, 0x21, 0x8f, 0x5e, 0x80, 0x82, 0xed, 0x86, 0xc4, 0xdf, 0xb7, 0x1c, 0xa1, 0xdb, 0x4d, 0x79, - 0x67, 0xb1, 0x2e, 0xca, 0xef, 0x77, 0x4a, 0x73, 0x6b, 0x6d, 0x9f, 0x85, 0x34, 0xf0, 0x95, 0x8e, - 0x55, 0x1d, 0xf4, 0x55, 0x03, 0x16, 0xb9, 0x4b, 0x7f, 0xcd, 0x0a, 0xad, 0xeb, 0x6d, 0xe2, 0xdb, - 0x44, 0x3a, 0xf5, 0x47, 0x5c, 0xe4, 0xc9, 0xb6, 0x4a, 0x06, 0x07, 0x91, 0xf9, 0xb5, 0x99, 0xe4, - 0x8c, 0x7b, 0x1b, 0x63, 0x7e, 0x31, 0x0f, 0xa7, 0xfb, 0xd2, 0x42, 0xcb, 0x90, 0xb3, 0xeb, 0xa2, - 0xeb, 0x20, 0xe8, 0xe6, 0xd6, 0xeb, 0x38, 0x67, 0xd7, 0xd1, 0x0a, 0xb3, 0x4c, 0x7c, 0x12, 0x04, - 0xd2, 0xe9, 0x3d, 0xa5, 0x8c, 0x08, 0x51, 0x8a, 0x35, 0x0c, 0x54, 0x82, 0x71, 0xc7, 0xda, 0x21, - 0x8e, 0xb0, 0x12, 0x99, 0xad, 0xb3, 0x41, 0x0b, 0x30, 0x2f, 0x47, 0xbf, 0x6c, 0x00, 0xf0, 0x06, - 0x52, 0x1b, 0x53, 0xec, 0x30, 0x38, 0xdb, 0x61, 0xa2, 0x94, 0x79, 0x2b, 0xa3, 0xff, 0x58, 0xe3, - 0x8a, 0xb6, 0x61, 0x82, 0x9a, 0x3d, 0x5e, 0xfd, 0xc8, 0x1b, 0x0a, 0x74, 0x3b, 0xa5, 0x89, 0x2d, - 0x46, 0x03, 0x0b, 0x5a, 0x74, 0xac, 0x7c, 0x12, 0xb6, 0x7d, 0x97, 0x0e, 0x2d, 0xdb, 0x42, 0x0a, - 0xbc, 0x15, 0x58, 0x95, 0x62, 0x0d, 0xc3, 0xfc, 0x93, 0x1c, 0x2c, 0xa5, 0x35, 0x9d, 0x6a, 0xea, - 0x09, 0xde, 0x5a, 0x71, 0xe0, 0x79, 0x7f, 0xf6, 0xe3, 0x23, 0x6e, 0xa7, 0x54, 0x3c, 0x88, 0xb8, - 0x3d, 0x16, 0x7c, 0xd1, 0xfb, 0xd5, 0x08, 0xe5, 0x8e, 0x38, 0x42, 0x8a, 0x72, 0x62, 0x94, 0x1e, - 0x87, 0xb1, 0x80, 0xce, 0x7c, 0x3e, 0xee, 0x96, 0x66, 0x73, 0xc4, 0x20, 0x14, 0xa3, 0xed, 0xda, - 0xa1, 0x88, 0x33, 0x52, 0x18, 0x37, 0x5c, 0x3b, 0xc4, 0x0c, 0x62, 0x7e, 0x39, 0x07, 0xcb, 0xfd, - 0x3b, 0x85, 0xbe, 0x6c, 0x00, 0xd4, 0xa9, 0x51, 0x4b, 0x45, 0x52, 0xde, 0xe6, 0x59, 0xc7, 0x35, - 0x86, 0x6b, 0x92, 0x53, 0x74, 0xb5, 0xab, 0x8a, 0x02, 0xac, 0x35, 0x04, 0x9d, 0x97, 0xa2, 0x7f, - 0xd5, 0x6a, 0x4a, 0x53, 0x50, 0xd5, 0xd9, 0x54, 0x10, 0xac, 0x61, 0xd1, 0x53, 0x8b, 0x6b, 0x35, - 0x49, 0xd0, 0xb2, 0x54, 0x20, 0x19, 0x3b, 0xb5, 0x5c, 0x95, 0x85, 0x38, 0x82, 0x9b, 0x0e, 0x3c, - 0x31, 0x40, 0x3b, 0x33, 0x0a, 0xea, 0x31, 0x7f, 0x64, 0xc0, 0xa9, 0x55, 0xa7, 0x1d, 0x84, 0xc4, - 0xff, 0x3f, 0x73, 0x53, 0xfe, 0x5f, 0x06, 0x3c, 0xda, 0xa7, 0xcf, 0x0f, 0xe1, 0xc2, 0xfc, 0x95, - 0xf8, 0x85, 0xf9, 0x8d, 0x51, 0x45, 0x3a, 0xb5, 0x1f, 0x7d, 0xee, 0xcd, 0x43, 0x98, 0xa5, 0x5a, - 0xab, 0xee, 0x35, 0x32, 0xda, 0x37, 0x9f, 0x80, 0xf1, 0x8f, 0xd2, 0xfd, 0x27, 0x29, 0x63, 0x6c, - 0x53, 0xc2, 0x1c, 0x66, 0xfe, 0x43, 0x0e, 0xb4, 0xf3, 0xea, 0x43, 0x10, 0x2b, 0x37, 0x26, 0x56, - 0x23, 0x9e, 0x40, 0xb5, 0xd3, 0x77, 0xbf, 0x88, 0xbf, 0xfd, 0x44, 0xc4, 0xdf, 0xd5, 0xcc, 0x38, - 0x1e, 0x1e, 0xf0, 0xf7, 0x86, 0x01, 0x8f, 0x46, 0xc8, 0xbd, 0xae, 0x9f, 0x07, 0xeb, 0x88, 0x67, - 0x61, 0xda, 0x8a, 0xaa, 0x89, 0x59, 0x54, 0x41, 0xae, 0x1a, 0x45, 0xac, 0xe3, 0x45, 0x41, 0x57, - 0xf9, 0x23, 0x06, 0x5d, 0x8d, 0x1d, 0x1e, 0x74, 0x65, 0xfe, 0x38, 0x07, 0x67, 0x7a, 0x7b, 0x26, - 0xa5, 0x7b, 0xb0, 0x9b, 0xd1, 0xe7, 0x60, 0x26, 0x14, 0x15, 0x34, 0x5d, 0xad, 0x42, 0xb4, 0xb7, - 0x35, 0x18, 0x8e, 0x61, 0xd2, 0x9a, 0x35, 0xbe, 0xae, 0xaa, 0x35, 0xaf, 0x25, 0xa3, 0xd3, 0x54, - 0xcd, 0x55, 0x0d, 0x86, 0x63, 0x98, 0x2a, 0x1c, 0x64, 0xec, 0xd8, 0xc3, 0xe7, 0xaa, 0x70, 0x52, - 0x46, 0x05, 0x5c, 0xf4, 0xfc, 0x55, 0xaf, 0xd9, 0x72, 0x08, 0x0b, 0x6a, 0x18, 0x67, 0x8d, 0x3d, - 0x23, 0xaa, 0x9c, 0xc4, 0x69, 0x48, 0x38, 0xbd, 0xae, 0xf9, 0x46, 0x1e, 0x4e, 0x44, 0xc3, 0xbe, - 0xea, 0xb9, 0x75, 0x9b, 0xc5, 0x56, 0x3c, 0x0f, 0x63, 0xe1, 0x41, 0x4b, 0x0e, 0xf6, 0xcf, 0xc8, - 0xe6, 0x6c, 0x1f, 0xb4, 0xe8, 0x6c, 0x9f, 0x4a, 0xa9, 0x42, 0x41, 0x98, 0x55, 0x42, 0x1b, 0x6a, - 0x75, 0xf0, 0x19, 0x78, 0x26, 0x2e, 0xcd, 0xf7, 0x3b, 0xa5, 0x94, 0x17, 0x0a, 0x2b, 0x8a, 0x52, - 0x5c, 0xe6, 0xd1, 0x6d, 0x98, 0x73, 0xac, 0x20, 0xbc, 0xd1, 0xaa, 0x5b, 0x21, 0xd9, 0xb6, 0x9b, - 0x44, 0xac, 0xb9, 0x61, 0x22, 0xe1, 0xd4, 0x6d, 0xe1, 0x46, 0x8c, 0x12, 0x4e, 0x50, 0x46, 0xfb, - 0x80, 0x68, 0xc9, 0xb6, 0x6f, 0xb9, 0x01, 0xef, 0x15, 0xe5, 0x37, 0x7c, 0xe4, 0x9d, 0x3a, 0xe2, - 0x6c, 0xf4, 0x50, 0xc3, 0x29, 0x1c, 0xd0, 0x93, 0x30, 0xe1, 0x13, 0x2b, 0x10, 0x93, 0x39, 0x15, - 0xad, 0x7f, 0xcc, 0x4a, 0xb1, 0x80, 0xea, 0x0b, 0x6a, 0xe2, 0x01, 0x0b, 0xea, 0xfb, 0x06, 0xcc, - 0x45, 0xd3, 0xf4, 0x10, 0xb6, 0xb9, 0x66, 0x7c, 0x9b, 0xbb, 0x9c, 0x95, 0x4a, 0xec, 0xb3, 0xb3, - 0x7d, 0x7d, 0x4c, 0xef, 0x1f, 0x8b, 0x05, 0xfb, 0x18, 0x4c, 0xc9, 0x55, 0x2d, 0xed, 0xc7, 0x11, - 0xfd, 0x24, 0x31, 0xcb, 0x42, 0x0b, 0x56, 0x15, 0x4c, 0x70, 0xc4, 0x8f, 0x6e, 0xac, 0x75, 0xb1, - 0x69, 0x0a, 0xb1, 0x57, 0x1b, 0xab, 0xdc, 0x4c, 0xd3, 0x36, 0x56, 0x59, 0x07, 0xdd, 0x80, 0x53, - 0x2d, 0xdf, 0x63, 0x0f, 0x18, 0xd6, 0x88, 0x55, 0x77, 0x6c, 0x97, 0xc8, 0xe3, 0x38, 0xbf, 0xac, - 0x7e, 0xb4, 0xdb, 0x29, 0x9d, 0xda, 0x4a, 0x47, 0xc1, 0xfd, 0xea, 0xc6, 0x83, 0x6e, 0xc7, 0x1e, - 0x1c, 0x74, 0x8b, 0x7e, 0x55, 0x39, 0xbd, 0x48, 0x50, 0x1c, 0x67, 0x83, 0xf8, 0xc1, 0xac, 0xa6, - 0x32, 0x45, 0xad, 0x47, 0x22, 0x55, 0x16, 0x4c, 0xb1, 0x62, 0xdf, 0xdf, 0xb3, 0x32, 0x71, 0x34, - 0xcf, 0x8a, 0xf9, 0xda, 0x38, 0x2c, 0x24, 0x37, 0xdb, 0xe3, 0x0f, 0x28, 0xfe, 0x0d, 0x03, 0x16, - 0xa4, 0xa0, 0x70, 0x9e, 0x44, 0xba, 0x87, 0x37, 0x32, 0x92, 0x4f, 0x6e, 0x36, 0xa8, 0xd7, 0x1d, - 0xdb, 0x09, 0x6e, 0xb8, 0x87, 0x3f, 0x7a, 0x19, 0xa6, 0x95, 0x17, 0xf5, 0x48, 0xd1, 0xc5, 0xf3, - 0xcc, 0x60, 0x88, 0x48, 0x60, 0x9d, 0x1e, 0x7a, 0xcd, 0x00, 0xa8, 0x49, 0x8d, 0x2e, 0x05, 0xe9, - 0x7a, 0x56, 0x82, 0xa4, 0xf6, 0x8a, 0xc8, 0x2e, 0x54, 0x45, 0x01, 0xd6, 0x18, 0xa3, 0x2f, 0x32, - 0xff, 0xa9, 0x32, 0x64, 0xa8, 0xe8, 0xd0, 0x96, 0x7c, 0x20, 0x6b, 0x91, 0x8e, 0xae, 0xf2, 0x94, - 0xd5, 0xa0, 0x81, 0x02, 0x1c, 0x6b, 0x84, 0xf9, 0x3c, 0xa8, 0x68, 0x30, 0xba, 0x42, 0x59, 0x3c, - 0xd8, 0x96, 0x15, 0xee, 0x09, 0x11, 0x54, 0x2b, 0xf4, 0xa2, 0x04, 0xe0, 0x08, 0xc7, 0xfc, 0x08, - 0xcc, 0x5d, 0xf2, 0xad, 0xd6, 0x9e, 0xcd, 0xfc, 0x94, 0xd4, 0xa8, 0x7f, 0x3b, 0x4c, 0x5a, 0xf5, - 0x7a, 0xda, 0xdb, 0xa8, 0x32, 0x2f, 0xc6, 0x12, 0x3e, 0x98, 0xfd, 0xfe, 0x4d, 0x03, 0x96, 0xd6, - 0x83, 0xd0, 0xf6, 0xd6, 0x48, 0x10, 0x52, 0xb5, 0x40, 0x2d, 0x88, 0xb6, 0x43, 0x06, 0xb0, 0xc1, - 0xd6, 0x60, 0x41, 0x5c, 0xa6, 0xb4, 0x77, 0x02, 0x12, 0x6a, 0x76, 0x98, 0x12, 0xce, 0xd5, 0x04, - 0x1c, 0xf7, 0xd4, 0xa0, 0x54, 0xc4, 0xad, 0x4a, 0x44, 0x25, 0x1f, 0xa7, 0x52, 0x4d, 0xc0, 0x71, - 0x4f, 0x0d, 0xf3, 0x3b, 0x79, 0x38, 0xc1, 0xba, 0x91, 0x78, 0xbc, 0xf4, 0x79, 0x03, 0xe6, 0xf6, - 0x6d, 0x3f, 0x6c, 0x5b, 0x8e, 0x7e, 0x3d, 0x34, 0xb2, 0x7c, 0x32, 0x5e, 0x37, 0x63, 0x84, 0xb9, - 0x03, 0x39, 0x5e, 0x86, 0x13, 0xcc, 0xd1, 0xaf, 0x1b, 0x30, 0x5f, 0x8f, 0x8f, 0x74, 0x36, 0x07, - 0xe4, 0xb4, 0x39, 0xe4, 0x51, 0x0d, 0x89, 0x42, 0x9c, 0xe4, 0x8f, 0xbe, 0x64, 0xc0, 0x7c, 0xbc, - 0x99, 0x52, 0x65, 0x1d, 0xc3, 0x20, 0xa9, 0x30, 0xc4, 0x78, 0x79, 0x80, 0x93, 0x4d, 0x30, 0xff, - 0xce, 0x10, 0x53, 0x1a, 0xc7, 0x1c, 0x40, 0x30, 0x4d, 0x98, 0xf0, 0xbd, 0x76, 0x28, 0x9c, 0xbc, - 0x53, 0xdc, 0x17, 0x88, 0x59, 0x09, 0x16, 0x10, 0x74, 0x17, 0xa6, 0x42, 0x27, 0xe0, 0x85, 0xa2, - 0xb7, 0x23, 0x5a, 0xf4, 0xdb, 0x1b, 0x55, 0x46, 0x4e, 0xdb, 0x74, 0x45, 0x09, 0x35, 0x1e, 0x24, - 0x2f, 0xf3, 0x6b, 0x06, 0x4c, 0x5d, 0xf1, 0x76, 0xc4, 0x72, 0xfe, 0x70, 0x06, 0xe7, 0x65, 0xb5, - 0xad, 0xaa, 0x6b, 0x8b, 0xc8, 0x52, 0x7b, 0x21, 0x76, 0x5a, 0x7e, 0x4c, 0xa3, 0xbd, 0xc2, 0xde, - 0x14, 0x53, 0x52, 0x57, 0xbc, 0x9d, 0xbe, 0xee, 0x94, 0xdf, 0x19, 0x87, 0xd9, 0x17, 0xad, 0x03, - 0xe2, 0x86, 0xd6, 0xf0, 0x0a, 0x88, 0x1e, 0x40, 0x5b, 0x2c, 0xaa, 0x4e, 0x33, 0x95, 0xa2, 0x03, - 0x68, 0x04, 0xc2, 0x3a, 0x5e, 0xa4, 0x57, 0xf8, 0x13, 0xc7, 0x34, 0x8d, 0xb0, 0x9a, 0x80, 0xe3, - 0x9e, 0x1a, 0xe8, 0x0a, 0x20, 0x11, 0xc7, 0x5f, 0xae, 0xd5, 0xbc, 0xb6, 0xcb, 0x35, 0x0b, 0x3f, - 0x9b, 0x2a, 0x9b, 0x7d, 0xb3, 0x07, 0x03, 0xa7, 0xd4, 0x42, 0x1f, 0x82, 0x62, 0x8d, 0x51, 0x16, - 0x16, 0x9c, 0x4e, 0x91, 0x5b, 0xf1, 0x2a, 0xa2, 0x75, 0xb5, 0x0f, 0x1e, 0xee, 0x4b, 0x81, 0xb6, - 0x34, 0x08, 0x3d, 0xdf, 0x6a, 0x10, 0x9d, 0xee, 0x44, 0xbc, 0xa5, 0xd5, 0x1e, 0x0c, 0x9c, 0x52, - 0x0b, 0x7d, 0x12, 0xa6, 0xc2, 0x3d, 0x9f, 0x04, 0x7b, 0x9e, 0x53, 0x17, 0xf7, 0x98, 0x23, 0x3a, - 0x2c, 0xc4, 0xec, 0x6f, 0x4b, 0xaa, 0x9a, 0x78, 0xcb, 0x22, 0x1c, 0xf1, 0x44, 0x3e, 0x4c, 0x04, - 0xf4, 0xb4, 0x1c, 0x14, 0x0b, 0x59, 0x58, 0xe5, 0x82, 0x3b, 0x3b, 0x80, 0x6b, 0xae, 0x12, 0xc6, - 0x01, 0x0b, 0x4e, 0xe6, 0xb7, 0x72, 0x30, 0xa3, 0x23, 0x0e, 0xa0, 0x22, 0x3e, 0x6d, 0xc0, 0x4c, - 0xcd, 0x73, 0x43, 0xdf, 0x73, 0xb8, 0x1b, 0x80, 0x2f, 0x90, 0x11, 0xdf, 0x01, 0x32, 0x52, 0x6b, - 0x24, 0xb4, 0x6c, 0x47, 0xf3, 0x28, 0x68, 0x6c, 0x70, 0x8c, 0x29, 0xfa, 0x9c, 0x01, 0xf3, 0x51, - 0x80, 0x47, 0xe4, 0x8f, 0xc8, 0xb4, 0x21, 0x4a, 0xe3, 0x5e, 0x88, 0x73, 0xc2, 0x49, 0xd6, 0xe6, - 0x0e, 0x2c, 0x24, 0x67, 0x9b, 0x0e, 0x65, 0xcb, 0x12, 0x6b, 0x3d, 0x1f, 0x0d, 0xe5, 0x96, 0x15, - 0x04, 0x98, 0x41, 0xd0, 0x3b, 0xa0, 0xd0, 0xb4, 0xfc, 0x86, 0xed, 0x5a, 0x0e, 0x1b, 0xc5, 0xbc, - 0xa6, 0x90, 0x44, 0x39, 0x56, 0x18, 0xe6, 0x0f, 0xc7, 0x60, 0x7a, 0x93, 0x58, 0x41, 0xdb, 0x27, - 0xcc, 0x61, 0x78, 0xec, 0x16, 0x79, 0xec, 0x61, 0x5d, 0x3e, 0xbb, 0x87, 0x75, 0xe8, 0x25, 0x80, - 0x5d, 0xdb, 0xb5, 0x83, 0xbd, 0x23, 0x3e, 0xd9, 0x63, 0x37, 0x4f, 0x17, 0x15, 0x05, 0xac, 0x51, - 0x8b, 0xdc, 0xfb, 0xe3, 0x87, 0xbc, 0xd9, 0x7d, 0xcd, 0xd0, 0x36, 0x8f, 0x89, 0x2c, 0xae, 0x33, - 0xb5, 0x89, 0x59, 0x91, 0x9b, 0xc9, 0x05, 0x37, 0xf4, 0x0f, 0x0e, 0xdd, 0x63, 0xb6, 0xa1, 0xe0, - 0x93, 0xa0, 0xdd, 0xa4, 0x67, 0x8b, 0xc9, 0xa1, 0x87, 0x81, 0x45, 0x43, 0x60, 0x51, 0x1f, 0x2b, - 0x4a, 0xcb, 0xcf, 0xc3, 0x6c, 0xac, 0x09, 0x68, 0x01, 0xf2, 0x77, 0xc8, 0x01, 0x97, 0x13, 0x4c, - 0x7f, 0xa2, 0xa5, 0xd8, 0x25, 0x88, 0x18, 0x96, 0xf7, 0xe6, 0x9e, 0x33, 0xcc, 0x1f, 0x4f, 0x80, - 0xb8, 0x30, 0x1b, 0x40, 0x17, 0xe8, 0x7e, 0xf2, 0xdc, 0x11, 0xfc, 0xe4, 0x57, 0x60, 0xc6, 0x76, - 0xed, 0xd0, 0xb6, 0x1c, 0x76, 0x00, 0x15, 0x7b, 0xd5, 0x93, 0x72, 0xfd, 0xaf, 0x6b, 0xb0, 0x14, - 0x3a, 0xb1, 0xba, 0xe8, 0x3a, 0x8c, 0x33, 0x65, 0x2e, 0xe4, 0x69, 0xf8, 0x5b, 0x3d, 0x76, 0xa1, - 0xcb, 0x23, 0xdb, 0x39, 0x25, 0x66, 0x60, 0xf3, 0x57, 0x94, 0xea, 0xdc, 0x24, 0xc4, 0x2a, 0x32, - 0xb0, 0x13, 0x70, 0xdc, 0x53, 0x83, 0x52, 0xd9, 0xb5, 0x6c, 0xa7, 0xed, 0x93, 0x88, 0xca, 0x44, - 0x9c, 0xca, 0xc5, 0x04, 0x1c, 0xf7, 0xd4, 0x40, 0xbb, 0x30, 0x23, 0xca, 0x78, 0x7c, 0xc3, 0xe4, - 0x11, 0x7b, 0xc9, 0xe2, 0x58, 0x2e, 0x6a, 0x94, 0x70, 0x8c, 0x2e, 0x6a, 0xc3, 0xa2, 0xed, 0xd6, - 0x3c, 0xb7, 0xe6, 0xb4, 0x03, 0x7b, 0x9f, 0x44, 0x61, 0xe5, 0x47, 0x61, 0x76, 0xb2, 0xdb, 0x29, - 0x2d, 0xae, 0x27, 0xc9, 0xe1, 0x5e, 0x0e, 0xe8, 0x53, 0x06, 0x9c, 0xac, 0x79, 0x6e, 0xc0, 0xde, - 0x6a, 0xed, 0x93, 0x0b, 0xbe, 0xef, 0xf9, 0x9c, 0xf7, 0xd4, 0x11, 0x79, 0x33, 0xbf, 0xc7, 0x6a, - 0x1a, 0x49, 0x9c, 0xce, 0x09, 0xbd, 0x02, 0x85, 0x96, 0xef, 0xed, 0xdb, 0x75, 0xe2, 0x8b, 0x58, - 0x99, 0x8d, 0x2c, 0x9e, 0x49, 0x6e, 0x09, 0x9a, 0x91, 0x26, 0x90, 0x25, 0x58, 0xf1, 0x33, 0xff, - 0xa0, 0x00, 0x73, 0x71, 0x74, 0xf4, 0x09, 0x80, 0x96, 0xef, 0x35, 0x49, 0xb8, 0x47, 0x54, 0x78, - 0xf0, 0xd5, 0x51, 0x9f, 0x28, 0x4a, 0x7a, 0xf2, 0x8e, 0x9c, 0x6a, 0xd2, 0xa8, 0x14, 0x6b, 0x1c, - 0x91, 0x0f, 0x93, 0x77, 0xf8, 0x9e, 0x26, 0xb6, 0xf8, 0x17, 0x33, 0x31, 0x48, 0x04, 0x67, 0x16, - 0xd7, 0x2a, 0x8a, 0xb0, 0x64, 0x84, 0x76, 0x20, 0x7f, 0x97, 0xec, 0x64, 0xf3, 0x98, 0xee, 0x16, - 0x11, 0x47, 0x85, 0xca, 0x64, 0xb7, 0x53, 0xca, 0xdf, 0x22, 0x3b, 0x98, 0x12, 0xa7, 0xfd, 0xaa, - 0xf3, 0xdb, 0x3e, 0xa1, 0x2a, 0x46, 0xec, 0x57, 0xec, 0xea, 0x90, 0xf7, 0x4b, 0x14, 0x61, 0xc9, - 0x08, 0xbd, 0x02, 0x53, 0x77, 0xad, 0x7d, 0xb2, 0xeb, 0x7b, 0x6e, 0x28, 0x02, 0x33, 0x46, 0x8c, - 0x40, 0xbd, 0x25, 0xc9, 0x09, 0xbe, 0x6c, 0xb7, 0x55, 0x85, 0x38, 0x62, 0x87, 0xf6, 0xa1, 0xe0, - 0x92, 0xbb, 0x98, 0x38, 0x76, 0x4d, 0x04, 0xff, 0x8d, 0x28, 0xd6, 0x57, 0x05, 0x35, 0xc1, 0x99, - 0x6d, 0x43, 0xb2, 0x0c, 0x2b, 0x5e, 0x74, 0x2e, 0x6f, 0x7b, 0x3b, 0x42, 0x51, 0x8d, 0x38, 0x97, - 0xea, 0xd8, 0xc7, 0xe7, 0xf2, 0x8a, 0xb7, 0x83, 0x29, 0x71, 0xba, 0x46, 0x6a, 0x2a, 0x2a, 0x40, - 0xa8, 0xa9, 0xab, 0xd9, 0x46, 0x43, 0xf0, 0x35, 0x12, 0x95, 0x62, 0x8d, 0x23, 0x1d, 0xdb, 0x86, - 0xf0, 0x32, 0x09, 0x45, 0x35, 0xe2, 0xd8, 0xc6, 0x7d, 0x56, 0x7c, 0x6c, 0x65, 0x19, 0x56, 0xbc, - 0xcc, 0x3f, 0x1d, 0x83, 0x19, 0x3d, 0x29, 0xc2, 0x00, 0x7b, 0xb5, 0x32, 0x17, 0x73, 0xc3, 0x98, - 0x8b, 0xd4, 0xda, 0x6f, 0x46, 0xb6, 0x8d, 0x3c, 0xf0, 0xaf, 0x67, 0x66, 0x2d, 0x45, 0xd6, 0xbe, - 0x56, 0x18, 0xe0, 0x18, 0xd3, 0x21, 0xae, 0x48, 0xa9, 0xfd, 0xc7, 0xcd, 0x00, 0xfe, 0x44, 0x4c, - 0xd9, 0x7f, 0xb1, 0x8d, 0xfd, 0x3c, 0x40, 0x94, 0x1e, 0x41, 0xf8, 0xc9, 0x95, 0x8f, 0x54, 0x4b, - 0xdb, 0xa0, 0x61, 0xa1, 0x27, 0x61, 0x82, 0x6e, 0x94, 0xa4, 0x2e, 0xde, 0x6e, 0xa9, 0x23, 0xd5, - 0x45, 0x56, 0x8a, 0x05, 0x14, 0x3d, 0x47, 0x6d, 0x9a, 0x68, 0x7b, 0x13, 0x4f, 0xb2, 0x96, 0x22, - 0x9b, 0x26, 0x82, 0xe1, 0x18, 0x26, 0x6d, 0x3a, 0xa1, 0xbb, 0x11, 0x93, 0x24, 0xad, 0xe9, 0x6c, - 0x8b, 0xc2, 0x1c, 0xc6, 0x8e, 0xf8, 0x89, 0xdd, 0x8b, 0x6d, 0x56, 0xe3, 0xda, 0x11, 0x3f, 0x01, - 0xc7, 0x3d, 0x35, 0xcc, 0x8f, 0xc0, 0x5c, 0x7c, 0x15, 0xd3, 0x21, 0x6e, 0xf9, 0xde, 0xae, 0xed, - 0x90, 0xa4, 0x73, 0x62, 0x8b, 0x17, 0x63, 0x09, 0x1f, 0xcc, 0x3b, 0xfa, 0x57, 0x79, 0x38, 0x71, - 0xb5, 0x61, 0xbb, 0xf7, 0x12, 0x6e, 0xc5, 0xb4, 0xac, 0x4b, 0xc6, 0xb0, 0x59, 0x97, 0xa2, 0xe0, - 0x73, 0x91, 0xd6, 0x2a, 0x3d, 0xf8, 0x5c, 0xe6, 0xbc, 0x8a, 0xe3, 0xa2, 0xef, 0x1b, 0xf0, 0x98, - 0x55, 0xe7, 0x76, 0x95, 0xe5, 0x88, 0xd2, 0x88, 0xa9, 0x94, 0xf1, 0x60, 0x44, 0x2d, 0xd9, 0xdb, - 0xf9, 0x95, 0xf2, 0x21, 0x5c, 0xf9, 0x69, 0xe1, 0x6d, 0xa2, 0x07, 0x8f, 0x1d, 0x86, 0x8a, 0x0f, - 0x6d, 0xfe, 0xf2, 0x35, 0x78, 0xeb, 0x03, 0x19, 0x0d, 0x75, 0x26, 0xf8, 0xb4, 0x01, 0x53, 0xdc, - 0x6b, 0x86, 0xc9, 0x2e, 0x5d, 0x3c, 0x56, 0xcb, 0xbe, 0x49, 0xfc, 0x40, 0xa6, 0x4e, 0xd0, 0x42, - 0xbd, 0xca, 0x5b, 0xeb, 0x02, 0x82, 0x35, 0x2c, 0xaa, 0x9e, 0xee, 0xd8, 0x6e, 0x5d, 0x4c, 0x93, - 0x52, 0x4f, 0x2f, 0xda, 0x6e, 0x1d, 0x33, 0x88, 0x52, 0x60, 0xf9, 0x7e, 0x0a, 0xcc, 0xfc, 0x5d, - 0x03, 0xe6, 0xd8, 0xdb, 0x92, 0xc8, 0x28, 0x7e, 0x56, 0xdd, 0x08, 0xf3, 0x66, 0x9c, 0x89, 0xdf, - 0x08, 0xdf, 0xef, 0x94, 0xa6, 0xf9, 0x6b, 0x94, 0xf8, 0x05, 0xf1, 0x07, 0xc5, 0xc1, 0x96, 0xdd, - 0x5b, 0xe7, 0x86, 0x3e, 0x77, 0x29, 0x37, 0x4e, 0x55, 0x12, 0xc1, 0x11, 0x3d, 0xf3, 0x8f, 0xf2, - 0x70, 0x22, 0x25, 0x48, 0x9a, 0x9e, 0x39, 0x27, 0x58, 0x9c, 0xa8, 0xbc, 0x75, 0x7d, 0x39, 0xf3, - 0x40, 0xec, 0x15, 0x16, 0x8e, 0x2a, 0x24, 0x49, 0xe9, 0x27, 0x5e, 0x88, 0x05, 0x73, 0xf4, 0x9b, - 0x06, 0x4c, 0x5b, 0x9a, 0xb0, 0xf3, 0x8b, 0xe8, 0x9d, 0xec, 0x1b, 0xd3, 0x23, 0xdb, 0x5a, 0x00, - 0x4d, 0x24, 0xca, 0x7a, 0x5b, 0x96, 0xdf, 0x03, 0xd3, 0x5a, 0x17, 0x86, 0x91, 0xd1, 0xe5, 0x17, - 0x60, 0x61, 0x24, 0x19, 0xff, 0x00, 0x0c, 0x9b, 0x8b, 0x83, 0xee, 0x08, 0x77, 0xf5, 0x27, 0x57, - 0x6a, 0xc4, 0xc5, 0x9b, 0x2b, 0x01, 0x35, 0x77, 0x60, 0x21, 0x69, 0x78, 0x67, 0x7e, 0x19, 0xf5, - 0x2e, 0x18, 0x32, 0x7b, 0x86, 0xf9, 0xd7, 0x39, 0x98, 0x14, 0x2f, 0x2d, 0x1e, 0x42, 0xec, 0xd9, - 0x9d, 0x98, 0x37, 0x7d, 0x3d, 0x93, 0x07, 0x22, 0x7d, 0x03, 0xcf, 0x82, 0x44, 0xe0, 0xd9, 0x8b, - 0xd9, 0xb0, 0x3b, 0x3c, 0xea, 0xec, 0x0b, 0x39, 0x98, 0x4f, 0xbc, 0x5c, 0x41, 0x9f, 0x31, 0x7a, - 0x83, 0x2d, 0x6e, 0x64, 0xfa, 0x38, 0x46, 0x45, 0x36, 0x1e, 0x1e, 0x77, 0x11, 0xc4, 0xf2, 0xf1, - 0x5c, 0xcf, 0x2c, 0x67, 0xdb, 0xa1, 0xa9, 0x79, 0xfe, 0xc5, 0x80, 0xd3, 0x7d, 0xdf, 0xf2, 0xb0, - 0x47, 0xca, 0x7e, 0x1c, 0x2a, 0x64, 0x2f, 0xe3, 0xb7, 0x79, 0xca, 0x8b, 0x9b, 0x7c, 0x57, 0x9a, - 0x64, 0x8f, 0x9e, 0x81, 0x19, 0xa6, 0xc7, 0xe9, 0xf2, 0x09, 0x49, 0x4b, 0x24, 0xdb, 0x62, 0x1e, - 0x93, 0xaa, 0x56, 0x8e, 0x63, 0x58, 0xe6, 0x57, 0x0d, 0x28, 0xf6, 0x7b, 0xb2, 0x3a, 0x80, 0x5d, - 0xfe, 0x0b, 0x89, 0x38, 0xb0, 0x52, 0x4f, 0x1c, 0x58, 0xc2, 0x32, 0x97, 0x21, 0x5f, 0x9a, 0x51, - 0x9c, 0x7f, 0x40, 0x98, 0xd3, 0xe7, 0x0d, 0x38, 0xd5, 0x47, 0x70, 0x7a, 0xe2, 0x01, 0x8d, 0x23, - 0xc7, 0x03, 0xe6, 0x06, 0x8d, 0x07, 0x34, 0xff, 0x36, 0x0f, 0x0b, 0xa2, 0x3d, 0xd1, 0x66, 0xfe, - 0x5c, 0x2c, 0x9a, 0xee, 0x6d, 0x89, 0x68, 0xba, 0xa5, 0x24, 0xfe, 0xff, 0x87, 0xd2, 0xfd, 0x74, - 0x85, 0xd2, 0xfd, 0x24, 0x07, 0x27, 0x53, 0x5f, 0xe6, 0xa2, 0xcf, 0xa6, 0x68, 0xc1, 0x5b, 0x19, - 0x3f, 0x01, 0x1e, 0x50, 0x0f, 0x8e, 0x1a, 0x7f, 0xf6, 0x25, 0x3d, 0xee, 0x8b, 0x1f, 0x13, 0x76, - 0x8f, 0xe1, 0x31, 0xf3, 0x90, 0x21, 0x60, 0xe6, 0xaf, 0xe5, 0xe1, 0xa9, 0x41, 0x09, 0xfd, 0x94, - 0x86, 0x08, 0x07, 0xb1, 0x10, 0xe1, 0x87, 0xb3, 0x43, 0x1d, 0x4f, 0xb4, 0xf0, 0xd7, 0xf2, 0x6a, - 0xdb, 0xeb, 0x95, 0xcf, 0x81, 0x2e, 0x55, 0x26, 0xa9, 0x15, 0x23, 0xf3, 0x6b, 0x45, 0xaa, 0x70, - 0xb2, 0xca, 0x8b, 0xef, 0x77, 0x4a, 0x8b, 0x22, 0xe7, 0x4e, 0x95, 0x84, 0xa2, 0x10, 0xcb, 0x4a, - 0xe8, 0x29, 0x28, 0xf8, 0x1c, 0x2a, 0x83, 0x22, 0xc5, 0x45, 0x11, 0x2f, 0xc3, 0x0a, 0x8a, 0x3e, - 0xa9, 0x99, 0x7d, 0x63, 0xc7, 0xf5, 0x38, 0xf4, 0xb0, 0xfb, 0xaf, 0x97, 0xa1, 0x10, 0xc8, 0x4c, - 0x59, 0xdc, 0x2b, 0xfa, 0xf4, 0x80, 0xb1, 0xb6, 0xf4, 0x94, 0x20, 0xd3, 0x66, 0xf1, 0xfe, 0xa9, - 0xa4, 0x5a, 0x8a, 0x24, 0x32, 0x95, 0x81, 0xce, 0x5d, 0x3c, 0x90, 0x62, 0x9c, 0xbf, 0x61, 0xc0, - 0xb4, 0x98, 0xad, 0x87, 0x10, 0xfe, 0x7b, 0x3b, 0x1e, 0xfe, 0x7b, 0x21, 0x13, 0xdd, 0xd1, 0x27, - 0xf6, 0xf7, 0x36, 0xcc, 0xe8, 0xc9, 0x19, 0xd0, 0x4b, 0x9a, 0xee, 0x33, 0x46, 0x79, 0x04, 0x2e, - 0xb5, 0x63, 0xa4, 0x17, 0xcd, 0xaf, 0x14, 0xd4, 0x28, 0xb2, 0x20, 0x63, 0x5d, 0x06, 0x8d, 0x43, - 0x65, 0x50, 0x17, 0x81, 0x5c, 0xf6, 0x22, 0x70, 0x1d, 0x0a, 0x52, 0x41, 0x89, 0x6d, 0xfc, 0x09, - 0x3d, 0x92, 0x87, 0xda, 0x02, 0x94, 0x98, 0x26, 0xb8, 0xec, 0x54, 0xa1, 0xe6, 0x50, 0x29, 0x4e, - 0x45, 0x06, 0xbd, 0x02, 0xd3, 0x77, 0x3d, 0xff, 0x8e, 0xe3, 0x59, 0x2c, 0x07, 0x1e, 0x64, 0xe1, - 0xdf, 0x56, 0xde, 0x15, 0x1e, 0x30, 0x7a, 0x2b, 0xa2, 0x8f, 0x75, 0x66, 0xa8, 0x0c, 0xf3, 0x4d, - 0xdb, 0xc5, 0xc4, 0xaa, 0xab, 0x28, 0xdf, 0x31, 0x9e, 0xa4, 0x4b, 0x1a, 0xb9, 0x9b, 0x71, 0x30, - 0x4e, 0xe2, 0xa3, 0x8f, 0x41, 0x21, 0x10, 0x09, 0x20, 0xb2, 0xb9, 0x89, 0x50, 0xc7, 0x23, 0x4e, - 0x34, 0x1a, 0x3b, 0x59, 0x82, 0x15, 0x43, 0xb4, 0x01, 0x4b, 0xbe, 0x78, 0x62, 0x1d, 0x4b, 0x6b, - 0xcb, 0xd7, 0x27, 0xcb, 0x05, 0x85, 0x53, 0xe0, 0x38, 0xb5, 0x16, 0xb5, 0x62, 0x58, 0x96, 0x11, - 0xee, 0x92, 0x2d, 0x68, 0xef, 0x32, 0x59, 0x29, 0x16, 0xd0, 0xc3, 0xa2, 0xc6, 0x0b, 0x23, 0x44, - 0x8d, 0x57, 0xe1, 0x64, 0x12, 0xc4, 0x1e, 0x82, 0xb3, 0xb7, 0xe7, 0xda, 0xee, 0xb1, 0x95, 0x86, - 0x84, 0xd3, 0xeb, 0xa2, 0x5b, 0x30, 0xe5, 0x13, 0x76, 0xbe, 0x28, 0xcb, 0xbb, 0xcf, 0xa1, 0x83, - 0x2e, 0xb0, 0x24, 0x80, 0x23, 0x5a, 0x74, 0xde, 0xad, 0x78, 0x9e, 0xaa, 0xeb, 0x19, 0x66, 0x60, - 0x17, 0x73, 0xdf, 0x27, 0x41, 0x83, 0xf9, 0xaf, 0x73, 0x30, 0x1b, 0x3b, 0x46, 0xa3, 0x27, 0x60, - 0x9c, 0xbd, 0x8c, 0x67, 0xea, 0xa1, 0x10, 0xa9, 0x30, 0x3e, 0x38, 0x1c, 0x86, 0xbe, 0x60, 0xc0, - 0x7c, 0x2b, 0xe6, 0xf2, 0x93, 0x9a, 0x73, 0xc4, 0x6b, 0x96, 0xb8, 0x1f, 0x51, 0xcb, 0xf0, 0x18, - 0x67, 0x86, 0x93, 0xdc, 0xe9, 0x02, 0x14, 0x71, 0x48, 0x0e, 0xf1, 0x19, 0xb6, 0xb0, 0x71, 0x14, - 0x89, 0xd5, 0x38, 0x18, 0x27, 0xf1, 0xe9, 0x0c, 0xb3, 0xde, 0x8d, 0x92, 0xaf, 0xba, 0x2c, 0x09, - 0xe0, 0x88, 0x16, 0x7a, 0x01, 0xe6, 0x44, 0x7a, 0xa2, 0x2d, 0xaf, 0x7e, 0xd9, 0x0a, 0xf6, 0x84, - 0x71, 0xaf, 0x0e, 0x23, 0xab, 0x31, 0x28, 0x4e, 0x60, 0xb3, 0xbe, 0x45, 0x39, 0xa0, 0x18, 0x81, - 0x89, 0x78, 0x02, 0xcc, 0xd5, 0x38, 0x18, 0x27, 0xf1, 0xd1, 0x3b, 0x34, 0xbd, 0xcf, 0xaf, 0x49, - 0x94, 0x36, 0x48, 0xd1, 0xfd, 0x65, 0x98, 0x6f, 0xb3, 0xb3, 0x50, 0x5d, 0x02, 0xc5, 0x7a, 0x54, - 0x0c, 0x6f, 0xc4, 0xc1, 0x38, 0x89, 0x8f, 0x9e, 0x87, 0x59, 0x9f, 0x6a, 0x37, 0x45, 0x80, 0xdf, - 0x9d, 0xa8, 0x8b, 0x00, 0xac, 0x03, 0x71, 0x1c, 0x17, 0x5d, 0x82, 0xc5, 0x28, 0x67, 0x8a, 0x24, - 0xc0, 0x2f, 0x53, 0x54, 0x12, 0x82, 0x72, 0x12, 0x01, 0xf7, 0xd6, 0x41, 0xbf, 0x08, 0x0b, 0xda, - 0x48, 0xac, 0xbb, 0x75, 0x72, 0x4f, 0xe4, 0xb5, 0x60, 0x1f, 0xa3, 0x58, 0x4d, 0xc0, 0x70, 0x0f, - 0x36, 0x7a, 0x2f, 0xcc, 0xd5, 0x3c, 0xc7, 0x61, 0x3a, 0x8e, 0x27, 0x5f, 0xe4, 0x09, 0x2c, 0x78, - 0xaa, 0x8f, 0x18, 0x04, 0x27, 0x30, 0xd1, 0x15, 0x40, 0xde, 0x4e, 0x40, 0xfc, 0x7d, 0x52, 0xbf, - 0xc4, 0x3f, 0xf6, 0x42, 0xb7, 0xf8, 0xd9, 0x78, 0x14, 0xe4, 0xb5, 0x1e, 0x0c, 0x9c, 0x52, 0x8b, - 0xe5, 0x30, 0xd0, 0x5e, 0x24, 0xcc, 0x65, 0x91, 0xbd, 0x3a, 0x79, 0x72, 0x7f, 0xe0, 0x73, 0x04, - 0x1f, 0x26, 0x78, 0x50, 0x6a, 0x71, 0x3e, 0x8b, 0x3c, 0x2e, 0x7a, 0x1e, 0xb6, 0x68, 0x8f, 0xe0, - 0xa5, 0x58, 0x70, 0x42, 0x9f, 0x80, 0xa9, 0x1d, 0x99, 0x94, 0xb3, 0xb8, 0x90, 0xc5, 0xbe, 0x98, - 0xc8, 0x2f, 0x1b, 0x9d, 0x4c, 0x15, 0x00, 0x47, 0x2c, 0xd1, 0x93, 0x30, 0x7d, 0x79, 0xab, 0xac, - 0xa4, 0x70, 0x91, 0xcd, 0xfe, 0x18, 0xad, 0x82, 0x75, 0x00, 0x5d, 0x61, 0xca, 0x5e, 0x42, 0x6c, - 0x8a, 0xa3, 0xfd, 0xb6, 0xd7, 0xfc, 0xa1, 0xd8, 0xec, 0xee, 0x0b, 0x57, 0x8b, 0x27, 0x12, 0xd8, - 0xa2, 0x1c, 0x2b, 0x0c, 0xf4, 0x32, 0x4c, 0x8b, 0xfd, 0x82, 0xe9, 0xa6, 0xa5, 0xa3, 0xbd, 0x76, - 0xc1, 0x11, 0x09, 0xac, 0xd3, 0x43, 0xcf, 0xc2, 0x74, 0x8b, 0xe5, 0x2a, 0x24, 0x17, 0xdb, 0x8e, - 0x53, 0x3c, 0xc9, 0xf4, 0xa6, 0xba, 0x14, 0xd8, 0x8a, 0x40, 0x58, 0xc7, 0x43, 0x4f, 0xcb, 0x8b, - 0xeb, 0xb7, 0xc4, 0xee, 0x78, 0xd4, 0xc5, 0xb5, 0xb2, 0x72, 0xfb, 0x84, 0x39, 0x9e, 0x7a, 0xc0, - 0x8d, 0xf1, 0x0e, 0x2c, 0x4b, 0x13, 0xab, 0x77, 0x91, 0x14, 0x8b, 0x31, 0x2f, 0xc1, 0xf2, 0xad, - 0xbe, 0x98, 0xf8, 0x10, 0x2a, 0x68, 0x17, 0xf2, 0x96, 0xb3, 0x53, 0x3c, 0x9d, 0x85, 0xad, 0xa8, - 0x3e, 0xde, 0xa4, 0xe5, 0x35, 0xde, 0xa8, 0x60, 0xca, 0xc0, 0xfc, 0x54, 0xe4, 0x84, 0x56, 0x59, - 0xbe, 0x3e, 0xae, 0x4b, 0xb6, 0x91, 0xc5, 0x07, 0x4a, 0x7a, 0xb2, 0xd7, 0xf2, 0x4d, 0x29, 0x55, - 0xae, 0x5b, 0x6a, 0x2d, 0x67, 0xf2, 0xec, 0x3c, 0x9e, 0xc1, 0x8c, 0x9f, 0xe8, 0xe2, 0x2b, 0xd9, - 0xfc, 0xc1, 0x98, 0x72, 0x44, 0x25, 0xee, 0x9e, 0x7d, 0x18, 0xb7, 0x83, 0xd0, 0xf6, 0x32, 0x7c, - 0xc8, 0x92, 0x48, 0xfd, 0xc5, 0x62, 0x08, 0x19, 0x00, 0x73, 0x56, 0x94, 0xa7, 0xdb, 0xb0, 0xdd, - 0x7b, 0xa2, 0xfb, 0xd7, 0x33, 0xbf, 0x54, 0xe6, 0x3c, 0x19, 0x00, 0x73, 0x56, 0xe8, 0x36, 0x97, - 0xb6, 0x6c, 0x3e, 0x46, 0x93, 0xfc, 0xc6, 0x14, 0x8f, 0xc0, 0x91, 0x12, 0x47, 0x79, 0x05, 0x4d, - 0x5b, 0xd8, 0x31, 0x23, 0xf2, 0xaa, 0x6e, 0xae, 0xa7, 0xf1, 0xaa, 0x6e, 0xae, 0x63, 0xca, 0x04, - 0x7d, 0xc6, 0x00, 0xb0, 0xd4, 0xc7, 0x96, 0xb2, 0x49, 0xf5, 0xdc, 0xef, 0xe3, 0x4d, 0x3c, 0xec, - 0x27, 0x82, 0x62, 0x8d, 0xb3, 0xf9, 0xba, 0x01, 0x8b, 0x3d, 0x8d, 0x4d, 0x7e, 0x1a, 0xcb, 0x18, - 0xf0, 0xd3, 0x58, 0x6b, 0xb0, 0x20, 0x92, 0xc3, 0x55, 0x5b, 0x8e, 0x9d, 0xfa, 0x18, 0x6c, 0x3b, - 0x01, 0xc7, 0x3d, 0x35, 0xcc, 0x3f, 0x37, 0x60, 0x5a, 0x8b, 0x5d, 0xa7, 0xf6, 0x35, 0x8b, 0xf1, - 0x17, 0xcd, 0x88, 0xf2, 0xe2, 0x31, 0xdf, 0x1b, 0x87, 0x71, 0x37, 0x70, 0x43, 0x4b, 0x7f, 0x14, - 0xb9, 0x81, 0x69, 0x29, 0x16, 0x50, 0x9e, 0xd8, 0x86, 0xf0, 0xcf, 0x9e, 0xe5, 0xf5, 0xc4, 0x36, - 0xa4, 0x85, 0x19, 0x84, 0xb1, 0xa3, 0x8a, 0x5e, 0xc4, 0xe7, 0x68, 0x69, 0xf8, 0x2c, 0x6a, 0xce, - 0x33, 0x18, 0x3a, 0x03, 0x79, 0xe2, 0xd6, 0x85, 0x55, 0xaa, 0x94, 0xd7, 0x05, 0xb7, 0x8e, 0x69, - 0xb9, 0x79, 0x0d, 0x66, 0xaa, 0xa4, 0xe6, 0x93, 0xf0, 0x45, 0x72, 0x30, 0x70, 0x96, 0xf7, 0x3b, - 0xe4, 0x20, 0x99, 0xe5, 0x9d, 0x56, 0xa7, 0xe5, 0xe6, 0xef, 0x1b, 0x90, 0xc8, 0x8a, 0xa8, 0xb9, - 0x84, 0x8c, 0x7e, 0x2e, 0xa1, 0x98, 0xf3, 0x22, 0x77, 0xa8, 0xf3, 0xe2, 0x0a, 0xa0, 0xa6, 0x15, - 0xd6, 0xf6, 0x62, 0x39, 0x3b, 0xc5, 0x81, 0x20, 0x7a, 0x29, 0xd3, 0x83, 0x81, 0x53, 0x6a, 0x99, - 0xaf, 0x1a, 0xd0, 0xf3, 0xd5, 0x32, 0xba, 0x8d, 0x11, 0x91, 0x40, 0x9b, 0x9f, 0x93, 0xd4, 0x36, - 0x26, 0xf3, 0x66, 0x4b, 0x38, 0x35, 0xa6, 0xa5, 0x3b, 0x46, 0x1e, 0x6e, 0xf9, 0x9b, 0x02, 0x65, - 0x4c, 0xaf, 0xc5, 0xc1, 0x38, 0x89, 0x6f, 0xde, 0x84, 0x82, 0x7c, 0x78, 0xc5, 0x5e, 0x2f, 0xc8, - 0xe3, 0x99, 0xfe, 0x7a, 0x81, 0x9e, 0xce, 0x18, 0x84, 0x0e, 0x53, 0xe0, 0xda, 0x97, 0xbd, 0x20, - 0x94, 0xaf, 0xc5, 0xb8, 0x13, 0xe6, 0xea, 0x3a, 0x2b, 0xc3, 0x0a, 0x6a, 0x2e, 0xc2, 0xbc, 0xf2, - 0xae, 0x70, 0xa1, 0x37, 0xbf, 0x95, 0x87, 0x99, 0xd8, 0x27, 0x4a, 0x1e, 0x3c, 0xd9, 0x83, 0x4f, - 0x4b, 0x8a, 0x97, 0x24, 0x3f, 0xa4, 0x97, 0x44, 0x77, 0x4b, 0x8d, 0x1d, 0xaf, 0x5b, 0x6a, 0x3c, - 0x1b, 0xb7, 0x54, 0x08, 0x93, 0xe2, 0x3b, 0x7d, 0x22, 0xca, 0x73, 0x33, 0xa3, 0x57, 0xd3, 0xe2, - 0xf9, 0x21, 0x0b, 0x6c, 0x95, 0x0a, 0x4c, 0xb2, 0x32, 0xbf, 0x31, 0x0e, 0x73, 0xf1, 0x77, 0xd4, - 0x03, 0xcc, 0xe4, 0x3b, 0x7a, 0x66, 0x72, 0xc8, 0x53, 0x62, 0x7e, 0xd4, 0x53, 0xe2, 0xd8, 0xa8, - 0xa7, 0xc4, 0xf1, 0x23, 0x9c, 0x12, 0x7b, 0xcf, 0x78, 0x13, 0x03, 0x9f, 0xf1, 0xde, 0xa7, 0xae, - 0x38, 0x27, 0x63, 0x77, 0x02, 0xd1, 0x15, 0x27, 0x8a, 0x4f, 0xc3, 0xaa, 0x57, 0x4f, 0xbd, 0x2a, - 0x2e, 0x3c, 0xc0, 0x1a, 0xf6, 0x53, 0x6f, 0x24, 0x87, 0x77, 0x44, 0xbd, 0x65, 0x88, 0xdb, 0xc8, - 0xe8, 0x53, 0x94, 0x6c, 0xf3, 0x83, 0xf8, 0xc6, 0x59, 0x8d, 0x40, 0x58, 0xc7, 0x63, 0x1f, 0xec, - 0x88, 0x7f, 0xa1, 0x84, 0x1d, 0xba, 0xf5, 0x0f, 0x76, 0x24, 0xbe, 0x68, 0x92, 0xc4, 0x37, 0xbf, - 0x9e, 0x87, 0xb9, 0x78, 0xc2, 0x65, 0x74, 0x57, 0x19, 0xac, 0x99, 0xd8, 0xca, 0x9c, 0xac, 0xf6, - 0x92, 0xb8, 0xef, 0x09, 0x94, 0x7f, 0x20, 0x71, 0x47, 0x3d, 0x6b, 0x3e, 0x3e, 0xc6, 0xe2, 0xe8, - 0x27, 0xd8, 0xb1, 0x1c, 0xcd, 0x51, 0x40, 0xa1, 0xb8, 0xd6, 0xcc, 0x9c, 0x7b, 0x14, 0x22, 0xa8, - 0x58, 0x61, 0x8d, 0x2d, 0x55, 0xef, 0xfb, 0xc4, 0xb7, 0x77, 0x6d, 0xf5, 0xb1, 0x08, 0xa6, 0x3c, - 0x6f, 0x8a, 0x32, 0xac, 0xa0, 0xe6, 0xab, 0x39, 0x88, 0x3e, 0x8d, 0xc3, 0x72, 0xbf, 0x06, 0x9a, - 0xd9, 0x20, 0xa6, 0xed, 0xca, 0xa8, 0x09, 0x96, 0x23, 0x8a, 0x22, 0x02, 0x44, 0x2b, 0xc1, 0x31, - 0x8e, 0xff, 0x03, 0x9f, 0xc4, 0xb1, 0x60, 0x3e, 0xf1, 0x00, 0x20, 0xf3, 0x88, 0xb2, 0xaf, 0xe4, - 0x61, 0x4a, 0x3d, 0xa1, 0x40, 0xef, 0x61, 0x69, 0x1b, 0xf7, 0x3c, 0x99, 0x4c, 0xf3, 0xad, 0x5a, - 0x72, 0xc5, 0x3d, 0xaf, 0x7e, 0xbf, 0x53, 0x9a, 0x57, 0xc8, 0xbc, 0x08, 0x8b, 0x0a, 0xd4, 0x48, - 0x6b, 0xfb, 0x4e, 0xd2, 0x48, 0xbb, 0x81, 0x37, 0x30, 0x2d, 0x47, 0xf7, 0x60, 0x72, 0x8f, 0x58, - 0x75, 0xe2, 0xcb, 0x0b, 0xf5, 0xcd, 0x8c, 0x9e, 0x7d, 0x5c, 0x66, 0x54, 0xa3, 0x61, 0xe0, 0xff, - 0x03, 0x2c, 0xd9, 0xd1, 0x8d, 0x6a, 0xc7, 0xab, 0x1f, 0x24, 0x93, 0x31, 0x56, 0xbc, 0xfa, 0x01, - 0x66, 0x10, 0xf4, 0x02, 0xcc, 0x85, 0x76, 0x93, 0xd0, 0xd3, 0xb4, 0xf6, 0xe1, 0x91, 0x7c, 0xe4, - 0x51, 0xdd, 0x8e, 0x41, 0x71, 0x02, 0x9b, 0x6e, 0x74, 0xb7, 0x03, 0xcf, 0x65, 0x49, 0x2b, 0x26, - 0xe2, 0xee, 0x97, 0x2b, 0xd5, 0x6b, 0x57, 0x59, 0xce, 0x0a, 0x85, 0x41, 0xb1, 0x6d, 0x16, 0xa7, - 0xed, 0x13, 0x71, 0xa1, 0xb1, 0x10, 0xbd, 0xa6, 0xe3, 0xe5, 0x58, 0x61, 0x98, 0x37, 0x60, 0x3e, - 0xd1, 0x55, 0x69, 0x0e, 0x1b, 0xe9, 0xe6, 0xf0, 0x60, 0x99, 0x0f, 0xff, 0xd8, 0x80, 0xc5, 0x9e, - 0xc5, 0x3b, 0x68, 0xa8, 0x63, 0x52, 0x93, 0xe7, 0x8e, 0xae, 0xc9, 0xf3, 0xc3, 0x69, 0xf2, 0xca, - 0xca, 0xb7, 0xdf, 0x3c, 0xfb, 0xc8, 0x77, 0xde, 0x3c, 0xfb, 0xc8, 0x77, 0xdf, 0x3c, 0xfb, 0xc8, - 0xab, 0xdd, 0xb3, 0xc6, 0xb7, 0xbb, 0x67, 0x8d, 0xef, 0x74, 0xcf, 0x1a, 0xdf, 0xed, 0x9e, 0x35, - 0x7e, 0xd0, 0x3d, 0x6b, 0xbc, 0xfe, 0xc3, 0xb3, 0x8f, 0xbc, 0x54, 0x90, 0x62, 0xf2, 0xdf, 0x01, - 0x00, 0x00, 0xff, 0xff, 0x1f, 0xc4, 0x47, 0xcd, 0xdf, 0x7c, 0x00, 0x00, + // 6862 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x5d, 0x8c, 0x24, 0x57, + 0x75, 0xb0, 0xab, 0x7f, 0x66, 0x7a, 0xce, 0xfc, 0xdf, 0x9d, 0x65, 0xc7, 0x6b, 0xef, 0xb6, 0x29, + 0x23, 0x7f, 0xe6, 0xfb, 0x60, 0x16, 0xd6, 0xf6, 0x17, 0x83, 0x91, 0x95, 0xee, 0x99, 0x5d, 0xef, + 0xac, 0x67, 0x76, 0x67, 0x6f, 0xcf, 0x7a, 0xc1, 0x60, 0x42, 0x4d, 0xf7, 0x9d, 0x9e, 0xda, 0xad, + 0xae, 0x6a, 0xaa, 0xaa, 0x67, 0x77, 0x0c, 0x02, 0x3b, 0xc8, 0x0e, 0x89, 0x40, 0x38, 0x01, 0x1e, + 0xa2, 0x88, 0x08, 0x45, 0x3c, 0x44, 0x21, 0x0f, 0x11, 0x4a, 0x94, 0x17, 0xa4, 0x44, 0x09, 0x48, + 0xe4, 0x21, 0x11, 0x91, 0x92, 0x00, 0x11, 0x74, 0xa0, 0x09, 0x0f, 0x89, 0x22, 0x45, 0x91, 0x88, + 0x22, 0x56, 0x8a, 0x14, 0xdd, 0xdf, 0xba, 0x55, 0x5d, 0x3d, 0xdb, 0x3d, 0x5d, 0xb3, 0x58, 0x49, + 0xde, 0xba, 0xef, 0x39, 0xf7, 0x9c, 0xfb, 0x73, 0xee, 0xb9, 0xe7, 0xdc, 0x73, 0xee, 0x2d, 0xd8, + 0x68, 0xda, 0xe1, 0x5e, 0x67, 0x67, 0xa5, 0xee, 0xb5, 0xce, 0x59, 0x7e, 0xd3, 0x6b, 0xfb, 0xde, + 0x4d, 0xf6, 0xe3, 0x9d, 0xbe, 0xe7, 0x38, 0x5e, 0x27, 0x0c, 0xce, 0xb5, 0x6f, 0x35, 0xcf, 0x59, + 0x6d, 0x3b, 0x38, 0xa7, 0x4a, 0xf6, 0xdf, 0x6d, 0x39, 0xed, 0x3d, 0xeb, 0xdd, 0xe7, 0x9a, 0xc4, + 0x25, 0xbe, 0x15, 0x92, 0xc6, 0x4a, 0xdb, 0xf7, 0x42, 0x0f, 0xbd, 0x2f, 0xa2, 0xb6, 0x22, 0xa9, + 0xb1, 0x1f, 0xbf, 0x24, 0xeb, 0xae, 0xb4, 0x6f, 0x35, 0x57, 0x28, 0xb5, 0x15, 0x55, 0x22, 0xa9, + 0x9d, 0x7e, 0xa7, 0xd6, 0x96, 0xa6, 0xd7, 0xf4, 0xce, 0x31, 0xa2, 0x3b, 0x9d, 0x5d, 0xf6, 0x8f, + 0xfd, 0x61, 0xbf, 0x38, 0xb3, 0xd3, 0x8f, 0xde, 0x7a, 0x3a, 0x58, 0xb1, 0x3d, 0xda, 0xb6, 0x73, + 0x3b, 0x56, 0x58, 0xdf, 0x3b, 0xb7, 0xdf, 0xd7, 0xa2, 0xd3, 0xa6, 0x86, 0x54, 0xf7, 0x7c, 0x92, + 0x86, 0xf3, 0x64, 0x84, 0xd3, 0xb2, 0xea, 0x7b, 0xb6, 0x4b, 0xfc, 0x83, 0xa8, 0xd7, 0x2d, 0x12, + 0x5a, 0x69, 0xb5, 0xce, 0x0d, 0xaa, 0xe5, 0x77, 0xdc, 0xd0, 0x6e, 0x91, 0xbe, 0x0a, 0xff, 0xff, + 0x5e, 0x15, 0x82, 0xfa, 0x1e, 0x69, 0x59, 0x7d, 0xf5, 0x9e, 0x18, 0x54, 0xaf, 0x13, 0xda, 0xce, + 0x39, 0xdb, 0x0d, 0x83, 0xd0, 0x4f, 0x56, 0x32, 0xbf, 0x91, 0x87, 0xa9, 0xca, 0x46, 0xb5, 0x16, + 0x5a, 0x61, 0x27, 0x40, 0xaf, 0x1b, 0x30, 0xe3, 0x78, 0x56, 0xa3, 0x6a, 0x39, 0x96, 0x5b, 0x27, + 0xfe, 0xb2, 0xf1, 0x88, 0xf1, 0xf8, 0xf4, 0xf9, 0x8d, 0x95, 0x71, 0xe6, 0x6b, 0xa5, 0x72, 0x3b, + 0xc0, 0x24, 0xf0, 0x3a, 0x7e, 0x9d, 0x60, 0xb2, 0x5b, 0x5d, 0xfa, 0x56, 0xb7, 0xfc, 0x40, 0xaf, + 0x5b, 0x9e, 0xd9, 0xd0, 0x38, 0xe1, 0x18, 0x5f, 0xf4, 0x45, 0x03, 0x16, 0xeb, 0x96, 0x6b, 0xf9, + 0x07, 0xdb, 0x96, 0xdf, 0x24, 0xe1, 0x73, 0xbe, 0xd7, 0x69, 0x2f, 0xe7, 0x8e, 0xa1, 0x35, 0x0f, + 0x8a, 0xd6, 0x2c, 0xae, 0x26, 0xd9, 0xe1, 0xfe, 0x16, 0xb0, 0x76, 0x05, 0xa1, 0xb5, 0xe3, 0x10, + 0xbd, 0x5d, 0xf9, 0xe3, 0x6c, 0x57, 0x2d, 0xc9, 0x0e, 0xf7, 0xb7, 0xc0, 0x7c, 0x2d, 0x0f, 0x8b, + 0x95, 0x8d, 0xea, 0xb6, 0x6f, 0xed, 0xee, 0xda, 0x75, 0xec, 0x75, 0x42, 0xdb, 0x6d, 0xa2, 0xb7, + 0xc3, 0xa4, 0xed, 0x36, 0x7d, 0x12, 0x04, 0x6c, 0x22, 0xa7, 0xaa, 0xf3, 0x82, 0xe8, 0xe4, 0x3a, + 0x2f, 0xc6, 0x12, 0x8e, 0x9e, 0x82, 0xe9, 0x80, 0xf8, 0xfb, 0x76, 0x9d, 0x6c, 0x79, 0x7e, 0xc8, + 0x46, 0xba, 0x58, 0x3d, 0x21, 0xd0, 0xa7, 0x6b, 0x11, 0x08, 0xeb, 0x78, 0xb4, 0x9a, 0xef, 0x79, + 0xa1, 0x80, 0xb3, 0x81, 0x98, 0x8a, 0xaa, 0xe1, 0x08, 0x84, 0x75, 0x3c, 0xf4, 0x86, 0x01, 0x0b, + 0x41, 0x68, 0xd7, 0x6f, 0xd9, 0x2e, 0x09, 0x82, 0x55, 0xcf, 0xdd, 0xb5, 0x9b, 0xcb, 0x45, 0x36, + 0x8a, 0x57, 0xc6, 0x1b, 0xc5, 0x5a, 0x82, 0x6a, 0x75, 0xa9, 0xd7, 0x2d, 0x2f, 0x24, 0x4b, 0x71, + 0x1f, 0x77, 0xb4, 0x06, 0x0b, 0x96, 0xeb, 0x7a, 0xa1, 0x15, 0xda, 0x9e, 0xbb, 0xe5, 0x93, 0x5d, + 0xfb, 0xce, 0x72, 0x81, 0x75, 0x67, 0x59, 0x74, 0x67, 0xa1, 0x92, 0x80, 0xe3, 0xbe, 0x1a, 0xe6, + 0x1a, 0x2c, 0x57, 0x5a, 0x3b, 0x56, 0x10, 0x58, 0x0d, 0xcf, 0x4f, 0xcc, 0xc6, 0xe3, 0x50, 0x6a, + 0x59, 0xed, 0xb6, 0xed, 0x36, 0xe9, 0x74, 0xe4, 0x1f, 0x9f, 0xaa, 0xce, 0xf4, 0xba, 0xe5, 0xd2, + 0xa6, 0x28, 0xc3, 0x0a, 0x6a, 0x7e, 0x2f, 0x07, 0xd3, 0x15, 0xd7, 0x72, 0x0e, 0x02, 0x3b, 0xc0, + 0x1d, 0x17, 0x7d, 0x04, 0x4a, 0x54, 0xbb, 0x34, 0xac, 0xd0, 0x12, 0x2b, 0xf2, 0x5d, 0x2b, 0x7c, + 0xb1, 0xaf, 0xe8, 0x8b, 0x3d, 0x1a, 0x17, 0x8a, 0xbd, 0xb2, 0xff, 0xee, 0x95, 0xab, 0x3b, 0x37, + 0x49, 0x3d, 0xdc, 0x24, 0xa1, 0x55, 0x45, 0xa2, 0x17, 0x10, 0x95, 0x61, 0x45, 0x15, 0x79, 0x50, + 0x08, 0xda, 0xa4, 0x2e, 0x56, 0xd8, 0xe6, 0x98, 0x92, 0x1c, 0x35, 0xbd, 0xd6, 0x26, 0xf5, 0xea, + 0x8c, 0x60, 0x5d, 0xa0, 0xff, 0x30, 0x63, 0x84, 0x6e, 0xc3, 0x44, 0xc0, 0x74, 0x8e, 0x58, 0x3c, + 0x57, 0xb3, 0x63, 0xc9, 0xc8, 0x56, 0xe7, 0x04, 0xd3, 0x09, 0xfe, 0x1f, 0x0b, 0x76, 0xe6, 0xdf, + 0x1b, 0x70, 0x42, 0xc3, 0xae, 0xf8, 0xcd, 0x4e, 0x8b, 0xb8, 0x21, 0x7a, 0x04, 0x0a, 0xae, 0xd5, + 0x22, 0x62, 0xa1, 0xa8, 0x26, 0x5f, 0xb1, 0x5a, 0x04, 0x33, 0x08, 0x7a, 0x14, 0x8a, 0xfb, 0x96, + 0xd3, 0x21, 0x6c, 0x90, 0xa6, 0xaa, 0xb3, 0x02, 0xa5, 0xf8, 0x02, 0x2d, 0xc4, 0x1c, 0x86, 0x3e, + 0x0e, 0x53, 0xec, 0xc7, 0x45, 0xdf, 0x6b, 0x65, 0xd4, 0x35, 0xd1, 0xc2, 0x17, 0x24, 0xd9, 0xea, + 0x6c, 0xaf, 0x5b, 0x9e, 0x52, 0x7f, 0x71, 0xc4, 0xd0, 0xfc, 0x07, 0x03, 0xe6, 0xb5, 0xce, 0x6d, + 0xd8, 0x41, 0x88, 0x3e, 0xd4, 0x27, 0x3c, 0x2b, 0xc3, 0x09, 0x0f, 0xad, 0xcd, 0x44, 0x67, 0x41, + 0xf4, 0xb4, 0x24, 0x4b, 0x34, 0xc1, 0x71, 0xa1, 0x68, 0x87, 0xa4, 0x15, 0x2c, 0xe7, 0x1e, 0xc9, + 0x3f, 0x3e, 0x7d, 0x7e, 0x3d, 0xb3, 0x69, 0x8c, 0xc6, 0x77, 0x9d, 0xd2, 0xc7, 0x9c, 0x8d, 0xf9, + 0xb5, 0x42, 0xac, 0x87, 0x54, 0xa2, 0x90, 0x07, 0x93, 0x2d, 0x12, 0xfa, 0x76, 0x9d, 0xaf, 0xab, + 0xe9, 0xf3, 0x6b, 0xe3, 0xb5, 0x62, 0x93, 0x11, 0x8b, 0x94, 0x25, 0xff, 0x1f, 0x60, 0xc9, 0x05, + 0xed, 0x41, 0xc1, 0xf2, 0x9b, 0xb2, 0xcf, 0x17, 0xb3, 0x99, 0xdf, 0x48, 0xe6, 0x2a, 0x7e, 0x33, + 0xc0, 0x8c, 0x03, 0x3a, 0x07, 0x53, 0x21, 0xf1, 0x5b, 0xb6, 0x6b, 0x85, 0x5c, 0xbb, 0x96, 0xaa, + 0x8b, 0x02, 0x6d, 0x6a, 0x5b, 0x02, 0x70, 0x84, 0x83, 0x1c, 0x98, 0x68, 0xf8, 0x07, 0xb8, 0xe3, + 0x2e, 0x17, 0xb2, 0x18, 0x8a, 0x35, 0x46, 0x2b, 0x5a, 0x4c, 0xfc, 0x3f, 0x16, 0x3c, 0xd0, 0x57, + 0x0c, 0x58, 0x6a, 0x11, 0x2b, 0xe8, 0xf8, 0x84, 0x76, 0x01, 0x93, 0x90, 0xb8, 0x54, 0x1b, 0x2e, + 0x17, 0x19, 0x73, 0x3c, 0xee, 0x3c, 0xf4, 0x53, 0xae, 0x3e, 0x2c, 0x9a, 0xb2, 0x94, 0x06, 0xc5, + 0xa9, 0xad, 0x31, 0xbf, 0x57, 0x80, 0xc5, 0x3e, 0x0d, 0x81, 0x9e, 0x84, 0x62, 0x7b, 0xcf, 0x0a, + 0xe4, 0x92, 0x3f, 0x2b, 0xe5, 0x6d, 0x8b, 0x16, 0xde, 0xed, 0x96, 0x67, 0x65, 0x15, 0x56, 0x80, + 0x39, 0x32, 0xdd, 0x53, 0x5b, 0x24, 0x08, 0xac, 0xa6, 0xd4, 0x03, 0x9a, 0x98, 0xb0, 0x62, 0x2c, + 0xe1, 0xe8, 0x57, 0x0c, 0x98, 0xe5, 0x22, 0x83, 0x49, 0xd0, 0x71, 0x42, 0xaa, 0xeb, 0xe8, 0xb0, + 0x5c, 0xce, 0x42, 0x3c, 0x39, 0xc9, 0xea, 0x49, 0xc1, 0x7d, 0x56, 0x2f, 0x0d, 0x70, 0x9c, 0x2f, + 0xba, 0x01, 0x53, 0x41, 0x68, 0xf9, 0x21, 0x69, 0x54, 0x42, 0xb6, 0xab, 0x4d, 0x9f, 0xff, 0xbf, + 0xc3, 0x29, 0x81, 0x6d, 0xbb, 0x45, 0xb8, 0xc2, 0xa9, 0x49, 0x02, 0x38, 0xa2, 0x85, 0x3e, 0x0e, + 0xe0, 0x77, 0xdc, 0x5a, 0xa7, 0xd5, 0xb2, 0xfc, 0x03, 0xb1, 0x83, 0x5f, 0x1a, 0xaf, 0x7b, 0x58, + 0xd1, 0x8b, 0xf6, 0xac, 0xa8, 0x0c, 0x6b, 0xfc, 0xd0, 0xab, 0x06, 0xcc, 0x72, 0x49, 0x94, 0x2d, + 0x98, 0xc8, 0xb8, 0x05, 0x8b, 0x74, 0x68, 0xd7, 0x74, 0x16, 0x38, 0xce, 0xd1, 0xfc, 0xdb, 0xf8, + 0x7e, 0x52, 0x0b, 0xa9, 0x75, 0xdd, 0x3c, 0x40, 0x1f, 0x84, 0x07, 0x83, 0x4e, 0xbd, 0x4e, 0x82, + 0x60, 0xb7, 0xe3, 0xe0, 0x8e, 0x7b, 0xc9, 0x0e, 0x42, 0xcf, 0x3f, 0xd8, 0xb0, 0x5b, 0x76, 0xc8, + 0x24, 0xae, 0x58, 0x3d, 0xd3, 0xeb, 0x96, 0x1f, 0xac, 0x0d, 0x42, 0xc2, 0x83, 0xeb, 0x23, 0x0b, + 0x1e, 0xea, 0xb8, 0x83, 0xc9, 0x73, 0xeb, 0xad, 0xdc, 0xeb, 0x96, 0x1f, 0xba, 0x3e, 0x18, 0x0d, + 0x1f, 0x46, 0xc3, 0xfc, 0x67, 0x03, 0x16, 0x64, 0xbf, 0xb6, 0x49, 0xab, 0xed, 0x50, 0xed, 0x72, + 0xfc, 0x86, 0x48, 0x18, 0x33, 0x44, 0x70, 0x36, 0xdb, 0x89, 0x6c, 0xff, 0x20, 0x6b, 0xc4, 0xfc, + 0x27, 0x03, 0x96, 0x92, 0xc8, 0xf7, 0x61, 0xf3, 0x0c, 0xe2, 0x9b, 0xe7, 0x95, 0x6c, 0x7b, 0x3b, + 0x60, 0x07, 0x7d, 0xbd, 0xd0, 0xdf, 0xd7, 0xff, 0xee, 0xdb, 0x68, 0xb4, 0x2b, 0xe6, 0x7f, 0x9e, + 0xbb, 0x62, 0xe1, 0x4d, 0xb5, 0x2b, 0xfe, 0x6e, 0x01, 0x66, 0x2a, 0x6e, 0x68, 0x57, 0x76, 0x77, + 0x6d, 0xd7, 0x0e, 0x0f, 0xd0, 0x67, 0x72, 0x70, 0xae, 0xed, 0x93, 0x5d, 0xe2, 0xfb, 0xa4, 0xb1, + 0xd6, 0xf1, 0x6d, 0xb7, 0x59, 0xab, 0xef, 0x91, 0x46, 0xc7, 0xb1, 0xdd, 0xe6, 0x7a, 0xd3, 0xf5, + 0x54, 0xf1, 0x85, 0x3b, 0xa4, 0xde, 0x61, 0x5d, 0xe2, 0x8b, 0xa2, 0x35, 0x5e, 0x97, 0xb6, 0x46, + 0x63, 0x5a, 0x7d, 0xa2, 0xd7, 0x2d, 0x9f, 0x1b, 0xb1, 0x12, 0x1e, 0xb5, 0x6b, 0xe8, 0xd3, 0x39, + 0x58, 0xf1, 0xc9, 0x47, 0x3b, 0xf6, 0xf0, 0xa3, 0xc1, 0xb5, 0x96, 0x33, 0xe6, 0xf6, 0x33, 0x12, + 0xcf, 0xea, 0xf9, 0x5e, 0xb7, 0x3c, 0x62, 0x1d, 0x3c, 0x62, 0xbf, 0xcc, 0x3f, 0x37, 0xa0, 0x34, + 0x82, 0xa7, 0x54, 0x8e, 0x7b, 0x4a, 0x53, 0x7d, 0x5e, 0x52, 0xd8, 0xef, 0x25, 0x3d, 0x37, 0xde, + 0xa0, 0x0d, 0xe3, 0x1d, 0xfd, 0xab, 0x01, 0x8b, 0x7d, 0xde, 0x14, 0xda, 0x83, 0xa5, 0xb6, 0xd7, + 0x90, 0x9a, 0xf0, 0x92, 0x15, 0xec, 0x31, 0x98, 0xe8, 0xde, 0x93, 0x74, 0x51, 0x6d, 0xa5, 0xc0, + 0xef, 0x76, 0xcb, 0xcb, 0x8a, 0x48, 0x02, 0x01, 0xa7, 0x52, 0x44, 0x6d, 0x28, 0xed, 0xda, 0xc4, + 0x69, 0x60, 0xb2, 0x2b, 0x24, 0x65, 0x4c, 0x9d, 0x77, 0x51, 0x50, 0xe3, 0x07, 0x09, 0xf2, 0x1f, + 0x56, 0x5c, 0xcc, 0x6b, 0x30, 0x17, 0x3f, 0x56, 0x1a, 0x62, 0xf2, 0xce, 0x40, 0xde, 0xf2, 0x5d, + 0x31, 0x75, 0xd3, 0x02, 0x21, 0x5f, 0xc1, 0x57, 0x30, 0x2d, 0x37, 0x7f, 0x56, 0x80, 0xf9, 0xaa, + 0xd3, 0x21, 0xcf, 0xf9, 0x84, 0x48, 0x4b, 0xba, 0x02, 0xf3, 0x6d, 0x9f, 0xec, 0xdb, 0xe4, 0x76, + 0x8d, 0x38, 0xa4, 0x1e, 0x7a, 0xbe, 0xa0, 0x7f, 0x4a, 0x54, 0x9f, 0xdf, 0x8a, 0x83, 0x71, 0x12, + 0x1f, 0x3d, 0x0b, 0x73, 0x56, 0x3d, 0xb4, 0xf7, 0x89, 0xa2, 0xc0, 0x1b, 0xf0, 0x16, 0x41, 0x61, + 0xae, 0x12, 0x83, 0xe2, 0x04, 0x36, 0xfa, 0x10, 0x2c, 0x07, 0x75, 0xcb, 0x21, 0xd7, 0xdb, 0x82, + 0xd5, 0xea, 0x1e, 0xa9, 0xdf, 0xda, 0xf2, 0x6c, 0x37, 0x14, 0x7e, 0xd3, 0x23, 0x82, 0xd2, 0x72, + 0x6d, 0x00, 0x1e, 0x1e, 0x48, 0x01, 0xfd, 0x89, 0x01, 0x67, 0xda, 0x3e, 0xd9, 0xf2, 0xbd, 0x96, + 0x47, 0x17, 0x44, 0x9f, 0x33, 0x21, 0x8c, 0xea, 0x17, 0xc6, 0x5c, 0xf9, 0xbc, 0xa4, 0xff, 0x30, + 0xe3, 0xad, 0xbd, 0x6e, 0xf9, 0xcc, 0xd6, 0x61, 0x0d, 0xc0, 0x87, 0xb7, 0x0f, 0xfd, 0x99, 0x01, + 0x67, 0xdb, 0x5e, 0x10, 0x1e, 0xd2, 0x85, 0xe2, 0xb1, 0x76, 0xc1, 0xec, 0x75, 0xcb, 0x67, 0xb7, + 0x0e, 0x6d, 0x01, 0xbe, 0x47, 0x0b, 0xcd, 0xde, 0x34, 0x2c, 0x6a, 0xb2, 0x27, 0x2c, 0xed, 0x67, + 0x60, 0x56, 0x0a, 0x03, 0x3f, 0x85, 0xe4, 0xb2, 0xa7, 0x3c, 0xa3, 0x8a, 0x0e, 0xc4, 0x71, 0x5c, + 0x2a, 0x77, 0x4a, 0x14, 0x79, 0xed, 0x84, 0xdc, 0x6d, 0xc5, 0xa0, 0x38, 0x81, 0x8d, 0xd6, 0xe1, + 0x84, 0x28, 0xc1, 0xa4, 0xed, 0xd8, 0x75, 0x6b, 0xd5, 0xeb, 0x08, 0x91, 0x2b, 0x56, 0x4f, 0xf5, + 0xba, 0xe5, 0x13, 0x5b, 0xfd, 0x60, 0x9c, 0x56, 0x07, 0x6d, 0xc0, 0x92, 0xd5, 0x09, 0x3d, 0xd5, + 0xff, 0x0b, 0xae, 0xb5, 0xe3, 0x90, 0x06, 0x13, 0xad, 0x52, 0x75, 0x99, 0x2a, 0xa2, 0x4a, 0x0a, + 0x1c, 0xa7, 0xd6, 0x42, 0x5b, 0x09, 0x6a, 0x35, 0x52, 0xf7, 0xdc, 0x06, 0x9f, 0xe5, 0x62, 0x64, + 0x2f, 0x54, 0x52, 0x70, 0x70, 0x6a, 0x4d, 0xe4, 0xc0, 0x5c, 0xcb, 0xba, 0x73, 0xdd, 0xb5, 0xf6, + 0x2d, 0xdb, 0xa1, 0x4c, 0x84, 0xb7, 0x35, 0xd8, 0x05, 0xe8, 0x84, 0xb6, 0xb3, 0xc2, 0x03, 0x0f, + 0x2b, 0xeb, 0x6e, 0x78, 0xd5, 0xaf, 0x85, 0x74, 0x5f, 0xa9, 0x22, 0x3a, 0xb0, 0x9b, 0x31, 0x5a, + 0x38, 0x41, 0x1b, 0x5d, 0x85, 0x93, 0x6c, 0x39, 0xae, 0x79, 0xb7, 0xdd, 0x35, 0xe2, 0x58, 0x07, + 0xb2, 0x03, 0x93, 0xac, 0x03, 0x0f, 0xf6, 0xba, 0xe5, 0x93, 0xb5, 0x34, 0x04, 0x9c, 0x5e, 0x8f, + 0xfa, 0x4c, 0x71, 0x00, 0x26, 0xfb, 0x76, 0x60, 0x7b, 0x2e, 0xf7, 0x99, 0x4a, 0x91, 0xcf, 0x54, + 0x1b, 0x8c, 0x86, 0x0f, 0xa3, 0x81, 0x7e, 0xcb, 0x80, 0xa5, 0xb4, 0x65, 0xb8, 0x3c, 0x95, 0xc5, + 0xb1, 0x6a, 0x62, 0x69, 0x71, 0x89, 0x48, 0x55, 0x0a, 0xa9, 0x8d, 0x40, 0xaf, 0x18, 0x30, 0x63, + 0x69, 0xf6, 0xde, 0x32, 0xb0, 0x56, 0x5d, 0x1e, 0xd7, 0xeb, 0x88, 0x28, 0x56, 0x17, 0x7a, 0xdd, + 0x72, 0xcc, 0xa6, 0xc4, 0x31, 0x8e, 0xe8, 0xb7, 0x0d, 0x38, 0x99, 0xba, 0xc6, 0x97, 0xa7, 0x8f, + 0x63, 0x84, 0x98, 0x90, 0xa4, 0xeb, 0x9c, 0xf4, 0x66, 0xa0, 0x37, 0x0c, 0xb5, 0x95, 0x6d, 0x4a, + 0xbf, 0x6f, 0x86, 0x35, 0xed, 0xda, 0x98, 0x26, 0x6e, 0x64, 0x10, 0x48, 0xc2, 0xd5, 0x13, 0xda, + 0xce, 0x28, 0x0b, 0x71, 0x92, 0x3d, 0xfa, 0xac, 0x21, 0xb7, 0x46, 0xd5, 0xa2, 0xd9, 0xe3, 0x6a, + 0x11, 0x8a, 0x76, 0x5a, 0xd5, 0xa0, 0x04, 0x73, 0xf4, 0x61, 0x38, 0x6d, 0xed, 0x78, 0x7e, 0x98, + 0xba, 0xf8, 0x96, 0xe7, 0xd8, 0x32, 0x3a, 0xdb, 0xeb, 0x96, 0x4f, 0x57, 0x06, 0x62, 0xe1, 0x43, + 0x28, 0x98, 0xdf, 0x2f, 0xc0, 0x0c, 0x8f, 0xc5, 0x89, 0xad, 0xeb, 0xeb, 0x06, 0x3c, 0x5c, 0xef, + 0xf8, 0x3e, 0x71, 0xc3, 0x5a, 0x48, 0xda, 0xfd, 0x1b, 0x97, 0x71, 0xac, 0x1b, 0xd7, 0x23, 0xbd, + 0x6e, 0xf9, 0xe1, 0xd5, 0x43, 0xf8, 0xe3, 0x43, 0x5b, 0x87, 0xfe, 0xca, 0x00, 0x53, 0x20, 0x54, + 0xad, 0xfa, 0xad, 0xa6, 0xef, 0x75, 0xdc, 0x46, 0x7f, 0x27, 0x72, 0xc7, 0xda, 0x89, 0xc7, 0x7a, + 0xdd, 0xb2, 0xb9, 0x7a, 0xcf, 0x56, 0xe0, 0x21, 0x5a, 0x8a, 0x9e, 0x83, 0x45, 0x81, 0x75, 0xe1, + 0x4e, 0x9b, 0xf8, 0x36, 0x35, 0xa7, 0x45, 0xe4, 0x2f, 0x0a, 0xa6, 0x26, 0x11, 0x70, 0x7f, 0x1d, + 0x14, 0xc0, 0xe4, 0x6d, 0x62, 0x37, 0xf7, 0x42, 0x69, 0x3e, 0x8d, 0x19, 0x41, 0x15, 0xf1, 0xb6, + 0x1b, 0x9c, 0x66, 0x75, 0xba, 0xd7, 0x2d, 0x4f, 0x8a, 0x3f, 0x58, 0x72, 0x32, 0xff, 0xa0, 0x00, + 0x20, 0xc5, 0x8b, 0xb4, 0xd1, 0xff, 0x83, 0xa9, 0x80, 0x84, 0x1c, 0x4b, 0x1c, 0xcb, 0xf1, 0xd3, + 0x4e, 0x59, 0x88, 0x23, 0x38, 0xba, 0x05, 0xc5, 0xb6, 0xd5, 0x09, 0x88, 0x98, 0xac, 0xcb, 0x99, + 0x4c, 0xd6, 0x16, 0xa5, 0xc8, 0x7d, 0x24, 0xf6, 0x13, 0x73, 0x1e, 0xe8, 0x53, 0x06, 0x00, 0x89, + 0x0f, 0xf0, 0xf4, 0xf9, 0x5a, 0x26, 0x2c, 0xa3, 0x39, 0xa0, 0x63, 0x50, 0x9d, 0xeb, 0x75, 0xcb, + 0xa0, 0x4d, 0x95, 0xc6, 0x16, 0xdd, 0x86, 0x92, 0x25, 0x75, 0x74, 0xe1, 0x38, 0x74, 0x34, 0x73, + 0x5d, 0x94, 0x90, 0x29, 0x66, 0xe8, 0xd3, 0x06, 0xcc, 0x05, 0x24, 0x14, 0x53, 0x45, 0x35, 0x85, + 0x30, 0x50, 0xc7, 0x14, 0x92, 0x5a, 0x8c, 0x26, 0xd7, 0x78, 0xf1, 0x32, 0x9c, 0xe0, 0x6b, 0x7e, + 0x7f, 0x1a, 0xe6, 0xa4, 0xc8, 0x44, 0x36, 0x27, 0x4f, 0x0e, 0x18, 0x60, 0x73, 0xae, 0xea, 0x40, + 0x1c, 0xc7, 0xa5, 0x95, 0x79, 0x04, 0x3f, 0x6e, 0x72, 0xaa, 0xca, 0x35, 0x1d, 0x88, 0xe3, 0xb8, + 0xa8, 0x05, 0xc5, 0x20, 0x24, 0x6d, 0x19, 0x4b, 0x18, 0xf3, 0xa8, 0x3b, 0x5a, 0x09, 0xd1, 0x69, + 0x21, 0xfd, 0x17, 0x60, 0xce, 0x05, 0x7d, 0xce, 0x80, 0xb9, 0x30, 0x16, 0xc7, 0x16, 0x62, 0x90, + 0x8d, 0x24, 0xc6, 0x43, 0xe4, 0x7c, 0x36, 0xe2, 0x65, 0x38, 0xc1, 0x3e, 0xc5, 0x0c, 0x2d, 0x1e, + 0xa3, 0x19, 0xfa, 0x22, 0x94, 0x5a, 0xd6, 0x9d, 0x5a, 0xc7, 0x6f, 0x1e, 0xdd, 0xdc, 0x15, 0x61, + 0x7e, 0x4e, 0x05, 0x2b, 0x7a, 0xe8, 0x55, 0x43, 0x5b, 0x5c, 0x93, 0x8c, 0xf8, 0x8d, 0x6c, 0x17, + 0x97, 0xd2, 0xe2, 0x03, 0x97, 0x59, 0x9f, 0x51, 0x58, 0xba, 0xef, 0x46, 0x21, 0x35, 0x70, 0xf8, + 0x02, 0x51, 0x06, 0xce, 0xd4, 0xb1, 0x1a, 0x38, 0xab, 0x31, 0x66, 0x38, 0xc1, 0x9c, 0xb5, 0x87, + 0xaf, 0x39, 0xd5, 0x1e, 0x38, 0xd6, 0xf6, 0xd4, 0x62, 0xcc, 0x70, 0x82, 0xf9, 0x60, 0x4f, 0x68, + 0xfa, 0x78, 0x3c, 0xa1, 0x99, 0x0c, 0x3c, 0xa1, 0xc3, 0x8d, 0xc4, 0xd9, 0x71, 0x8d, 0x44, 0x74, + 0x19, 0x50, 0xe3, 0xc0, 0xb5, 0x5a, 0x76, 0x5d, 0x28, 0x4b, 0xb6, 0x41, 0xcc, 0x31, 0x4f, 0xf9, + 0xb4, 0x50, 0x64, 0x68, 0xad, 0x0f, 0x03, 0xa7, 0xd4, 0x32, 0xff, 0xdd, 0x80, 0x85, 0x55, 0xc7, + 0xeb, 0x34, 0x6e, 0x58, 0x61, 0x7d, 0x8f, 0x47, 0x29, 0xd0, 0xb3, 0x50, 0xb2, 0xdd, 0x90, 0xf8, + 0xfb, 0x96, 0x23, 0x74, 0xbb, 0x29, 0x03, 0x39, 0xeb, 0xa2, 0xfc, 0x6e, 0xb7, 0x3c, 0xb7, 0xd6, + 0xf1, 0x59, 0xfa, 0x0f, 0x5f, 0xe9, 0x58, 0xd5, 0x41, 0x5f, 0x36, 0x60, 0x91, 0xc7, 0x39, 0xd6, + 0xac, 0xd0, 0xba, 0xd6, 0x21, 0xbe, 0x4d, 0x64, 0xa4, 0x63, 0xcc, 0x45, 0x9e, 0x6c, 0xab, 0x64, + 0x70, 0x10, 0x99, 0x5f, 0x9b, 0x49, 0xce, 0xb8, 0xbf, 0x31, 0xe6, 0xe7, 0xf3, 0xf0, 0xe0, 0x40, + 0x5a, 0xe8, 0x34, 0xe4, 0xec, 0x86, 0xe8, 0x3a, 0x08, 0xba, 0xb9, 0xf5, 0x06, 0xce, 0xd9, 0x0d, + 0xb4, 0xc2, 0x2c, 0x13, 0x9f, 0x04, 0x81, 0x3c, 0xf4, 0x9e, 0x52, 0x46, 0x84, 0x28, 0xc5, 0x1a, + 0x06, 0x2a, 0x43, 0xd1, 0xb1, 0x76, 0x88, 0x23, 0xac, 0x44, 0x66, 0xeb, 0x6c, 0xd0, 0x02, 0xcc, + 0xcb, 0xd1, 0x2f, 0x1b, 0x00, 0xbc, 0x81, 0xd4, 0xc6, 0x14, 0x3b, 0x0c, 0xce, 0x76, 0x98, 0x28, + 0x65, 0xde, 0xca, 0xe8, 0x3f, 0xd6, 0xb8, 0xa2, 0x6d, 0x98, 0xa0, 0x66, 0x8f, 0xd7, 0x38, 0xf2, + 0x86, 0x02, 0xbd, 0x6e, 0x79, 0x62, 0x8b, 0xd1, 0xc0, 0x82, 0x16, 0x1d, 0x2b, 0x9f, 0x84, 0x1d, + 0xdf, 0xa5, 0x43, 0xcb, 0xb6, 0x90, 0x12, 0x6f, 0x05, 0x56, 0xa5, 0x58, 0xc3, 0x30, 0xff, 0x38, + 0x07, 0x4b, 0x69, 0x4d, 0xa7, 0x9a, 0x7a, 0x82, 0xb7, 0x56, 0x38, 0x3c, 0xef, 0xcf, 0x7e, 0x7c, + 0x44, 0xc8, 0x4e, 0x05, 0xb6, 0x44, 0x52, 0x81, 0xe0, 0x8b, 0xde, 0xaf, 0x46, 0x28, 0x77, 0xc4, + 0x11, 0x52, 0x94, 0x13, 0xa3, 0xf4, 0x08, 0x14, 0x02, 0x3a, 0xf3, 0xf9, 0xf8, 0xb1, 0x34, 0x9b, + 0x23, 0x06, 0xa1, 0x18, 0x1d, 0xd7, 0x0e, 0x45, 0x4e, 0x9e, 0xc2, 0xb8, 0xee, 0xda, 0x21, 0x66, + 0x10, 0xf3, 0x8b, 0x39, 0x38, 0x3d, 0xb8, 0x53, 0xe8, 0x8b, 0x06, 0x40, 0x83, 0x1a, 0xb5, 0x54, + 0x24, 0x65, 0x88, 0xd3, 0x3a, 0xae, 0x31, 0x5c, 0x93, 0x9c, 0xa2, 0x78, 0xb7, 0x2a, 0x0a, 0xb0, + 0xd6, 0x10, 0x74, 0x5e, 0x8a, 0xfe, 0x15, 0xab, 0x25, 0x4d, 0x41, 0x55, 0x67, 0x53, 0x41, 0xb0, + 0x86, 0x45, 0xbd, 0x16, 0xd7, 0x6a, 0x91, 0xa0, 0x6d, 0xa9, 0xa4, 0x4b, 0xe6, 0xb5, 0x5c, 0x91, + 0x85, 0x38, 0x82, 0x9b, 0x0e, 0x3c, 0x3a, 0x44, 0x3b, 0x33, 0x4a, 0x80, 0x33, 0xff, 0xcd, 0x80, + 0x53, 0xab, 0x4e, 0x27, 0x08, 0x89, 0xff, 0x3f, 0x26, 0x7d, 0xe0, 0x3f, 0x0c, 0x78, 0x68, 0x40, + 0x9f, 0xef, 0x43, 0x16, 0xc1, 0xcb, 0xf1, 0x2c, 0x82, 0xeb, 0xe3, 0x8a, 0x74, 0x6a, 0x3f, 0x06, + 0x24, 0x13, 0x84, 0x30, 0x4b, 0xb5, 0x56, 0xc3, 0x6b, 0x66, 0xb4, 0x6f, 0x3e, 0x0a, 0xc5, 0x8f, + 0xd2, 0xfd, 0x27, 0x29, 0x63, 0x6c, 0x53, 0xc2, 0x1c, 0x66, 0xbe, 0x0f, 0x44, 0xc8, 0x3d, 0xb1, + 0x78, 0x8c, 0x61, 0x16, 0x8f, 0xf9, 0x77, 0x39, 0xd0, 0xbc, 0xdd, 0xfb, 0x20, 0x94, 0x6e, 0x4c, + 0x28, 0xc7, 0xf4, 0x5f, 0x35, 0xdf, 0x7d, 0x50, 0x6e, 0xed, 0x7e, 0x22, 0xb7, 0xf6, 0x4a, 0x66, + 0x1c, 0x0f, 0x4f, 0xad, 0xfd, 0x8e, 0x01, 0x0f, 0x45, 0xc8, 0xfd, 0x07, 0x47, 0xf7, 0xd6, 0x30, + 0x4f, 0xc1, 0xb4, 0x15, 0x55, 0x13, 0x32, 0xa0, 0xd2, 0xc9, 0x35, 0x8a, 0x58, 0xc7, 0x8b, 0x32, + 0xf9, 0xf2, 0x47, 0xcc, 0xe4, 0x2b, 0x1c, 0x9e, 0xc9, 0x67, 0xfe, 0x34, 0x07, 0x67, 0xfa, 0x7b, + 0x26, 0xd7, 0xc6, 0x70, 0x71, 0xd5, 0xa7, 0x61, 0x26, 0x14, 0x15, 0x34, 0x4d, 0xaf, 0x2e, 0x43, + 0x6c, 0x6b, 0x30, 0x1c, 0xc3, 0xa4, 0x35, 0xeb, 0x7c, 0x55, 0xd6, 0xea, 0x5e, 0x5b, 0xe6, 0x81, + 0xaa, 0x9a, 0xab, 0x1a, 0x0c, 0xc7, 0x30, 0x55, 0x86, 0x4d, 0xe1, 0xd8, 0x33, 0x6c, 0x6a, 0x70, + 0x52, 0xe6, 0x14, 0x5c, 0xf4, 0xfc, 0x55, 0xaf, 0xd5, 0x76, 0x88, 0xc8, 0x04, 0xa5, 0x8d, 0x3d, + 0x23, 0xaa, 0x9c, 0xc4, 0x69, 0x48, 0x38, 0xbd, 0xae, 0xf9, 0x9d, 0x3c, 0x9c, 0x88, 0x86, 0x7d, + 0xd5, 0x73, 0x1b, 0x36, 0xcb, 0xcc, 0x78, 0x06, 0x0a, 0xe1, 0x41, 0x5b, 0x0e, 0xf6, 0xff, 0x91, + 0xcd, 0xd9, 0x3e, 0x68, 0xd3, 0xd9, 0x3e, 0x95, 0x52, 0x85, 0x82, 0x30, 0xab, 0x84, 0x36, 0xd4, + 0xea, 0xe0, 0x33, 0xf0, 0x64, 0x5c, 0x9a, 0xef, 0x76, 0xcb, 0x29, 0x77, 0x81, 0x56, 0x14, 0xa5, + 0xb8, 0xcc, 0xa3, 0x9b, 0x30, 0xe7, 0x58, 0x41, 0x78, 0xbd, 0xdd, 0xb0, 0x42, 0xb2, 0x6d, 0xb7, + 0x88, 0x58, 0x73, 0xa3, 0xa4, 0x57, 0xaa, 0x58, 0xe3, 0x46, 0x8c, 0x12, 0x4e, 0x50, 0x46, 0xfb, + 0x80, 0x68, 0xc9, 0xb6, 0x6f, 0xb9, 0x01, 0xef, 0x15, 0xe5, 0x37, 0x7a, 0x3a, 0xa7, 0x72, 0x90, + 0x36, 0xfa, 0xa8, 0xe1, 0x14, 0x0e, 0xe8, 0x31, 0x98, 0xf0, 0x89, 0x15, 0x88, 0xc9, 0x9c, 0x8a, + 0xd6, 0x3f, 0x66, 0xa5, 0x58, 0x40, 0xf5, 0x05, 0x35, 0x71, 0x8f, 0x05, 0xf5, 0x03, 0x03, 0xe6, + 0xa2, 0x69, 0xba, 0x0f, 0x9b, 0x64, 0x2b, 0xbe, 0x49, 0x5e, 0xca, 0x4a, 0x25, 0x0e, 0xd8, 0x17, + 0xbf, 0x5c, 0xd4, 0xfb, 0xc7, 0xd2, 0xeb, 0x3e, 0x06, 0x53, 0x72, 0x55, 0x4b, 0xeb, 0x73, 0xcc, + 0x53, 0x96, 0x98, 0x5d, 0xa2, 0xa5, 0x85, 0x0b, 0x26, 0x38, 0xe2, 0x47, 0xb7, 0xe5, 0x86, 0xd8, + 0x72, 0x85, 0xd8, 0xab, 0x6d, 0x59, 0x6e, 0xc5, 0x69, 0xdb, 0xb2, 0xac, 0x83, 0xae, 0xc3, 0xa9, + 0xb6, 0xef, 0xb1, 0xab, 0x42, 0x6b, 0xc4, 0x6a, 0x38, 0xb6, 0x4b, 0xa4, 0x33, 0xcf, 0x43, 0xdd, + 0x0f, 0xf5, 0xba, 0xe5, 0x53, 0x5b, 0xe9, 0x28, 0x78, 0x50, 0xdd, 0x78, 0x7a, 0x7b, 0x61, 0x88, + 0xf4, 0xf6, 0x5f, 0x55, 0x47, 0x66, 0x24, 0x10, 0x49, 0xe6, 0x1f, 0xcc, 0x6a, 0x2a, 0x53, 0xd4, + 0x7a, 0x24, 0x52, 0x15, 0xc1, 0x14, 0x2b, 0xf6, 0x83, 0xcf, 0x65, 0x26, 0x8e, 0x78, 0x2e, 0x13, + 0x65, 0x29, 0x4e, 0x1e, 0x7f, 0x96, 0xa2, 0xf9, 0x5a, 0x11, 0x16, 0x92, 0x5b, 0xfb, 0xf1, 0xe7, + 0xc4, 0xff, 0x86, 0x01, 0x0b, 0x52, 0x2c, 0x39, 0x4f, 0x22, 0x8f, 0xb2, 0x37, 0x32, 0x5a, 0x0d, + 0xdc, 0x48, 0x51, 0xb7, 0xb6, 0xb6, 0x13, 0xdc, 0x70, 0x1f, 0x7f, 0xf4, 0x12, 0x4c, 0xab, 0x13, + 0xdf, 0x23, 0x25, 0xc8, 0xcf, 0x33, 0xf3, 0x24, 0x22, 0x81, 0x75, 0x7a, 0xe8, 0x35, 0x03, 0xa0, + 0x2e, 0xf7, 0x0f, 0x29, 0xb6, 0xd7, 0xb2, 0x12, 0x5b, 0xb5, 0x33, 0x45, 0x56, 0xa8, 0x2a, 0x0a, + 0xb0, 0xc6, 0x18, 0x7d, 0x9e, 0x9d, 0xf5, 0x2a, 0xb3, 0x89, 0x0a, 0x2a, 0x6d, 0xc9, 0x07, 0xb2, + 0x5e, 0x40, 0x51, 0xd8, 0x51, 0xd9, 0x28, 0x1a, 0x28, 0xc0, 0xb1, 0x46, 0x98, 0xcf, 0x80, 0xca, + 0x5c, 0xa3, 0xfa, 0x80, 0xe5, 0xae, 0x6d, 0x59, 0xe1, 0x9e, 0x10, 0x41, 0xa5, 0x0f, 0x2e, 0x4a, + 0x00, 0x8e, 0x70, 0xcc, 0x8f, 0xc0, 0xdc, 0x73, 0xbe, 0xd5, 0xde, 0xb3, 0xd9, 0x99, 0x2a, 0x75, + 0x40, 0xde, 0x0e, 0x93, 0x56, 0xa3, 0x91, 0x76, 0xe7, 0xb1, 0xc2, 0x8b, 0xb1, 0x84, 0x0f, 0xe7, + 0x6b, 0x7c, 0xc3, 0x80, 0xa5, 0xf5, 0x20, 0xb4, 0xbd, 0x35, 0x12, 0x84, 0x54, 0x09, 0x51, 0x7b, + 0xa5, 0xe3, 0x90, 0x21, 0x2c, 0xbe, 0x35, 0x58, 0x10, 0x81, 0x9f, 0xce, 0x4e, 0x40, 0x42, 0xcd, + 0xea, 0x53, 0xc2, 0xb9, 0x9a, 0x80, 0xe3, 0xbe, 0x1a, 0x94, 0x8a, 0x88, 0x00, 0x45, 0x54, 0xf2, + 0x71, 0x2a, 0xb5, 0x04, 0x1c, 0xf7, 0xd5, 0x30, 0xbf, 0x9d, 0x87, 0x13, 0xac, 0x1b, 0x89, 0x4b, + 0x89, 0x9f, 0x35, 0x60, 0x6e, 0xdf, 0xf6, 0xc3, 0x8e, 0xe5, 0xe8, 0xa1, 0xac, 0xb1, 0xe5, 0x93, + 0xf1, 0x7a, 0x21, 0x46, 0x98, 0x1f, 0x76, 0xc7, 0xcb, 0x70, 0x82, 0x39, 0xfa, 0x75, 0x03, 0xe6, + 0x1b, 0xf1, 0x91, 0xce, 0xc6, 0x99, 0x4f, 0x9b, 0x43, 0x9e, 0x81, 0x91, 0x28, 0xc4, 0x49, 0xfe, + 0xe8, 0x0b, 0x06, 0xcc, 0xc7, 0x9b, 0x29, 0x55, 0xd6, 0x31, 0x0c, 0x92, 0x4a, 0x99, 0x8c, 0x97, + 0x07, 0x38, 0xd9, 0x04, 0xf3, 0x6f, 0x0c, 0x31, 0xa5, 0x71, 0xcc, 0x21, 0x04, 0xd3, 0x84, 0x09, + 0xdf, 0xeb, 0x84, 0xe2, 0x40, 0x7a, 0x8a, 0x9f, 0x5b, 0x62, 0x56, 0x82, 0x05, 0x04, 0xdd, 0x86, + 0xa9, 0xd0, 0x09, 0x78, 0xa1, 0xe8, 0xed, 0x98, 0xfe, 0xc3, 0xf6, 0x46, 0x8d, 0x91, 0xd3, 0xb6, + 0x78, 0x51, 0x42, 0x4d, 0x15, 0xc9, 0xcb, 0xfc, 0xaa, 0x01, 0x53, 0x97, 0xbd, 0x1d, 0xb1, 0x9c, + 0x3f, 0x9c, 0x81, 0x77, 0xae, 0x36, 0x71, 0x15, 0x62, 0x89, 0xec, 0xc2, 0x67, 0x63, 0xbe, 0xf9, + 0xc3, 0x1a, 0xed, 0x15, 0xf6, 0x56, 0x00, 0x25, 0x75, 0xd9, 0xdb, 0x19, 0x78, 0xf4, 0xf3, 0x3b, + 0x45, 0x98, 0x7d, 0xde, 0x3a, 0x20, 0x6e, 0x68, 0x8d, 0xae, 0x80, 0xa8, 0xbb, 0xdb, 0x66, 0x19, + 0x80, 0x9a, 0x61, 0x16, 0xb9, 0xbb, 0x11, 0x08, 0xeb, 0x78, 0x91, 0x5e, 0xe1, 0x57, 0x97, 0xd3, + 0x34, 0xc2, 0x6a, 0x02, 0x8e, 0xfb, 0x6a, 0xa0, 0xcb, 0x80, 0xc4, 0x45, 0x8c, 0x4a, 0xbd, 0xee, + 0x75, 0x5c, 0xae, 0x59, 0xb8, 0x27, 0xac, 0x3c, 0x84, 0xcd, 0x3e, 0x0c, 0x9c, 0x52, 0x0b, 0x7d, + 0x08, 0x96, 0xeb, 0x8c, 0xb2, 0xb0, 0x17, 0x75, 0x8a, 0xdc, 0x67, 0x50, 0xd9, 0xb7, 0xab, 0x03, + 0xf0, 0xf0, 0x40, 0x0a, 0xb4, 0xa5, 0x41, 0xe8, 0xf9, 0x56, 0x93, 0xe8, 0x74, 0x27, 0xe2, 0x2d, + 0xad, 0xf5, 0x61, 0xe0, 0x94, 0x5a, 0xe8, 0x93, 0x30, 0x15, 0xee, 0xf9, 0x24, 0xd8, 0xf3, 0x9c, + 0x86, 0x88, 0xb9, 0x8e, 0x79, 0x3c, 0x22, 0x66, 0x7f, 0x5b, 0x52, 0xd5, 0xc4, 0x5b, 0x16, 0xe1, + 0x88, 0x27, 0xf2, 0x61, 0x22, 0xa0, 0xbe, 0x79, 0xb0, 0x5c, 0xca, 0xc2, 0x07, 0x10, 0xdc, 0x99, + 0xbb, 0xaf, 0x1d, 0xcc, 0x30, 0x0e, 0x58, 0x70, 0x32, 0xbf, 0x99, 0x83, 0x19, 0x1d, 0x71, 0x08, + 0x15, 0xf1, 0x29, 0x03, 0x66, 0xea, 0x9e, 0x1b, 0xfa, 0x9e, 0xc3, 0x0f, 0x1d, 0xf8, 0x02, 0x19, + 0xf3, 0x7e, 0x2f, 0x23, 0xb5, 0x46, 0x42, 0xcb, 0x76, 0xb4, 0xf3, 0x0b, 0x8d, 0x0d, 0x8e, 0x31, + 0x45, 0x9f, 0x31, 0x60, 0x3e, 0x4a, 0x46, 0x89, 0x4e, 0x3f, 0x32, 0x6d, 0x88, 0xd2, 0xb8, 0x17, + 0xe2, 0x9c, 0x70, 0x92, 0xb5, 0xb9, 0x03, 0x0b, 0xc9, 0xd9, 0xa6, 0x43, 0xd9, 0xb6, 0xc4, 0x5a, + 0xcf, 0x47, 0x43, 0xb9, 0x65, 0x05, 0x01, 0x66, 0x10, 0xf4, 0x0e, 0x28, 0xb5, 0x2c, 0xbf, 0x69, + 0xbb, 0x96, 0xc3, 0x46, 0x31, 0xaf, 0x29, 0x24, 0x51, 0x8e, 0x15, 0x86, 0xf9, 0xe3, 0x02, 0x4c, + 0x6b, 0x97, 0x78, 0x8e, 0xdf, 0x22, 0x8f, 0xdd, 0x0d, 0xcd, 0x67, 0x78, 0x37, 0xf4, 0x45, 0x80, + 0x5d, 0xdb, 0xb5, 0x83, 0xbd, 0x23, 0xde, 0x3a, 0x65, 0x51, 0xb2, 0x8b, 0x8a, 0x02, 0xd6, 0xa8, + 0x45, 0xa1, 0x88, 0xe2, 0x21, 0x77, 0xf1, 0x5f, 0x33, 0xb4, 0xcd, 0x63, 0x22, 0x8b, 0xd0, 0xab, + 0x36, 0x31, 0x2b, 0x72, 0x33, 0xb9, 0xe0, 0x86, 0xfe, 0xc1, 0xa1, 0x7b, 0xcc, 0x36, 0x94, 0x7c, + 0x12, 0x74, 0x5a, 0xd4, 0xb7, 0x98, 0x1c, 0x79, 0x18, 0x58, 0xe6, 0x06, 0x16, 0xf5, 0xb1, 0xa2, + 0x74, 0xfa, 0x19, 0x98, 0x8d, 0x35, 0x01, 0x2d, 0x40, 0xfe, 0x16, 0x39, 0xe0, 0x72, 0x82, 0xe9, + 0x4f, 0xb4, 0x14, 0x0b, 0xd8, 0x88, 0x61, 0x79, 0x6f, 0xee, 0x69, 0xc3, 0xf4, 0x20, 0xf5, 0xa6, + 0xd8, 0x51, 0xce, 0xd3, 0xe9, 0x5c, 0x38, 0xda, 0xb5, 0x53, 0x35, 0x17, 0x3c, 0x4d, 0x80, 0xc3, + 0xcc, 0x9f, 0x4e, 0x80, 0x88, 0x26, 0x0e, 0xa1, 0x7c, 0xf4, 0x20, 0x42, 0xee, 0x08, 0x41, 0x84, + 0xcb, 0x30, 0x63, 0xbb, 0x76, 0x68, 0x5b, 0x0e, 0xf3, 0xaf, 0xc5, 0xe6, 0xf8, 0x98, 0x54, 0x38, + 0xeb, 0x1a, 0x2c, 0x85, 0x4e, 0xac, 0x2e, 0xba, 0x06, 0x45, 0xb6, 0x7b, 0x08, 0x01, 0x1e, 0x3d, + 0xe4, 0xc9, 0xa2, 0xdd, 0x3c, 0xed, 0x9f, 0x53, 0x62, 0x16, 0x3d, 0xbf, 0x77, 0xab, 0x1c, 0x35, + 0x21, 0xc7, 0x91, 0x45, 0x9f, 0x80, 0xe3, 0xbe, 0x1a, 0x94, 0xca, 0xae, 0x65, 0x3b, 0x1d, 0x9f, + 0x44, 0x54, 0x26, 0xe2, 0x54, 0x2e, 0x26, 0xe0, 0xb8, 0xaf, 0x06, 0xda, 0x85, 0x19, 0x51, 0xc6, + 0x93, 0x3f, 0x26, 0x8f, 0xd8, 0x4b, 0x96, 0xe4, 0x73, 0x51, 0xa3, 0x84, 0x63, 0x74, 0x51, 0x07, + 0x16, 0x6d, 0xb7, 0xee, 0xb9, 0x75, 0xa7, 0x13, 0xd8, 0xfb, 0x24, 0xca, 0xb9, 0x3f, 0x0a, 0xb3, + 0x93, 0xbd, 0x6e, 0x79, 0x71, 0x3d, 0x49, 0x0e, 0xf7, 0x73, 0x40, 0xaf, 0x1a, 0x70, 0xb2, 0xee, + 0xb9, 0x01, 0xbb, 0xc8, 0xb6, 0x4f, 0x2e, 0xf8, 0xbe, 0xe7, 0x73, 0xde, 0x53, 0x47, 0xe4, 0xcd, + 0x8e, 0x75, 0x56, 0xd3, 0x48, 0xe2, 0x74, 0x4e, 0xe8, 0x65, 0x28, 0xb5, 0x7d, 0x6f, 0xdf, 0x6e, + 0x10, 0x5f, 0x24, 0x12, 0x6d, 0x64, 0x71, 0xb1, 0x76, 0x4b, 0xd0, 0x8c, 0x54, 0x8f, 0x2c, 0xc1, + 0x8a, 0x9f, 0xf9, 0xfb, 0x25, 0x98, 0x8b, 0xa3, 0xa3, 0x4f, 0x00, 0xb4, 0x7d, 0xaf, 0x45, 0xc2, + 0x3d, 0xa2, 0x72, 0xa7, 0xaf, 0x8c, 0x7b, 0x7f, 0x53, 0xd2, 0x93, 0x09, 0x04, 0x54, 0x5d, 0x44, + 0xa5, 0x58, 0xe3, 0x88, 0x7c, 0x98, 0xbc, 0xc5, 0x37, 0x51, 0x61, 0x53, 0x3c, 0x9f, 0x89, 0x05, + 0x24, 0x38, 0xb3, 0xa4, 0x5f, 0x51, 0x84, 0x25, 0x23, 0xb4, 0x03, 0xf9, 0xdb, 0x64, 0x27, 0x9b, + 0x9b, 0x86, 0x37, 0x88, 0xf0, 0x4d, 0xaa, 0x93, 0xbd, 0x6e, 0x39, 0x7f, 0x83, 0xec, 0x60, 0x4a, + 0x9c, 0xf6, 0xab, 0xc1, 0x43, 0xa1, 0x42, 0x55, 0x8c, 0xd9, 0xaf, 0x58, 0x5c, 0x95, 0xf7, 0x4b, + 0x14, 0x61, 0xc9, 0x08, 0xbd, 0x0c, 0x53, 0xb7, 0xad, 0x7d, 0xb2, 0xeb, 0x7b, 0x6e, 0x28, 0xb2, + 0x56, 0xc6, 0x4c, 0xcf, 0xbd, 0x21, 0xc9, 0x09, 0xbe, 0x6c, 0x7b, 0x57, 0x85, 0x38, 0x62, 0x87, + 0xf6, 0xa1, 0xe4, 0x92, 0xdb, 0x98, 0x38, 0x76, 0x5d, 0x64, 0x46, 0x8e, 0x29, 0xd6, 0x57, 0x04, + 0x35, 0xc1, 0x99, 0xed, 0x7b, 0xb2, 0x0c, 0x2b, 0x5e, 0x74, 0x2e, 0x6f, 0x7a, 0x3b, 0x42, 0x51, + 0x8d, 0x39, 0x97, 0xca, 0xcf, 0xe4, 0x73, 0x79, 0xd9, 0xdb, 0xc1, 0x94, 0x38, 0x5d, 0x23, 0x75, + 0x95, 0x32, 0x21, 0xd4, 0xd4, 0x95, 0x6c, 0x53, 0x45, 0xf8, 0x1a, 0x89, 0x4a, 0xb1, 0xc6, 0x91, + 0x8e, 0x6d, 0x53, 0x1c, 0x6b, 0x09, 0x45, 0x35, 0xe6, 0xd8, 0xc6, 0x0f, 0xc9, 0xf8, 0xd8, 0xca, + 0x32, 0xac, 0x78, 0x99, 0x3f, 0x29, 0xc0, 0x8c, 0xfe, 0x90, 0xc8, 0x10, 0x7b, 0xb5, 0xb2, 0x4f, + 0x73, 0xa3, 0xd8, 0xa7, 0xd4, 0xbd, 0xd0, 0x2e, 0xa5, 0xcb, 0x13, 0x86, 0xf5, 0xcc, 0xcc, 0xb3, + 0xc8, 0xbd, 0xd0, 0x0a, 0x03, 0x1c, 0x63, 0x3a, 0x42, 0x04, 0x98, 0x1a, 0x39, 0xdc, 0x0c, 0x28, + 0xc6, 0x8d, 0x9c, 0xd8, 0xc6, 0x7e, 0x1e, 0x20, 0x7a, 0x50, 0x43, 0x84, 0x01, 0x94, 0xf5, 0xa4, + 0x3d, 0xf4, 0xa1, 0x61, 0xa1, 0xc7, 0x60, 0x82, 0x6e, 0x94, 0xa4, 0x21, 0x2e, 0xb6, 0x29, 0x1f, + 0xee, 0x22, 0x2b, 0xc5, 0x02, 0x8a, 0x9e, 0xa6, 0x36, 0x4d, 0xb4, 0xbd, 0x89, 0xfb, 0x6a, 0x4b, + 0x91, 0x4d, 0x13, 0xc1, 0x70, 0x0c, 0x93, 0x36, 0x9d, 0xd0, 0xdd, 0x88, 0x49, 0x92, 0xd6, 0x74, + 0xb6, 0x45, 0x61, 0x0e, 0x63, 0x67, 0x0a, 0x89, 0xdd, 0x8b, 0x6d, 0x56, 0x45, 0xed, 0x4c, 0x21, + 0x01, 0xc7, 0x7d, 0x35, 0x68, 0x67, 0x44, 0x04, 0x63, 0x9a, 0x27, 0xba, 0x0d, 0x88, 0x3d, 0x7c, + 0x04, 0xe6, 0xe2, 0xab, 0x9d, 0x4e, 0x45, 0xdb, 0xf7, 0x76, 0x6d, 0x87, 0x24, 0x4f, 0x4d, 0xb6, + 0x78, 0x31, 0x96, 0xf0, 0xe1, 0x8e, 0x6d, 0xff, 0x22, 0x0f, 0x27, 0xae, 0x34, 0x6d, 0xf7, 0x4e, + 0xe2, 0xbc, 0x33, 0xed, 0x99, 0x37, 0x63, 0xd4, 0x67, 0xde, 0xa2, 0x0c, 0x7e, 0xf1, 0x8e, 0x5e, + 0x7a, 0x06, 0xbf, 0x7c, 0x64, 0x2f, 0x8e, 0x8b, 0x7e, 0x60, 0xc0, 0xc3, 0x56, 0x83, 0xdb, 0x5f, + 0x96, 0x23, 0x4a, 0x23, 0xa6, 0x72, 0x2d, 0x04, 0x63, 0x6a, 0xd3, 0xfe, 0xce, 0xaf, 0x54, 0x0e, + 0xe1, 0xca, 0xdd, 0x98, 0xb7, 0x89, 0x1e, 0x3c, 0x7c, 0x18, 0x2a, 0x3e, 0xb4, 0xf9, 0xa7, 0xaf, + 0xc2, 0x5b, 0xef, 0xc9, 0x68, 0x24, 0x67, 0xe5, 0x53, 0x06, 0x4c, 0xf1, 0xe3, 0x3c, 0x4c, 0x76, + 0xe9, 0x22, 0xb3, 0xda, 0xf6, 0x0b, 0xc4, 0x0f, 0xe4, 0xfb, 0x13, 0x9a, 0x8b, 0x52, 0xd9, 0x5a, + 0x17, 0x10, 0xac, 0x61, 0x51, 0x35, 0x76, 0xcb, 0x76, 0x1b, 0x62, 0x9a, 0x94, 0x1a, 0x7b, 0xde, + 0x76, 0x1b, 0x98, 0x41, 0x94, 0xa2, 0xcb, 0x0f, 0x52, 0x74, 0xe6, 0x57, 0x0c, 0x98, 0x63, 0x17, + 0x74, 0x22, 0xe3, 0xf9, 0x29, 0x15, 0x18, 0xe7, 0xcd, 0x38, 0x13, 0x0f, 0x8c, 0xdf, 0xed, 0x96, + 0xa7, 0xf9, 0x95, 0x9e, 0x78, 0x9c, 0xfc, 0x83, 0xc2, 0xe3, 0x66, 0xe1, 0xfb, 0xdc, 0xc8, 0x0e, + 0xa1, 0x3a, 0x5f, 0xaa, 0x49, 0x22, 0x38, 0xa2, 0x67, 0xfe, 0x61, 0x1e, 0x4e, 0xa4, 0x64, 0x9a, + 0x53, 0x67, 0x78, 0x82, 0x25, 0xdb, 0xca, 0xe0, 0xf3, 0x4b, 0x99, 0x67, 0xb3, 0xaf, 0xb0, 0x9c, + 0x5e, 0x21, 0x49, 0x6a, 0xe9, 0xf3, 0x42, 0x2c, 0x98, 0xa3, 0xdf, 0x34, 0x60, 0xda, 0xd2, 0x84, + 0x9d, 0xc7, 0xe3, 0x77, 0xb2, 0x6f, 0x4c, 0x9f, 0x6c, 0x6b, 0x79, 0x44, 0x91, 0x28, 0xeb, 0x6d, + 0x39, 0xfd, 0x1e, 0x98, 0xd6, 0xba, 0x30, 0x8a, 0x8c, 0x9e, 0x7e, 0x16, 0x16, 0xc6, 0x92, 0xf1, + 0x0f, 0xc0, 0xa8, 0x0f, 0x9a, 0x50, 0x65, 0x7b, 0x5b, 0xbf, 0xb7, 0xa6, 0x46, 0x5c, 0x5c, 0x5c, + 0x13, 0x50, 0x73, 0x07, 0x16, 0x92, 0x06, 0x7a, 0xe6, 0x51, 0xb2, 0x77, 0xc1, 0x88, 0x4f, 0x90, + 0x98, 0x7f, 0x99, 0x83, 0x49, 0x71, 0x5d, 0xe5, 0x3e, 0xa4, 0xe0, 0xdd, 0x8a, 0x1d, 0xf3, 0xaf, + 0x67, 0x72, 0xcb, 0x66, 0x60, 0xfe, 0x5d, 0x90, 0xc8, 0xbf, 0x7b, 0x3e, 0x1b, 0x76, 0x87, 0x27, + 0xdf, 0xfd, 0x67, 0x0e, 0xe6, 0x13, 0xd7, 0x7f, 0xd0, 0xeb, 0x46, 0x7f, 0xce, 0xc9, 0xf5, 0x4c, + 0x6f, 0x18, 0xa9, 0xf4, 0xd0, 0xc3, 0xd3, 0x4f, 0x82, 0xd8, 0x4b, 0x4f, 0xd7, 0x32, 0x7b, 0x24, + 0xf2, 0xcd, 0xf3, 0xe8, 0x93, 0xf9, 0x8f, 0x06, 0x3c, 0x38, 0xf0, 0xfa, 0x15, 0xbb, 0x57, 0xee, + 0xc7, 0xa1, 0x42, 0xd2, 0x33, 0xbe, 0x4e, 0xa9, 0x0e, 0xb3, 0x93, 0x57, 0x81, 0x93, 0xec, 0xd1, + 0x93, 0x30, 0xc3, 0x76, 0x0d, 0xba, 0x58, 0x43, 0xd2, 0x16, 0xa7, 0x77, 0xec, 0x1c, 0xa7, 0xa6, + 0x95, 0xe3, 0x18, 0x96, 0xf9, 0x65, 0x03, 0x96, 0x07, 0xdd, 0x32, 0x1e, 0xc2, 0x5b, 0xf8, 0x85, + 0x44, 0xf2, 0x5d, 0xb9, 0x2f, 0xf9, 0x2e, 0xe1, 0x2f, 0xc8, 0x3c, 0x3b, 0xcd, 0x54, 0xcf, 0xdf, + 0x23, 0xb7, 0xec, 0xb3, 0x06, 0x9c, 0x1a, 0x20, 0xa6, 0x7d, 0x49, 0x98, 0xc6, 0x91, 0x93, 0x30, + 0x73, 0xc3, 0x26, 0x61, 0x9a, 0x7f, 0x9d, 0x87, 0x05, 0xd1, 0x9e, 0xc8, 0x74, 0x78, 0x3a, 0x96, + 0xc2, 0xf8, 0xb6, 0x44, 0x0a, 0xe3, 0x52, 0x12, 0xff, 0x7f, 0xf3, 0x17, 0xdf, 0x5c, 0xf9, 0x8b, + 0x3f, 0xcb, 0xc1, 0xc9, 0xd4, 0xcb, 0xd4, 0xe8, 0xd3, 0x29, 0x3a, 0xf7, 0x46, 0xc6, 0xb7, 0xb6, + 0x87, 0xd4, 0xba, 0xe3, 0x26, 0xfd, 0x7d, 0x41, 0x4f, 0xb6, 0xe3, 0x3a, 0x74, 0xf7, 0x18, 0xee, + 0x9f, 0x8f, 0x98, 0x77, 0x67, 0xfe, 0x5a, 0x1e, 0x1e, 0x1f, 0x96, 0xd0, 0x9b, 0x34, 0x2f, 0x3b, + 0x88, 0xe5, 0x65, 0xdf, 0xa7, 0xfd, 0xf0, 0x58, 0x52, 0xb4, 0xbf, 0x9a, 0x57, 0xdb, 0x5e, 0xbf, + 0x7c, 0x0e, 0x15, 0xea, 0x99, 0xa4, 0x36, 0x93, 0x7c, 0x12, 0x2d, 0x52, 0x85, 0x93, 0x35, 0x5e, + 0x7c, 0xb7, 0x5b, 0x5e, 0x14, 0xcf, 0x24, 0xd5, 0x48, 0x28, 0x0a, 0xb1, 0xac, 0x84, 0x1e, 0x87, + 0x92, 0xcf, 0xa1, 0x32, 0x13, 0x55, 0xc4, 0xcb, 0x78, 0x19, 0x56, 0x50, 0xf4, 0x49, 0xcd, 0xc8, + 0x2c, 0x1c, 0xd7, 0x7d, 0xde, 0xc3, 0xc2, 0x80, 0x2f, 0x41, 0x29, 0x90, 0x8f, 0x9b, 0xf1, 0xb3, + 0xda, 0x27, 0x86, 0x4c, 0x70, 0xa6, 0x3e, 0x89, 0x7c, 0xe9, 0x8c, 0xf7, 0x4f, 0xbd, 0x83, 0xa6, + 0x48, 0x22, 0x53, 0xb9, 0x03, 0xfc, 0xe0, 0x09, 0x52, 0x5c, 0x81, 0xef, 0x18, 0x30, 0x2d, 0x66, + 0xeb, 0x3e, 0xe4, 0x5c, 0xdf, 0x8c, 0xe7, 0x5c, 0x5f, 0xc8, 0x44, 0x77, 0x0c, 0x48, 0xb8, 0xbe, + 0x09, 0x33, 0xfa, 0x7b, 0x1a, 0xe8, 0x45, 0x4d, 0xf7, 0x19, 0xe3, 0xdc, 0xdb, 0x97, 0xda, 0x31, + 0xd2, 0x8b, 0xe6, 0x97, 0x4a, 0x6a, 0x14, 0x59, 0x66, 0xb7, 0x2e, 0x83, 0xc6, 0xa1, 0x32, 0xa8, + 0x8b, 0x40, 0x2e, 0x7b, 0x11, 0xb8, 0x06, 0x25, 0xa9, 0xa0, 0xc4, 0x36, 0xfe, 0xa8, 0x9e, 0xd0, + 0x44, 0x6d, 0x01, 0x4a, 0x4c, 0x13, 0x5c, 0xe6, 0xc3, 0xa8, 0x39, 0x54, 0x8a, 0x53, 0x91, 0x41, + 0x2f, 0xc3, 0xf4, 0x6d, 0xcf, 0xbf, 0xe5, 0x78, 0x16, 0x7b, 0xb6, 0x10, 0xb2, 0x38, 0x75, 0x57, + 0x67, 0x39, 0x3c, 0x6f, 0xf6, 0x46, 0x44, 0x1f, 0xeb, 0xcc, 0x50, 0x05, 0xe6, 0x5b, 0xb6, 0x8b, + 0x89, 0xd5, 0x50, 0xa9, 0xd5, 0x05, 0xfe, 0xae, 0x9a, 0x34, 0x72, 0x37, 0xe3, 0x60, 0x9c, 0xc4, + 0x47, 0x1f, 0x83, 0x52, 0x20, 0xde, 0xec, 0xc8, 0x26, 0x3e, 0xa2, 0x9c, 0x31, 0x4e, 0x34, 0x1a, + 0x3b, 0x59, 0x82, 0x15, 0x43, 0xb4, 0x01, 0x4b, 0xbe, 0xb8, 0x15, 0x1f, 0x7b, 0x9e, 0x99, 0xaf, + 0x4f, 0xf6, 0x7c, 0x17, 0x4e, 0x81, 0xe3, 0xd4, 0x5a, 0xd4, 0x8a, 0x61, 0x0f, 0xc3, 0xf0, 0x83, + 0x62, 0xed, 0x6c, 0x95, 0x09, 0x7c, 0x03, 0x0b, 0xe8, 0x61, 0xa9, 0xfa, 0xa5, 0x31, 0x52, 0xf5, + 0x6b, 0x70, 0x32, 0x09, 0x62, 0x77, 0xf7, 0xd9, 0x73, 0x01, 0xda, 0xee, 0xb1, 0x95, 0x86, 0x84, + 0xd3, 0xeb, 0xa2, 0x1b, 0x30, 0xe5, 0x13, 0xe6, 0x5f, 0x54, 0x64, 0x44, 0x76, 0xe4, 0xdc, 0x13, + 0x2c, 0x09, 0xe0, 0x88, 0x16, 0x9d, 0x77, 0x2b, 0xfe, 0xb4, 0xd8, 0xb5, 0x0c, 0x3f, 0x30, 0x21, + 0xe6, 0x7e, 0xc0, 0x9b, 0x1a, 0xe6, 0x4f, 0xe6, 0x60, 0x36, 0xe6, 0xb4, 0xa3, 0x47, 0xa1, 0xc8, + 0x1e, 0x33, 0x60, 0xea, 0xa1, 0x14, 0xa9, 0x30, 0x3e, 0x38, 0x1c, 0x86, 0x3e, 0x67, 0xc0, 0x7c, + 0x3b, 0x76, 0xc0, 0x28, 0x35, 0xe7, 0x98, 0xc1, 0x9f, 0xf8, 0xa9, 0xa5, 0xf6, 0x28, 0x67, 0x9c, + 0x19, 0x4e, 0x72, 0xa7, 0x0b, 0x50, 0xa4, 0x63, 0x39, 0xc4, 0x67, 0xd8, 0xc2, 0xc6, 0x51, 0x24, + 0x56, 0xe3, 0x60, 0x9c, 0xc4, 0xa7, 0x33, 0xcc, 0x7a, 0x37, 0xce, 0xcb, 0xf3, 0x15, 0x49, 0x00, + 0x47, 0xb4, 0xd0, 0xb3, 0x30, 0x27, 0x5e, 0x94, 0xda, 0xf2, 0x1a, 0x97, 0xac, 0x60, 0x4f, 0x18, + 0xf7, 0xca, 0x19, 0x59, 0x8d, 0x41, 0x71, 0x02, 0x9b, 0xf5, 0x2d, 0x7a, 0xb6, 0x8b, 0x11, 0x98, + 0x88, 0xbf, 0x59, 0xba, 0x1a, 0x07, 0xe3, 0x24, 0x3e, 0x7a, 0x87, 0xa6, 0xf7, 0x79, 0xf0, 0x46, + 0x69, 0x83, 0x14, 0xdd, 0x5f, 0x81, 0xf9, 0x0e, 0xf3, 0x85, 0x1a, 0x12, 0x28, 0xd6, 0xa3, 0x62, + 0x78, 0x3d, 0x0e, 0xc6, 0x49, 0x7c, 0xf4, 0x0c, 0xcc, 0xfa, 0x54, 0xbb, 0x29, 0x02, 0x3c, 0xa2, + 0xa3, 0xc2, 0x0e, 0x58, 0x07, 0xe2, 0x38, 0x2e, 0x7a, 0x0e, 0x16, 0xa3, 0x67, 0x6e, 0x24, 0x01, + 0x1e, 0xe2, 0x51, 0xef, 0x46, 0x54, 0x92, 0x08, 0xb8, 0xbf, 0x0e, 0xfa, 0x45, 0x58, 0xd0, 0x46, + 0x62, 0xdd, 0x6d, 0x90, 0x3b, 0xe2, 0x29, 0x12, 0xf6, 0xad, 0x9d, 0xd5, 0x04, 0x0c, 0xf7, 0x61, + 0xa3, 0xf7, 0xc2, 0x5c, 0xdd, 0x73, 0x1c, 0xa6, 0xe3, 0xf8, 0x7b, 0x99, 0xfc, 0xcd, 0x11, 0xfe, + 0x3a, 0x4b, 0x0c, 0x82, 0x13, 0x98, 0xe8, 0x32, 0x20, 0x6f, 0x27, 0x20, 0xfe, 0x3e, 0x69, 0x3c, + 0xc7, 0xbf, 0x65, 0x45, 0xb7, 0xf8, 0xd9, 0x78, 0x32, 0xe8, 0xd5, 0x3e, 0x0c, 0x9c, 0x52, 0x8b, + 0x3d, 0x3b, 0xa1, 0x5d, 0xcc, 0x98, 0xcb, 0xe2, 0x15, 0xf6, 0xa4, 0xe7, 0x7e, 0xcf, 0x5b, 0x19, + 0x3e, 0x4c, 0xf0, 0xdc, 0xdc, 0xe5, 0xf9, 0x2c, 0x9e, 0xde, 0xd1, 0x9f, 0xce, 0x8b, 0xf6, 0x08, + 0x5e, 0x8a, 0x05, 0x27, 0xf4, 0x09, 0x98, 0xda, 0x91, 0xef, 0xa8, 0x2e, 0x2f, 0x64, 0xb1, 0x2f, + 0x26, 0x9e, 0x04, 0x8e, 0x3c, 0x53, 0x05, 0xc0, 0x11, 0x4b, 0xf4, 0x18, 0x4c, 0x5f, 0xda, 0xaa, + 0x28, 0x29, 0x5c, 0x64, 0xb3, 0x5f, 0xa0, 0x55, 0xb0, 0x0e, 0xa0, 0x2b, 0x4c, 0xd9, 0x4b, 0x88, + 0x4d, 0x71, 0xb4, 0xdf, 0xf6, 0x9b, 0x3f, 0x14, 0x9b, 0x45, 0xda, 0x70, 0x6d, 0xf9, 0x44, 0x02, + 0x5b, 0x94, 0x63, 0x85, 0x81, 0x5e, 0x82, 0x69, 0xb1, 0x5f, 0x30, 0xdd, 0xb4, 0x74, 0xb4, 0x4b, + 0x3f, 0x38, 0x22, 0x81, 0x75, 0x7a, 0xe8, 0x29, 0x98, 0x6e, 0xb3, 0xe7, 0x25, 0xc9, 0xc5, 0x8e, + 0xe3, 0x2c, 0x9f, 0x64, 0x7a, 0x53, 0x85, 0x20, 0xb6, 0x22, 0x10, 0xd6, 0xf1, 0xd0, 0x13, 0x32, + 0x9c, 0xfe, 0x96, 0x58, 0x44, 0x49, 0x85, 0xd3, 0x95, 0x95, 0x3b, 0x20, 0xdb, 0xf3, 0xd4, 0x3d, + 0xe2, 0xd8, 0x3b, 0x70, 0x5a, 0x9a, 0x58, 0xfd, 0x8b, 0x64, 0x79, 0x39, 0x76, 0x4a, 0x70, 0xfa, + 0xc6, 0x40, 0x4c, 0x7c, 0x08, 0x15, 0xb4, 0x0b, 0x79, 0xcb, 0xd9, 0x59, 0x7e, 0x30, 0x0b, 0x5b, + 0x51, 0x7d, 0x9b, 0x4e, 0x7b, 0x8a, 0x7a, 0xa3, 0x8a, 0x29, 0x03, 0xf3, 0xd5, 0xe8, 0xc8, 0x5b, + 0x3d, 0xcc, 0xf6, 0x71, 0x5d, 0xb2, 0x8d, 0x2c, 0xbe, 0xbf, 0xd4, 0xf7, 0xe0, 0x30, 0xdf, 0x94, + 0x52, 0xe5, 0xba, 0xad, 0xd6, 0x72, 0x26, 0x77, 0xfd, 0xe3, 0x8f, 0xce, 0x71, 0x8f, 0x2e, 0xbe, + 0x92, 0xcd, 0x1f, 0x16, 0xd4, 0x41, 0x54, 0x22, 0xd2, 0xed, 0x43, 0xd1, 0x0e, 0x42, 0xdb, 0xcb, + 0xf0, 0x3e, 0x4f, 0xe2, 0xb5, 0x36, 0x96, 0xd9, 0xc8, 0x00, 0x98, 0xb3, 0xa2, 0x3c, 0xdd, 0xa6, + 0xed, 0xde, 0x11, 0xdd, 0xbf, 0x96, 0x79, 0x08, 0x9b, 0xf3, 0x64, 0x00, 0xcc, 0x59, 0xa1, 0x9b, + 0x5c, 0xda, 0xb2, 0xf9, 0xd6, 0x56, 0xf2, 0x13, 0x7a, 0x3c, 0x2f, 0x48, 0x4a, 0x1c, 0xe5, 0x15, + 0xb4, 0x6c, 0x61, 0xc7, 0x8c, 0xc9, 0xab, 0xb6, 0xb9, 0x9e, 0xc6, 0xab, 0xb6, 0xb9, 0x8e, 0x29, + 0x13, 0xf4, 0xba, 0x01, 0x60, 0xa9, 0x6f, 0xc9, 0x65, 0xf3, 0x3a, 0xf7, 0xa0, 0x6f, 0xd3, 0xf1, + 0x64, 0xa4, 0x08, 0x8a, 0x35, 0xce, 0xe6, 0xbf, 0x18, 0xa0, 0x7d, 0x80, 0x27, 0xca, 0x84, 0x31, + 0x86, 0xce, 0x84, 0xc9, 0x8d, 0x98, 0x09, 0x93, 0x1f, 0x29, 0x13, 0xa6, 0x30, 0x7a, 0x26, 0x4c, + 0x71, 0x70, 0x26, 0x8c, 0xf9, 0x86, 0x01, 0x8b, 0x7d, 0x73, 0x93, 0xfc, 0xd0, 0xa1, 0x31, 0xe4, + 0x87, 0x0e, 0xd7, 0x60, 0x41, 0x3c, 0x5f, 0x58, 0x6b, 0x3b, 0x76, 0xea, 0x15, 0xc0, 0xed, 0x04, + 0x1c, 0xf7, 0xd5, 0x30, 0xff, 0xd4, 0x80, 0x69, 0xed, 0xc6, 0x02, 0xed, 0x07, 0xbb, 0xd9, 0x21, + 0x9a, 0x11, 0xbd, 0xdc, 0xc8, 0x8e, 0x1a, 0x39, 0x8c, 0x9f, 0x7a, 0x37, 0xb5, 0x07, 0xba, 0xa2, + 0x53, 0x6f, 0x5a, 0x8a, 0x05, 0x94, 0x3f, 0xbd, 0x44, 0xf8, 0x47, 0x2c, 0xf3, 0xfa, 0xd3, 0x4b, + 0xa4, 0x8d, 0x19, 0x84, 0xb1, 0xa3, 0xfb, 0x9a, 0x48, 0x92, 0xd2, 0x1e, 0x8a, 0xb4, 0xa8, 0xf7, + 0xc2, 0x60, 0xe8, 0x0c, 0xe4, 0x89, 0xdb, 0x10, 0x46, 0xb8, 0xd2, 0xd5, 0x17, 0xdc, 0x06, 0xa6, + 0xe5, 0xe6, 0x55, 0x98, 0xa9, 0x91, 0xba, 0x4f, 0xc2, 0xe7, 0xc9, 0xc1, 0xd0, 0xdf, 0x21, 0xb8, + 0x45, 0x0e, 0x92, 0xdf, 0x21, 0xa0, 0xd5, 0x69, 0xb9, 0xf9, 0x7b, 0x06, 0x24, 0xde, 0xed, 0xd4, + 0x4e, 0xc0, 0x8c, 0x41, 0x27, 0x60, 0xb1, 0xb3, 0x9a, 0xdc, 0xa1, 0x67, 0x35, 0x97, 0x01, 0xb5, + 0xac, 0xb0, 0xbe, 0x17, 0x7b, 0x55, 0x56, 0xf8, 0x3f, 0xd1, 0xfd, 0xa8, 0x3e, 0x0c, 0x9c, 0x52, + 0xcb, 0x7c, 0xc5, 0x80, 0xbe, 0x6f, 0x50, 0xd2, 0x5d, 0x9b, 0x88, 0x27, 0xde, 0xb9, 0x5b, 0xa8, + 0x76, 0x6d, 0xf9, 0xb2, 0xbb, 0x84, 0x53, 0xdf, 0x41, 0x9e, 0x3e, 0x49, 0x5f, 0x9e, 0xdf, 0x24, + 0x51, 0xbe, 0xc3, 0x5a, 0x1c, 0x8c, 0x93, 0xf8, 0xe6, 0x0b, 0x50, 0x92, 0xd7, 0xed, 0xd8, 0x9d, + 0x15, 0xe9, 0x8d, 0xea, 0x77, 0x56, 0xa8, 0x33, 0xca, 0x20, 0x74, 0x98, 0x02, 0xd7, 0xbe, 0xe4, + 0x05, 0xa1, 0xbc, 0x23, 0xc8, 0xcf, 0x9c, 0xae, 0xac, 0xb3, 0x32, 0xac, 0xa0, 0xe6, 0x22, 0xcc, + 0xab, 0xc3, 0x24, 0x2e, 0xf4, 0xe6, 0x37, 0xf3, 0x30, 0x13, 0xfb, 0xb2, 0xd0, 0xbd, 0x27, 0x7b, + 0xf8, 0x69, 0x49, 0x39, 0x14, 0xca, 0x8f, 0x78, 0x28, 0xa4, 0x9f, 0xc2, 0x15, 0x8e, 0xf7, 0x14, + 0xae, 0x98, 0xcd, 0x29, 0x5c, 0x08, 0x93, 0xe2, 0xab, 0xab, 0x22, 0xd5, 0x76, 0x33, 0xa3, 0xbb, + 0xf2, 0xe2, 0xd2, 0x29, 0xcb, 0x2e, 0x96, 0x0a, 0x4c, 0xb2, 0x32, 0xbf, 0x5e, 0x84, 0xb9, 0xf8, + 0xed, 0xf9, 0x21, 0x66, 0xf2, 0x1d, 0x7d, 0x33, 0x39, 0xa2, 0x53, 0x9c, 0x1f, 0xd7, 0x29, 0x2e, + 0x8c, 0xeb, 0x14, 0x17, 0x8f, 0xe0, 0x14, 0xf7, 0xbb, 0xb4, 0x13, 0x43, 0xbb, 0xb4, 0xef, 0x53, + 0x11, 0xdd, 0xc9, 0x58, 0x08, 0x24, 0x8a, 0xe8, 0xa2, 0xf8, 0x34, 0xac, 0x7a, 0x8d, 0xd4, 0xc8, + 0x78, 0xe9, 0x1e, 0xc6, 0xbf, 0x9f, 0x1a, 0x80, 0x1d, 0xfd, 0xdc, 0xed, 0x2d, 0x23, 0x04, 0x5f, + 0xa3, 0x0f, 0x0b, 0xb3, 0xcd, 0x0f, 0xe2, 0x1b, 0x67, 0x2d, 0x02, 0x61, 0x1d, 0x8f, 0x7d, 0x52, + 0x26, 0xfe, 0x0d, 0x1d, 0x76, 0xc6, 0xa0, 0x7f, 0x52, 0x26, 0xf1, 0xcd, 0x9d, 0x24, 0xbe, 0xf9, + 0xb5, 0x3c, 0xcc, 0xc5, 0x9f, 0x04, 0x47, 0xb7, 0x95, 0x7d, 0x9e, 0x89, 0x6b, 0xc0, 0xc9, 0x6a, + 0xf7, 0xc7, 0x07, 0x3a, 0xdc, 0xfc, 0x73, 0xb7, 0x3b, 0xea, 0x32, 0xfb, 0xf1, 0x31, 0x16, 0x9e, + 0xae, 0x60, 0xc7, 0x5e, 0x11, 0x8f, 0xb2, 0x35, 0x45, 0x14, 0x37, 0x73, 0xee, 0x51, 0xfe, 0xa5, + 0x62, 0x85, 0x35, 0xb6, 0x54, 0xbd, 0xef, 0x13, 0xdf, 0xde, 0xb5, 0xd5, 0xe7, 0x4c, 0x98, 0xf2, + 0x7c, 0x41, 0x94, 0x61, 0x05, 0x35, 0x5f, 0xc9, 0x41, 0xf4, 0xf1, 0x26, 0xf6, 0x3a, 0x71, 0xa0, + 0x99, 0x0d, 0x62, 0xda, 0x2e, 0x8f, 0xfb, 0x04, 0x78, 0x44, 0x51, 0x24, 0xbc, 0x68, 0x25, 0x38, + 0xc6, 0xf1, 0xe7, 0xf0, 0xd1, 0x26, 0x0b, 0xe6, 0x13, 0xb7, 0x30, 0x32, 0x4f, 0xd7, 0xfb, 0x52, + 0x1e, 0xa6, 0xd4, 0x3d, 0x16, 0xf4, 0x1e, 0xf6, 0xb0, 0xe8, 0x9e, 0x27, 0x9f, 0x7b, 0x7d, 0xab, + 0xf6, 0xfc, 0xe7, 0x9e, 0xd7, 0xb8, 0xdb, 0x2d, 0xcf, 0x2b, 0x64, 0x5e, 0x84, 0x45, 0x05, 0x6a, + 0xa4, 0x75, 0x7c, 0x27, 0x69, 0xa4, 0x5d, 0xc7, 0x1b, 0x98, 0x96, 0xa3, 0x3b, 0x30, 0xb9, 0x47, + 0xac, 0x06, 0xf1, 0x65, 0xfe, 0xc0, 0x66, 0x46, 0x77, 0x6f, 0x2e, 0x31, 0xaa, 0xd1, 0x30, 0xf0, + 0xff, 0x01, 0x96, 0xec, 0xe8, 0x46, 0xb5, 0xe3, 0x35, 0x0e, 0x92, 0xcf, 0x85, 0x56, 0xbd, 0xc6, + 0x01, 0x66, 0x10, 0xf4, 0x2c, 0xcc, 0x85, 0x76, 0x8b, 0x78, 0x9d, 0x50, 0xff, 0x34, 0x4e, 0x3e, + 0x3a, 0x40, 0xde, 0x8e, 0x41, 0x71, 0x02, 0x9b, 0x6e, 0x74, 0x37, 0x03, 0xcf, 0x65, 0x4f, 0x95, + 0x4c, 0xc4, 0x4f, 0x9b, 0x2e, 0xd7, 0xae, 0x5e, 0x61, 0x2f, 0x95, 0x28, 0x0c, 0x8a, 0x6d, 0xb3, + 0x64, 0x79, 0x9f, 0x88, 0xf8, 0xcd, 0x42, 0x74, 0xa5, 0x91, 0x97, 0x63, 0x85, 0x61, 0x5e, 0x87, + 0xf9, 0x44, 0x57, 0xa5, 0x39, 0x6c, 0xa4, 0x9b, 0xc3, 0xc3, 0xbd, 0xcd, 0xf9, 0x47, 0x06, 0x2c, + 0xf6, 0x2d, 0xde, 0x61, 0xf3, 0x48, 0x93, 0x9a, 0x3c, 0x77, 0x74, 0x4d, 0x9e, 0x1f, 0x4d, 0x93, + 0x57, 0x57, 0xbe, 0xf5, 0xa3, 0xb3, 0x0f, 0x7c, 0xfb, 0x47, 0x67, 0x1f, 0xf8, 0xee, 0x8f, 0xce, + 0x3e, 0xf0, 0x4a, 0xef, 0xac, 0xf1, 0xad, 0xde, 0x59, 0xe3, 0xdb, 0xbd, 0xb3, 0xc6, 0x77, 0x7b, + 0x67, 0x8d, 0x1f, 0xf6, 0xce, 0x1a, 0x6f, 0xfc, 0xf8, 0xec, 0x03, 0x2f, 0x96, 0xa4, 0x98, 0xfc, + 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0x63, 0x67, 0xc6, 0x88, 0xad, 0x82, 0x00, 0x00, } func (m *ALBStatus) Marshal() (dAtA []byte, err error) { @@ -3312,6 +3411,34 @@ func (m *AnalysisRunSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.MeasurementRetention) > 0 { + for iNdEx := len(m.MeasurementRetention) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.MeasurementRetention[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + } + if len(m.DryRun) > 0 { + for iNdEx := len(m.DryRun) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.DryRun[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } i-- if m.Terminate { dAtA[i] = 1 @@ -3371,6 +3498,28 @@ func (m *AnalysisRunStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.DryRunSummary != nil { + { + size, err := m.DryRunSummary.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + { + size, err := m.RunSummary.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a if m.StartedAt != nil { { size, err := m.StartedAt.MarshalToSizedBuffer(dAtA[:i]) @@ -3553,6 +3702,34 @@ func (m *AnalysisTemplateSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.MeasurementRetention) > 0 { + for iNdEx := len(m.MeasurementRetention) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.MeasurementRetention[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + if len(m.DryRun) > 0 { + for iNdEx := len(m.DryRun) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.DryRun[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } if len(m.Args) > 0 { for iNdEx := len(m.Args) - 1; iNdEx >= 0; iNdEx-- { { @@ -4626,6 +4803,34 @@ func (m *DatadogMetric) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *DryRun) 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 *DryRun) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DryRun) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.MetricName) + copy(dAtA[i:], m.MetricName) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.MetricName))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *Experiment) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -4915,10 +5120,24 @@ func (m *ExperimentSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.ScaleDownDelaySeconds != nil { - i = encodeVarintGenerated(dAtA, i, uint64(*m.ScaleDownDelaySeconds)) - i-- - dAtA[i] = 0x30 + if len(m.DryRun) > 0 { + for iNdEx := len(m.DryRun) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.DryRun[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } + } + if m.ScaleDownDelaySeconds != nil { + i = encodeVarintGenerated(dAtA, i, uint64(*m.ScaleDownDelaySeconds)) + i-- + dAtA[i] = 0x30 } if len(m.Analyses) > 0 { for iNdEx := len(m.Analyses) - 1; iNdEx >= 0; iNdEx-- { @@ -5562,6 +5781,37 @@ func (m *Measurement) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *MeasurementRetention) 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 *MeasurementRetention) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MeasurementRetention) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i = encodeVarintGenerated(dAtA, i, uint64(m.Limit)) + i-- + dAtA[i] = 0x10 + i -= len(m.MetricName) + copy(dAtA[i:], m.MetricName) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.MetricName))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *Metric) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -5819,6 +6069,14 @@ func (m *MetricResult) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + i-- + if m.DryRun { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x58 i = encodeVarintGenerated(dAtA, i, uint64(m.ConsecutiveError)) i-- dAtA[i] = 0x50 @@ -6261,6 +6519,20 @@ func (m *RolloutAnalysis) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.DryRun) > 0 { + for iNdEx := len(m.DryRun) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.DryRun[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } if len(m.Args) > 0 { for iNdEx := len(m.Args) - 1; iNdEx >= 0; iNdEx-- { { @@ -7202,6 +7474,44 @@ func (m *RolloutTrafficRouting) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *RunSummary) 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 *RunSummary) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RunSummary) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i = encodeVarintGenerated(dAtA, i, uint64(m.Error)) + i-- + dAtA[i] = 0x28 + i = encodeVarintGenerated(dAtA, i, uint64(m.Inconclusive)) + i-- + dAtA[i] = 0x20 + i = encodeVarintGenerated(dAtA, i, uint64(m.Failed)) + i-- + dAtA[i] = 0x18 + i = encodeVarintGenerated(dAtA, i, uint64(m.Successful)) + i-- + dAtA[i] = 0x10 + i = encodeVarintGenerated(dAtA, i, uint64(m.Count)) + i-- + dAtA[i] = 0x8 + return len(dAtA) - i, nil +} + func (m *SMITrafficRouting) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -8007,6 +8317,18 @@ func (m *AnalysisRunSpec) Size() (n int) { } } n += 2 + if len(m.DryRun) > 0 { + for _, e := range m.DryRun { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + if len(m.MeasurementRetention) > 0 { + for _, e := range m.MeasurementRetention { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } return n } @@ -8030,6 +8352,12 @@ func (m *AnalysisRunStatus) Size() (n int) { l = m.StartedAt.Size() n += 1 + l + sovGenerated(uint64(l)) } + l = m.RunSummary.Size() + n += 1 + l + sovGenerated(uint64(l)) + if m.DryRunSummary != nil { + l = m.DryRunSummary.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -8096,6 +8424,18 @@ func (m *AnalysisTemplateSpec) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) } } + if len(m.DryRun) > 0 { + for _, e := range m.DryRun { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + if len(m.MeasurementRetention) > 0 { + for _, e := range m.MeasurementRetention { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } return n } @@ -8489,6 +8829,17 @@ func (m *DatadogMetric) Size() (n int) { return n } +func (m *DryRun) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.MetricName) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + func (m *Experiment) Size() (n int) { if m == nil { return 0 @@ -8607,6 +8958,12 @@ func (m *ExperimentSpec) Size() (n int) { if m.ScaleDownDelaySeconds != nil { n += 1 + sovGenerated(uint64(*m.ScaleDownDelaySeconds)) } + if len(m.DryRun) > 0 { + for _, e := range m.DryRun { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } return n } @@ -8833,6 +9190,18 @@ func (m *Measurement) Size() (n int) { return n } +func (m *MeasurementRetention) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.MetricName) + n += 1 + l + sovGenerated(uint64(l)) + n += 1 + sovGenerated(uint64(m.Limit)) + return n +} + func (m *Metric) Size() (n int) { if m == nil { return 0 @@ -8939,6 +9308,7 @@ func (m *MetricResult) Size() (n int) { n += 1 + sovGenerated(uint64(m.Inconclusive)) n += 1 + sovGenerated(uint64(m.Error)) n += 1 + sovGenerated(uint64(m.ConsecutiveError)) + n += 2 return n } @@ -9094,6 +9464,12 @@ func (m *RolloutAnalysis) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) } } + if len(m.DryRun) > 0 { + for _, e := range m.DryRun { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } return n } @@ -9410,6 +9786,20 @@ func (m *RolloutTrafficRouting) Size() (n int) { return n } +func (m *RunSummary) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += 1 + sovGenerated(uint64(m.Count)) + n += 1 + sovGenerated(uint64(m.Successful)) + n += 1 + sovGenerated(uint64(m.Failed)) + n += 1 + sovGenerated(uint64(m.Inconclusive)) + n += 1 + sovGenerated(uint64(m.Error)) + return n +} + func (m *SMITrafficRouting) Size() (n int) { if m == nil { return 0 @@ -9761,10 +10151,22 @@ func (this *AnalysisRunSpec) String() string { repeatedStringForArgs += strings.Replace(strings.Replace(f.String(), "Argument", "Argument", 1), `&`, ``, 1) + "," } repeatedStringForArgs += "}" + repeatedStringForDryRun := "[]DryRun{" + for _, f := range this.DryRun { + repeatedStringForDryRun += strings.Replace(strings.Replace(f.String(), "DryRun", "DryRun", 1), `&`, ``, 1) + "," + } + repeatedStringForDryRun += "}" + repeatedStringForMeasurementRetention := "[]MeasurementRetention{" + for _, f := range this.MeasurementRetention { + repeatedStringForMeasurementRetention += strings.Replace(strings.Replace(f.String(), "MeasurementRetention", "MeasurementRetention", 1), `&`, ``, 1) + "," + } + repeatedStringForMeasurementRetention += "}" s := strings.Join([]string{`&AnalysisRunSpec{`, `Metrics:` + repeatedStringForMetrics + `,`, `Args:` + repeatedStringForArgs + `,`, `Terminate:` + fmt.Sprintf("%v", this.Terminate) + `,`, + `DryRun:` + repeatedStringForDryRun + `,`, + `MeasurementRetention:` + repeatedStringForMeasurementRetention + `,`, `}`, }, "") return s @@ -9783,6 +10185,8 @@ func (this *AnalysisRunStatus) String() string { `Message:` + fmt.Sprintf("%v", this.Message) + `,`, `MetricResults:` + repeatedStringForMetricResults + `,`, `StartedAt:` + strings.Replace(fmt.Sprintf("%v", this.StartedAt), "Time", "v1.Time", 1) + `,`, + `RunSummary:` + strings.Replace(strings.Replace(this.RunSummary.String(), "RunSummary", "RunSummary", 1), `&`, ``, 1) + `,`, + `DryRunSummary:` + strings.Replace(this.DryRunSummary.String(), "RunSummary", "RunSummary", 1) + `,`, `}`, }, "") return s @@ -9839,9 +10243,21 @@ func (this *AnalysisTemplateSpec) String() string { repeatedStringForArgs += strings.Replace(strings.Replace(f.String(), "Argument", "Argument", 1), `&`, ``, 1) + "," } repeatedStringForArgs += "}" + repeatedStringForDryRun := "[]DryRun{" + for _, f := range this.DryRun { + repeatedStringForDryRun += strings.Replace(strings.Replace(f.String(), "DryRun", "DryRun", 1), `&`, ``, 1) + "," + } + repeatedStringForDryRun += "}" + repeatedStringForMeasurementRetention := "[]MeasurementRetention{" + for _, f := range this.MeasurementRetention { + repeatedStringForMeasurementRetention += strings.Replace(strings.Replace(f.String(), "MeasurementRetention", "MeasurementRetention", 1), `&`, ``, 1) + "," + } + repeatedStringForMeasurementRetention += "}" s := strings.Join([]string{`&AnalysisTemplateSpec{`, `Metrics:` + repeatedStringForMetrics + `,`, `Args:` + repeatedStringForArgs + `,`, + `DryRun:` + repeatedStringForDryRun + `,`, + `MeasurementRetention:` + repeatedStringForMeasurementRetention + `,`, `}`, }, "") return s @@ -10093,6 +10509,16 @@ func (this *DatadogMetric) String() string { }, "") return s } +func (this *DryRun) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&DryRun{`, + `MetricName:` + fmt.Sprintf("%v", this.MetricName) + `,`, + `}`, + }, "") + return s +} func (this *Experiment) String() string { if this == nil { return "nil" @@ -10182,6 +10608,11 @@ func (this *ExperimentSpec) String() string { repeatedStringForAnalyses += strings.Replace(strings.Replace(f.String(), "ExperimentAnalysisTemplateRef", "ExperimentAnalysisTemplateRef", 1), `&`, ``, 1) + "," } repeatedStringForAnalyses += "}" + repeatedStringForDryRun := "[]DryRun{" + for _, f := range this.DryRun { + repeatedStringForDryRun += strings.Replace(strings.Replace(f.String(), "DryRun", "DryRun", 1), `&`, ``, 1) + "," + } + repeatedStringForDryRun += "}" s := strings.Join([]string{`&ExperimentSpec{`, `Templates:` + repeatedStringForTemplates + `,`, `Duration:` + fmt.Sprintf("%v", this.Duration) + `,`, @@ -10189,6 +10620,7 @@ func (this *ExperimentSpec) String() string { `Terminate:` + fmt.Sprintf("%v", this.Terminate) + `,`, `Analyses:` + repeatedStringForAnalyses + `,`, `ScaleDownDelaySeconds:` + valueToStringGenerated(this.ScaleDownDelaySeconds) + `,`, + `DryRun:` + repeatedStringForDryRun + `,`, `}`, }, "") return s @@ -10372,6 +10804,17 @@ func (this *Measurement) String() string { }, "") return s } +func (this *MeasurementRetention) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&MeasurementRetention{`, + `MetricName:` + fmt.Sprintf("%v", this.MetricName) + `,`, + `Limit:` + fmt.Sprintf("%v", this.Limit) + `,`, + `}`, + }, "") + return s +} func (this *Metric) String() string { if this == nil { return "nil" @@ -10423,13 +10866,13 @@ func (this *MetricResult) String() string { `Phase:` + fmt.Sprintf("%v", this.Phase) + `,`, `Measurements:` + repeatedStringForMeasurements + `,`, `Message:` + fmt.Sprintf("%v", this.Message) + `,`, - `Dry-Run:` + fmt.Sprintf("%v", this.DryRun) + `,`, `Count:` + fmt.Sprintf("%v", this.Count) + `,`, `Successful:` + fmt.Sprintf("%v", this.Successful) + `,`, `Failed:` + fmt.Sprintf("%v", this.Failed) + `,`, `Inconclusive:` + fmt.Sprintf("%v", this.Inconclusive) + `,`, `Error:` + fmt.Sprintf("%v", this.Error) + `,`, `ConsecutiveError:` + fmt.Sprintf("%v", this.ConsecutiveError) + `,`, + `DryRun:` + fmt.Sprintf("%v", this.DryRun) + `,`, `}`, }, "") return s @@ -10577,9 +11020,15 @@ func (this *RolloutAnalysis) String() string { repeatedStringForArgs += strings.Replace(strings.Replace(f.String(), "AnalysisRunArgument", "AnalysisRunArgument", 1), `&`, ``, 1) + "," } repeatedStringForArgs += "}" + repeatedStringForDryRun := "[]DryRun{" + for _, f := range this.DryRun { + repeatedStringForDryRun += strings.Replace(strings.Replace(f.String(), "DryRun", "DryRun", 1), `&`, ``, 1) + "," + } + repeatedStringForDryRun += "}" s := strings.Join([]string{`&RolloutAnalysis{`, `Templates:` + repeatedStringForTemplates + `,`, `Args:` + repeatedStringForArgs + `,`, + `DryRun:` + repeatedStringForDryRun + `,`, `}`, }, "") return s @@ -10805,6 +11254,20 @@ func (this *RolloutTrafficRouting) String() string { }, "") return s } +func (this *RunSummary) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&RunSummary{`, + `Count:` + fmt.Sprintf("%v", this.Count) + `,`, + `Successful:` + fmt.Sprintf("%v", this.Successful) + `,`, + `Failed:` + fmt.Sprintf("%v", this.Failed) + `,`, + `Inconclusive:` + fmt.Sprintf("%v", this.Inconclusive) + `,`, + `Error:` + fmt.Sprintf("%v", this.Error) + `,`, + `}`, + }, "") + return s +} func (this *SMITrafficRouting) String() string { if this == nil { return "nil" @@ -11145,7 +11608,10 @@ func (m *ALBStatus) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -11346,7 +11812,10 @@ func (m *ALBTrafficRouting) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -11428,7 +11897,10 @@ func (m *AmbassadorTrafficRouting) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -11577,7 +12049,10 @@ func (m *AnalysisRun) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -11727,7 +12202,10 @@ func (m *AnalysisRunArgument) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -11844,7 +12322,10 @@ func (m *AnalysisRunList) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -11976,61 +12457,11 @@ func (m *AnalysisRunSpec) Unmarshal(dAtA []byte) error { } } m.Terminate = bool(v != 0) - default: - iNdEx = preIndex - skippy, err := skipGenerated(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *AnalysisRunStatus) 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: AnalysisRunStatus: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: AnalysisRunStatus: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Phase", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field DryRun", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -12040,7 +12471,128 @@ func (m *AnalysisRunStatus) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DryRun = append(m.DryRun, DryRun{}) + if err := m.DryRun[len(m.DryRun)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MeasurementRetention", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MeasurementRetention = append(m.MeasurementRetention, MeasurementRetention{}) + if err := m.MeasurementRetention[len(m.MeasurementRetention)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + 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 *AnalysisRunStatus) 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: AnalysisRunStatus: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AnalysisRunStatus: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Phase", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -12160,13 +12712,85 @@ func (m *AnalysisRunStatus) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RunSummary", 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 err := m.RunSummary.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DryRunSummary", 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.DryRunSummary == nil { + m.DryRunSummary = &RunSummary{} + } + if err := m.DryRunSummary.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -12256,7 +12880,10 @@ func (m *AnalysisRunStrategy) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -12372,7 +12999,10 @@ func (m *AnalysisTemplate) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -12489,7 +13119,10 @@ func (m *AnalysisTemplateList) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -12601,13 +13234,84 @@ func (m *AnalysisTemplateSpec) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DryRun", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DryRun = append(m.DryRun, DryRun{}) + if err := m.DryRun[len(m.DryRun)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MeasurementRetention", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MeasurementRetention = append(m.MeasurementRetention, MeasurementRetention{}) + if err := m.MeasurementRetention[len(m.MeasurementRetention)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -12729,7 +13433,10 @@ func (m *AntiAffinity) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -12880,7 +13587,10 @@ func (m *Argument) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -12999,7 +13709,10 @@ func (m *ArgumentValueFrom) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -13113,7 +13826,10 @@ func (m *AwsResourceRef) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -13319,7 +14035,10 @@ func (m *BlueGreenStatus) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -13769,7 +14488,10 @@ func (m *BlueGreenStrategy) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -13959,7 +14681,10 @@ func (m *CanaryStatus) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -14173,7 +14898,10 @@ func (m *CanaryStep) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -14653,7 +15381,10 @@ func (m *CanaryStrategy) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -14769,7 +15500,10 @@ func (m *CloudWatchMetric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -15010,7 +15744,10 @@ func (m *CloudWatchMetricDataQuery) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -15190,7 +15927,10 @@ func (m *CloudWatchMetricStat) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -15339,7 +16079,10 @@ func (m *CloudWatchMetricStatMetric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -15453,7 +16196,10 @@ func (m *CloudWatchMetricStatMetricDimension) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -15569,7 +16315,10 @@ func (m *ClusterAnalysisTemplate) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -15617,7 +16366,127 @@ func (m *ClusterAnalysisTemplateList) Unmarshal(dAtA []byte) error { if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ListMeta", wireType) } - var msglen int + 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 err := m.ListMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Items", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Items = append(m.Items, ClusterAnalysisTemplate{}) + if err := m.Items[len(m.Items)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + 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 *DatadogMetric) 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: DatadogMetric: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DatadogMetric: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Interval", wireType) + } + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -15627,30 +16496,29 @@ func (m *ClusterAnalysisTemplateList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.ListMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.Interval = DurationString(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Items", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -15660,25 +16528,23 @@ func (m *ClusterAnalysisTemplateList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - m.Items = append(m.Items, ClusterAnalysisTemplate{}) - if err := m.Items[len(m.Items)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.Query = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -15686,7 +16552,10 @@ func (m *ClusterAnalysisTemplateList) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -15701,7 +16570,7 @@ func (m *ClusterAnalysisTemplateList) Unmarshal(dAtA []byte) error { } return nil } -func (m *DatadogMetric) Unmarshal(dAtA []byte) error { +func (m *DryRun) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -15724,47 +16593,15 @@ func (m *DatadogMetric) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: DatadogMetric: wiretype end group for non-group") + return fmt.Errorf("proto: DryRun: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: DatadogMetric: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: DryRun: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Interval", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenerated - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthGenerated - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Interval = DurationString(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MetricName", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -15792,7 +16629,7 @@ func (m *DatadogMetric) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Query = string(dAtA[iNdEx:postIndex]) + m.MetricName = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -15800,7 +16637,10 @@ func (m *DatadogMetric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -15949,7 +16789,10 @@ func (m *Experiment) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -16127,7 +16970,10 @@ func (m *ExperimentAnalysisRunStatus) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -16315,7 +17161,10 @@ func (m *ExperimentAnalysisTemplateRef) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -16559,7 +17408,10 @@ func (m *ExperimentCondition) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -16676,7 +17528,10 @@ func (m *ExperimentList) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -16880,13 +17735,50 @@ func (m *ExperimentSpec) Unmarshal(dAtA []byte) error { } } m.ScaleDownDelaySeconds = &v + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DryRun", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DryRun = append(m.DryRun, DryRun{}) + if err := m.DryRun[len(m.DryRun)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -17138,7 +18030,10 @@ func (m *ExperimentStatus) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -17220,7 +18115,10 @@ func (m *FieldRef) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -17334,7 +18232,10 @@ func (m *GraphiteMetric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -17480,7 +18381,10 @@ func (m *IstioDestinationRule) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -17636,7 +18540,10 @@ func (m *IstioTrafficRouting) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -17784,7 +18691,10 @@ func (m *IstioVirtualService) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -17900,7 +18810,10 @@ func (m *JobMetric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -18209,7 +19122,10 @@ func (m *KayentaMetric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -18357,7 +19273,10 @@ func (m *KayentaScope) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -18445,7 +19364,10 @@ func (m *KayentaThreshold) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -18773,7 +19695,7 @@ func (m *Measurement) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > postIndex { @@ -18826,7 +19748,114 @@ func (m *Measurement) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + 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 *MeasurementRetention) 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: MeasurementRetention: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MeasurementRetention: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MetricName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MetricName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + m.Limit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Limit |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + 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 { @@ -19213,7 +20242,10 @@ func (m *Metric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -19587,7 +20619,10 @@ func (m *MetricProvider) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -19860,7 +20895,26 @@ func (m *MetricResult) Unmarshal(dAtA []byte) error { if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field ConsecutiveError", wireType) } - m.ConsecutiveError = 0 + m.ConsecutiveError = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ConsecutiveError |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DryRun", wireType) + } + var v int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -19870,18 +20924,22 @@ func (m *MetricResult) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.ConsecutiveError |= int32(b&0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } } + m.DryRun = bool(v != 0) default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -19995,7 +21053,10 @@ func (m *NewRelicMetric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -20219,7 +21280,7 @@ func (m *NginxTrafficRouting) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > postIndex { @@ -20236,7 +21297,10 @@ func (m *NginxTrafficRouting) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -20382,7 +21446,10 @@ func (m *ObjectRef) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -20497,7 +21564,10 @@ func (m *PauseCondition) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -20657,7 +21727,7 @@ func (m *PodTemplateMetadata) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > postIndex { @@ -20784,7 +21854,7 @@ func (m *PodTemplateMetadata) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > postIndex { @@ -20801,7 +21871,10 @@ func (m *PodTemplateMetadata) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -20870,7 +21943,10 @@ func (m *PreferredDuringSchedulingIgnoredDuringExecution) Unmarshal(dAtA []byte) if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -20984,7 +22060,10 @@ func (m *PrometheusMetric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -21034,7 +22113,10 @@ func (m *RequiredDuringSchedulingIgnoredDuringExecution) Unmarshal(dAtA []byte) if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -21183,7 +22265,10 @@ func (m *Rollout) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -21295,13 +22380,50 @@ func (m *RolloutAnalysis) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DryRun", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DryRun = append(m.DryRun, DryRun{}) + if err := m.DryRun[len(m.DryRun)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -21404,7 +22526,10 @@ func (m *RolloutAnalysisBackground) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -21550,7 +22675,10 @@ func (m *RolloutAnalysisRunStatus) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -21652,7 +22780,10 @@ func (m *RolloutAnalysisTemplate) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -21896,7 +23027,10 @@ func (m *RolloutCondition) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -22046,7 +23180,10 @@ func (m *RolloutExperimentStep) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -22234,7 +23371,10 @@ func (m *RolloutExperimentStepAnalysisTemplateRef) Unmarshal(dAtA []byte) error if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -22457,7 +23597,10 @@ func (m *RolloutExperimentTemplate) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -22574,7 +23717,10 @@ func (m *RolloutList) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -22660,7 +23806,10 @@ func (m *RolloutPause) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -23039,7 +24188,10 @@ func (m *RolloutSpec) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -23779,7 +24931,10 @@ func (m *RolloutStatus) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -23901,7 +25056,10 @@ func (m *RolloutStrategy) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -24131,7 +25289,158 @@ func (m *RolloutTrafficRouting) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + 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 *RunSummary) 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: RunSummary: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RunSummary: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Count", wireType) + } + m.Count = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Count |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Successful", wireType) + } + m.Successful = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Successful |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Failed", wireType) + } + m.Failed = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Failed |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Inconclusive", wireType) + } + m.Inconclusive = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Inconclusive |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Error", wireType) + } + m.Error = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Error |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + 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 { @@ -24245,7 +25554,10 @@ func (m *SMITrafficRouting) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -24442,7 +25754,10 @@ func (m *ScopeDetail) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -24556,7 +25871,10 @@ func (m *SecretKeyRef) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -24666,7 +25984,10 @@ func (m *SetCanaryScale) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -24755,7 +26076,10 @@ func (m *StickinessConfig) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -24856,7 +26180,10 @@ func (m *TLSRoute) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -24906,7 +26233,10 @@ func (m *TemplateService) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -25132,7 +26462,10 @@ func (m *TemplateSpec) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -25474,7 +26807,10 @@ func (m *TemplateStatus) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -25645,7 +26981,10 @@ func (m *TrafficWeights) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -25767,7 +27106,10 @@ func (m *ValueFrom) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -25881,7 +27223,10 @@ func (m *WavefrontMetric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -26132,7 +27477,10 @@ func (m *WebMetric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -26246,7 +27594,10 @@ func (m *WebMetricHeader) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -26379,7 +27730,10 @@ func (m *WeightDestination) Unmarshal(dAtA []byte) error { if err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { diff --git a/pkg/apis/rollouts/v1alpha1/generated.proto b/pkg/apis/rollouts/v1alpha1/generated.proto index 7885f04580..300a6337e3 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.proto +++ b/pkg/apis/rollouts/v1alpha1/generated.proto @@ -1,5 +1,5 @@ /* -Copyright 2021 The Kubernetes sample-controller Authors. +Copyright 2022 The Kubernetes sample-controller Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,6 +24,8 @@ package github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1; import "k8s.io/api/batch/v1/generated.proto"; import "k8s.io/api/core/v1/generated.proto"; import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; import "k8s.io/apimachinery/pkg/util/intstr/generated.proto"; // Package-wide variables from generator "generated". @@ -114,6 +116,18 @@ message AnalysisRunSpec { // Terminate is used to prematurely stop the run (e.g. rollout completed and analysis is no longer desired) optional bool terminate = 3; + + // DryRun object contains the settings for running the analysis in Dry-Run mode + // +patchMergeKey=metricName + // +patchStrategy=merge + // +optional + repeated DryRun dryRun = 4; + + // MeasurementRetention object contains the settings for retaining the number of measurements during the analysis + // +patchMergeKey=metricName + // +patchStrategy=merge + // +optional + repeated MeasurementRetention measurementRetention = 5; } // AnalysisRunStatus is the status for a AnalysisRun resource @@ -129,6 +143,12 @@ message AnalysisRunStatus { // StartedAt indicates when the analysisRun first started optional k8s.io.apimachinery.pkg.apis.meta.v1.Time startedAt = 4; + + // RunSummary contains the final results from the metric executions + optional RunSummary runSummary = 5; + + // DryRunSummary contains the final results from the metric executions in the dry-run mode + optional RunSummary dryRunSummary = 6; } // AnalysisRunStrategy configuration for the analysis runs and experiments to retain @@ -172,6 +192,18 @@ message AnalysisTemplateSpec { // +patchStrategy=merge // +optional repeated Argument args = 2; + + // DryRun object contains the settings for running the analysis in Dry-Run mode + // +patchMergeKey=metricName + // +patchStrategy=merge + // +optional + repeated DryRun dryRun = 3; + + // MeasurementRetention object contains the settings for retaining the number of measurements during the analysis + // +patchMergeKey=metricName + // +patchStrategy=merge + // +optional + repeated MeasurementRetention measurementRetention = 4; } // AntiAffinity defines which inter-pod scheduling rule to use for anti-affinity injection @@ -492,6 +524,13 @@ message DatadogMetric { optional string query = 2; } +// DryRun defines the settings for running the analysis in Dry-Run mode. +message DryRun { + // Name of the metric which needs to be evaluated in the Dry-Run mode. Wildcard '*' is supported and denotes all + // the available metrics. + optional string metricName = 1; +} + // Experiment is a specification for an Experiment resource // +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object @@ -604,6 +643,12 @@ message ExperimentSpec { // more information // +optional optional int32 scaleDownDelaySeconds = 6; + + // DryRun object contains the settings for running the analysis in Dry-Run mode + // +patchMergeKey=metricName + // +patchStrategy=merge + // +optional + repeated DryRun dryRun = 7; } // ExperimentStatus is the status for a Experiment resource @@ -748,6 +793,15 @@ message Measurement { optional k8s.io.apimachinery.pkg.apis.meta.v1.Time resumeAt = 7; } +// MeasurementRetention defines the settings for retaining the number of measurements during the analysis. +message MeasurementRetention { + // MetricName is the name of the metric on which this retention policy should be applied. + optional string metricName = 1; + + // Limit is the maximum number of measurements to be retained for this given metric. + optional int32 limit = 2; +} + // Metric defines a metric in which to perform analysis message Metric { // Name is the name of the metric @@ -859,6 +913,9 @@ message MetricResult { // ConsecutiveError is the number of times an error was encountered during measurement in succession // Resets to zero when non-errors are encountered optional int32 consecutiveError = 10; + + // DryRun indicates whether this metric is running in a dry-run mode or not + optional bool dryRun = 11; } // NewRelicMetric defines the newrelic query to perform canary analysis @@ -950,6 +1007,12 @@ message RolloutAnalysis { // +patchMergeKey=name // +patchStrategy=merge repeated AnalysisRunArgument args = 2; + + // DryRun object contains the settings for running the analysis in Dry-Run mode + // +patchMergeKey=metricName + // +patchStrategy=merge + // +optional + repeated DryRun dryRun = 3; } // RolloutAnalysisBackground defines a template that is used to create a background analysisRun @@ -1265,6 +1328,24 @@ message RolloutTrafficRouting { optional AmbassadorTrafficRouting ambassador = 5; } +// RunSummary contains the final results from the metric executions +message RunSummary { + // This is equal to the sum of Successful, Failed, Inconclusive + optional int32 count = 1; + + // Successful is the number of times the metric was measured Successful + optional int32 successful = 2; + + // Failed is the number of times the metric was measured Failed + optional int32 failed = 3; + + // Inconclusive is the number of times the metric was measured Inconclusive + optional int32 inconclusive = 4; + + // Error is the number of times an error was encountered during measurement + optional int32 error = 5; +} + // SMITrafficRouting configuration for TrafficSplit Custom Resource to control traffic routing message SMITrafficRouting { // RootService holds the name of that clients use to communicate. diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index 67a31048bf..7e24562d25 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -1,7 +1,7 @@ // +build !ignore_autogenerated /* -Copyright 2021 The Kubernetes sample-controller Authors. +Copyright 2022 The Kubernetes sample-controller Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -58,6 +58,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ClusterAnalysisTemplate": schema_pkg_apis_rollouts_v1alpha1_ClusterAnalysisTemplate(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ClusterAnalysisTemplateList": schema_pkg_apis_rollouts_v1alpha1_ClusterAnalysisTemplateList(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DatadogMetric": schema_pkg_apis_rollouts_v1alpha1_DatadogMetric(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DryRun": schema_pkg_apis_rollouts_v1alpha1_DryRun(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Experiment": schema_pkg_apis_rollouts_v1alpha1_Experiment(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ExperimentAnalysisRunStatus": schema_pkg_apis_rollouts_v1alpha1_ExperimentAnalysisRunStatus(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ExperimentAnalysisTemplateRef": schema_pkg_apis_rollouts_v1alpha1_ExperimentAnalysisTemplateRef(ref), @@ -75,6 +76,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.KayentaScope": schema_pkg_apis_rollouts_v1alpha1_KayentaScope(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.KayentaThreshold": schema_pkg_apis_rollouts_v1alpha1_KayentaThreshold(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Measurement": schema_pkg_apis_rollouts_v1alpha1_Measurement(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.MeasurementRetention": schema_pkg_apis_rollouts_v1alpha1_MeasurementRetention(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Metric": schema_pkg_apis_rollouts_v1alpha1_Metric(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.MetricProvider": schema_pkg_apis_rollouts_v1alpha1_MetricProvider(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.MetricResult": schema_pkg_apis_rollouts_v1alpha1_MetricResult(ref), @@ -101,6 +103,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutStatus": schema_pkg_apis_rollouts_v1alpha1_RolloutStatus(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutStrategy": schema_pkg_apis_rollouts_v1alpha1_RolloutStrategy(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutTrafficRouting": schema_pkg_apis_rollouts_v1alpha1_RolloutTrafficRouting(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RunSummary": schema_pkg_apis_rollouts_v1alpha1_RunSummary(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SMITrafficRouting": schema_pkg_apis_rollouts_v1alpha1_SMITrafficRouting(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ScopeDetail": schema_pkg_apis_rollouts_v1alpha1_ScopeDetail(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SecretKeyRef": schema_pkg_apis_rollouts_v1alpha1_SecretKeyRef(ref), @@ -420,12 +423,52 @@ func schema_pkg_apis_rollouts_v1alpha1_AnalysisRunSpec(ref common.ReferenceCallb Format: "", }, }, + "dryRun": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "DryRun object contains the settings for running the analysis in Dry-Run mode", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DryRun"), + }, + }, + }, + }, + }, + "measurementRetention": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "MeasurementRetention object contains the settings for retaining the number of measurements during the analysis", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.MeasurementRetention"), + }, + }, + }, + }, + }, }, Required: []string{"metrics"}, }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Argument", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Metric"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Argument", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DryRun", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.MeasurementRetention", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Metric"}, } } @@ -471,12 +514,25 @@ func schema_pkg_apis_rollouts_v1alpha1_AnalysisRunStatus(ref common.ReferenceCal Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, + "runSummary": { + SchemaProps: spec.SchemaProps{ + Description: "RunSummary contains the final results from the metric executions", + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RunSummary"), + }, + }, + "dryRunSummary": { + SchemaProps: spec.SchemaProps{ + Description: "DryRunSummary contains the final results from the metric executions in the dry-run mode", + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RunSummary"), + }, + }, }, Required: []string{"phase"}, }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.MetricResult", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.MetricResult", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RunSummary", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } @@ -645,12 +701,52 @@ func schema_pkg_apis_rollouts_v1alpha1_AnalysisTemplateSpec(ref common.Reference }, }, }, + "dryRun": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "DryRun object contains the settings for running the analysis in Dry-Run mode", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DryRun"), + }, + }, + }, + }, + }, + "measurementRetention": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "MeasurementRetention object contains the settings for retaining the number of measurements during the analysis", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.MeasurementRetention"), + }, + }, + }, + }, + }, }, Required: []string{"metrics"}, }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Argument", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Metric"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Argument", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DryRun", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.MeasurementRetention", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Metric"}, } } @@ -1429,6 +1525,28 @@ func schema_pkg_apis_rollouts_v1alpha1_DatadogMetric(ref common.ReferenceCallbac } } +func schema_pkg_apis_rollouts_v1alpha1_DryRun(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "DryRun defines the settings for running the analysis in Dry-Run mode.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "metricName": { + SchemaProps: spec.SchemaProps{ + Description: "Name of the metric which needs to be evaluated in the Dry-Run mode. Wildcard '*' is supported and denotes all the available metrics.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"metricName"}, + }, + }, + } +} + func schema_pkg_apis_rollouts_v1alpha1_Experiment(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -1772,12 +1890,32 @@ func schema_pkg_apis_rollouts_v1alpha1_ExperimentSpec(ref common.ReferenceCallba Format: "int32", }, }, + "dryRun": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "DryRun object contains the settings for running the analysis in Dry-Run mode", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DryRun"), + }, + }, + }, + }, + }, }, Required: []string{"templates"}, }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ExperimentAnalysisTemplateRef", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TemplateSpec"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DryRun", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ExperimentAnalysisTemplateRef", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TemplateSpec"}, } } @@ -2275,6 +2413,36 @@ func schema_pkg_apis_rollouts_v1alpha1_Measurement(ref common.ReferenceCallback) } } +func schema_pkg_apis_rollouts_v1alpha1_MeasurementRetention(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "MeasurementRetention defines the settings for retaining the number of measurements during the analysis.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "metricName": { + SchemaProps: spec.SchemaProps{ + Description: "MetricName is the name of the metric on which this retention policy should be applied.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "limit": { + SchemaProps: spec.SchemaProps{ + Description: "Limit is the maximum number of measurements to be retained for this given metric.", + Default: 0, + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + Required: []string{"metricName", "limit"}, + }, + }, + } +} + func schema_pkg_apis_rollouts_v1alpha1_Metric(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -2513,6 +2681,13 @@ func schema_pkg_apis_rollouts_v1alpha1_MetricResult(ref common.ReferenceCallback Format: "int32", }, }, + "dryRun": { + SchemaProps: spec.SchemaProps{ + Description: "DryRun indicates whether this metric is running in a dry-run mode or not", + Type: []string{"boolean"}, + Format: "", + }, + }, }, Required: []string{"name", "phase"}, }, @@ -2852,11 +3027,31 @@ func schema_pkg_apis_rollouts_v1alpha1_RolloutAnalysis(ref common.ReferenceCallb }, }, }, + "dryRun": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "DryRun object contains the settings for running the analysis in Dry-Run mode", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DryRun"), + }, + }, + }, + }, + }, }, }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisRunArgument", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutAnalysisTemplate"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisRunArgument", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DryRun", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutAnalysisTemplate"}, } } @@ -2901,6 +3096,26 @@ func schema_pkg_apis_rollouts_v1alpha1_RolloutAnalysisBackground(ref common.Refe }, }, }, + "dryRun": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "DryRun object contains the settings for running the analysis in Dry-Run mode", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DryRun"), + }, + }, + }, + }, + }, "startingStep": { SchemaProps: spec.SchemaProps{ Description: "StartingStep indicates which step the background analysis should start on If not listed, controller defaults to 0", @@ -2912,7 +3127,7 @@ func schema_pkg_apis_rollouts_v1alpha1_RolloutAnalysisBackground(ref common.Refe }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisRunArgument", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutAnalysisTemplate"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisRunArgument", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DryRun", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutAnalysisTemplate"}, } } @@ -3662,6 +3877,54 @@ func schema_pkg_apis_rollouts_v1alpha1_RolloutTrafficRouting(ref common.Referenc } } +func schema_pkg_apis_rollouts_v1alpha1_RunSummary(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "RunSummary contains the final results from the metric executions", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "count": { + SchemaProps: spec.SchemaProps{ + Description: "This is equal to the sum of Successful, Failed, Inconclusive", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "successful": { + SchemaProps: spec.SchemaProps{ + Description: "Successful is the number of times the metric was measured Successful", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "failed": { + SchemaProps: spec.SchemaProps{ + Description: "Failed is the number of times the metric was measured Failed", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "inconclusive": { + SchemaProps: spec.SchemaProps{ + Description: "Inconclusive is the number of times the metric was measured Inconclusive", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "error": { + SchemaProps: spec.SchemaProps{ + Description: "Error is the number of times an error was encountered during measurement", + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + }, + }, + } +} + func schema_pkg_apis_rollouts_v1alpha1_SMITrafficRouting(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ From f41982075e251d9fabed7c3ba587f2e91379508a Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Thu, 13 Jan 2022 16:04:40 -0800 Subject: [PATCH 043/175] fix: status.alb should be optionally populated (#1766) Signed-off-by: Jesse Suen --- .github/workflows/go.yml | 10 +- pkg/apis/rollouts/v1alpha1/generated.pb.go | 889 +++++++++--------- .../rollouts/v1alpha1/openapi_generated.go | 1 - pkg/apis/rollouts/v1alpha1/types.go | 2 +- .../v1alpha1/zz_generated.deepcopy.go | 6 +- rollout/trafficrouting/alb/alb.go | 4 + rollout/trafficrouting/alb/alb_test.go | 13 +- 7 files changed, 471 insertions(+), 454 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index e7472b3c38..be83bb25c6 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -71,6 +71,12 @@ jobs: uses: actions/setup-go@v1 with: go-version: 1.16.2 + # k8s codegen generates files into GOPATH location instead of the GitHub git checkout location + # This symlink is necessary to ensure that `git diff` detects changes + - name: Create symlink in GOPATH + run: | + mkdir -p ~/go/src/github.com/argoproj + ln -s $(pwd) ~/go/src/github.com/argoproj/argo-rollouts - uses: actions/cache@v2 with: path: /home/runner/.cache/go-build @@ -92,10 +98,6 @@ jobs: - name: Add /usr/local/bin to PATH run: | echo "/usr/local/bin" >> $GITHUB_PATH - - name: Create links - run: | - mkdir -p ~/go/src/github.com/argoproj - cp -a ../argo-rollouts ~/go/src/github.com/argoproj - name: Run codegen run: | diff --git a/pkg/apis/rollouts/v1alpha1/generated.pb.go b/pkg/apis/rollouts/v1alpha1/generated.pb.go index 3f052727e0..b3fb258963 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.pb.go +++ b/pkg/apis/rollouts/v1alpha1/generated.pb.go @@ -2676,436 +2676,436 @@ func init() { } var fileDescriptor_e0e705f843545fab = []byte{ - // 6862 bytes of a gzipped FileDescriptorProto + // 6861 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x5d, 0x8c, 0x24, 0x57, 0x75, 0xb0, 0xab, 0x7f, 0x66, 0x7a, 0xce, 0xfc, 0xdf, 0x9d, 0x65, 0xc7, 0x6b, 0xef, 0xb6, 0x29, - 0x23, 0x7f, 0xe6, 0xfb, 0x60, 0x16, 0xd6, 0xf6, 0x17, 0x83, 0x91, 0x95, 0xee, 0x99, 0x5d, 0xef, - 0xac, 0x67, 0x76, 0x67, 0x6f, 0xcf, 0x7a, 0xc1, 0x60, 0x42, 0x4d, 0xf7, 0x9d, 0x9e, 0xda, 0xad, - 0xae, 0x6a, 0xaa, 0xaa, 0x67, 0x77, 0x0c, 0x02, 0x3b, 0xc8, 0x0e, 0x89, 0x40, 0x38, 0x01, 0x1e, - 0xa2, 0x88, 0x08, 0x45, 0x3c, 0x44, 0x21, 0x0f, 0x11, 0x4a, 0x94, 0x17, 0xa4, 0x44, 0x09, 0x48, - 0xe4, 0x21, 0x11, 0x91, 0x92, 0x00, 0x11, 0x74, 0xa0, 0x09, 0x0f, 0x89, 0x22, 0x45, 0x91, 0x88, - 0x22, 0x56, 0x8a, 0x14, 0xdd, 0xdf, 0xba, 0x55, 0x5d, 0x3d, 0xdb, 0x3d, 0x5d, 0xb3, 0x58, 0x49, - 0xde, 0xba, 0xef, 0x39, 0xf7, 0x9c, 0xfb, 0x73, 0xee, 0xb9, 0xe7, 0xdc, 0x73, 0xee, 0x2d, 0xd8, - 0x68, 0xda, 0xe1, 0x5e, 0x67, 0x67, 0xa5, 0xee, 0xb5, 0xce, 0x59, 0x7e, 0xd3, 0x6b, 0xfb, 0xde, - 0x4d, 0xf6, 0xe3, 0x9d, 0xbe, 0xe7, 0x38, 0x5e, 0x27, 0x0c, 0xce, 0xb5, 0x6f, 0x35, 0xcf, 0x59, - 0x6d, 0x3b, 0x38, 0xa7, 0x4a, 0xf6, 0xdf, 0x6d, 0x39, 0xed, 0x3d, 0xeb, 0xdd, 0xe7, 0x9a, 0xc4, - 0x25, 0xbe, 0x15, 0x92, 0xc6, 0x4a, 0xdb, 0xf7, 0x42, 0x0f, 0xbd, 0x2f, 0xa2, 0xb6, 0x22, 0xa9, - 0xb1, 0x1f, 0xbf, 0x24, 0xeb, 0xae, 0xb4, 0x6f, 0x35, 0x57, 0x28, 0xb5, 0x15, 0x55, 0x22, 0xa9, - 0x9d, 0x7e, 0xa7, 0xd6, 0x96, 0xa6, 0xd7, 0xf4, 0xce, 0x31, 0xa2, 0x3b, 0x9d, 0x5d, 0xf6, 0x8f, - 0xfd, 0x61, 0xbf, 0x38, 0xb3, 0xd3, 0x8f, 0xde, 0x7a, 0x3a, 0x58, 0xb1, 0x3d, 0xda, 0xb6, 0x73, - 0x3b, 0x56, 0x58, 0xdf, 0x3b, 0xb7, 0xdf, 0xd7, 0xa2, 0xd3, 0xa6, 0x86, 0x54, 0xf7, 0x7c, 0x92, - 0x86, 0xf3, 0x64, 0x84, 0xd3, 0xb2, 0xea, 0x7b, 0xb6, 0x4b, 0xfc, 0x83, 0xa8, 0xd7, 0x2d, 0x12, - 0x5a, 0x69, 0xb5, 0xce, 0x0d, 0xaa, 0xe5, 0x77, 0xdc, 0xd0, 0x6e, 0x91, 0xbe, 0x0a, 0xff, 0xff, - 0x5e, 0x15, 0x82, 0xfa, 0x1e, 0x69, 0x59, 0x7d, 0xf5, 0x9e, 0x18, 0x54, 0xaf, 0x13, 0xda, 0xce, - 0x39, 0xdb, 0x0d, 0x83, 0xd0, 0x4f, 0x56, 0x32, 0xbf, 0x91, 0x87, 0xa9, 0xca, 0x46, 0xb5, 0x16, - 0x5a, 0x61, 0x27, 0x40, 0xaf, 0x1b, 0x30, 0xe3, 0x78, 0x56, 0xa3, 0x6a, 0x39, 0x96, 0x5b, 0x27, - 0xfe, 0xb2, 0xf1, 0x88, 0xf1, 0xf8, 0xf4, 0xf9, 0x8d, 0x95, 0x71, 0xe6, 0x6b, 0xa5, 0x72, 0x3b, - 0xc0, 0x24, 0xf0, 0x3a, 0x7e, 0x9d, 0x60, 0xb2, 0x5b, 0x5d, 0xfa, 0x56, 0xb7, 0xfc, 0x40, 0xaf, - 0x5b, 0x9e, 0xd9, 0xd0, 0x38, 0xe1, 0x18, 0x5f, 0xf4, 0x45, 0x03, 0x16, 0xeb, 0x96, 0x6b, 0xf9, - 0x07, 0xdb, 0x96, 0xdf, 0x24, 0xe1, 0x73, 0xbe, 0xd7, 0x69, 0x2f, 0xe7, 0x8e, 0xa1, 0x35, 0x0f, - 0x8a, 0xd6, 0x2c, 0xae, 0x26, 0xd9, 0xe1, 0xfe, 0x16, 0xb0, 0x76, 0x05, 0xa1, 0xb5, 0xe3, 0x10, - 0xbd, 0x5d, 0xf9, 0xe3, 0x6c, 0x57, 0x2d, 0xc9, 0x0e, 0xf7, 0xb7, 0xc0, 0x7c, 0x2d, 0x0f, 0x8b, - 0x95, 0x8d, 0xea, 0xb6, 0x6f, 0xed, 0xee, 0xda, 0x75, 0xec, 0x75, 0x42, 0xdb, 0x6d, 0xa2, 0xb7, - 0xc3, 0xa4, 0xed, 0x36, 0x7d, 0x12, 0x04, 0x6c, 0x22, 0xa7, 0xaa, 0xf3, 0x82, 0xe8, 0xe4, 0x3a, - 0x2f, 0xc6, 0x12, 0x8e, 0x9e, 0x82, 0xe9, 0x80, 0xf8, 0xfb, 0x76, 0x9d, 0x6c, 0x79, 0x7e, 0xc8, - 0x46, 0xba, 0x58, 0x3d, 0x21, 0xd0, 0xa7, 0x6b, 0x11, 0x08, 0xeb, 0x78, 0xb4, 0x9a, 0xef, 0x79, - 0xa1, 0x80, 0xb3, 0x81, 0x98, 0x8a, 0xaa, 0xe1, 0x08, 0x84, 0x75, 0x3c, 0xf4, 0x86, 0x01, 0x0b, - 0x41, 0x68, 0xd7, 0x6f, 0xd9, 0x2e, 0x09, 0x82, 0x55, 0xcf, 0xdd, 0xb5, 0x9b, 0xcb, 0x45, 0x36, - 0x8a, 0x57, 0xc6, 0x1b, 0xc5, 0x5a, 0x82, 0x6a, 0x75, 0xa9, 0xd7, 0x2d, 0x2f, 0x24, 0x4b, 0x71, - 0x1f, 0x77, 0xb4, 0x06, 0x0b, 0x96, 0xeb, 0x7a, 0xa1, 0x15, 0xda, 0x9e, 0xbb, 0xe5, 0x93, 0x5d, - 0xfb, 0xce, 0x72, 0x81, 0x75, 0x67, 0x59, 0x74, 0x67, 0xa1, 0x92, 0x80, 0xe3, 0xbe, 0x1a, 0xe6, - 0x1a, 0x2c, 0x57, 0x5a, 0x3b, 0x56, 0x10, 0x58, 0x0d, 0xcf, 0x4f, 0xcc, 0xc6, 0xe3, 0x50, 0x6a, - 0x59, 0xed, 0xb6, 0xed, 0x36, 0xe9, 0x74, 0xe4, 0x1f, 0x9f, 0xaa, 0xce, 0xf4, 0xba, 0xe5, 0xd2, - 0xa6, 0x28, 0xc3, 0x0a, 0x6a, 0x7e, 0x2f, 0x07, 0xd3, 0x15, 0xd7, 0x72, 0x0e, 0x02, 0x3b, 0xc0, - 0x1d, 0x17, 0x7d, 0x04, 0x4a, 0x54, 0xbb, 0x34, 0xac, 0xd0, 0x12, 0x2b, 0xf2, 0x5d, 0x2b, 0x7c, - 0xb1, 0xaf, 0xe8, 0x8b, 0x3d, 0x1a, 0x17, 0x8a, 0xbd, 0xb2, 0xff, 0xee, 0x95, 0xab, 0x3b, 0x37, - 0x49, 0x3d, 0xdc, 0x24, 0xa1, 0x55, 0x45, 0xa2, 0x17, 0x10, 0x95, 0x61, 0x45, 0x15, 0x79, 0x50, - 0x08, 0xda, 0xa4, 0x2e, 0x56, 0xd8, 0xe6, 0x98, 0x92, 0x1c, 0x35, 0xbd, 0xd6, 0x26, 0xf5, 0xea, - 0x8c, 0x60, 0x5d, 0xa0, 0xff, 0x30, 0x63, 0x84, 0x6e, 0xc3, 0x44, 0xc0, 0x74, 0x8e, 0x58, 0x3c, - 0x57, 0xb3, 0x63, 0xc9, 0xc8, 0x56, 0xe7, 0x04, 0xd3, 0x09, 0xfe, 0x1f, 0x0b, 0x76, 0xe6, 0xdf, - 0x1b, 0x70, 0x42, 0xc3, 0xae, 0xf8, 0xcd, 0x4e, 0x8b, 0xb8, 0x21, 0x7a, 0x04, 0x0a, 0xae, 0xd5, - 0x22, 0x62, 0xa1, 0xa8, 0x26, 0x5f, 0xb1, 0x5a, 0x04, 0x33, 0x08, 0x7a, 0x14, 0x8a, 0xfb, 0x96, - 0xd3, 0x21, 0x6c, 0x90, 0xa6, 0xaa, 0xb3, 0x02, 0xa5, 0xf8, 0x02, 0x2d, 0xc4, 0x1c, 0x86, 0x3e, - 0x0e, 0x53, 0xec, 0xc7, 0x45, 0xdf, 0x6b, 0x65, 0xd4, 0x35, 0xd1, 0xc2, 0x17, 0x24, 0xd9, 0xea, - 0x6c, 0xaf, 0x5b, 0x9e, 0x52, 0x7f, 0x71, 0xc4, 0xd0, 0xfc, 0x07, 0x03, 0xe6, 0xb5, 0xce, 0x6d, - 0xd8, 0x41, 0x88, 0x3e, 0xd4, 0x27, 0x3c, 0x2b, 0xc3, 0x09, 0x0f, 0xad, 0xcd, 0x44, 0x67, 0x41, - 0xf4, 0xb4, 0x24, 0x4b, 0x34, 0xc1, 0x71, 0xa1, 0x68, 0x87, 0xa4, 0x15, 0x2c, 0xe7, 0x1e, 0xc9, - 0x3f, 0x3e, 0x7d, 0x7e, 0x3d, 0xb3, 0x69, 0x8c, 0xc6, 0x77, 0x9d, 0xd2, 0xc7, 0x9c, 0x8d, 0xf9, - 0xb5, 0x42, 0xac, 0x87, 0x54, 0xa2, 0x90, 0x07, 0x93, 0x2d, 0x12, 0xfa, 0x76, 0x9d, 0xaf, 0xab, - 0xe9, 0xf3, 0x6b, 0xe3, 0xb5, 0x62, 0x93, 0x11, 0x8b, 0x94, 0x25, 0xff, 0x1f, 0x60, 0xc9, 0x05, - 0xed, 0x41, 0xc1, 0xf2, 0x9b, 0xb2, 0xcf, 0x17, 0xb3, 0x99, 0xdf, 0x48, 0xe6, 0x2a, 0x7e, 0x33, - 0xc0, 0x8c, 0x03, 0x3a, 0x07, 0x53, 0x21, 0xf1, 0x5b, 0xb6, 0x6b, 0x85, 0x5c, 0xbb, 0x96, 0xaa, - 0x8b, 0x02, 0x6d, 0x6a, 0x5b, 0x02, 0x70, 0x84, 0x83, 0x1c, 0x98, 0x68, 0xf8, 0x07, 0xb8, 0xe3, - 0x2e, 0x17, 0xb2, 0x18, 0x8a, 0x35, 0x46, 0x2b, 0x5a, 0x4c, 0xfc, 0x3f, 0x16, 0x3c, 0xd0, 0x57, - 0x0c, 0x58, 0x6a, 0x11, 0x2b, 0xe8, 0xf8, 0x84, 0x76, 0x01, 0x93, 0x90, 0xb8, 0x54, 0x1b, 0x2e, - 0x17, 0x19, 0x73, 0x3c, 0xee, 0x3c, 0xf4, 0x53, 0xae, 0x3e, 0x2c, 0x9a, 0xb2, 0x94, 0x06, 0xc5, - 0xa9, 0xad, 0x31, 0xbf, 0x57, 0x80, 0xc5, 0x3e, 0x0d, 0x81, 0x9e, 0x84, 0x62, 0x7b, 0xcf, 0x0a, - 0xe4, 0x92, 0x3f, 0x2b, 0xe5, 0x6d, 0x8b, 0x16, 0xde, 0xed, 0x96, 0x67, 0x65, 0x15, 0x56, 0x80, - 0x39, 0x32, 0xdd, 0x53, 0x5b, 0x24, 0x08, 0xac, 0xa6, 0xd4, 0x03, 0x9a, 0x98, 0xb0, 0x62, 0x2c, - 0xe1, 0xe8, 0x57, 0x0c, 0x98, 0xe5, 0x22, 0x83, 0x49, 0xd0, 0x71, 0x42, 0xaa, 0xeb, 0xe8, 0xb0, - 0x5c, 0xce, 0x42, 0x3c, 0x39, 0xc9, 0xea, 0x49, 0xc1, 0x7d, 0x56, 0x2f, 0x0d, 0x70, 0x9c, 0x2f, - 0xba, 0x01, 0x53, 0x41, 0x68, 0xf9, 0x21, 0x69, 0x54, 0x42, 0xb6, 0xab, 0x4d, 0x9f, 0xff, 0xbf, - 0xc3, 0x29, 0x81, 0x6d, 0xbb, 0x45, 0xb8, 0xc2, 0xa9, 0x49, 0x02, 0x38, 0xa2, 0x85, 0x3e, 0x0e, - 0xe0, 0x77, 0xdc, 0x5a, 0xa7, 0xd5, 0xb2, 0xfc, 0x03, 0xb1, 0x83, 0x5f, 0x1a, 0xaf, 0x7b, 0x58, - 0xd1, 0x8b, 0xf6, 0xac, 0xa8, 0x0c, 0x6b, 0xfc, 0xd0, 0xab, 0x06, 0xcc, 0x72, 0x49, 0x94, 0x2d, - 0x98, 0xc8, 0xb8, 0x05, 0x8b, 0x74, 0x68, 0xd7, 0x74, 0x16, 0x38, 0xce, 0xd1, 0xfc, 0xdb, 0xf8, - 0x7e, 0x52, 0x0b, 0xa9, 0x75, 0xdd, 0x3c, 0x40, 0x1f, 0x84, 0x07, 0x83, 0x4e, 0xbd, 0x4e, 0x82, - 0x60, 0xb7, 0xe3, 0xe0, 0x8e, 0x7b, 0xc9, 0x0e, 0x42, 0xcf, 0x3f, 0xd8, 0xb0, 0x5b, 0x76, 0xc8, - 0x24, 0xae, 0x58, 0x3d, 0xd3, 0xeb, 0x96, 0x1f, 0xac, 0x0d, 0x42, 0xc2, 0x83, 0xeb, 0x23, 0x0b, - 0x1e, 0xea, 0xb8, 0x83, 0xc9, 0x73, 0xeb, 0xad, 0xdc, 0xeb, 0x96, 0x1f, 0xba, 0x3e, 0x18, 0x0d, - 0x1f, 0x46, 0xc3, 0xfc, 0x67, 0x03, 0x16, 0x64, 0xbf, 0xb6, 0x49, 0xab, 0xed, 0x50, 0xed, 0x72, - 0xfc, 0x86, 0x48, 0x18, 0x33, 0x44, 0x70, 0x36, 0xdb, 0x89, 0x6c, 0xff, 0x20, 0x6b, 0xc4, 0xfc, - 0x27, 0x03, 0x96, 0x92, 0xc8, 0xf7, 0x61, 0xf3, 0x0c, 0xe2, 0x9b, 0xe7, 0x95, 0x6c, 0x7b, 0x3b, - 0x60, 0x07, 0x7d, 0xbd, 0xd0, 0xdf, 0xd7, 0xff, 0xee, 0xdb, 0x68, 0xb4, 0x2b, 0xe6, 0x7f, 0x9e, - 0xbb, 0x62, 0xe1, 0x4d, 0xb5, 0x2b, 0xfe, 0x6e, 0x01, 0x66, 0x2a, 0x6e, 0x68, 0x57, 0x76, 0x77, - 0x6d, 0xd7, 0x0e, 0x0f, 0xd0, 0x67, 0x72, 0x70, 0xae, 0xed, 0x93, 0x5d, 0xe2, 0xfb, 0xa4, 0xb1, - 0xd6, 0xf1, 0x6d, 0xb7, 0x59, 0xab, 0xef, 0x91, 0x46, 0xc7, 0xb1, 0xdd, 0xe6, 0x7a, 0xd3, 0xf5, - 0x54, 0xf1, 0x85, 0x3b, 0xa4, 0xde, 0x61, 0x5d, 0xe2, 0x8b, 0xa2, 0x35, 0x5e, 0x97, 0xb6, 0x46, - 0x63, 0x5a, 0x7d, 0xa2, 0xd7, 0x2d, 0x9f, 0x1b, 0xb1, 0x12, 0x1e, 0xb5, 0x6b, 0xe8, 0xd3, 0x39, - 0x58, 0xf1, 0xc9, 0x47, 0x3b, 0xf6, 0xf0, 0xa3, 0xc1, 0xb5, 0x96, 0x33, 0xe6, 0xf6, 0x33, 0x12, - 0xcf, 0xea, 0xf9, 0x5e, 0xb7, 0x3c, 0x62, 0x1d, 0x3c, 0x62, 0xbf, 0xcc, 0x3f, 0x37, 0xa0, 0x34, - 0x82, 0xa7, 0x54, 0x8e, 0x7b, 0x4a, 0x53, 0x7d, 0x5e, 0x52, 0xd8, 0xef, 0x25, 0x3d, 0x37, 0xde, - 0xa0, 0x0d, 0xe3, 0x1d, 0xfd, 0xab, 0x01, 0x8b, 0x7d, 0xde, 0x14, 0xda, 0x83, 0xa5, 0xb6, 0xd7, - 0x90, 0x9a, 0xf0, 0x92, 0x15, 0xec, 0x31, 0x98, 0xe8, 0xde, 0x93, 0x74, 0x51, 0x6d, 0xa5, 0xc0, - 0xef, 0x76, 0xcb, 0xcb, 0x8a, 0x48, 0x02, 0x01, 0xa7, 0x52, 0x44, 0x6d, 0x28, 0xed, 0xda, 0xc4, - 0x69, 0x60, 0xb2, 0x2b, 0x24, 0x65, 0x4c, 0x9d, 0x77, 0x51, 0x50, 0xe3, 0x07, 0x09, 0xf2, 0x1f, - 0x56, 0x5c, 0xcc, 0x6b, 0x30, 0x17, 0x3f, 0x56, 0x1a, 0x62, 0xf2, 0xce, 0x40, 0xde, 0xf2, 0x5d, - 0x31, 0x75, 0xd3, 0x02, 0x21, 0x5f, 0xc1, 0x57, 0x30, 0x2d, 0x37, 0x7f, 0x56, 0x80, 0xf9, 0xaa, - 0xd3, 0x21, 0xcf, 0xf9, 0x84, 0x48, 0x4b, 0xba, 0x02, 0xf3, 0x6d, 0x9f, 0xec, 0xdb, 0xe4, 0x76, - 0x8d, 0x38, 0xa4, 0x1e, 0x7a, 0xbe, 0xa0, 0x7f, 0x4a, 0x54, 0x9f, 0xdf, 0x8a, 0x83, 0x71, 0x12, - 0x1f, 0x3d, 0x0b, 0x73, 0x56, 0x3d, 0xb4, 0xf7, 0x89, 0xa2, 0xc0, 0x1b, 0xf0, 0x16, 0x41, 0x61, - 0xae, 0x12, 0x83, 0xe2, 0x04, 0x36, 0xfa, 0x10, 0x2c, 0x07, 0x75, 0xcb, 0x21, 0xd7, 0xdb, 0x82, - 0xd5, 0xea, 0x1e, 0xa9, 0xdf, 0xda, 0xf2, 0x6c, 0x37, 0x14, 0x7e, 0xd3, 0x23, 0x82, 0xd2, 0x72, - 0x6d, 0x00, 0x1e, 0x1e, 0x48, 0x01, 0xfd, 0x89, 0x01, 0x67, 0xda, 0x3e, 0xd9, 0xf2, 0xbd, 0x96, - 0x47, 0x17, 0x44, 0x9f, 0x33, 0x21, 0x8c, 0xea, 0x17, 0xc6, 0x5c, 0xf9, 0xbc, 0xa4, 0xff, 0x30, - 0xe3, 0xad, 0xbd, 0x6e, 0xf9, 0xcc, 0xd6, 0x61, 0x0d, 0xc0, 0x87, 0xb7, 0x0f, 0xfd, 0x99, 0x01, - 0x67, 0xdb, 0x5e, 0x10, 0x1e, 0xd2, 0x85, 0xe2, 0xb1, 0x76, 0xc1, 0xec, 0x75, 0xcb, 0x67, 0xb7, - 0x0e, 0x6d, 0x01, 0xbe, 0x47, 0x0b, 0xcd, 0xde, 0x34, 0x2c, 0x6a, 0xb2, 0x27, 0x2c, 0xed, 0x67, - 0x60, 0x56, 0x0a, 0x03, 0x3f, 0x85, 0xe4, 0xb2, 0xa7, 0x3c, 0xa3, 0x8a, 0x0e, 0xc4, 0x71, 0x5c, - 0x2a, 0x77, 0x4a, 0x14, 0x79, 0xed, 0x84, 0xdc, 0x6d, 0xc5, 0xa0, 0x38, 0x81, 0x8d, 0xd6, 0xe1, - 0x84, 0x28, 0xc1, 0xa4, 0xed, 0xd8, 0x75, 0x6b, 0xd5, 0xeb, 0x08, 0x91, 0x2b, 0x56, 0x4f, 0xf5, - 0xba, 0xe5, 0x13, 0x5b, 0xfd, 0x60, 0x9c, 0x56, 0x07, 0x6d, 0xc0, 0x92, 0xd5, 0x09, 0x3d, 0xd5, - 0xff, 0x0b, 0xae, 0xb5, 0xe3, 0x90, 0x06, 0x13, 0xad, 0x52, 0x75, 0x99, 0x2a, 0xa2, 0x4a, 0x0a, - 0x1c, 0xa7, 0xd6, 0x42, 0x5b, 0x09, 0x6a, 0x35, 0x52, 0xf7, 0xdc, 0x06, 0x9f, 0xe5, 0x62, 0x64, - 0x2f, 0x54, 0x52, 0x70, 0x70, 0x6a, 0x4d, 0xe4, 0xc0, 0x5c, 0xcb, 0xba, 0x73, 0xdd, 0xb5, 0xf6, - 0x2d, 0xdb, 0xa1, 0x4c, 0x84, 0xb7, 0x35, 0xd8, 0x05, 0xe8, 0x84, 0xb6, 0xb3, 0xc2, 0x03, 0x0f, - 0x2b, 0xeb, 0x6e, 0x78, 0xd5, 0xaf, 0x85, 0x74, 0x5f, 0xa9, 0x22, 0x3a, 0xb0, 0x9b, 0x31, 0x5a, - 0x38, 0x41, 0x1b, 0x5d, 0x85, 0x93, 0x6c, 0x39, 0xae, 0x79, 0xb7, 0xdd, 0x35, 0xe2, 0x58, 0x07, - 0xb2, 0x03, 0x93, 0xac, 0x03, 0x0f, 0xf6, 0xba, 0xe5, 0x93, 0xb5, 0x34, 0x04, 0x9c, 0x5e, 0x8f, - 0xfa, 0x4c, 0x71, 0x00, 0x26, 0xfb, 0x76, 0x60, 0x7b, 0x2e, 0xf7, 0x99, 0x4a, 0x91, 0xcf, 0x54, - 0x1b, 0x8c, 0x86, 0x0f, 0xa3, 0x81, 0x7e, 0xcb, 0x80, 0xa5, 0xb4, 0x65, 0xb8, 0x3c, 0x95, 0xc5, - 0xb1, 0x6a, 0x62, 0x69, 0x71, 0x89, 0x48, 0x55, 0x0a, 0xa9, 0x8d, 0x40, 0xaf, 0x18, 0x30, 0x63, - 0x69, 0xf6, 0xde, 0x32, 0xb0, 0x56, 0x5d, 0x1e, 0xd7, 0xeb, 0x88, 0x28, 0x56, 0x17, 0x7a, 0xdd, - 0x72, 0xcc, 0xa6, 0xc4, 0x31, 0x8e, 0xe8, 0xb7, 0x0d, 0x38, 0x99, 0xba, 0xc6, 0x97, 0xa7, 0x8f, - 0x63, 0x84, 0x98, 0x90, 0xa4, 0xeb, 0x9c, 0xf4, 0x66, 0xa0, 0x37, 0x0c, 0xb5, 0x95, 0x6d, 0x4a, - 0xbf, 0x6f, 0x86, 0x35, 0xed, 0xda, 0x98, 0x26, 0x6e, 0x64, 0x10, 0x48, 0xc2, 0xd5, 0x13, 0xda, - 0xce, 0x28, 0x0b, 0x71, 0x92, 0x3d, 0xfa, 0xac, 0x21, 0xb7, 0x46, 0xd5, 0xa2, 0xd9, 0xe3, 0x6a, - 0x11, 0x8a, 0x76, 0x5a, 0xd5, 0xa0, 0x04, 0x73, 0xf4, 0x61, 0x38, 0x6d, 0xed, 0x78, 0x7e, 0x98, - 0xba, 0xf8, 0x96, 0xe7, 0xd8, 0x32, 0x3a, 0xdb, 0xeb, 0x96, 0x4f, 0x57, 0x06, 0x62, 0xe1, 0x43, - 0x28, 0x98, 0xdf, 0x2f, 0xc0, 0x0c, 0x8f, 0xc5, 0x89, 0xad, 0xeb, 0xeb, 0x06, 0x3c, 0x5c, 0xef, - 0xf8, 0x3e, 0x71, 0xc3, 0x5a, 0x48, 0xda, 0xfd, 0x1b, 0x97, 0x71, 0xac, 0x1b, 0xd7, 0x23, 0xbd, - 0x6e, 0xf9, 0xe1, 0xd5, 0x43, 0xf8, 0xe3, 0x43, 0x5b, 0x87, 0xfe, 0xca, 0x00, 0x53, 0x20, 0x54, - 0xad, 0xfa, 0xad, 0xa6, 0xef, 0x75, 0xdc, 0x46, 0x7f, 0x27, 0x72, 0xc7, 0xda, 0x89, 0xc7, 0x7a, - 0xdd, 0xb2, 0xb9, 0x7a, 0xcf, 0x56, 0xe0, 0x21, 0x5a, 0x8a, 0x9e, 0x83, 0x45, 0x81, 0x75, 0xe1, - 0x4e, 0x9b, 0xf8, 0x36, 0x35, 0xa7, 0x45, 0xe4, 0x2f, 0x0a, 0xa6, 0x26, 0x11, 0x70, 0x7f, 0x1d, - 0x14, 0xc0, 0xe4, 0x6d, 0x62, 0x37, 0xf7, 0x42, 0x69, 0x3e, 0x8d, 0x19, 0x41, 0x15, 0xf1, 0xb6, - 0x1b, 0x9c, 0x66, 0x75, 0xba, 0xd7, 0x2d, 0x4f, 0x8a, 0x3f, 0x58, 0x72, 0x32, 0xff, 0xa0, 0x00, - 0x20, 0xc5, 0x8b, 0xb4, 0xd1, 0xff, 0x83, 0xa9, 0x80, 0x84, 0x1c, 0x4b, 0x1c, 0xcb, 0xf1, 0xd3, - 0x4e, 0x59, 0x88, 0x23, 0x38, 0xba, 0x05, 0xc5, 0xb6, 0xd5, 0x09, 0x88, 0x98, 0xac, 0xcb, 0x99, - 0x4c, 0xd6, 0x16, 0xa5, 0xc8, 0x7d, 0x24, 0xf6, 0x13, 0x73, 0x1e, 0xe8, 0x53, 0x06, 0x00, 0x89, - 0x0f, 0xf0, 0xf4, 0xf9, 0x5a, 0x26, 0x2c, 0xa3, 0x39, 0xa0, 0x63, 0x50, 0x9d, 0xeb, 0x75, 0xcb, - 0xa0, 0x4d, 0x95, 0xc6, 0x16, 0xdd, 0x86, 0x92, 0x25, 0x75, 0x74, 0xe1, 0x38, 0x74, 0x34, 0x73, - 0x5d, 0x94, 0x90, 0x29, 0x66, 0xe8, 0xd3, 0x06, 0xcc, 0x05, 0x24, 0x14, 0x53, 0x45, 0x35, 0x85, - 0x30, 0x50, 0xc7, 0x14, 0x92, 0x5a, 0x8c, 0x26, 0xd7, 0x78, 0xf1, 0x32, 0x9c, 0xe0, 0x6b, 0x7e, - 0x7f, 0x1a, 0xe6, 0xa4, 0xc8, 0x44, 0x36, 0x27, 0x4f, 0x0e, 0x18, 0x60, 0x73, 0xae, 0xea, 0x40, - 0x1c, 0xc7, 0xa5, 0x95, 0x79, 0x04, 0x3f, 0x6e, 0x72, 0xaa, 0xca, 0x35, 0x1d, 0x88, 0xe3, 0xb8, - 0xa8, 0x05, 0xc5, 0x20, 0x24, 0x6d, 0x19, 0x4b, 0x18, 0xf3, 0xa8, 0x3b, 0x5a, 0x09, 0xd1, 0x69, - 0x21, 0xfd, 0x17, 0x60, 0xce, 0x05, 0x7d, 0xce, 0x80, 0xb9, 0x30, 0x16, 0xc7, 0x16, 0x62, 0x90, - 0x8d, 0x24, 0xc6, 0x43, 0xe4, 0x7c, 0x36, 0xe2, 0x65, 0x38, 0xc1, 0x3e, 0xc5, 0x0c, 0x2d, 0x1e, - 0xa3, 0x19, 0xfa, 0x22, 0x94, 0x5a, 0xd6, 0x9d, 0x5a, 0xc7, 0x6f, 0x1e, 0xdd, 0xdc, 0x15, 0x61, - 0x7e, 0x4e, 0x05, 0x2b, 0x7a, 0xe8, 0x55, 0x43, 0x5b, 0x5c, 0x93, 0x8c, 0xf8, 0x8d, 0x6c, 0x17, - 0x97, 0xd2, 0xe2, 0x03, 0x97, 0x59, 0x9f, 0x51, 0x58, 0xba, 0xef, 0x46, 0x21, 0x35, 0x70, 0xf8, - 0x02, 0x51, 0x06, 0xce, 0xd4, 0xb1, 0x1a, 0x38, 0xab, 0x31, 0x66, 0x38, 0xc1, 0x9c, 0xb5, 0x87, - 0xaf, 0x39, 0xd5, 0x1e, 0x38, 0xd6, 0xf6, 0xd4, 0x62, 0xcc, 0x70, 0x82, 0xf9, 0x60, 0x4f, 0x68, - 0xfa, 0x78, 0x3c, 0xa1, 0x99, 0x0c, 0x3c, 0xa1, 0xc3, 0x8d, 0xc4, 0xd9, 0x71, 0x8d, 0x44, 0x74, - 0x19, 0x50, 0xe3, 0xc0, 0xb5, 0x5a, 0x76, 0x5d, 0x28, 0x4b, 0xb6, 0x41, 0xcc, 0x31, 0x4f, 0xf9, - 0xb4, 0x50, 0x64, 0x68, 0xad, 0x0f, 0x03, 0xa7, 0xd4, 0x32, 0xff, 0xdd, 0x80, 0x85, 0x55, 0xc7, - 0xeb, 0x34, 0x6e, 0x58, 0x61, 0x7d, 0x8f, 0x47, 0x29, 0xd0, 0xb3, 0x50, 0xb2, 0xdd, 0x90, 0xf8, - 0xfb, 0x96, 0x23, 0x74, 0xbb, 0x29, 0x03, 0x39, 0xeb, 0xa2, 0xfc, 0x6e, 0xb7, 0x3c, 0xb7, 0xd6, - 0xf1, 0x59, 0xfa, 0x0f, 0x5f, 0xe9, 0x58, 0xd5, 0x41, 0x5f, 0x36, 0x60, 0x91, 0xc7, 0x39, 0xd6, - 0xac, 0xd0, 0xba, 0xd6, 0x21, 0xbe, 0x4d, 0x64, 0xa4, 0x63, 0xcc, 0x45, 0x9e, 0x6c, 0xab, 0x64, - 0x70, 0x10, 0x99, 0x5f, 0x9b, 0x49, 0xce, 0xb8, 0xbf, 0x31, 0xe6, 0xe7, 0xf3, 0xf0, 0xe0, 0x40, - 0x5a, 0xe8, 0x34, 0xe4, 0xec, 0x86, 0xe8, 0x3a, 0x08, 0xba, 0xb9, 0xf5, 0x06, 0xce, 0xd9, 0x0d, - 0xb4, 0xc2, 0x2c, 0x13, 0x9f, 0x04, 0x81, 0x3c, 0xf4, 0x9e, 0x52, 0x46, 0x84, 0x28, 0xc5, 0x1a, - 0x06, 0x2a, 0x43, 0xd1, 0xb1, 0x76, 0x88, 0x23, 0xac, 0x44, 0x66, 0xeb, 0x6c, 0xd0, 0x02, 0xcc, - 0xcb, 0xd1, 0x2f, 0x1b, 0x00, 0xbc, 0x81, 0xd4, 0xc6, 0x14, 0x3b, 0x0c, 0xce, 0x76, 0x98, 0x28, - 0x65, 0xde, 0xca, 0xe8, 0x3f, 0xd6, 0xb8, 0xa2, 0x6d, 0x98, 0xa0, 0x66, 0x8f, 0xd7, 0x38, 0xf2, - 0x86, 0x02, 0xbd, 0x6e, 0x79, 0x62, 0x8b, 0xd1, 0xc0, 0x82, 0x16, 0x1d, 0x2b, 0x9f, 0x84, 0x1d, - 0xdf, 0xa5, 0x43, 0xcb, 0xb6, 0x90, 0x12, 0x6f, 0x05, 0x56, 0xa5, 0x58, 0xc3, 0x30, 0xff, 0x38, - 0x07, 0x4b, 0x69, 0x4d, 0xa7, 0x9a, 0x7a, 0x82, 0xb7, 0x56, 0x38, 0x3c, 0xef, 0xcf, 0x7e, 0x7c, - 0x44, 0xc8, 0x4e, 0x05, 0xb6, 0x44, 0x52, 0x81, 0xe0, 0x8b, 0xde, 0xaf, 0x46, 0x28, 0x77, 0xc4, - 0x11, 0x52, 0x94, 0x13, 0xa3, 0xf4, 0x08, 0x14, 0x02, 0x3a, 0xf3, 0xf9, 0xf8, 0xb1, 0x34, 0x9b, - 0x23, 0x06, 0xa1, 0x18, 0x1d, 0xd7, 0x0e, 0x45, 0x4e, 0x9e, 0xc2, 0xb8, 0xee, 0xda, 0x21, 0x66, - 0x10, 0xf3, 0x8b, 0x39, 0x38, 0x3d, 0xb8, 0x53, 0xe8, 0x8b, 0x06, 0x40, 0x83, 0x1a, 0xb5, 0x54, - 0x24, 0x65, 0x88, 0xd3, 0x3a, 0xae, 0x31, 0x5c, 0x93, 0x9c, 0xa2, 0x78, 0xb7, 0x2a, 0x0a, 0xb0, - 0xd6, 0x10, 0x74, 0x5e, 0x8a, 0xfe, 0x15, 0xab, 0x25, 0x4d, 0x41, 0x55, 0x67, 0x53, 0x41, 0xb0, - 0x86, 0x45, 0xbd, 0x16, 0xd7, 0x6a, 0x91, 0xa0, 0x6d, 0xa9, 0xa4, 0x4b, 0xe6, 0xb5, 0x5c, 0x91, - 0x85, 0x38, 0x82, 0x9b, 0x0e, 0x3c, 0x3a, 0x44, 0x3b, 0x33, 0x4a, 0x80, 0x33, 0xff, 0xcd, 0x80, - 0x53, 0xab, 0x4e, 0x27, 0x08, 0x89, 0xff, 0x3f, 0x26, 0x7d, 0xe0, 0x3f, 0x0c, 0x78, 0x68, 0x40, - 0x9f, 0xef, 0x43, 0x16, 0xc1, 0xcb, 0xf1, 0x2c, 0x82, 0xeb, 0xe3, 0x8a, 0x74, 0x6a, 0x3f, 0x06, - 0x24, 0x13, 0x84, 0x30, 0x4b, 0xb5, 0x56, 0xc3, 0x6b, 0x66, 0xb4, 0x6f, 0x3e, 0x0a, 0xc5, 0x8f, - 0xd2, 0xfd, 0x27, 0x29, 0x63, 0x6c, 0x53, 0xc2, 0x1c, 0x66, 0xbe, 0x0f, 0x44, 0xc8, 0x3d, 0xb1, - 0x78, 0x8c, 0x61, 0x16, 0x8f, 0xf9, 0x77, 0x39, 0xd0, 0xbc, 0xdd, 0xfb, 0x20, 0x94, 0x6e, 0x4c, - 0x28, 0xc7, 0xf4, 0x5f, 0x35, 0xdf, 0x7d, 0x50, 0x6e, 0xed, 0x7e, 0x22, 0xb7, 0xf6, 0x4a, 0x66, - 0x1c, 0x0f, 0x4f, 0xad, 0xfd, 0x8e, 0x01, 0x0f, 0x45, 0xc8, 0xfd, 0x07, 0x47, 0xf7, 0xd6, 0x30, - 0x4f, 0xc1, 0xb4, 0x15, 0x55, 0x13, 0x32, 0xa0, 0xd2, 0xc9, 0x35, 0x8a, 0x58, 0xc7, 0x8b, 0x32, - 0xf9, 0xf2, 0x47, 0xcc, 0xe4, 0x2b, 0x1c, 0x9e, 0xc9, 0x67, 0xfe, 0x34, 0x07, 0x67, 0xfa, 0x7b, - 0x26, 0xd7, 0xc6, 0x70, 0x71, 0xd5, 0xa7, 0x61, 0x26, 0x14, 0x15, 0x34, 0x4d, 0xaf, 0x2e, 0x43, - 0x6c, 0x6b, 0x30, 0x1c, 0xc3, 0xa4, 0x35, 0xeb, 0x7c, 0x55, 0xd6, 0xea, 0x5e, 0x5b, 0xe6, 0x81, - 0xaa, 0x9a, 0xab, 0x1a, 0x0c, 0xc7, 0x30, 0x55, 0x86, 0x4d, 0xe1, 0xd8, 0x33, 0x6c, 0x6a, 0x70, - 0x52, 0xe6, 0x14, 0x5c, 0xf4, 0xfc, 0x55, 0xaf, 0xd5, 0x76, 0x88, 0xc8, 0x04, 0xa5, 0x8d, 0x3d, - 0x23, 0xaa, 0x9c, 0xc4, 0x69, 0x48, 0x38, 0xbd, 0xae, 0xf9, 0x9d, 0x3c, 0x9c, 0x88, 0x86, 0x7d, - 0xd5, 0x73, 0x1b, 0x36, 0xcb, 0xcc, 0x78, 0x06, 0x0a, 0xe1, 0x41, 0x5b, 0x0e, 0xf6, 0xff, 0x91, - 0xcd, 0xd9, 0x3e, 0x68, 0xd3, 0xd9, 0x3e, 0x95, 0x52, 0x85, 0x82, 0x30, 0xab, 0x84, 0x36, 0xd4, - 0xea, 0xe0, 0x33, 0xf0, 0x64, 0x5c, 0x9a, 0xef, 0x76, 0xcb, 0x29, 0x77, 0x81, 0x56, 0x14, 0xa5, - 0xb8, 0xcc, 0xa3, 0x9b, 0x30, 0xe7, 0x58, 0x41, 0x78, 0xbd, 0xdd, 0xb0, 0x42, 0xb2, 0x6d, 0xb7, - 0x88, 0x58, 0x73, 0xa3, 0xa4, 0x57, 0xaa, 0x58, 0xe3, 0x46, 0x8c, 0x12, 0x4e, 0x50, 0x46, 0xfb, - 0x80, 0x68, 0xc9, 0xb6, 0x6f, 0xb9, 0x01, 0xef, 0x15, 0xe5, 0x37, 0x7a, 0x3a, 0xa7, 0x72, 0x90, - 0x36, 0xfa, 0xa8, 0xe1, 0x14, 0x0e, 0xe8, 0x31, 0x98, 0xf0, 0x89, 0x15, 0x88, 0xc9, 0x9c, 0x8a, - 0xd6, 0x3f, 0x66, 0xa5, 0x58, 0x40, 0xf5, 0x05, 0x35, 0x71, 0x8f, 0x05, 0xf5, 0x03, 0x03, 0xe6, - 0xa2, 0x69, 0xba, 0x0f, 0x9b, 0x64, 0x2b, 0xbe, 0x49, 0x5e, 0xca, 0x4a, 0x25, 0x0e, 0xd8, 0x17, - 0xbf, 0x5c, 0xd4, 0xfb, 0xc7, 0xd2, 0xeb, 0x3e, 0x06, 0x53, 0x72, 0x55, 0x4b, 0xeb, 0x73, 0xcc, - 0x53, 0x96, 0x98, 0x5d, 0xa2, 0xa5, 0x85, 0x0b, 0x26, 0x38, 0xe2, 0x47, 0xb7, 0xe5, 0x86, 0xd8, - 0x72, 0x85, 0xd8, 0xab, 0x6d, 0x59, 0x6e, 0xc5, 0x69, 0xdb, 0xb2, 0xac, 0x83, 0xae, 0xc3, 0xa9, - 0xb6, 0xef, 0xb1, 0xab, 0x42, 0x6b, 0xc4, 0x6a, 0x38, 0xb6, 0x4b, 0xa4, 0x33, 0xcf, 0x43, 0xdd, - 0x0f, 0xf5, 0xba, 0xe5, 0x53, 0x5b, 0xe9, 0x28, 0x78, 0x50, 0xdd, 0x78, 0x7a, 0x7b, 0x61, 0x88, - 0xf4, 0xf6, 0x5f, 0x55, 0x47, 0x66, 0x24, 0x10, 0x49, 0xe6, 0x1f, 0xcc, 0x6a, 0x2a, 0x53, 0xd4, - 0x7a, 0x24, 0x52, 0x15, 0xc1, 0x14, 0x2b, 0xf6, 0x83, 0xcf, 0x65, 0x26, 0x8e, 0x78, 0x2e, 0x13, - 0x65, 0x29, 0x4e, 0x1e, 0x7f, 0x96, 0xa2, 0xf9, 0x5a, 0x11, 0x16, 0x92, 0x5b, 0xfb, 0xf1, 0xe7, - 0xc4, 0xff, 0x86, 0x01, 0x0b, 0x52, 0x2c, 0x39, 0x4f, 0x22, 0x8f, 0xb2, 0x37, 0x32, 0x5a, 0x0d, - 0xdc, 0x48, 0x51, 0xb7, 0xb6, 0xb6, 0x13, 0xdc, 0x70, 0x1f, 0x7f, 0xf4, 0x12, 0x4c, 0xab, 0x13, - 0xdf, 0x23, 0x25, 0xc8, 0xcf, 0x33, 0xf3, 0x24, 0x22, 0x81, 0x75, 0x7a, 0xe8, 0x35, 0x03, 0xa0, - 0x2e, 0xf7, 0x0f, 0x29, 0xb6, 0xd7, 0xb2, 0x12, 0x5b, 0xb5, 0x33, 0x45, 0x56, 0xa8, 0x2a, 0x0a, - 0xb0, 0xc6, 0x18, 0x7d, 0x9e, 0x9d, 0xf5, 0x2a, 0xb3, 0x89, 0x0a, 0x2a, 0x6d, 0xc9, 0x07, 0xb2, - 0x5e, 0x40, 0x51, 0xd8, 0x51, 0xd9, 0x28, 0x1a, 0x28, 0xc0, 0xb1, 0x46, 0x98, 0xcf, 0x80, 0xca, - 0x5c, 0xa3, 0xfa, 0x80, 0xe5, 0xae, 0x6d, 0x59, 0xe1, 0x9e, 0x10, 0x41, 0xa5, 0x0f, 0x2e, 0x4a, - 0x00, 0x8e, 0x70, 0xcc, 0x8f, 0xc0, 0xdc, 0x73, 0xbe, 0xd5, 0xde, 0xb3, 0xd9, 0x99, 0x2a, 0x75, - 0x40, 0xde, 0x0e, 0x93, 0x56, 0xa3, 0x91, 0x76, 0xe7, 0xb1, 0xc2, 0x8b, 0xb1, 0x84, 0x0f, 0xe7, - 0x6b, 0x7c, 0xc3, 0x80, 0xa5, 0xf5, 0x20, 0xb4, 0xbd, 0x35, 0x12, 0x84, 0x54, 0x09, 0x51, 0x7b, - 0xa5, 0xe3, 0x90, 0x21, 0x2c, 0xbe, 0x35, 0x58, 0x10, 0x81, 0x9f, 0xce, 0x4e, 0x40, 0x42, 0xcd, - 0xea, 0x53, 0xc2, 0xb9, 0x9a, 0x80, 0xe3, 0xbe, 0x1a, 0x94, 0x8a, 0x88, 0x00, 0x45, 0x54, 0xf2, - 0x71, 0x2a, 0xb5, 0x04, 0x1c, 0xf7, 0xd5, 0x30, 0xbf, 0x9d, 0x87, 0x13, 0xac, 0x1b, 0x89, 0x4b, - 0x89, 0x9f, 0x35, 0x60, 0x6e, 0xdf, 0xf6, 0xc3, 0x8e, 0xe5, 0xe8, 0xa1, 0xac, 0xb1, 0xe5, 0x93, - 0xf1, 0x7a, 0x21, 0x46, 0x98, 0x1f, 0x76, 0xc7, 0xcb, 0x70, 0x82, 0x39, 0xfa, 0x75, 0x03, 0xe6, - 0x1b, 0xf1, 0x91, 0xce, 0xc6, 0x99, 0x4f, 0x9b, 0x43, 0x9e, 0x81, 0x91, 0x28, 0xc4, 0x49, 0xfe, - 0xe8, 0x0b, 0x06, 0xcc, 0xc7, 0x9b, 0x29, 0x55, 0xd6, 0x31, 0x0c, 0x92, 0x4a, 0x99, 0x8c, 0x97, - 0x07, 0x38, 0xd9, 0x04, 0xf3, 0x6f, 0x0c, 0x31, 0xa5, 0x71, 0xcc, 0x21, 0x04, 0xd3, 0x84, 0x09, - 0xdf, 0xeb, 0x84, 0xe2, 0x40, 0x7a, 0x8a, 0x9f, 0x5b, 0x62, 0x56, 0x82, 0x05, 0x04, 0xdd, 0x86, - 0xa9, 0xd0, 0x09, 0x78, 0xa1, 0xe8, 0xed, 0x98, 0xfe, 0xc3, 0xf6, 0x46, 0x8d, 0x91, 0xd3, 0xb6, - 0x78, 0x51, 0x42, 0x4d, 0x15, 0xc9, 0xcb, 0xfc, 0xaa, 0x01, 0x53, 0x97, 0xbd, 0x1d, 0xb1, 0x9c, - 0x3f, 0x9c, 0x81, 0x77, 0xae, 0x36, 0x71, 0x15, 0x62, 0x89, 0xec, 0xc2, 0x67, 0x63, 0xbe, 0xf9, - 0xc3, 0x1a, 0xed, 0x15, 0xf6, 0x56, 0x00, 0x25, 0x75, 0xd9, 0xdb, 0x19, 0x78, 0xf4, 0xf3, 0x3b, - 0x45, 0x98, 0x7d, 0xde, 0x3a, 0x20, 0x6e, 0x68, 0x8d, 0xae, 0x80, 0xa8, 0xbb, 0xdb, 0x66, 0x19, - 0x80, 0x9a, 0x61, 0x16, 0xb9, 0xbb, 0x11, 0x08, 0xeb, 0x78, 0x91, 0x5e, 0xe1, 0x57, 0x97, 0xd3, - 0x34, 0xc2, 0x6a, 0x02, 0x8e, 0xfb, 0x6a, 0xa0, 0xcb, 0x80, 0xc4, 0x45, 0x8c, 0x4a, 0xbd, 0xee, - 0x75, 0x5c, 0xae, 0x59, 0xb8, 0x27, 0xac, 0x3c, 0x84, 0xcd, 0x3e, 0x0c, 0x9c, 0x52, 0x0b, 0x7d, - 0x08, 0x96, 0xeb, 0x8c, 0xb2, 0xb0, 0x17, 0x75, 0x8a, 0xdc, 0x67, 0x50, 0xd9, 0xb7, 0xab, 0x03, - 0xf0, 0xf0, 0x40, 0x0a, 0xb4, 0xa5, 0x41, 0xe8, 0xf9, 0x56, 0x93, 0xe8, 0x74, 0x27, 0xe2, 0x2d, - 0xad, 0xf5, 0x61, 0xe0, 0x94, 0x5a, 0xe8, 0x93, 0x30, 0x15, 0xee, 0xf9, 0x24, 0xd8, 0xf3, 0x9c, - 0x86, 0x88, 0xb9, 0x8e, 0x79, 0x3c, 0x22, 0x66, 0x7f, 0x5b, 0x52, 0xd5, 0xc4, 0x5b, 0x16, 0xe1, - 0x88, 0x27, 0xf2, 0x61, 0x22, 0xa0, 0xbe, 0x79, 0xb0, 0x5c, 0xca, 0xc2, 0x07, 0x10, 0xdc, 0x99, - 0xbb, 0xaf, 0x1d, 0xcc, 0x30, 0x0e, 0x58, 0x70, 0x32, 0xbf, 0x99, 0x83, 0x19, 0x1d, 0x71, 0x08, - 0x15, 0xf1, 0x29, 0x03, 0x66, 0xea, 0x9e, 0x1b, 0xfa, 0x9e, 0xc3, 0x0f, 0x1d, 0xf8, 0x02, 0x19, - 0xf3, 0x7e, 0x2f, 0x23, 0xb5, 0x46, 0x42, 0xcb, 0x76, 0xb4, 0xf3, 0x0b, 0x8d, 0x0d, 0x8e, 0x31, - 0x45, 0x9f, 0x31, 0x60, 0x3e, 0x4a, 0x46, 0x89, 0x4e, 0x3f, 0x32, 0x6d, 0x88, 0xd2, 0xb8, 0x17, - 0xe2, 0x9c, 0x70, 0x92, 0xb5, 0xb9, 0x03, 0x0b, 0xc9, 0xd9, 0xa6, 0x43, 0xd9, 0xb6, 0xc4, 0x5a, - 0xcf, 0x47, 0x43, 0xb9, 0x65, 0x05, 0x01, 0x66, 0x10, 0xf4, 0x0e, 0x28, 0xb5, 0x2c, 0xbf, 0x69, - 0xbb, 0x96, 0xc3, 0x46, 0x31, 0xaf, 0x29, 0x24, 0x51, 0x8e, 0x15, 0x86, 0xf9, 0xe3, 0x02, 0x4c, - 0x6b, 0x97, 0x78, 0x8e, 0xdf, 0x22, 0x8f, 0xdd, 0x0d, 0xcd, 0x67, 0x78, 0x37, 0xf4, 0x45, 0x80, - 0x5d, 0xdb, 0xb5, 0x83, 0xbd, 0x23, 0xde, 0x3a, 0x65, 0x51, 0xb2, 0x8b, 0x8a, 0x02, 0xd6, 0xa8, - 0x45, 0xa1, 0x88, 0xe2, 0x21, 0x77, 0xf1, 0x5f, 0x33, 0xb4, 0xcd, 0x63, 0x22, 0x8b, 0xd0, 0xab, - 0x36, 0x31, 0x2b, 0x72, 0x33, 0xb9, 0xe0, 0x86, 0xfe, 0xc1, 0xa1, 0x7b, 0xcc, 0x36, 0x94, 0x7c, - 0x12, 0x74, 0x5a, 0xd4, 0xb7, 0x98, 0x1c, 0x79, 0x18, 0x58, 0xe6, 0x06, 0x16, 0xf5, 0xb1, 0xa2, - 0x74, 0xfa, 0x19, 0x98, 0x8d, 0x35, 0x01, 0x2d, 0x40, 0xfe, 0x16, 0x39, 0xe0, 0x72, 0x82, 0xe9, - 0x4f, 0xb4, 0x14, 0x0b, 0xd8, 0x88, 0x61, 0x79, 0x6f, 0xee, 0x69, 0xc3, 0xf4, 0x20, 0xf5, 0xa6, - 0xd8, 0x51, 0xce, 0xd3, 0xe9, 0x5c, 0x38, 0xda, 0xb5, 0x53, 0x35, 0x17, 0x3c, 0x4d, 0x80, 0xc3, - 0xcc, 0x9f, 0x4e, 0x80, 0x88, 0x26, 0x0e, 0xa1, 0x7c, 0xf4, 0x20, 0x42, 0xee, 0x08, 0x41, 0x84, - 0xcb, 0x30, 0x63, 0xbb, 0x76, 0x68, 0x5b, 0x0e, 0xf3, 0xaf, 0xc5, 0xe6, 0xf8, 0x98, 0x54, 0x38, - 0xeb, 0x1a, 0x2c, 0x85, 0x4e, 0xac, 0x2e, 0xba, 0x06, 0x45, 0xb6, 0x7b, 0x08, 0x01, 0x1e, 0x3d, - 0xe4, 0xc9, 0xa2, 0xdd, 0x3c, 0xed, 0x9f, 0x53, 0x62, 0x16, 0x3d, 0xbf, 0x77, 0xab, 0x1c, 0x35, - 0x21, 0xc7, 0x91, 0x45, 0x9f, 0x80, 0xe3, 0xbe, 0x1a, 0x94, 0xca, 0xae, 0x65, 0x3b, 0x1d, 0x9f, - 0x44, 0x54, 0x26, 0xe2, 0x54, 0x2e, 0x26, 0xe0, 0xb8, 0xaf, 0x06, 0xda, 0x85, 0x19, 0x51, 0xc6, - 0x93, 0x3f, 0x26, 0x8f, 0xd8, 0x4b, 0x96, 0xe4, 0x73, 0x51, 0xa3, 0x84, 0x63, 0x74, 0x51, 0x07, - 0x16, 0x6d, 0xb7, 0xee, 0xb9, 0x75, 0xa7, 0x13, 0xd8, 0xfb, 0x24, 0xca, 0xb9, 0x3f, 0x0a, 0xb3, - 0x93, 0xbd, 0x6e, 0x79, 0x71, 0x3d, 0x49, 0x0e, 0xf7, 0x73, 0x40, 0xaf, 0x1a, 0x70, 0xb2, 0xee, - 0xb9, 0x01, 0xbb, 0xc8, 0xb6, 0x4f, 0x2e, 0xf8, 0xbe, 0xe7, 0x73, 0xde, 0x53, 0x47, 0xe4, 0xcd, - 0x8e, 0x75, 0x56, 0xd3, 0x48, 0xe2, 0x74, 0x4e, 0xe8, 0x65, 0x28, 0xb5, 0x7d, 0x6f, 0xdf, 0x6e, - 0x10, 0x5f, 0x24, 0x12, 0x6d, 0x64, 0x71, 0xb1, 0x76, 0x4b, 0xd0, 0x8c, 0x54, 0x8f, 0x2c, 0xc1, - 0x8a, 0x9f, 0xf9, 0xfb, 0x25, 0x98, 0x8b, 0xa3, 0xa3, 0x4f, 0x00, 0xb4, 0x7d, 0xaf, 0x45, 0xc2, - 0x3d, 0xa2, 0x72, 0xa7, 0xaf, 0x8c, 0x7b, 0x7f, 0x53, 0xd2, 0x93, 0x09, 0x04, 0x54, 0x5d, 0x44, - 0xa5, 0x58, 0xe3, 0x88, 0x7c, 0x98, 0xbc, 0xc5, 0x37, 0x51, 0x61, 0x53, 0x3c, 0x9f, 0x89, 0x05, - 0x24, 0x38, 0xb3, 0xa4, 0x5f, 0x51, 0x84, 0x25, 0x23, 0xb4, 0x03, 0xf9, 0xdb, 0x64, 0x27, 0x9b, - 0x9b, 0x86, 0x37, 0x88, 0xf0, 0x4d, 0xaa, 0x93, 0xbd, 0x6e, 0x39, 0x7f, 0x83, 0xec, 0x60, 0x4a, - 0x9c, 0xf6, 0xab, 0xc1, 0x43, 0xa1, 0x42, 0x55, 0x8c, 0xd9, 0xaf, 0x58, 0x5c, 0x95, 0xf7, 0x4b, - 0x14, 0x61, 0xc9, 0x08, 0xbd, 0x0c, 0x53, 0xb7, 0xad, 0x7d, 0xb2, 0xeb, 0x7b, 0x6e, 0x28, 0xb2, - 0x56, 0xc6, 0x4c, 0xcf, 0xbd, 0x21, 0xc9, 0x09, 0xbe, 0x6c, 0x7b, 0x57, 0x85, 0x38, 0x62, 0x87, - 0xf6, 0xa1, 0xe4, 0x92, 0xdb, 0x98, 0x38, 0x76, 0x5d, 0x64, 0x46, 0x8e, 0x29, 0xd6, 0x57, 0x04, - 0x35, 0xc1, 0x99, 0xed, 0x7b, 0xb2, 0x0c, 0x2b, 0x5e, 0x74, 0x2e, 0x6f, 0x7a, 0x3b, 0x42, 0x51, - 0x8d, 0x39, 0x97, 0xca, 0xcf, 0xe4, 0x73, 0x79, 0xd9, 0xdb, 0xc1, 0x94, 0x38, 0x5d, 0x23, 0x75, - 0x95, 0x32, 0x21, 0xd4, 0xd4, 0x95, 0x6c, 0x53, 0x45, 0xf8, 0x1a, 0x89, 0x4a, 0xb1, 0xc6, 0x91, - 0x8e, 0x6d, 0x53, 0x1c, 0x6b, 0x09, 0x45, 0x35, 0xe6, 0xd8, 0xc6, 0x0f, 0xc9, 0xf8, 0xd8, 0xca, - 0x32, 0xac, 0x78, 0x99, 0x3f, 0x29, 0xc0, 0x8c, 0xfe, 0x90, 0xc8, 0x10, 0x7b, 0xb5, 0xb2, 0x4f, - 0x73, 0xa3, 0xd8, 0xa7, 0xd4, 0xbd, 0xd0, 0x2e, 0xa5, 0xcb, 0x13, 0x86, 0xf5, 0xcc, 0xcc, 0xb3, - 0xc8, 0xbd, 0xd0, 0x0a, 0x03, 0x1c, 0x63, 0x3a, 0x42, 0x04, 0x98, 0x1a, 0x39, 0xdc, 0x0c, 0x28, - 0xc6, 0x8d, 0x9c, 0xd8, 0xc6, 0x7e, 0x1e, 0x20, 0x7a, 0x50, 0x43, 0x84, 0x01, 0x94, 0xf5, 0xa4, - 0x3d, 0xf4, 0xa1, 0x61, 0xa1, 0xc7, 0x60, 0x82, 0x6e, 0x94, 0xa4, 0x21, 0x2e, 0xb6, 0x29, 0x1f, - 0xee, 0x22, 0x2b, 0xc5, 0x02, 0x8a, 0x9e, 0xa6, 0x36, 0x4d, 0xb4, 0xbd, 0x89, 0xfb, 0x6a, 0x4b, - 0x91, 0x4d, 0x13, 0xc1, 0x70, 0x0c, 0x93, 0x36, 0x9d, 0xd0, 0xdd, 0x88, 0x49, 0x92, 0xd6, 0x74, - 0xb6, 0x45, 0x61, 0x0e, 0x63, 0x67, 0x0a, 0x89, 0xdd, 0x8b, 0x6d, 0x56, 0x45, 0xed, 0x4c, 0x21, - 0x01, 0xc7, 0x7d, 0x35, 0x68, 0x67, 0x44, 0x04, 0x63, 0x9a, 0x27, 0xba, 0x0d, 0x88, 0x3d, 0x7c, - 0x04, 0xe6, 0xe2, 0xab, 0x9d, 0x4e, 0x45, 0xdb, 0xf7, 0x76, 0x6d, 0x87, 0x24, 0x4f, 0x4d, 0xb6, - 0x78, 0x31, 0x96, 0xf0, 0xe1, 0x8e, 0x6d, 0xff, 0x22, 0x0f, 0x27, 0xae, 0x34, 0x6d, 0xf7, 0x4e, - 0xe2, 0xbc, 0x33, 0xed, 0x99, 0x37, 0x63, 0xd4, 0x67, 0xde, 0xa2, 0x0c, 0x7e, 0xf1, 0x8e, 0x5e, - 0x7a, 0x06, 0xbf, 0x7c, 0x64, 0x2f, 0x8e, 0x8b, 0x7e, 0x60, 0xc0, 0xc3, 0x56, 0x83, 0xdb, 0x5f, - 0x96, 0x23, 0x4a, 0x23, 0xa6, 0x72, 0x2d, 0x04, 0x63, 0x6a, 0xd3, 0xfe, 0xce, 0xaf, 0x54, 0x0e, - 0xe1, 0xca, 0xdd, 0x98, 0xb7, 0x89, 0x1e, 0x3c, 0x7c, 0x18, 0x2a, 0x3e, 0xb4, 0xf9, 0xa7, 0xaf, - 0xc2, 0x5b, 0xef, 0xc9, 0x68, 0x24, 0x67, 0xe5, 0x53, 0x06, 0x4c, 0xf1, 0xe3, 0x3c, 0x4c, 0x76, - 0xe9, 0x22, 0xb3, 0xda, 0xf6, 0x0b, 0xc4, 0x0f, 0xe4, 0xfb, 0x13, 0x9a, 0x8b, 0x52, 0xd9, 0x5a, - 0x17, 0x10, 0xac, 0x61, 0x51, 0x35, 0x76, 0xcb, 0x76, 0x1b, 0x62, 0x9a, 0x94, 0x1a, 0x7b, 0xde, - 0x76, 0x1b, 0x98, 0x41, 0x94, 0xa2, 0xcb, 0x0f, 0x52, 0x74, 0xe6, 0x57, 0x0c, 0x98, 0x63, 0x17, - 0x74, 0x22, 0xe3, 0xf9, 0x29, 0x15, 0x18, 0xe7, 0xcd, 0x38, 0x13, 0x0f, 0x8c, 0xdf, 0xed, 0x96, - 0xa7, 0xf9, 0x95, 0x9e, 0x78, 0x9c, 0xfc, 0x83, 0xc2, 0xe3, 0x66, 0xe1, 0xfb, 0xdc, 0xc8, 0x0e, - 0xa1, 0x3a, 0x5f, 0xaa, 0x49, 0x22, 0x38, 0xa2, 0x67, 0xfe, 0x61, 0x1e, 0x4e, 0xa4, 0x64, 0x9a, - 0x53, 0x67, 0x78, 0x82, 0x25, 0xdb, 0xca, 0xe0, 0xf3, 0x4b, 0x99, 0x67, 0xb3, 0xaf, 0xb0, 0x9c, - 0x5e, 0x21, 0x49, 0x6a, 0xe9, 0xf3, 0x42, 0x2c, 0x98, 0xa3, 0xdf, 0x34, 0x60, 0xda, 0xd2, 0x84, - 0x9d, 0xc7, 0xe3, 0x77, 0xb2, 0x6f, 0x4c, 0x9f, 0x6c, 0x6b, 0x79, 0x44, 0x91, 0x28, 0xeb, 0x6d, - 0x39, 0xfd, 0x1e, 0x98, 0xd6, 0xba, 0x30, 0x8a, 0x8c, 0x9e, 0x7e, 0x16, 0x16, 0xc6, 0x92, 0xf1, - 0x0f, 0xc0, 0xa8, 0x0f, 0x9a, 0x50, 0x65, 0x7b, 0x5b, 0xbf, 0xb7, 0xa6, 0x46, 0x5c, 0x5c, 0x5c, - 0x13, 0x50, 0x73, 0x07, 0x16, 0x92, 0x06, 0x7a, 0xe6, 0x51, 0xb2, 0x77, 0xc1, 0x88, 0x4f, 0x90, - 0x98, 0x7f, 0x99, 0x83, 0x49, 0x71, 0x5d, 0xe5, 0x3e, 0xa4, 0xe0, 0xdd, 0x8a, 0x1d, 0xf3, 0xaf, - 0x67, 0x72, 0xcb, 0x66, 0x60, 0xfe, 0x5d, 0x90, 0xc8, 0xbf, 0x7b, 0x3e, 0x1b, 0x76, 0x87, 0x27, - 0xdf, 0xfd, 0x67, 0x0e, 0xe6, 0x13, 0xd7, 0x7f, 0xd0, 0xeb, 0x46, 0x7f, 0xce, 0xc9, 0xf5, 0x4c, - 0x6f, 0x18, 0xa9, 0xf4, 0xd0, 0xc3, 0xd3, 0x4f, 0x82, 0xd8, 0x4b, 0x4f, 0xd7, 0x32, 0x7b, 0x24, - 0xf2, 0xcd, 0xf3, 0xe8, 0x93, 0xf9, 0x8f, 0x06, 0x3c, 0x38, 0xf0, 0xfa, 0x15, 0xbb, 0x57, 0xee, - 0xc7, 0xa1, 0x42, 0xd2, 0x33, 0xbe, 0x4e, 0xa9, 0x0e, 0xb3, 0x93, 0x57, 0x81, 0x93, 0xec, 0xd1, - 0x93, 0x30, 0xc3, 0x76, 0x0d, 0xba, 0x58, 0x43, 0xd2, 0x16, 0xa7, 0x77, 0xec, 0x1c, 0xa7, 0xa6, - 0x95, 0xe3, 0x18, 0x96, 0xf9, 0x65, 0x03, 0x96, 0x07, 0xdd, 0x32, 0x1e, 0xc2, 0x5b, 0xf8, 0x85, - 0x44, 0xf2, 0x5d, 0xb9, 0x2f, 0xf9, 0x2e, 0xe1, 0x2f, 0xc8, 0x3c, 0x3b, 0xcd, 0x54, 0xcf, 0xdf, - 0x23, 0xb7, 0xec, 0xb3, 0x06, 0x9c, 0x1a, 0x20, 0xa6, 0x7d, 0x49, 0x98, 0xc6, 0x91, 0x93, 0x30, - 0x73, 0xc3, 0x26, 0x61, 0x9a, 0x7f, 0x9d, 0x87, 0x05, 0xd1, 0x9e, 0xc8, 0x74, 0x78, 0x3a, 0x96, - 0xc2, 0xf8, 0xb6, 0x44, 0x0a, 0xe3, 0x52, 0x12, 0xff, 0x7f, 0xf3, 0x17, 0xdf, 0x5c, 0xf9, 0x8b, - 0x3f, 0xcb, 0xc1, 0xc9, 0xd4, 0xcb, 0xd4, 0xe8, 0xd3, 0x29, 0x3a, 0xf7, 0x46, 0xc6, 0xb7, 0xb6, - 0x87, 0xd4, 0xba, 0xe3, 0x26, 0xfd, 0x7d, 0x41, 0x4f, 0xb6, 0xe3, 0x3a, 0x74, 0xf7, 0x18, 0xee, - 0x9f, 0x8f, 0x98, 0x77, 0x67, 0xfe, 0x5a, 0x1e, 0x1e, 0x1f, 0x96, 0xd0, 0x9b, 0x34, 0x2f, 0x3b, - 0x88, 0xe5, 0x65, 0xdf, 0xa7, 0xfd, 0xf0, 0x58, 0x52, 0xb4, 0xbf, 0x9a, 0x57, 0xdb, 0x5e, 0xbf, - 0x7c, 0x0e, 0x15, 0xea, 0x99, 0xa4, 0x36, 0x93, 0x7c, 0x12, 0x2d, 0x52, 0x85, 0x93, 0x35, 0x5e, - 0x7c, 0xb7, 0x5b, 0x5e, 0x14, 0xcf, 0x24, 0xd5, 0x48, 0x28, 0x0a, 0xb1, 0xac, 0x84, 0x1e, 0x87, - 0x92, 0xcf, 0xa1, 0x32, 0x13, 0x55, 0xc4, 0xcb, 0x78, 0x19, 0x56, 0x50, 0xf4, 0x49, 0xcd, 0xc8, - 0x2c, 0x1c, 0xd7, 0x7d, 0xde, 0xc3, 0xc2, 0x80, 0x2f, 0x41, 0x29, 0x90, 0x8f, 0x9b, 0xf1, 0xb3, - 0xda, 0x27, 0x86, 0x4c, 0x70, 0xa6, 0x3e, 0x89, 0x7c, 0xe9, 0x8c, 0xf7, 0x4f, 0xbd, 0x83, 0xa6, - 0x48, 0x22, 0x53, 0xb9, 0x03, 0xfc, 0xe0, 0x09, 0x52, 0x5c, 0x81, 0xef, 0x18, 0x30, 0x2d, 0x66, - 0xeb, 0x3e, 0xe4, 0x5c, 0xdf, 0x8c, 0xe7, 0x5c, 0x5f, 0xc8, 0x44, 0x77, 0x0c, 0x48, 0xb8, 0xbe, - 0x09, 0x33, 0xfa, 0x7b, 0x1a, 0xe8, 0x45, 0x4d, 0xf7, 0x19, 0xe3, 0xdc, 0xdb, 0x97, 0xda, 0x31, - 0xd2, 0x8b, 0xe6, 0x97, 0x4a, 0x6a, 0x14, 0x59, 0x66, 0xb7, 0x2e, 0x83, 0xc6, 0xa1, 0x32, 0xa8, - 0x8b, 0x40, 0x2e, 0x7b, 0x11, 0xb8, 0x06, 0x25, 0xa9, 0xa0, 0xc4, 0x36, 0xfe, 0xa8, 0x9e, 0xd0, - 0x44, 0x6d, 0x01, 0x4a, 0x4c, 0x13, 0x5c, 0xe6, 0xc3, 0xa8, 0x39, 0x54, 0x8a, 0x53, 0x91, 0x41, - 0x2f, 0xc3, 0xf4, 0x6d, 0xcf, 0xbf, 0xe5, 0x78, 0x16, 0x7b, 0xb6, 0x10, 0xb2, 0x38, 0x75, 0x57, - 0x67, 0x39, 0x3c, 0x6f, 0xf6, 0x46, 0x44, 0x1f, 0xeb, 0xcc, 0x50, 0x05, 0xe6, 0x5b, 0xb6, 0x8b, - 0x89, 0xd5, 0x50, 0xa9, 0xd5, 0x05, 0xfe, 0xae, 0x9a, 0x34, 0x72, 0x37, 0xe3, 0x60, 0x9c, 0xc4, - 0x47, 0x1f, 0x83, 0x52, 0x20, 0xde, 0xec, 0xc8, 0x26, 0x3e, 0xa2, 0x9c, 0x31, 0x4e, 0x34, 0x1a, - 0x3b, 0x59, 0x82, 0x15, 0x43, 0xb4, 0x01, 0x4b, 0xbe, 0xb8, 0x15, 0x1f, 0x7b, 0x9e, 0x99, 0xaf, - 0x4f, 0xf6, 0x7c, 0x17, 0x4e, 0x81, 0xe3, 0xd4, 0x5a, 0xd4, 0x8a, 0x61, 0x0f, 0xc3, 0xf0, 0x83, - 0x62, 0xed, 0x6c, 0x95, 0x09, 0x7c, 0x03, 0x0b, 0xe8, 0x61, 0xa9, 0xfa, 0xa5, 0x31, 0x52, 0xf5, - 0x6b, 0x70, 0x32, 0x09, 0x62, 0x77, 0xf7, 0xd9, 0x73, 0x01, 0xda, 0xee, 0xb1, 0x95, 0x86, 0x84, - 0xd3, 0xeb, 0xa2, 0x1b, 0x30, 0xe5, 0x13, 0xe6, 0x5f, 0x54, 0x64, 0x44, 0x76, 0xe4, 0xdc, 0x13, - 0x2c, 0x09, 0xe0, 0x88, 0x16, 0x9d, 0x77, 0x2b, 0xfe, 0xb4, 0xd8, 0xb5, 0x0c, 0x3f, 0x30, 0x21, - 0xe6, 0x7e, 0xc0, 0x9b, 0x1a, 0xe6, 0x4f, 0xe6, 0x60, 0x36, 0xe6, 0xb4, 0xa3, 0x47, 0xa1, 0xc8, - 0x1e, 0x33, 0x60, 0xea, 0xa1, 0x14, 0xa9, 0x30, 0x3e, 0x38, 0x1c, 0x86, 0x3e, 0x67, 0xc0, 0x7c, - 0x3b, 0x76, 0xc0, 0x28, 0x35, 0xe7, 0x98, 0xc1, 0x9f, 0xf8, 0xa9, 0xa5, 0xf6, 0x28, 0x67, 0x9c, - 0x19, 0x4e, 0x72, 0xa7, 0x0b, 0x50, 0xa4, 0x63, 0x39, 0xc4, 0x67, 0xd8, 0xc2, 0xc6, 0x51, 0x24, - 0x56, 0xe3, 0x60, 0x9c, 0xc4, 0xa7, 0x33, 0xcc, 0x7a, 0x37, 0xce, 0xcb, 0xf3, 0x15, 0x49, 0x00, - 0x47, 0xb4, 0xd0, 0xb3, 0x30, 0x27, 0x5e, 0x94, 0xda, 0xf2, 0x1a, 0x97, 0xac, 0x60, 0x4f, 0x18, - 0xf7, 0xca, 0x19, 0x59, 0x8d, 0x41, 0x71, 0x02, 0x9b, 0xf5, 0x2d, 0x7a, 0xb6, 0x8b, 0x11, 0x98, - 0x88, 0xbf, 0x59, 0xba, 0x1a, 0x07, 0xe3, 0x24, 0x3e, 0x7a, 0x87, 0xa6, 0xf7, 0x79, 0xf0, 0x46, - 0x69, 0x83, 0x14, 0xdd, 0x5f, 0x81, 0xf9, 0x0e, 0xf3, 0x85, 0x1a, 0x12, 0x28, 0xd6, 0xa3, 0x62, - 0x78, 0x3d, 0x0e, 0xc6, 0x49, 0x7c, 0xf4, 0x0c, 0xcc, 0xfa, 0x54, 0xbb, 0x29, 0x02, 0x3c, 0xa2, - 0xa3, 0xc2, 0x0e, 0x58, 0x07, 0xe2, 0x38, 0x2e, 0x7a, 0x0e, 0x16, 0xa3, 0x67, 0x6e, 0x24, 0x01, - 0x1e, 0xe2, 0x51, 0xef, 0x46, 0x54, 0x92, 0x08, 0xb8, 0xbf, 0x0e, 0xfa, 0x45, 0x58, 0xd0, 0x46, - 0x62, 0xdd, 0x6d, 0x90, 0x3b, 0xe2, 0x29, 0x12, 0xf6, 0xad, 0x9d, 0xd5, 0x04, 0x0c, 0xf7, 0x61, - 0xa3, 0xf7, 0xc2, 0x5c, 0xdd, 0x73, 0x1c, 0xa6, 0xe3, 0xf8, 0x7b, 0x99, 0xfc, 0xcd, 0x11, 0xfe, - 0x3a, 0x4b, 0x0c, 0x82, 0x13, 0x98, 0xe8, 0x32, 0x20, 0x6f, 0x27, 0x20, 0xfe, 0x3e, 0x69, 0x3c, - 0xc7, 0xbf, 0x65, 0x45, 0xb7, 0xf8, 0xd9, 0x78, 0x32, 0xe8, 0xd5, 0x3e, 0x0c, 0x9c, 0x52, 0x8b, - 0x3d, 0x3b, 0xa1, 0x5d, 0xcc, 0x98, 0xcb, 0xe2, 0x15, 0xf6, 0xa4, 0xe7, 0x7e, 0xcf, 0x5b, 0x19, - 0x3e, 0x4c, 0xf0, 0xdc, 0xdc, 0xe5, 0xf9, 0x2c, 0x9e, 0xde, 0xd1, 0x9f, 0xce, 0x8b, 0xf6, 0x08, - 0x5e, 0x8a, 0x05, 0x27, 0xf4, 0x09, 0x98, 0xda, 0x91, 0xef, 0xa8, 0x2e, 0x2f, 0x64, 0xb1, 0x2f, - 0x26, 0x9e, 0x04, 0x8e, 0x3c, 0x53, 0x05, 0xc0, 0x11, 0x4b, 0xf4, 0x18, 0x4c, 0x5f, 0xda, 0xaa, - 0x28, 0x29, 0x5c, 0x64, 0xb3, 0x5f, 0xa0, 0x55, 0xb0, 0x0e, 0xa0, 0x2b, 0x4c, 0xd9, 0x4b, 0x88, - 0x4d, 0x71, 0xb4, 0xdf, 0xf6, 0x9b, 0x3f, 0x14, 0x9b, 0x45, 0xda, 0x70, 0x6d, 0xf9, 0x44, 0x02, - 0x5b, 0x94, 0x63, 0x85, 0x81, 0x5e, 0x82, 0x69, 0xb1, 0x5f, 0x30, 0xdd, 0xb4, 0x74, 0xb4, 0x4b, - 0x3f, 0x38, 0x22, 0x81, 0x75, 0x7a, 0xe8, 0x29, 0x98, 0x6e, 0xb3, 0xe7, 0x25, 0xc9, 0xc5, 0x8e, - 0xe3, 0x2c, 0x9f, 0x64, 0x7a, 0x53, 0x85, 0x20, 0xb6, 0x22, 0x10, 0xd6, 0xf1, 0xd0, 0x13, 0x32, - 0x9c, 0xfe, 0x96, 0x58, 0x44, 0x49, 0x85, 0xd3, 0x95, 0x95, 0x3b, 0x20, 0xdb, 0xf3, 0xd4, 0x3d, - 0xe2, 0xd8, 0x3b, 0x70, 0x5a, 0x9a, 0x58, 0xfd, 0x8b, 0x64, 0x79, 0x39, 0x76, 0x4a, 0x70, 0xfa, - 0xc6, 0x40, 0x4c, 0x7c, 0x08, 0x15, 0xb4, 0x0b, 0x79, 0xcb, 0xd9, 0x59, 0x7e, 0x30, 0x0b, 0x5b, - 0x51, 0x7d, 0x9b, 0x4e, 0x7b, 0x8a, 0x7a, 0xa3, 0x8a, 0x29, 0x03, 0xf3, 0xd5, 0xe8, 0xc8, 0x5b, - 0x3d, 0xcc, 0xf6, 0x71, 0x5d, 0xb2, 0x8d, 0x2c, 0xbe, 0xbf, 0xd4, 0xf7, 0xe0, 0x30, 0xdf, 0x94, - 0x52, 0xe5, 0xba, 0xad, 0xd6, 0x72, 0x26, 0x77, 0xfd, 0xe3, 0x8f, 0xce, 0x71, 0x8f, 0x2e, 0xbe, - 0x92, 0xcd, 0x1f, 0x16, 0xd4, 0x41, 0x54, 0x22, 0xd2, 0xed, 0x43, 0xd1, 0x0e, 0x42, 0xdb, 0xcb, - 0xf0, 0x3e, 0x4f, 0xe2, 0xb5, 0x36, 0x96, 0xd9, 0xc8, 0x00, 0x98, 0xb3, 0xa2, 0x3c, 0xdd, 0xa6, - 0xed, 0xde, 0x11, 0xdd, 0xbf, 0x96, 0x79, 0x08, 0x9b, 0xf3, 0x64, 0x00, 0xcc, 0x59, 0xa1, 0x9b, - 0x5c, 0xda, 0xb2, 0xf9, 0xd6, 0x56, 0xf2, 0x13, 0x7a, 0x3c, 0x2f, 0x48, 0x4a, 0x1c, 0xe5, 0x15, - 0xb4, 0x6c, 0x61, 0xc7, 0x8c, 0xc9, 0xab, 0xb6, 0xb9, 0x9e, 0xc6, 0xab, 0xb6, 0xb9, 0x8e, 0x29, - 0x13, 0xf4, 0xba, 0x01, 0x60, 0xa9, 0x6f, 0xc9, 0x65, 0xf3, 0x3a, 0xf7, 0xa0, 0x6f, 0xd3, 0xf1, - 0x64, 0xa4, 0x08, 0x8a, 0x35, 0xce, 0xe6, 0xbf, 0x18, 0xa0, 0x7d, 0x80, 0x27, 0xca, 0x84, 0x31, - 0x86, 0xce, 0x84, 0xc9, 0x8d, 0x98, 0x09, 0x93, 0x1f, 0x29, 0x13, 0xa6, 0x30, 0x7a, 0x26, 0x4c, - 0x71, 0x70, 0x26, 0x8c, 0xf9, 0x86, 0x01, 0x8b, 0x7d, 0x73, 0x93, 0xfc, 0xd0, 0xa1, 0x31, 0xe4, - 0x87, 0x0e, 0xd7, 0x60, 0x41, 0x3c, 0x5f, 0x58, 0x6b, 0x3b, 0x76, 0xea, 0x15, 0xc0, 0xed, 0x04, - 0x1c, 0xf7, 0xd5, 0x30, 0xff, 0xd4, 0x80, 0x69, 0xed, 0xc6, 0x02, 0xed, 0x07, 0xbb, 0xd9, 0x21, - 0x9a, 0x11, 0xbd, 0xdc, 0xc8, 0x8e, 0x1a, 0x39, 0x8c, 0x9f, 0x7a, 0x37, 0xb5, 0x07, 0xba, 0xa2, - 0x53, 0x6f, 0x5a, 0x8a, 0x05, 0x94, 0x3f, 0xbd, 0x44, 0xf8, 0x47, 0x2c, 0xf3, 0xfa, 0xd3, 0x4b, - 0xa4, 0x8d, 0x19, 0x84, 0xb1, 0xa3, 0xfb, 0x9a, 0x48, 0x92, 0xd2, 0x1e, 0x8a, 0xb4, 0xa8, 0xf7, - 0xc2, 0x60, 0xe8, 0x0c, 0xe4, 0x89, 0xdb, 0x10, 0x46, 0xb8, 0xd2, 0xd5, 0x17, 0xdc, 0x06, 0xa6, - 0xe5, 0xe6, 0x55, 0x98, 0xa9, 0x91, 0xba, 0x4f, 0xc2, 0xe7, 0xc9, 0xc1, 0xd0, 0xdf, 0x21, 0xb8, - 0x45, 0x0e, 0x92, 0xdf, 0x21, 0xa0, 0xd5, 0x69, 0xb9, 0xf9, 0x7b, 0x06, 0x24, 0xde, 0xed, 0xd4, - 0x4e, 0xc0, 0x8c, 0x41, 0x27, 0x60, 0xb1, 0xb3, 0x9a, 0xdc, 0xa1, 0x67, 0x35, 0x97, 0x01, 0xb5, - 0xac, 0xb0, 0xbe, 0x17, 0x7b, 0x55, 0x56, 0xf8, 0x3f, 0xd1, 0xfd, 0xa8, 0x3e, 0x0c, 0x9c, 0x52, - 0xcb, 0x7c, 0xc5, 0x80, 0xbe, 0x6f, 0x50, 0xd2, 0x5d, 0x9b, 0x88, 0x27, 0xde, 0xb9, 0x5b, 0xa8, - 0x76, 0x6d, 0xf9, 0xb2, 0xbb, 0x84, 0x53, 0xdf, 0x41, 0x9e, 0x3e, 0x49, 0x5f, 0x9e, 0xdf, 0x24, - 0x51, 0xbe, 0xc3, 0x5a, 0x1c, 0x8c, 0x93, 0xf8, 0xe6, 0x0b, 0x50, 0x92, 0xd7, 0xed, 0xd8, 0x9d, - 0x15, 0xe9, 0x8d, 0xea, 0x77, 0x56, 0xa8, 0x33, 0xca, 0x20, 0x74, 0x98, 0x02, 0xd7, 0xbe, 0xe4, - 0x05, 0xa1, 0xbc, 0x23, 0xc8, 0xcf, 0x9c, 0xae, 0xac, 0xb3, 0x32, 0xac, 0xa0, 0xe6, 0x22, 0xcc, - 0xab, 0xc3, 0x24, 0x2e, 0xf4, 0xe6, 0x37, 0xf3, 0x30, 0x13, 0xfb, 0xb2, 0xd0, 0xbd, 0x27, 0x7b, - 0xf8, 0x69, 0x49, 0x39, 0x14, 0xca, 0x8f, 0x78, 0x28, 0xa4, 0x9f, 0xc2, 0x15, 0x8e, 0xf7, 0x14, - 0xae, 0x98, 0xcd, 0x29, 0x5c, 0x08, 0x93, 0xe2, 0xab, 0xab, 0x22, 0xd5, 0x76, 0x33, 0xa3, 0xbb, - 0xf2, 0xe2, 0xd2, 0x29, 0xcb, 0x2e, 0x96, 0x0a, 0x4c, 0xb2, 0x32, 0xbf, 0x5e, 0x84, 0xb9, 0xf8, - 0xed, 0xf9, 0x21, 0x66, 0xf2, 0x1d, 0x7d, 0x33, 0x39, 0xa2, 0x53, 0x9c, 0x1f, 0xd7, 0x29, 0x2e, - 0x8c, 0xeb, 0x14, 0x17, 0x8f, 0xe0, 0x14, 0xf7, 0xbb, 0xb4, 0x13, 0x43, 0xbb, 0xb4, 0xef, 0x53, - 0x11, 0xdd, 0xc9, 0x58, 0x08, 0x24, 0x8a, 0xe8, 0xa2, 0xf8, 0x34, 0xac, 0x7a, 0x8d, 0xd4, 0xc8, - 0x78, 0xe9, 0x1e, 0xc6, 0xbf, 0x9f, 0x1a, 0x80, 0x1d, 0xfd, 0xdc, 0xed, 0x2d, 0x23, 0x04, 0x5f, - 0xa3, 0x0f, 0x0b, 0xb3, 0xcd, 0x0f, 0xe2, 0x1b, 0x67, 0x2d, 0x02, 0x61, 0x1d, 0x8f, 0x7d, 0x52, - 0x26, 0xfe, 0x0d, 0x1d, 0x76, 0xc6, 0xa0, 0x7f, 0x52, 0x26, 0xf1, 0xcd, 0x9d, 0x24, 0xbe, 0xf9, - 0xb5, 0x3c, 0xcc, 0xc5, 0x9f, 0x04, 0x47, 0xb7, 0x95, 0x7d, 0x9e, 0x89, 0x6b, 0xc0, 0xc9, 0x6a, - 0xf7, 0xc7, 0x07, 0x3a, 0xdc, 0xfc, 0x73, 0xb7, 0x3b, 0xea, 0x32, 0xfb, 0xf1, 0x31, 0x16, 0x9e, - 0xae, 0x60, 0xc7, 0x5e, 0x11, 0x8f, 0xb2, 0x35, 0x45, 0x14, 0x37, 0x73, 0xee, 0x51, 0xfe, 0xa5, - 0x62, 0x85, 0x35, 0xb6, 0x54, 0xbd, 0xef, 0x13, 0xdf, 0xde, 0xb5, 0xd5, 0xe7, 0x4c, 0x98, 0xf2, - 0x7c, 0x41, 0x94, 0x61, 0x05, 0x35, 0x5f, 0xc9, 0x41, 0xf4, 0xf1, 0x26, 0xf6, 0x3a, 0x71, 0xa0, - 0x99, 0x0d, 0x62, 0xda, 0x2e, 0x8f, 0xfb, 0x04, 0x78, 0x44, 0x51, 0x24, 0xbc, 0x68, 0x25, 0x38, - 0xc6, 0xf1, 0xe7, 0xf0, 0xd1, 0x26, 0x0b, 0xe6, 0x13, 0xb7, 0x30, 0x32, 0x4f, 0xd7, 0xfb, 0x52, - 0x1e, 0xa6, 0xd4, 0x3d, 0x16, 0xf4, 0x1e, 0xf6, 0xb0, 0xe8, 0x9e, 0x27, 0x9f, 0x7b, 0x7d, 0xab, - 0xf6, 0xfc, 0xe7, 0x9e, 0xd7, 0xb8, 0xdb, 0x2d, 0xcf, 0x2b, 0x64, 0x5e, 0x84, 0x45, 0x05, 0x6a, - 0xa4, 0x75, 0x7c, 0x27, 0x69, 0xa4, 0x5d, 0xc7, 0x1b, 0x98, 0x96, 0xa3, 0x3b, 0x30, 0xb9, 0x47, - 0xac, 0x06, 0xf1, 0x65, 0xfe, 0xc0, 0x66, 0x46, 0x77, 0x6f, 0x2e, 0x31, 0xaa, 0xd1, 0x30, 0xf0, - 0xff, 0x01, 0x96, 0xec, 0xe8, 0x46, 0xb5, 0xe3, 0x35, 0x0e, 0x92, 0xcf, 0x85, 0x56, 0xbd, 0xc6, - 0x01, 0x66, 0x10, 0xf4, 0x2c, 0xcc, 0x85, 0x76, 0x8b, 0x78, 0x9d, 0x50, 0xff, 0x34, 0x4e, 0x3e, - 0x3a, 0x40, 0xde, 0x8e, 0x41, 0x71, 0x02, 0x9b, 0x6e, 0x74, 0x37, 0x03, 0xcf, 0x65, 0x4f, 0x95, - 0x4c, 0xc4, 0x4f, 0x9b, 0x2e, 0xd7, 0xae, 0x5e, 0x61, 0x2f, 0x95, 0x28, 0x0c, 0x8a, 0x6d, 0xb3, - 0x64, 0x79, 0x9f, 0x88, 0xf8, 0xcd, 0x42, 0x74, 0xa5, 0x91, 0x97, 0x63, 0x85, 0x61, 0x5e, 0x87, - 0xf9, 0x44, 0x57, 0xa5, 0x39, 0x6c, 0xa4, 0x9b, 0xc3, 0xc3, 0xbd, 0xcd, 0xf9, 0x47, 0x06, 0x2c, - 0xf6, 0x2d, 0xde, 0x61, 0xf3, 0x48, 0x93, 0x9a, 0x3c, 0x77, 0x74, 0x4d, 0x9e, 0x1f, 0x4d, 0x93, - 0x57, 0x57, 0xbe, 0xf5, 0xa3, 0xb3, 0x0f, 0x7c, 0xfb, 0x47, 0x67, 0x1f, 0xf8, 0xee, 0x8f, 0xce, - 0x3e, 0xf0, 0x4a, 0xef, 0xac, 0xf1, 0xad, 0xde, 0x59, 0xe3, 0xdb, 0xbd, 0xb3, 0xc6, 0x77, 0x7b, - 0x67, 0x8d, 0x1f, 0xf6, 0xce, 0x1a, 0x6f, 0xfc, 0xf8, 0xec, 0x03, 0x2f, 0x96, 0xa4, 0x98, 0xfc, - 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0x63, 0x67, 0xc6, 0x88, 0xad, 0x82, 0x00, 0x00, + 0x23, 0x7f, 0xe6, 0xfb, 0x60, 0x16, 0xd6, 0xf6, 0xf7, 0x19, 0x8c, 0xac, 0xaf, 0x7b, 0x66, 0xd7, + 0x3b, 0xeb, 0x99, 0xdd, 0xd9, 0xdb, 0xb3, 0x5e, 0x30, 0x98, 0x50, 0xd3, 0x7d, 0xa7, 0xa7, 0x76, + 0xab, 0xab, 0x9a, 0xaa, 0xea, 0xd9, 0x1d, 0x83, 0xc0, 0x0e, 0xb2, 0x43, 0x22, 0x10, 0x4e, 0x80, + 0x87, 0x28, 0x22, 0x42, 0x11, 0x0f, 0x51, 0xc8, 0x43, 0x84, 0x12, 0xe5, 0x05, 0x29, 0x51, 0x02, + 0x12, 0x79, 0x48, 0x44, 0xa4, 0x24, 0x40, 0x04, 0x1d, 0xdc, 0x24, 0x0f, 0x89, 0x22, 0x45, 0x91, + 0x88, 0x22, 0x56, 0x8a, 0x14, 0xdd, 0xdf, 0xba, 0x55, 0x5d, 0x3d, 0xdb, 0x3d, 0x5d, 0xb3, 0x58, + 0x49, 0xde, 0xba, 0xef, 0x39, 0xf7, 0x9c, 0xfb, 0x73, 0xee, 0xb9, 0xe7, 0xdc, 0x73, 0xee, 0x2d, + 0xd8, 0x68, 0xda, 0xe1, 0x5e, 0x67, 0x67, 0xa5, 0xee, 0xb5, 0xce, 0x59, 0x7e, 0xd3, 0x6b, 0xfb, + 0xde, 0x4d, 0xf6, 0xe3, 0xdd, 0xbe, 0xe7, 0x38, 0x5e, 0x27, 0x0c, 0xce, 0xb5, 0x6f, 0x35, 0xcf, + 0x59, 0x6d, 0x3b, 0x38, 0xa7, 0x4a, 0xf6, 0xdf, 0x6b, 0x39, 0xed, 0x3d, 0xeb, 0xbd, 0xe7, 0x9a, + 0xc4, 0x25, 0xbe, 0x15, 0x92, 0xc6, 0x4a, 0xdb, 0xf7, 0x42, 0x0f, 0x7d, 0x20, 0xa2, 0xb6, 0x22, + 0xa9, 0xb1, 0x1f, 0xbf, 0x20, 0xeb, 0xae, 0xb4, 0x6f, 0x35, 0x57, 0x28, 0xb5, 0x15, 0x55, 0x22, + 0xa9, 0x9d, 0x7e, 0xb7, 0xd6, 0x96, 0xa6, 0xd7, 0xf4, 0xce, 0x31, 0xa2, 0x3b, 0x9d, 0x5d, 0xf6, + 0x8f, 0xfd, 0x61, 0xbf, 0x38, 0xb3, 0xd3, 0x8f, 0xde, 0x7a, 0x3a, 0x58, 0xb1, 0x3d, 0xda, 0xb6, + 0x73, 0x3b, 0x56, 0x58, 0xdf, 0x3b, 0xb7, 0xdf, 0xd7, 0xa2, 0xd3, 0xa6, 0x86, 0x54, 0xf7, 0x7c, + 0x92, 0x86, 0xf3, 0x64, 0x84, 0xd3, 0xb2, 0xea, 0x7b, 0xb6, 0x4b, 0xfc, 0x83, 0xa8, 0xd7, 0x2d, + 0x12, 0x5a, 0x69, 0xb5, 0xce, 0x0d, 0xaa, 0xe5, 0x77, 0xdc, 0xd0, 0x6e, 0x91, 0xbe, 0x0a, 0xff, + 0xf7, 0x5e, 0x15, 0x82, 0xfa, 0x1e, 0x69, 0x59, 0x7d, 0xf5, 0x9e, 0x18, 0x54, 0xaf, 0x13, 0xda, + 0xce, 0x39, 0xdb, 0x0d, 0x83, 0xd0, 0x4f, 0x56, 0x32, 0xbf, 0x95, 0x87, 0xa9, 0xca, 0x46, 0xb5, + 0x16, 0x5a, 0x61, 0x27, 0x40, 0xaf, 0x1b, 0x30, 0xe3, 0x78, 0x56, 0xa3, 0x6a, 0x39, 0x96, 0x5b, + 0x27, 0xfe, 0xb2, 0xf1, 0x88, 0xf1, 0xf8, 0xf4, 0xf9, 0x8d, 0x95, 0x71, 0xe6, 0x6b, 0xa5, 0x72, + 0x3b, 0xc0, 0x24, 0xf0, 0x3a, 0x7e, 0x9d, 0x60, 0xb2, 0x5b, 0x5d, 0xfa, 0x4e, 0xb7, 0xfc, 0x40, + 0xaf, 0x5b, 0x9e, 0xd9, 0xd0, 0x38, 0xe1, 0x18, 0x5f, 0xf4, 0x65, 0x03, 0x16, 0xeb, 0x96, 0x6b, + 0xf9, 0x07, 0xdb, 0x96, 0xdf, 0x24, 0xe1, 0x73, 0xbe, 0xd7, 0x69, 0x2f, 0xe7, 0x8e, 0xa1, 0x35, + 0x0f, 0x8a, 0xd6, 0x2c, 0xae, 0x26, 0xd9, 0xe1, 0xfe, 0x16, 0xb0, 0x76, 0x05, 0xa1, 0xb5, 0xe3, + 0x10, 0xbd, 0x5d, 0xf9, 0xe3, 0x6c, 0x57, 0x2d, 0xc9, 0x0e, 0xf7, 0xb7, 0xc0, 0x7c, 0x2d, 0x0f, + 0x8b, 0x95, 0x8d, 0xea, 0xb6, 0x6f, 0xed, 0xee, 0xda, 0x75, 0xec, 0x75, 0x42, 0xdb, 0x6d, 0xa2, + 0x77, 0xc2, 0xa4, 0xed, 0x36, 0x7d, 0x12, 0x04, 0x6c, 0x22, 0xa7, 0xaa, 0xf3, 0x82, 0xe8, 0xe4, + 0x3a, 0x2f, 0xc6, 0x12, 0x8e, 0x9e, 0x82, 0xe9, 0x80, 0xf8, 0xfb, 0x76, 0x9d, 0x6c, 0x79, 0x7e, + 0xc8, 0x46, 0xba, 0x58, 0x3d, 0x21, 0xd0, 0xa7, 0x6b, 0x11, 0x08, 0xeb, 0x78, 0xb4, 0x9a, 0xef, + 0x79, 0xa1, 0x80, 0xb3, 0x81, 0x98, 0x8a, 0xaa, 0xe1, 0x08, 0x84, 0x75, 0x3c, 0xf4, 0x86, 0x01, + 0x0b, 0x41, 0x68, 0xd7, 0x6f, 0xd9, 0x2e, 0x09, 0x82, 0x55, 0xcf, 0xdd, 0xb5, 0x9b, 0xcb, 0x45, + 0x36, 0x8a, 0x57, 0xc6, 0x1b, 0xc5, 0x5a, 0x82, 0x6a, 0x75, 0xa9, 0xd7, 0x2d, 0x2f, 0x24, 0x4b, + 0x71, 0x1f, 0x77, 0xb4, 0x06, 0x0b, 0x96, 0xeb, 0x7a, 0xa1, 0x15, 0xda, 0x9e, 0xbb, 0xe5, 0x93, + 0x5d, 0xfb, 0xce, 0x72, 0x81, 0x75, 0x67, 0x59, 0x74, 0x67, 0xa1, 0x92, 0x80, 0xe3, 0xbe, 0x1a, + 0xe6, 0x1a, 0x2c, 0x57, 0x5a, 0x3b, 0x56, 0x10, 0x58, 0x0d, 0xcf, 0x4f, 0xcc, 0xc6, 0xe3, 0x50, + 0x6a, 0x59, 0xed, 0xb6, 0xed, 0x36, 0xe9, 0x74, 0xe4, 0x1f, 0x9f, 0xaa, 0xce, 0xf4, 0xba, 0xe5, + 0xd2, 0xa6, 0x28, 0xc3, 0x0a, 0x6a, 0xfe, 0x20, 0x07, 0xd3, 0x15, 0xd7, 0x72, 0x0e, 0x02, 0x3b, + 0xc0, 0x1d, 0x17, 0x7d, 0x0c, 0x4a, 0x54, 0xbb, 0x34, 0xac, 0xd0, 0x12, 0x2b, 0xf2, 0x3d, 0x2b, + 0x7c, 0xb1, 0xaf, 0xe8, 0x8b, 0x3d, 0x1a, 0x17, 0x8a, 0xbd, 0xb2, 0xff, 0xde, 0x95, 0xab, 0x3b, + 0x37, 0x49, 0x3d, 0xdc, 0x24, 0xa1, 0x55, 0x45, 0xa2, 0x17, 0x10, 0x95, 0x61, 0x45, 0x15, 0x79, + 0x50, 0x08, 0xda, 0xa4, 0x2e, 0x56, 0xd8, 0xe6, 0x98, 0x92, 0x1c, 0x35, 0xbd, 0xd6, 0x26, 0xf5, + 0xea, 0x8c, 0x60, 0x5d, 0xa0, 0xff, 0x30, 0x63, 0x84, 0x6e, 0xc3, 0x44, 0xc0, 0x74, 0x8e, 0x58, + 0x3c, 0x57, 0xb3, 0x63, 0xc9, 0xc8, 0x56, 0xe7, 0x04, 0xd3, 0x09, 0xfe, 0x1f, 0x0b, 0x76, 0xe6, + 0xdf, 0x1a, 0x70, 0x42, 0xc3, 0xae, 0xf8, 0xcd, 0x4e, 0x8b, 0xb8, 0x21, 0x7a, 0x04, 0x0a, 0xae, + 0xd5, 0x22, 0x62, 0xa1, 0xa8, 0x26, 0x5f, 0xb1, 0x5a, 0x04, 0x33, 0x08, 0x7a, 0x14, 0x8a, 0xfb, + 0x96, 0xd3, 0x21, 0x6c, 0x90, 0xa6, 0xaa, 0xb3, 0x02, 0xa5, 0xf8, 0x02, 0x2d, 0xc4, 0x1c, 0x86, + 0x3e, 0x09, 0x53, 0xec, 0xc7, 0x45, 0xdf, 0x6b, 0x65, 0xd4, 0x35, 0xd1, 0xc2, 0x17, 0x24, 0xd9, + 0xea, 0x6c, 0xaf, 0x5b, 0x9e, 0x52, 0x7f, 0x71, 0xc4, 0xd0, 0xfc, 0x3b, 0x03, 0xe6, 0xb5, 0xce, + 0x6d, 0xd8, 0x41, 0x88, 0x3e, 0xd2, 0x27, 0x3c, 0x2b, 0xc3, 0x09, 0x0f, 0xad, 0xcd, 0x44, 0x67, + 0x41, 0xf4, 0xb4, 0x24, 0x4b, 0x34, 0xc1, 0x71, 0xa1, 0x68, 0x87, 0xa4, 0x15, 0x2c, 0xe7, 0x1e, + 0xc9, 0x3f, 0x3e, 0x7d, 0x7e, 0x3d, 0xb3, 0x69, 0x8c, 0xc6, 0x77, 0x9d, 0xd2, 0xc7, 0x9c, 0x8d, + 0xf9, 0x8d, 0x42, 0xac, 0x87, 0x54, 0xa2, 0x90, 0x07, 0x93, 0x2d, 0x12, 0xfa, 0x76, 0x9d, 0xaf, + 0xab, 0xe9, 0xf3, 0x6b, 0xe3, 0xb5, 0x62, 0x93, 0x11, 0x8b, 0x94, 0x25, 0xff, 0x1f, 0x60, 0xc9, + 0x05, 0xed, 0x41, 0xc1, 0xf2, 0x9b, 0xb2, 0xcf, 0x17, 0xb3, 0x99, 0xdf, 0x48, 0xe6, 0x2a, 0x7e, + 0x33, 0xc0, 0x8c, 0x03, 0x3a, 0x07, 0x53, 0x21, 0xf1, 0x5b, 0xb6, 0x6b, 0x85, 0x5c, 0xbb, 0x96, + 0xaa, 0x8b, 0x02, 0x6d, 0x6a, 0x5b, 0x02, 0x70, 0x84, 0x83, 0x1c, 0x98, 0x68, 0xf8, 0x07, 0xb8, + 0xe3, 0x2e, 0x17, 0xb2, 0x18, 0x8a, 0x35, 0x46, 0x2b, 0x5a, 0x4c, 0xfc, 0x3f, 0x16, 0x3c, 0xd0, + 0xd7, 0x0c, 0x58, 0x6a, 0x11, 0x2b, 0xe8, 0xf8, 0x84, 0x76, 0x01, 0x93, 0x90, 0xb8, 0x54, 0x1b, + 0x2e, 0x17, 0x19, 0x73, 0x3c, 0xee, 0x3c, 0xf4, 0x53, 0xae, 0x3e, 0x2c, 0x9a, 0xb2, 0x94, 0x06, + 0xc5, 0xa9, 0xad, 0x31, 0x7f, 0x50, 0x80, 0xc5, 0x3e, 0x0d, 0x81, 0x9e, 0x84, 0x62, 0x7b, 0xcf, + 0x0a, 0xe4, 0x92, 0x3f, 0x2b, 0xe5, 0x6d, 0x8b, 0x16, 0xde, 0xed, 0x96, 0x67, 0x65, 0x15, 0x56, + 0x80, 0x39, 0x32, 0xdd, 0x53, 0x5b, 0x24, 0x08, 0xac, 0xa6, 0xd4, 0x03, 0x9a, 0x98, 0xb0, 0x62, + 0x2c, 0xe1, 0xe8, 0x97, 0x0c, 0x98, 0xe5, 0x22, 0x83, 0x49, 0xd0, 0x71, 0x42, 0xaa, 0xeb, 0xe8, + 0xb0, 0x5c, 0xce, 0x42, 0x3c, 0x39, 0xc9, 0xea, 0x49, 0xc1, 0x7d, 0x56, 0x2f, 0x0d, 0x70, 0x9c, + 0x2f, 0xba, 0x01, 0x53, 0x41, 0x68, 0xf9, 0x21, 0x69, 0x54, 0x42, 0xb6, 0xab, 0x4d, 0x9f, 0xff, + 0xdf, 0xc3, 0x29, 0x81, 0x6d, 0xbb, 0x45, 0xb8, 0xc2, 0xa9, 0x49, 0x02, 0x38, 0xa2, 0x85, 0x3e, + 0x09, 0xe0, 0x77, 0xdc, 0x5a, 0xa7, 0xd5, 0xb2, 0xfc, 0x03, 0xb1, 0x83, 0x5f, 0x1a, 0xaf, 0x7b, + 0x58, 0xd1, 0x8b, 0xf6, 0xac, 0xa8, 0x0c, 0x6b, 0xfc, 0xd0, 0xab, 0x06, 0xcc, 0x72, 0x49, 0x94, + 0x2d, 0x98, 0xc8, 0xb8, 0x05, 0x8b, 0x74, 0x68, 0xd7, 0x74, 0x16, 0x38, 0xce, 0xd1, 0xfc, 0xeb, + 0xf8, 0x7e, 0x52, 0x0b, 0xa9, 0x75, 0xdd, 0x3c, 0x40, 0x1f, 0x86, 0x07, 0x83, 0x4e, 0xbd, 0x4e, + 0x82, 0x60, 0xb7, 0xe3, 0xe0, 0x8e, 0x7b, 0xc9, 0x0e, 0x42, 0xcf, 0x3f, 0xd8, 0xb0, 0x5b, 0x76, + 0xc8, 0x24, 0xae, 0x58, 0x3d, 0xd3, 0xeb, 0x96, 0x1f, 0xac, 0x0d, 0x42, 0xc2, 0x83, 0xeb, 0x23, + 0x0b, 0x1e, 0xea, 0xb8, 0x83, 0xc9, 0x73, 0xeb, 0xad, 0xdc, 0xeb, 0x96, 0x1f, 0xba, 0x3e, 0x18, + 0x0d, 0x1f, 0x46, 0xc3, 0xfc, 0x27, 0x03, 0x16, 0x64, 0xbf, 0xb6, 0x49, 0xab, 0xed, 0x50, 0xed, + 0x72, 0xfc, 0x86, 0x48, 0x18, 0x33, 0x44, 0x70, 0x36, 0xdb, 0x89, 0x6c, 0xff, 0x20, 0x6b, 0xc4, + 0xfc, 0x47, 0x03, 0x96, 0x92, 0xc8, 0xf7, 0x61, 0xf3, 0x0c, 0xe2, 0x9b, 0xe7, 0x95, 0x6c, 0x7b, + 0x3b, 0x60, 0x07, 0x7d, 0xbd, 0xd0, 0xdf, 0xd7, 0xff, 0xea, 0xdb, 0x68, 0xb4, 0x2b, 0xe6, 0x7f, + 0x9e, 0xbb, 0x62, 0xe1, 0x2d, 0xb5, 0x2b, 0xfe, 0x76, 0x01, 0x66, 0x2a, 0x6e, 0x68, 0x57, 0x76, + 0x77, 0x6d, 0xd7, 0x0e, 0x0f, 0xd0, 0xe7, 0x72, 0x70, 0xae, 0xed, 0x93, 0x5d, 0xe2, 0xfb, 0xa4, + 0xb1, 0xd6, 0xf1, 0x6d, 0xb7, 0x59, 0xab, 0xef, 0x91, 0x46, 0xc7, 0xb1, 0xdd, 0xe6, 0x7a, 0xd3, + 0xf5, 0x54, 0xf1, 0x85, 0x3b, 0xa4, 0xde, 0x61, 0x5d, 0xe2, 0x8b, 0xa2, 0x35, 0x5e, 0x97, 0xb6, + 0x46, 0x63, 0x5a, 0x7d, 0xa2, 0xd7, 0x2d, 0x9f, 0x1b, 0xb1, 0x12, 0x1e, 0xb5, 0x6b, 0xe8, 0xb3, + 0x39, 0x58, 0xf1, 0xc9, 0xc7, 0x3b, 0xf6, 0xf0, 0xa3, 0xc1, 0xb5, 0x96, 0x33, 0xe6, 0xf6, 0x33, + 0x12, 0xcf, 0xea, 0xf9, 0x5e, 0xb7, 0x3c, 0x62, 0x1d, 0x3c, 0x62, 0xbf, 0xcc, 0x3f, 0x35, 0xa0, + 0x34, 0x82, 0xa7, 0x54, 0x8e, 0x7b, 0x4a, 0x53, 0x7d, 0x5e, 0x52, 0xd8, 0xef, 0x25, 0x3d, 0x37, + 0xde, 0xa0, 0x0d, 0xe3, 0x1d, 0xfd, 0x8b, 0x01, 0x8b, 0x7d, 0xde, 0x14, 0xda, 0x83, 0xa5, 0xb6, + 0xd7, 0x90, 0x9a, 0xf0, 0x92, 0x15, 0xec, 0x31, 0x98, 0xe8, 0xde, 0x93, 0x74, 0x51, 0x6d, 0xa5, + 0xc0, 0xef, 0x76, 0xcb, 0xcb, 0x8a, 0x48, 0x02, 0x01, 0xa7, 0x52, 0x44, 0x6d, 0x28, 0xed, 0xda, + 0xc4, 0x69, 0x60, 0xb2, 0x2b, 0x24, 0x65, 0x4c, 0x9d, 0x77, 0x51, 0x50, 0xe3, 0x07, 0x09, 0xf2, + 0x1f, 0x56, 0x5c, 0xcc, 0x6b, 0x30, 0x17, 0x3f, 0x56, 0x1a, 0x62, 0xf2, 0xce, 0x40, 0xde, 0xf2, + 0x5d, 0x31, 0x75, 0xd3, 0x02, 0x21, 0x5f, 0xc1, 0x57, 0x30, 0x2d, 0x37, 0x7f, 0x56, 0x80, 0xf9, + 0xaa, 0xd3, 0x21, 0xcf, 0xf9, 0x84, 0x48, 0x4b, 0xba, 0x02, 0xf3, 0x6d, 0x9f, 0xec, 0xdb, 0xe4, + 0x76, 0x8d, 0x38, 0xa4, 0x1e, 0x7a, 0xbe, 0xa0, 0x7f, 0x4a, 0x54, 0x9f, 0xdf, 0x8a, 0x83, 0x71, + 0x12, 0x1f, 0x3d, 0x0b, 0x73, 0x56, 0x3d, 0xb4, 0xf7, 0x89, 0xa2, 0xc0, 0x1b, 0xf0, 0x36, 0x41, + 0x61, 0xae, 0x12, 0x83, 0xe2, 0x04, 0x36, 0xfa, 0x08, 0x2c, 0x07, 0x75, 0xcb, 0x21, 0xd7, 0xdb, + 0x82, 0xd5, 0xea, 0x1e, 0xa9, 0xdf, 0xda, 0xf2, 0x6c, 0x37, 0x14, 0x7e, 0xd3, 0x23, 0x82, 0xd2, + 0x72, 0x6d, 0x00, 0x1e, 0x1e, 0x48, 0x01, 0xfd, 0x91, 0x01, 0x67, 0xda, 0x3e, 0xd9, 0xf2, 0xbd, + 0x96, 0x47, 0x17, 0x44, 0x9f, 0x33, 0x21, 0x8c, 0xea, 0x17, 0xc6, 0x5c, 0xf9, 0xbc, 0xa4, 0xff, + 0x30, 0xe3, 0xed, 0xbd, 0x6e, 0xf9, 0xcc, 0xd6, 0x61, 0x0d, 0xc0, 0x87, 0xb7, 0x0f, 0xfd, 0x89, + 0x01, 0x67, 0xdb, 0x5e, 0x10, 0x1e, 0xd2, 0x85, 0xe2, 0xb1, 0x76, 0xc1, 0xec, 0x75, 0xcb, 0x67, + 0xb7, 0x0e, 0x6d, 0x01, 0xbe, 0x47, 0x0b, 0xcd, 0xde, 0x34, 0x2c, 0x6a, 0xb2, 0x27, 0x2c, 0xed, + 0x67, 0x60, 0x56, 0x0a, 0x03, 0x3f, 0x85, 0xe4, 0xb2, 0xa7, 0x3c, 0xa3, 0x8a, 0x0e, 0xc4, 0x71, + 0x5c, 0x2a, 0x77, 0x4a, 0x14, 0x79, 0xed, 0x84, 0xdc, 0x6d, 0xc5, 0xa0, 0x38, 0x81, 0x8d, 0xd6, + 0xe1, 0x84, 0x28, 0xc1, 0xa4, 0xed, 0xd8, 0x75, 0x6b, 0xd5, 0xeb, 0x08, 0x91, 0x2b, 0x56, 0x4f, + 0xf5, 0xba, 0xe5, 0x13, 0x5b, 0xfd, 0x60, 0x9c, 0x56, 0x07, 0x6d, 0xc0, 0x92, 0xd5, 0x09, 0x3d, + 0xd5, 0xff, 0x0b, 0xae, 0xb5, 0xe3, 0x90, 0x06, 0x13, 0xad, 0x52, 0x75, 0x99, 0x2a, 0xa2, 0x4a, + 0x0a, 0x1c, 0xa7, 0xd6, 0x42, 0x5b, 0x09, 0x6a, 0x35, 0x52, 0xf7, 0xdc, 0x06, 0x9f, 0xe5, 0x62, + 0x64, 0x2f, 0x54, 0x52, 0x70, 0x70, 0x6a, 0x4d, 0xe4, 0xc0, 0x5c, 0xcb, 0xba, 0x73, 0xdd, 0xb5, + 0xf6, 0x2d, 0xdb, 0xa1, 0x4c, 0x84, 0xb7, 0x35, 0xd8, 0x05, 0xe8, 0x84, 0xb6, 0xb3, 0xc2, 0x03, + 0x0f, 0x2b, 0xeb, 0x6e, 0x78, 0xd5, 0xaf, 0x85, 0x74, 0x5f, 0xa9, 0x22, 0x3a, 0xb0, 0x9b, 0x31, + 0x5a, 0x38, 0x41, 0x1b, 0x5d, 0x85, 0x93, 0x6c, 0x39, 0xae, 0x79, 0xb7, 0xdd, 0x35, 0xe2, 0x58, + 0x07, 0xb2, 0x03, 0x93, 0xac, 0x03, 0x0f, 0xf6, 0xba, 0xe5, 0x93, 0xb5, 0x34, 0x04, 0x9c, 0x5e, + 0x8f, 0xfa, 0x4c, 0x71, 0x00, 0x26, 0xfb, 0x76, 0x60, 0x7b, 0x2e, 0xf7, 0x99, 0x4a, 0x91, 0xcf, + 0x54, 0x1b, 0x8c, 0x86, 0x0f, 0xa3, 0x81, 0x7e, 0xc3, 0x80, 0xa5, 0xb4, 0x65, 0xb8, 0x3c, 0x95, + 0xc5, 0xb1, 0x6a, 0x62, 0x69, 0x71, 0x89, 0x48, 0x55, 0x0a, 0xa9, 0x8d, 0x40, 0xaf, 0x18, 0x30, + 0x63, 0x69, 0xf6, 0xde, 0x32, 0xb0, 0x56, 0x5d, 0x1e, 0xd7, 0xeb, 0x88, 0x28, 0x56, 0x17, 0x7a, + 0xdd, 0x72, 0xcc, 0xa6, 0xc4, 0x31, 0x8e, 0xe8, 0x37, 0x0d, 0x38, 0x99, 0xba, 0xc6, 0x97, 0xa7, + 0x8f, 0x63, 0x84, 0x98, 0x90, 0xa4, 0xeb, 0x9c, 0xf4, 0x66, 0xa0, 0x37, 0x0c, 0xb5, 0x95, 0x6d, + 0x4a, 0xbf, 0x6f, 0x86, 0x35, 0xed, 0xda, 0x98, 0x26, 0x6e, 0x64, 0x10, 0x48, 0xc2, 0xd5, 0x13, + 0xda, 0xce, 0x28, 0x0b, 0x71, 0x92, 0x3d, 0xfa, 0xbc, 0x21, 0xb7, 0x46, 0xd5, 0xa2, 0xd9, 0xe3, + 0x6a, 0x11, 0x8a, 0x76, 0x5a, 0xd5, 0xa0, 0x04, 0x73, 0xf4, 0x51, 0x38, 0x6d, 0xed, 0x78, 0x7e, + 0x98, 0xba, 0xf8, 0x96, 0xe7, 0xd8, 0x32, 0x3a, 0xdb, 0xeb, 0x96, 0x4f, 0x57, 0x06, 0x62, 0xe1, + 0x43, 0x28, 0x98, 0x3f, 0x2c, 0xc0, 0x0c, 0x8f, 0xc5, 0x89, 0xad, 0xeb, 0x9b, 0x06, 0x3c, 0x5c, + 0xef, 0xf8, 0x3e, 0x71, 0xc3, 0x5a, 0x48, 0xda, 0xfd, 0x1b, 0x97, 0x71, 0xac, 0x1b, 0xd7, 0x23, + 0xbd, 0x6e, 0xf9, 0xe1, 0xd5, 0x43, 0xf8, 0xe3, 0x43, 0x5b, 0x87, 0xfe, 0xc2, 0x00, 0x53, 0x20, + 0x54, 0xad, 0xfa, 0xad, 0xa6, 0xef, 0x75, 0xdc, 0x46, 0x7f, 0x27, 0x72, 0xc7, 0xda, 0x89, 0xc7, + 0x7a, 0xdd, 0xb2, 0xb9, 0x7a, 0xcf, 0x56, 0xe0, 0x21, 0x5a, 0x8a, 0x9e, 0x83, 0x45, 0x81, 0x75, + 0xe1, 0x4e, 0x9b, 0xf8, 0x36, 0x35, 0xa7, 0x45, 0xe4, 0x2f, 0x0a, 0xa6, 0x26, 0x11, 0x70, 0x7f, + 0x1d, 0x14, 0xc0, 0xe4, 0x6d, 0x62, 0x37, 0xf7, 0x42, 0x69, 0x3e, 0x8d, 0x19, 0x41, 0x15, 0xf1, + 0xb6, 0x1b, 0x9c, 0x66, 0x75, 0xba, 0xd7, 0x2d, 0x4f, 0x8a, 0x3f, 0x58, 0x72, 0x32, 0x7f, 0xaf, + 0x00, 0x20, 0xc5, 0x8b, 0xb4, 0xd1, 0xff, 0x81, 0xa9, 0x80, 0x84, 0x1c, 0x4b, 0x1c, 0xcb, 0xf1, + 0xd3, 0x4e, 0x59, 0x88, 0x23, 0x38, 0xba, 0x05, 0xc5, 0xb6, 0xd5, 0x09, 0x88, 0x98, 0xac, 0xcb, + 0x99, 0x4c, 0xd6, 0x16, 0xa5, 0xc8, 0x7d, 0x24, 0xf6, 0x13, 0x73, 0x1e, 0xe8, 0x33, 0x06, 0x00, + 0x89, 0x0f, 0xf0, 0xf4, 0xf9, 0x5a, 0x26, 0x2c, 0xa3, 0x39, 0xa0, 0x63, 0x50, 0x9d, 0xeb, 0x75, + 0xcb, 0xa0, 0x4d, 0x95, 0xc6, 0x16, 0xdd, 0x86, 0x92, 0x25, 0x75, 0x74, 0xe1, 0x38, 0x74, 0x34, + 0x73, 0x5d, 0x94, 0x90, 0x29, 0x66, 0xe8, 0xb3, 0x06, 0xcc, 0x05, 0x24, 0x14, 0x53, 0x45, 0x35, + 0x85, 0x30, 0x50, 0xc7, 0x14, 0x92, 0x5a, 0x8c, 0x26, 0xd7, 0x78, 0xf1, 0x32, 0x9c, 0xe0, 0x6b, + 0xfe, 0x70, 0x1a, 0xe6, 0xa4, 0xc8, 0x44, 0x36, 0x27, 0x4f, 0x0e, 0x18, 0x60, 0x73, 0xae, 0xea, + 0x40, 0x1c, 0xc7, 0xa5, 0x95, 0x79, 0x04, 0x3f, 0x6e, 0x72, 0xaa, 0xca, 0x35, 0x1d, 0x88, 0xe3, + 0xb8, 0xa8, 0x05, 0xc5, 0x20, 0x24, 0x6d, 0x19, 0x4b, 0x18, 0xf3, 0xa8, 0x3b, 0x5a, 0x09, 0xd1, + 0x69, 0x21, 0xfd, 0x17, 0x60, 0xce, 0x05, 0x7d, 0xc1, 0x80, 0xb9, 0x30, 0x16, 0xc7, 0x16, 0x62, + 0x90, 0x8d, 0x24, 0xc6, 0x43, 0xe4, 0x7c, 0x36, 0xe2, 0x65, 0x38, 0xc1, 0x3e, 0xc5, 0x0c, 0x2d, + 0x1e, 0xa3, 0x19, 0xfa, 0x22, 0x94, 0x5a, 0xd6, 0x9d, 0x5a, 0xc7, 0x6f, 0x1e, 0xdd, 0xdc, 0x15, + 0x61, 0x7e, 0x4e, 0x05, 0x2b, 0x7a, 0xe8, 0x55, 0x43, 0x5b, 0x5c, 0x93, 0x8c, 0xf8, 0x8d, 0x6c, + 0x17, 0x97, 0xd2, 0xe2, 0x03, 0x97, 0x59, 0x9f, 0x51, 0x58, 0xba, 0xef, 0x46, 0x21, 0x35, 0x70, + 0xf8, 0x02, 0x51, 0x06, 0xce, 0xd4, 0xb1, 0x1a, 0x38, 0xab, 0x31, 0x66, 0x38, 0xc1, 0x9c, 0xb5, + 0x87, 0xaf, 0x39, 0xd5, 0x1e, 0x38, 0xd6, 0xf6, 0xd4, 0x62, 0xcc, 0x70, 0x82, 0xf9, 0x60, 0x4f, + 0x68, 0xfa, 0x78, 0x3c, 0xa1, 0x99, 0x0c, 0x3c, 0xa1, 0xc3, 0x8d, 0xc4, 0xd9, 0x71, 0x8d, 0x44, + 0x74, 0x19, 0x50, 0xe3, 0xc0, 0xb5, 0x5a, 0x76, 0x5d, 0x28, 0x4b, 0xb6, 0x41, 0xcc, 0x31, 0x4f, + 0xf9, 0xb4, 0x50, 0x64, 0x68, 0xad, 0x0f, 0x03, 0xa7, 0xd4, 0x32, 0xff, 0xcd, 0x80, 0x85, 0x55, + 0xc7, 0xeb, 0x34, 0x6e, 0x58, 0x61, 0x7d, 0x8f, 0x47, 0x29, 0xd0, 0xb3, 0x50, 0xb2, 0xdd, 0x90, + 0xf8, 0xfb, 0x96, 0x23, 0x74, 0xbb, 0x29, 0x03, 0x39, 0xeb, 0xa2, 0xfc, 0x6e, 0xb7, 0x3c, 0xb7, + 0xd6, 0xf1, 0x59, 0xfa, 0x0f, 0x5f, 0xe9, 0x58, 0xd5, 0x41, 0x5f, 0x35, 0x60, 0x91, 0xc7, 0x39, + 0xd6, 0xac, 0xd0, 0xba, 0xd6, 0x21, 0xbe, 0x4d, 0x64, 0xa4, 0x63, 0xcc, 0x45, 0x9e, 0x6c, 0xab, + 0x64, 0x70, 0x10, 0x99, 0x5f, 0x9b, 0x49, 0xce, 0xb8, 0xbf, 0x31, 0xe6, 0x17, 0xf3, 0xf0, 0xe0, + 0x40, 0x5a, 0xe8, 0x34, 0xe4, 0xec, 0x86, 0xe8, 0x3a, 0x08, 0xba, 0xb9, 0xf5, 0x06, 0xce, 0xd9, + 0x0d, 0xb4, 0xc2, 0x2c, 0x13, 0x9f, 0x04, 0x81, 0x3c, 0xf4, 0x9e, 0x52, 0x46, 0x84, 0x28, 0xc5, + 0x1a, 0x06, 0x2a, 0x43, 0xd1, 0xb1, 0x76, 0x88, 0x23, 0xac, 0x44, 0x66, 0xeb, 0x6c, 0xd0, 0x02, + 0xcc, 0xcb, 0xd1, 0x2f, 0x1a, 0x00, 0xbc, 0x81, 0xd4, 0xc6, 0x14, 0x3b, 0x0c, 0xce, 0x76, 0x98, + 0x28, 0x65, 0xde, 0xca, 0xe8, 0x3f, 0xd6, 0xb8, 0xa2, 0x6d, 0x98, 0xa0, 0x66, 0x8f, 0xd7, 0x38, + 0xf2, 0x86, 0x02, 0xbd, 0x6e, 0x79, 0x62, 0x8b, 0xd1, 0xc0, 0x82, 0x16, 0x1d, 0x2b, 0x9f, 0x84, + 0x1d, 0xdf, 0xa5, 0x43, 0xcb, 0xb6, 0x90, 0x12, 0x6f, 0x05, 0x56, 0xa5, 0x58, 0xc3, 0x30, 0xff, + 0x30, 0x07, 0x4b, 0x69, 0x4d, 0xa7, 0x9a, 0x7a, 0x82, 0xb7, 0x56, 0x38, 0x3c, 0x1f, 0xcc, 0x7e, + 0x7c, 0x44, 0xc8, 0x4e, 0x05, 0xb6, 0x44, 0x52, 0x81, 0xe0, 0x8b, 0x3e, 0xa8, 0x46, 0x28, 0x77, + 0xc4, 0x11, 0x52, 0x94, 0x13, 0xa3, 0xf4, 0x08, 0x14, 0x02, 0x3a, 0xf3, 0xf9, 0xf8, 0xb1, 0x34, + 0x9b, 0x23, 0x06, 0xa1, 0x18, 0x1d, 0xd7, 0x0e, 0x45, 0x4e, 0x9e, 0xc2, 0xb8, 0xee, 0xda, 0x21, + 0x66, 0x10, 0xf3, 0xcb, 0x39, 0x38, 0x3d, 0xb8, 0x53, 0xe8, 0xcb, 0x06, 0x40, 0x83, 0x1a, 0xb5, + 0x54, 0x24, 0x65, 0x88, 0xd3, 0x3a, 0xae, 0x31, 0x5c, 0x93, 0x9c, 0xa2, 0x78, 0xb7, 0x2a, 0x0a, + 0xb0, 0xd6, 0x10, 0x74, 0x5e, 0x8a, 0xfe, 0x15, 0xab, 0x25, 0x4d, 0x41, 0x55, 0x67, 0x53, 0x41, + 0xb0, 0x86, 0x45, 0xbd, 0x16, 0xd7, 0x6a, 0x91, 0xa0, 0x6d, 0xa9, 0xa4, 0x4b, 0xe6, 0xb5, 0x5c, + 0x91, 0x85, 0x38, 0x82, 0x9b, 0x0e, 0x3c, 0x3a, 0x44, 0x3b, 0x33, 0x4a, 0x80, 0x33, 0xff, 0xd5, + 0x80, 0x53, 0xab, 0x4e, 0x27, 0x08, 0x89, 0xff, 0xdf, 0x26, 0x7d, 0xe0, 0xdf, 0x0d, 0x78, 0x68, + 0x40, 0x9f, 0xef, 0x43, 0x16, 0xc1, 0xcb, 0xf1, 0x2c, 0x82, 0xeb, 0xe3, 0x8a, 0x74, 0x6a, 0x3f, + 0x06, 0x24, 0x13, 0x84, 0x30, 0x4b, 0xb5, 0x56, 0xc3, 0x6b, 0x66, 0xb4, 0x6f, 0x3e, 0x0a, 0xc5, + 0x8f, 0xd3, 0xfd, 0x27, 0x29, 0x63, 0x6c, 0x53, 0xc2, 0x1c, 0x66, 0x7e, 0x00, 0x44, 0xc8, 0x3d, + 0xb1, 0x78, 0x8c, 0x61, 0x16, 0x8f, 0xf9, 0x37, 0x39, 0xd0, 0xbc, 0xdd, 0xfb, 0x20, 0x94, 0x6e, + 0x4c, 0x28, 0xc7, 0xf4, 0x5f, 0x35, 0xdf, 0x7d, 0x50, 0x6e, 0xed, 0x7e, 0x22, 0xb7, 0xf6, 0x4a, + 0x66, 0x1c, 0x0f, 0x4f, 0xad, 0xfd, 0x9e, 0x01, 0x0f, 0x45, 0xc8, 0xfd, 0x07, 0x47, 0xf7, 0xd6, + 0x30, 0x4f, 0xc1, 0xb4, 0x15, 0x55, 0x13, 0x32, 0xa0, 0xd2, 0xc9, 0x35, 0x8a, 0x58, 0xc7, 0x8b, + 0x32, 0xf9, 0xf2, 0x47, 0xcc, 0xe4, 0x2b, 0x1c, 0x9e, 0xc9, 0x67, 0xfe, 0x34, 0x07, 0x67, 0xfa, + 0x7b, 0x26, 0xd7, 0xc6, 0x70, 0x71, 0xd5, 0xa7, 0x61, 0x26, 0x14, 0x15, 0x34, 0x4d, 0xaf, 0x2e, + 0x43, 0x6c, 0x6b, 0x30, 0x1c, 0xc3, 0xa4, 0x35, 0xeb, 0x7c, 0x55, 0xd6, 0xea, 0x5e, 0x5b, 0xe6, + 0x81, 0xaa, 0x9a, 0xab, 0x1a, 0x0c, 0xc7, 0x30, 0x55, 0x86, 0x4d, 0xe1, 0xd8, 0x33, 0x6c, 0x6a, + 0x70, 0x52, 0xe6, 0x14, 0x5c, 0xf4, 0xfc, 0x55, 0xaf, 0xd5, 0x76, 0x88, 0xc8, 0x04, 0xa5, 0x8d, + 0x3d, 0x23, 0xaa, 0x9c, 0xc4, 0x69, 0x48, 0x38, 0xbd, 0xae, 0xf9, 0xbd, 0x3c, 0x9c, 0x88, 0x86, + 0x7d, 0xd5, 0x73, 0x1b, 0x36, 0xcb, 0xcc, 0x78, 0x06, 0x0a, 0xe1, 0x41, 0x5b, 0x0e, 0xf6, 0xff, + 0x92, 0xcd, 0xd9, 0x3e, 0x68, 0xd3, 0xd9, 0x3e, 0x95, 0x52, 0x85, 0x82, 0x30, 0xab, 0x84, 0x36, + 0xd4, 0xea, 0xe0, 0x33, 0xf0, 0x64, 0x5c, 0x9a, 0xef, 0x76, 0xcb, 0x29, 0x77, 0x81, 0x56, 0x14, + 0xa5, 0xb8, 0xcc, 0xa3, 0x9b, 0x30, 0xe7, 0x58, 0x41, 0x78, 0xbd, 0xdd, 0xb0, 0x42, 0xb2, 0x6d, + 0xb7, 0x88, 0x58, 0x73, 0xa3, 0xa4, 0x57, 0xaa, 0x58, 0xe3, 0x46, 0x8c, 0x12, 0x4e, 0x50, 0x46, + 0xfb, 0x80, 0x68, 0xc9, 0xb6, 0x6f, 0xb9, 0x01, 0xef, 0x15, 0xe5, 0x37, 0x7a, 0x3a, 0xa7, 0x72, + 0x90, 0x36, 0xfa, 0xa8, 0xe1, 0x14, 0x0e, 0xe8, 0x31, 0x98, 0xf0, 0x89, 0x15, 0x88, 0xc9, 0x9c, + 0x8a, 0xd6, 0x3f, 0x66, 0xa5, 0x58, 0x40, 0xf5, 0x05, 0x35, 0x71, 0x8f, 0x05, 0xf5, 0x23, 0x03, + 0xe6, 0xa2, 0x69, 0xba, 0x0f, 0x9b, 0x64, 0x2b, 0xbe, 0x49, 0x5e, 0xca, 0x4a, 0x25, 0x0e, 0xd8, + 0x17, 0xbf, 0x5a, 0xd4, 0xfb, 0xc7, 0xd2, 0xeb, 0x3e, 0x01, 0x53, 0x72, 0x55, 0x4b, 0xeb, 0x73, + 0xcc, 0x53, 0x96, 0x98, 0x5d, 0xa2, 0xa5, 0x85, 0x0b, 0x26, 0x38, 0xe2, 0x47, 0xb7, 0xe5, 0x86, + 0xd8, 0x72, 0x85, 0xd8, 0xab, 0x6d, 0x59, 0x6e, 0xc5, 0x69, 0xdb, 0xb2, 0xac, 0x83, 0xae, 0xc3, + 0xa9, 0xb6, 0xef, 0xb1, 0xab, 0x42, 0x6b, 0xc4, 0x6a, 0x38, 0xb6, 0x4b, 0xa4, 0x33, 0xcf, 0x43, + 0xdd, 0x0f, 0xf5, 0xba, 0xe5, 0x53, 0x5b, 0xe9, 0x28, 0x78, 0x50, 0xdd, 0x78, 0x7a, 0x7b, 0x61, + 0x88, 0xf4, 0xf6, 0x5f, 0x56, 0x47, 0x66, 0x24, 0x10, 0x49, 0xe6, 0x1f, 0xce, 0x6a, 0x2a, 0x53, + 0xd4, 0x7a, 0x24, 0x52, 0x15, 0xc1, 0x14, 0x2b, 0xf6, 0x83, 0xcf, 0x65, 0x26, 0x8e, 0x78, 0x2e, + 0x13, 0x65, 0x29, 0x4e, 0x1e, 0x7f, 0x96, 0xa2, 0xf9, 0x5a, 0x11, 0x16, 0x92, 0x5b, 0xfb, 0xf1, + 0xe7, 0xc4, 0xff, 0x9a, 0x01, 0x0b, 0x52, 0x2c, 0x39, 0x4f, 0x22, 0x8f, 0xb2, 0x37, 0x32, 0x5a, + 0x0d, 0xdc, 0x48, 0x51, 0xb7, 0xb6, 0xb6, 0x13, 0xdc, 0x70, 0x1f, 0x7f, 0xf4, 0x12, 0x4c, 0xab, + 0x13, 0xdf, 0x23, 0x25, 0xc8, 0xcf, 0x33, 0xf3, 0x24, 0x22, 0x81, 0x75, 0x7a, 0xe8, 0x35, 0x03, + 0xa0, 0x2e, 0xf7, 0x0f, 0x29, 0xb6, 0xd7, 0xb2, 0x12, 0x5b, 0xb5, 0x33, 0x45, 0x56, 0xa8, 0x2a, + 0x0a, 0xb0, 0xc6, 0x18, 0x7d, 0x91, 0x9d, 0xf5, 0x2a, 0xb3, 0x89, 0x0a, 0x2a, 0x6d, 0xc9, 0x87, + 0xb2, 0x5e, 0x40, 0x51, 0xd8, 0x51, 0xd9, 0x28, 0x1a, 0x28, 0xc0, 0xb1, 0x46, 0x98, 0xcf, 0x80, + 0xca, 0x5c, 0xa3, 0xfa, 0x80, 0xe5, 0xae, 0x6d, 0x59, 0xe1, 0x9e, 0x10, 0x41, 0xa5, 0x0f, 0x2e, + 0x4a, 0x00, 0x8e, 0x70, 0xcc, 0x8f, 0xc1, 0xdc, 0x73, 0xbe, 0xd5, 0xde, 0xb3, 0xd9, 0x99, 0x2a, + 0x75, 0x40, 0xde, 0x09, 0x93, 0x56, 0xa3, 0x91, 0x76, 0xe7, 0xb1, 0xc2, 0x8b, 0xb1, 0x84, 0x0f, + 0xe7, 0x6b, 0x7c, 0xcb, 0x80, 0xa5, 0xf5, 0x20, 0xb4, 0xbd, 0x35, 0x12, 0x84, 0x54, 0x09, 0x51, + 0x7b, 0xa5, 0xe3, 0x90, 0x21, 0x2c, 0xbe, 0x35, 0x58, 0x10, 0x81, 0x9f, 0xce, 0x4e, 0x40, 0x42, + 0xcd, 0xea, 0x53, 0xc2, 0xb9, 0x9a, 0x80, 0xe3, 0xbe, 0x1a, 0x94, 0x8a, 0x88, 0x00, 0x45, 0x54, + 0xf2, 0x71, 0x2a, 0xb5, 0x04, 0x1c, 0xf7, 0xd5, 0x30, 0xbf, 0x9b, 0x87, 0x13, 0xac, 0x1b, 0x89, + 0x4b, 0x89, 0x9f, 0x37, 0x60, 0x6e, 0xdf, 0xf6, 0xc3, 0x8e, 0xe5, 0xe8, 0xa1, 0xac, 0xb1, 0xe5, + 0x93, 0xf1, 0x7a, 0x21, 0x46, 0x98, 0x1f, 0x76, 0xc7, 0xcb, 0x70, 0x82, 0x39, 0xfa, 0x55, 0x03, + 0xe6, 0x1b, 0xf1, 0x91, 0xce, 0xc6, 0x99, 0x4f, 0x9b, 0x43, 0x9e, 0x81, 0x91, 0x28, 0xc4, 0x49, + 0xfe, 0xe8, 0x4b, 0x06, 0xcc, 0xc7, 0x9b, 0x29, 0x55, 0xd6, 0x31, 0x0c, 0x92, 0x4a, 0x99, 0x8c, + 0x97, 0x07, 0x38, 0xd9, 0x04, 0xf3, 0xaf, 0x0c, 0x31, 0xa5, 0x71, 0xcc, 0x21, 0x04, 0xd3, 0x84, + 0x09, 0xdf, 0xeb, 0x84, 0xe2, 0x40, 0x7a, 0x8a, 0x9f, 0x5b, 0x62, 0x56, 0x82, 0x05, 0x04, 0xdd, + 0x86, 0xa9, 0xd0, 0x09, 0x78, 0xa1, 0xe8, 0xed, 0x98, 0xfe, 0xc3, 0xf6, 0x46, 0x8d, 0x91, 0xd3, + 0xb6, 0x78, 0x51, 0x42, 0x4d, 0x15, 0xc9, 0xcb, 0xfc, 0xba, 0x01, 0x53, 0x97, 0xbd, 0x1d, 0xb1, + 0x9c, 0x3f, 0x9a, 0x81, 0x77, 0xae, 0x36, 0x71, 0x15, 0x62, 0x89, 0xec, 0xc2, 0x67, 0x63, 0xbe, + 0xf9, 0xc3, 0x1a, 0xed, 0x15, 0xf6, 0x56, 0x00, 0x25, 0x75, 0xd9, 0xdb, 0x19, 0x78, 0xf4, 0xf3, + 0x5b, 0x45, 0x98, 0x7d, 0xde, 0x3a, 0x20, 0x6e, 0x68, 0x8d, 0xae, 0x80, 0xa8, 0xbb, 0xdb, 0x66, + 0x19, 0x80, 0x9a, 0x61, 0x16, 0xb9, 0xbb, 0x11, 0x08, 0xeb, 0x78, 0x91, 0x5e, 0xe1, 0x57, 0x97, + 0xd3, 0x34, 0xc2, 0x6a, 0x02, 0x8e, 0xfb, 0x6a, 0xa0, 0xcb, 0x80, 0xc4, 0x45, 0x8c, 0x4a, 0xbd, + 0xee, 0x75, 0x5c, 0xae, 0x59, 0xb8, 0x27, 0xac, 0x3c, 0x84, 0xcd, 0x3e, 0x0c, 0x9c, 0x52, 0x0b, + 0x7d, 0x04, 0x96, 0xeb, 0x8c, 0xb2, 0xb0, 0x17, 0x75, 0x8a, 0xdc, 0x67, 0x50, 0xd9, 0xb7, 0xab, + 0x03, 0xf0, 0xf0, 0x40, 0x0a, 0xb4, 0xa5, 0x41, 0xe8, 0xf9, 0x56, 0x93, 0xe8, 0x74, 0x27, 0xe2, + 0x2d, 0xad, 0xf5, 0x61, 0xe0, 0x94, 0x5a, 0xe8, 0xd3, 0x30, 0x15, 0xee, 0xf9, 0x24, 0xd8, 0xf3, + 0x9c, 0x86, 0x88, 0xb9, 0x8e, 0x79, 0x3c, 0x22, 0x66, 0x7f, 0x5b, 0x52, 0xd5, 0xc4, 0x5b, 0x16, + 0xe1, 0x88, 0x27, 0xf2, 0x61, 0x22, 0xa0, 0xbe, 0x79, 0xb0, 0x5c, 0xca, 0xc2, 0x07, 0x10, 0xdc, + 0x99, 0xbb, 0xaf, 0x1d, 0xcc, 0x30, 0x0e, 0x58, 0x70, 0x32, 0xbf, 0x9d, 0x83, 0x19, 0x1d, 0x71, + 0x08, 0x15, 0xf1, 0x19, 0x03, 0x66, 0xea, 0x9e, 0x1b, 0xfa, 0x9e, 0xc3, 0x0f, 0x1d, 0xf8, 0x02, + 0x19, 0xf3, 0x7e, 0x2f, 0x23, 0xb5, 0x46, 0x42, 0xcb, 0x76, 0xb4, 0xf3, 0x0b, 0x8d, 0x0d, 0x8e, + 0x31, 0x45, 0x9f, 0x33, 0x60, 0x3e, 0x4a, 0x46, 0x89, 0x4e, 0x3f, 0x32, 0x6d, 0x88, 0xd2, 0xb8, + 0x17, 0xe2, 0x9c, 0x70, 0x92, 0xb5, 0xb9, 0x03, 0x0b, 0xc9, 0xd9, 0xa6, 0x43, 0xd9, 0xb6, 0xc4, + 0x5a, 0xcf, 0x47, 0x43, 0xb9, 0x65, 0x05, 0x01, 0x66, 0x10, 0xf4, 0x2e, 0x28, 0xb5, 0x2c, 0xbf, + 0x69, 0xbb, 0x96, 0xc3, 0x46, 0x31, 0xaf, 0x29, 0x24, 0x51, 0x8e, 0x15, 0x86, 0xf9, 0x93, 0x02, + 0x4c, 0x6b, 0x97, 0x78, 0x8e, 0xdf, 0x22, 0x8f, 0xdd, 0x0d, 0xcd, 0x67, 0x78, 0x37, 0xf4, 0x45, + 0x80, 0x5d, 0xdb, 0xb5, 0x83, 0xbd, 0x23, 0xde, 0x3a, 0x65, 0x51, 0xb2, 0x8b, 0x8a, 0x02, 0xd6, + 0xa8, 0x45, 0xa1, 0x88, 0xe2, 0x21, 0x77, 0xf1, 0x5f, 0x33, 0xb4, 0xcd, 0x63, 0x22, 0x8b, 0xd0, + 0xab, 0x36, 0x31, 0x2b, 0x72, 0x33, 0xb9, 0xe0, 0x86, 0xfe, 0xc1, 0xa1, 0x7b, 0xcc, 0x36, 0x94, + 0x7c, 0x12, 0x74, 0x5a, 0xd4, 0xb7, 0x98, 0x1c, 0x79, 0x18, 0x58, 0xe6, 0x06, 0x16, 0xf5, 0xb1, + 0xa2, 0x74, 0xfa, 0x19, 0x98, 0x8d, 0x35, 0x01, 0x2d, 0x40, 0xfe, 0x16, 0x39, 0xe0, 0x72, 0x82, + 0xe9, 0x4f, 0xb4, 0x14, 0x0b, 0xd8, 0x88, 0x61, 0x79, 0x7f, 0xee, 0x69, 0xc3, 0xf4, 0x20, 0xf5, + 0xa6, 0xd8, 0x51, 0xce, 0xd3, 0xe9, 0x5c, 0x38, 0xda, 0xb5, 0x53, 0x35, 0x17, 0x3c, 0x4d, 0x80, + 0xc3, 0xcc, 0x9f, 0x4e, 0x80, 0x88, 0x26, 0x0e, 0xa1, 0x7c, 0xf4, 0x20, 0x42, 0xee, 0x08, 0x41, + 0x84, 0xcb, 0x30, 0x63, 0xbb, 0x76, 0x68, 0x5b, 0x0e, 0xf3, 0xaf, 0xc5, 0xe6, 0xf8, 0x98, 0x54, + 0x38, 0xeb, 0x1a, 0x2c, 0x85, 0x4e, 0xac, 0x2e, 0xba, 0x06, 0x45, 0xb6, 0x7b, 0x08, 0x01, 0x1e, + 0x3d, 0xe4, 0xc9, 0xa2, 0xdd, 0x3c, 0xed, 0x9f, 0x53, 0x62, 0x16, 0x3d, 0xbf, 0x77, 0xab, 0x1c, + 0x35, 0x21, 0xc7, 0x91, 0x45, 0x9f, 0x80, 0xe3, 0xbe, 0x1a, 0x94, 0xca, 0xae, 0x65, 0x3b, 0x1d, + 0x9f, 0x44, 0x54, 0x26, 0xe2, 0x54, 0x2e, 0x26, 0xe0, 0xb8, 0xaf, 0x06, 0xda, 0x85, 0x19, 0x51, + 0xc6, 0x93, 0x3f, 0x26, 0x8f, 0xd8, 0x4b, 0x96, 0xe4, 0x73, 0x51, 0xa3, 0x84, 0x63, 0x74, 0x51, + 0x07, 0x16, 0x6d, 0xb7, 0xee, 0xb9, 0x75, 0xa7, 0x13, 0xd8, 0xfb, 0x24, 0xca, 0xb9, 0x3f, 0x0a, + 0xb3, 0x93, 0xbd, 0x6e, 0x79, 0x71, 0x3d, 0x49, 0x0e, 0xf7, 0x73, 0x40, 0xaf, 0x1a, 0x70, 0xb2, + 0xee, 0xb9, 0x01, 0xbb, 0xc8, 0xb6, 0x4f, 0x2e, 0xf8, 0xbe, 0xe7, 0x73, 0xde, 0x53, 0x47, 0xe4, + 0xcd, 0x8e, 0x75, 0x56, 0xd3, 0x48, 0xe2, 0x74, 0x4e, 0xe8, 0x65, 0x28, 0xb5, 0x7d, 0x6f, 0xdf, + 0x6e, 0x10, 0x5f, 0x24, 0x12, 0x6d, 0x64, 0x71, 0xb1, 0x76, 0x4b, 0xd0, 0x8c, 0x54, 0x8f, 0x2c, + 0xc1, 0x8a, 0x9f, 0xf9, 0xbb, 0x25, 0x98, 0x8b, 0xa3, 0xa3, 0x4f, 0x01, 0xb4, 0x7d, 0xaf, 0x45, + 0xc2, 0x3d, 0xa2, 0x72, 0xa7, 0xaf, 0x8c, 0x7b, 0x7f, 0x53, 0xd2, 0x93, 0x09, 0x04, 0x54, 0x5d, + 0x44, 0xa5, 0x58, 0xe3, 0x88, 0x7c, 0x98, 0xbc, 0xc5, 0x37, 0x51, 0x61, 0x53, 0x3c, 0x9f, 0x89, + 0x05, 0x24, 0x38, 0xb3, 0xa4, 0x5f, 0x51, 0x84, 0x25, 0x23, 0xb4, 0x03, 0xf9, 0xdb, 0x64, 0x27, + 0x9b, 0x9b, 0x86, 0x37, 0x88, 0xf0, 0x4d, 0xaa, 0x93, 0xbd, 0x6e, 0x39, 0x7f, 0x83, 0xec, 0x60, + 0x4a, 0x9c, 0xf6, 0xab, 0xc1, 0x43, 0xa1, 0x42, 0x55, 0x8c, 0xd9, 0xaf, 0x58, 0x5c, 0x95, 0xf7, + 0x4b, 0x14, 0x61, 0xc9, 0x08, 0xbd, 0x0c, 0x53, 0xb7, 0xad, 0x7d, 0xb2, 0xeb, 0x7b, 0x6e, 0x28, + 0xb2, 0x56, 0xc6, 0x4c, 0xcf, 0xbd, 0x21, 0xc9, 0x09, 0xbe, 0x6c, 0x7b, 0x57, 0x85, 0x38, 0x62, + 0x87, 0xf6, 0xa1, 0xe4, 0x92, 0xdb, 0x98, 0x38, 0x76, 0x5d, 0x64, 0x46, 0x8e, 0x29, 0xd6, 0x57, + 0x04, 0x35, 0xc1, 0x99, 0xed, 0x7b, 0xb2, 0x0c, 0x2b, 0x5e, 0x74, 0x2e, 0x6f, 0x7a, 0x3b, 0x42, + 0x51, 0x8d, 0x39, 0x97, 0xca, 0xcf, 0xe4, 0x73, 0x79, 0xd9, 0xdb, 0xc1, 0x94, 0x38, 0x5d, 0x23, + 0x75, 0x95, 0x32, 0x21, 0xd4, 0xd4, 0x95, 0x6c, 0x53, 0x45, 0xf8, 0x1a, 0x89, 0x4a, 0xb1, 0xc6, + 0x91, 0x8e, 0x6d, 0x53, 0x1c, 0x6b, 0x09, 0x45, 0x35, 0xe6, 0xd8, 0xc6, 0x0f, 0xc9, 0xf8, 0xd8, + 0xca, 0x32, 0xac, 0x78, 0x99, 0xff, 0x50, 0x80, 0x19, 0xfd, 0x21, 0x91, 0x21, 0xf6, 0x6a, 0x65, + 0x9f, 0xe6, 0x46, 0xb1, 0x4f, 0xa9, 0x7b, 0xa1, 0x5d, 0x4a, 0x97, 0x27, 0x0c, 0xeb, 0x99, 0x99, + 0x67, 0x91, 0x7b, 0xa1, 0x15, 0x06, 0x38, 0xc6, 0x74, 0x84, 0x08, 0x30, 0x35, 0x72, 0xb8, 0x19, + 0x50, 0x8c, 0x1b, 0x39, 0xb1, 0x8d, 0xfd, 0x3c, 0x40, 0xf4, 0xa0, 0x86, 0x08, 0x03, 0x28, 0xeb, + 0x49, 0x7b, 0xe8, 0x43, 0xc3, 0x42, 0x8f, 0xc1, 0x04, 0xdd, 0x28, 0x49, 0x43, 0x5c, 0x6c, 0x53, + 0x3e, 0xdc, 0x45, 0x56, 0x8a, 0x05, 0x14, 0x3d, 0x4d, 0x6d, 0x9a, 0x68, 0x7b, 0x13, 0xf7, 0xd5, + 0x96, 0x22, 0x9b, 0x26, 0x82, 0xe1, 0x18, 0x26, 0x6d, 0x3a, 0xa1, 0xbb, 0x11, 0x93, 0x24, 0xad, + 0xe9, 0x6c, 0x8b, 0xc2, 0x1c, 0xc6, 0xce, 0x14, 0x12, 0xbb, 0x17, 0xdb, 0xac, 0x8a, 0xda, 0x99, + 0x42, 0x02, 0x8e, 0xfb, 0x6a, 0xd0, 0xce, 0x88, 0x08, 0xc6, 0x34, 0x4f, 0x74, 0x1b, 0x10, 0x7b, + 0xf8, 0x18, 0xcc, 0xc5, 0x57, 0x3b, 0x9d, 0x8a, 0xb6, 0xef, 0xed, 0xda, 0x0e, 0x49, 0x9e, 0x9a, + 0x6c, 0xf1, 0x62, 0x2c, 0xe1, 0xc3, 0x1d, 0xdb, 0xfe, 0x59, 0x1e, 0x4e, 0x5c, 0x69, 0xda, 0xee, + 0x9d, 0xc4, 0x79, 0x67, 0xda, 0x33, 0x6f, 0xc6, 0xa8, 0xcf, 0xbc, 0x45, 0x19, 0xfc, 0xe2, 0x1d, + 0xbd, 0xf4, 0x0c, 0x7e, 0xf9, 0xc8, 0x5e, 0x1c, 0x17, 0xfd, 0xc8, 0x80, 0x87, 0xad, 0x06, 0xb7, + 0xbf, 0x2c, 0x47, 0x94, 0x46, 0x4c, 0xe5, 0x5a, 0x08, 0xc6, 0xd4, 0xa6, 0xfd, 0x9d, 0x5f, 0xa9, + 0x1c, 0xc2, 0x95, 0xbb, 0x31, 0xef, 0x10, 0x3d, 0x78, 0xf8, 0x30, 0x54, 0x7c, 0x68, 0xf3, 0x4f, + 0x5f, 0x85, 0xb7, 0xdf, 0x93, 0xd1, 0x48, 0xce, 0xca, 0x67, 0x0c, 0x98, 0xe2, 0xc7, 0x79, 0x98, + 0xec, 0xd2, 0x45, 0x66, 0xb5, 0xed, 0x17, 0x88, 0x1f, 0xc8, 0xf7, 0x27, 0x34, 0x17, 0xa5, 0xb2, + 0xb5, 0x2e, 0x20, 0x58, 0xc3, 0xa2, 0x6a, 0xec, 0x96, 0xed, 0x36, 0xc4, 0x34, 0x29, 0x35, 0xf6, + 0xbc, 0xed, 0x36, 0x30, 0x83, 0x28, 0x45, 0x97, 0x1f, 0xa4, 0xe8, 0xcc, 0xaf, 0x19, 0x30, 0xc7, + 0x2e, 0xe8, 0x44, 0xc6, 0xf3, 0x53, 0x2a, 0x30, 0xce, 0x9b, 0x71, 0x26, 0x1e, 0x18, 0xbf, 0xdb, + 0x2d, 0x4f, 0xf3, 0x2b, 0x3d, 0xf1, 0x38, 0xf9, 0x87, 0x85, 0xc7, 0xcd, 0xc2, 0xf7, 0xb9, 0x91, + 0x1d, 0x42, 0x75, 0xbe, 0x54, 0x93, 0x44, 0x70, 0x44, 0xcf, 0xfc, 0xfd, 0x3c, 0x9c, 0x48, 0xc9, + 0x34, 0xa7, 0xce, 0xf0, 0x04, 0x4b, 0xb6, 0x95, 0xc1, 0xe7, 0x97, 0x32, 0xcf, 0x66, 0x5f, 0x61, + 0x39, 0xbd, 0x42, 0x92, 0xd4, 0xd2, 0xe7, 0x85, 0x58, 0x30, 0x47, 0xbf, 0x6e, 0xc0, 0xb4, 0xa5, + 0x09, 0x3b, 0x8f, 0xc7, 0xef, 0x64, 0xdf, 0x98, 0x3e, 0xd9, 0xd6, 0xf2, 0x88, 0x22, 0x51, 0xd6, + 0xdb, 0x72, 0xfa, 0x7d, 0x30, 0xad, 0x75, 0x61, 0x14, 0x19, 0x3d, 0xfd, 0x2c, 0x2c, 0x8c, 0x25, + 0xe3, 0x1f, 0x82, 0x51, 0x1f, 0x34, 0xa1, 0xca, 0xf6, 0xb6, 0x7e, 0x6f, 0x4d, 0x8d, 0xb8, 0xb8, + 0xb8, 0x26, 0xa0, 0xe6, 0x0e, 0x2c, 0x24, 0x0d, 0xf4, 0xcc, 0xa3, 0x64, 0xef, 0x81, 0x11, 0x9f, + 0x20, 0x31, 0xff, 0x3c, 0x07, 0x93, 0xe2, 0xba, 0xca, 0x7d, 0x48, 0xc1, 0xbb, 0x15, 0x3b, 0xe6, + 0x5f, 0xcf, 0xe4, 0x96, 0xcd, 0xc0, 0xfc, 0xbb, 0x20, 0x91, 0x7f, 0xf7, 0x7c, 0x36, 0xec, 0x0e, + 0x4f, 0xbe, 0xfb, 0x8f, 0x1c, 0xcc, 0x27, 0xae, 0xff, 0xa0, 0xd7, 0x8d, 0xfe, 0x9c, 0x93, 0xeb, + 0x99, 0xde, 0x30, 0x52, 0xe9, 0xa1, 0x87, 0xa7, 0x9f, 0x04, 0xb1, 0x97, 0x9e, 0xae, 0x65, 0xf6, + 0x48, 0xe4, 0x5b, 0xe7, 0xd1, 0x27, 0xf3, 0xef, 0x0d, 0x78, 0x70, 0xe0, 0xf5, 0x2b, 0x76, 0xaf, + 0xdc, 0x8f, 0x43, 0x85, 0xa4, 0x67, 0x7c, 0x9d, 0x52, 0x1d, 0x66, 0x27, 0xaf, 0x02, 0x27, 0xd9, + 0xa3, 0x27, 0x61, 0x86, 0xed, 0x1a, 0x74, 0xb1, 0x86, 0xa4, 0x2d, 0x4e, 0xef, 0xd8, 0x39, 0x4e, + 0x4d, 0x2b, 0xc7, 0x31, 0x2c, 0xf3, 0xab, 0x06, 0x2c, 0x0f, 0xba, 0x65, 0x3c, 0x84, 0xb7, 0xf0, + 0xff, 0x12, 0xc9, 0x77, 0xe5, 0xbe, 0xe4, 0xbb, 0x84, 0xbf, 0x20, 0xf3, 0xec, 0x34, 0x53, 0x3d, + 0x7f, 0x8f, 0xdc, 0xb2, 0xcf, 0x1b, 0x70, 0x6a, 0x80, 0x98, 0xf6, 0x25, 0x61, 0x1a, 0x47, 0x4e, + 0xc2, 0xcc, 0x0d, 0x9b, 0x84, 0x69, 0xfe, 0x65, 0x1e, 0x16, 0x44, 0x7b, 0x22, 0xd3, 0xe1, 0xe9, + 0x58, 0x0a, 0xe3, 0x3b, 0x12, 0x29, 0x8c, 0x4b, 0x49, 0xfc, 0xff, 0xc9, 0x5f, 0x7c, 0x6b, 0xe5, + 0x2f, 0xfe, 0x2c, 0x07, 0x27, 0x53, 0x2f, 0x53, 0xa3, 0xcf, 0xa6, 0xe8, 0xdc, 0x1b, 0x19, 0xdf, + 0xda, 0x1e, 0x52, 0xeb, 0x8e, 0x9b, 0xf4, 0xf7, 0x25, 0x3d, 0xd9, 0x8e, 0xeb, 0xd0, 0xdd, 0x63, + 0xb8, 0x7f, 0x3e, 0x62, 0xde, 0x9d, 0xf9, 0x2b, 0x79, 0x78, 0x7c, 0x58, 0x42, 0x6f, 0xd1, 0xbc, + 0xec, 0x20, 0x96, 0x97, 0x7d, 0x9f, 0xf6, 0xc3, 0x63, 0x49, 0xd1, 0xfe, 0x7a, 0x5e, 0x6d, 0x7b, + 0xfd, 0xf2, 0x39, 0x54, 0xa8, 0x67, 0x92, 0xda, 0x4c, 0xf2, 0x49, 0xb4, 0x48, 0x15, 0x4e, 0xd6, + 0x78, 0xf1, 0xdd, 0x6e, 0x79, 0x51, 0x3c, 0x93, 0x54, 0x23, 0xa1, 0x28, 0xc4, 0xb2, 0x12, 0x7a, + 0x1c, 0x4a, 0x3e, 0x87, 0xca, 0x4c, 0x54, 0x11, 0x2f, 0xe3, 0x65, 0x58, 0x41, 0xd1, 0xa7, 0x35, + 0x23, 0xb3, 0x70, 0x5c, 0xf7, 0x79, 0x0f, 0x0b, 0x03, 0xbe, 0x04, 0xa5, 0x40, 0x3e, 0x6e, 0xc6, + 0xcf, 0x6a, 0x9f, 0x18, 0x32, 0xc1, 0x99, 0xfa, 0x24, 0xf2, 0xa5, 0x33, 0xde, 0x3f, 0xf5, 0x0e, + 0x9a, 0x22, 0x89, 0x4c, 0xe5, 0x0e, 0xf0, 0x83, 0x27, 0x48, 0x71, 0x05, 0xbe, 0x67, 0xc0, 0xb4, + 0x98, 0xad, 0xfb, 0x90, 0x73, 0x7d, 0x33, 0x9e, 0x73, 0x7d, 0x21, 0x13, 0xdd, 0x31, 0x20, 0xe1, + 0xfa, 0x26, 0xcc, 0xe8, 0xef, 0x69, 0xa0, 0x17, 0x35, 0xdd, 0x67, 0x8c, 0x73, 0x6f, 0x5f, 0x6a, + 0xc7, 0x48, 0x2f, 0x9a, 0x5f, 0x29, 0xa9, 0x51, 0x64, 0x99, 0xdd, 0xba, 0x0c, 0x1a, 0x87, 0xca, + 0xa0, 0x2e, 0x02, 0xb9, 0xec, 0x45, 0xe0, 0x1a, 0x94, 0xa4, 0x82, 0x12, 0xdb, 0xf8, 0xa3, 0x7a, + 0x42, 0x13, 0xb5, 0x05, 0x28, 0x31, 0x4d, 0x70, 0x99, 0x0f, 0xa3, 0xe6, 0x50, 0x29, 0x4e, 0x45, + 0x06, 0xbd, 0x0c, 0xd3, 0xb7, 0x3d, 0xff, 0x96, 0xe3, 0x59, 0xec, 0xd9, 0x42, 0xc8, 0xe2, 0xd4, + 0x5d, 0x9d, 0xe5, 0xf0, 0xbc, 0xd9, 0x1b, 0x11, 0x7d, 0xac, 0x33, 0x43, 0x15, 0x98, 0x6f, 0xd9, + 0x2e, 0x26, 0x56, 0x43, 0xa5, 0x56, 0x17, 0xf8, 0xbb, 0x6a, 0xd2, 0xc8, 0xdd, 0x8c, 0x83, 0x71, + 0x12, 0x1f, 0x7d, 0x02, 0x4a, 0x81, 0x78, 0xb3, 0x23, 0x9b, 0xf8, 0x88, 0x72, 0xc6, 0x38, 0xd1, + 0x68, 0xec, 0x64, 0x09, 0x56, 0x0c, 0xd1, 0x06, 0x2c, 0xf9, 0xe2, 0x56, 0x7c, 0xec, 0x79, 0x66, + 0xbe, 0x3e, 0xd9, 0xf3, 0x5d, 0x38, 0x05, 0x8e, 0x53, 0x6b, 0x51, 0x2b, 0x86, 0x3d, 0x0c, 0xc3, + 0x0f, 0x8a, 0xb5, 0xb3, 0x55, 0x26, 0xf0, 0x0d, 0x2c, 0xa0, 0x87, 0xa5, 0xea, 0x97, 0xc6, 0x48, + 0xd5, 0xaf, 0xc1, 0xc9, 0x24, 0x88, 0xdd, 0xdd, 0x67, 0xcf, 0x05, 0x68, 0xbb, 0xc7, 0x56, 0x1a, + 0x12, 0x4e, 0xaf, 0x8b, 0x6e, 0xc0, 0x94, 0x4f, 0x98, 0x7f, 0x51, 0x91, 0x11, 0xd9, 0x91, 0x73, + 0x4f, 0xb0, 0x24, 0x80, 0x23, 0x5a, 0x74, 0xde, 0xad, 0xf8, 0xd3, 0x62, 0xd7, 0x32, 0xfc, 0xc0, + 0x84, 0x98, 0xfb, 0x01, 0x6f, 0x6a, 0x98, 0x6f, 0xce, 0xc1, 0x6c, 0xcc, 0x69, 0x47, 0x8f, 0x42, + 0x91, 0x3d, 0x66, 0xc0, 0xd4, 0x43, 0x29, 0x52, 0x61, 0x7c, 0x70, 0x38, 0x0c, 0x7d, 0xc1, 0x80, + 0xf9, 0x76, 0xec, 0x80, 0x51, 0x6a, 0xce, 0x31, 0x83, 0x3f, 0xf1, 0x53, 0x4b, 0xed, 0x51, 0xce, + 0x38, 0x33, 0x9c, 0xe4, 0x4e, 0x17, 0xa0, 0x48, 0xc7, 0x72, 0x88, 0xcf, 0xb0, 0x85, 0x8d, 0xa3, + 0x48, 0xac, 0xc6, 0xc1, 0x38, 0x89, 0x4f, 0x67, 0x98, 0xf5, 0x6e, 0x9c, 0x97, 0xe7, 0x2b, 0x92, + 0x00, 0x8e, 0x68, 0xa1, 0x67, 0x61, 0x4e, 0xbc, 0x28, 0xb5, 0xe5, 0x35, 0x2e, 0x59, 0xc1, 0x9e, + 0x30, 0xee, 0x95, 0x33, 0xb2, 0x1a, 0x83, 0xe2, 0x04, 0x36, 0xeb, 0x5b, 0xf4, 0x6c, 0x17, 0x23, + 0x30, 0x11, 0x7f, 0xb3, 0x74, 0x35, 0x0e, 0xc6, 0x49, 0x7c, 0xf4, 0x2e, 0x4d, 0xef, 0xf3, 0xe0, + 0x8d, 0xd2, 0x06, 0x29, 0xba, 0xbf, 0x02, 0xf3, 0x1d, 0xe6, 0x0b, 0x35, 0x24, 0x50, 0xac, 0x47, + 0xc5, 0xf0, 0x7a, 0x1c, 0x8c, 0x93, 0xf8, 0xe8, 0x19, 0x98, 0xf5, 0xa9, 0x76, 0x53, 0x04, 0x78, + 0x44, 0x47, 0x85, 0x1d, 0xb0, 0x0e, 0xc4, 0x71, 0x5c, 0xf4, 0x1c, 0x2c, 0x46, 0xcf, 0xdc, 0x48, + 0x02, 0x3c, 0xc4, 0xa3, 0xde, 0x8d, 0xa8, 0x24, 0x11, 0x70, 0x7f, 0x1d, 0xf4, 0xff, 0x61, 0x41, + 0x1b, 0x89, 0x75, 0xb7, 0x41, 0xee, 0x88, 0xa7, 0x48, 0xd8, 0xb7, 0x76, 0x56, 0x13, 0x30, 0xdc, + 0x87, 0x8d, 0xde, 0x0f, 0x73, 0x75, 0xcf, 0x71, 0x98, 0x8e, 0xe3, 0xef, 0x65, 0xf2, 0x37, 0x47, + 0xf8, 0xeb, 0x2c, 0x31, 0x08, 0x4e, 0x60, 0xa2, 0xcb, 0x80, 0xbc, 0x9d, 0x80, 0xf8, 0xfb, 0xa4, + 0xf1, 0x1c, 0xff, 0x96, 0x15, 0xdd, 0xe2, 0x67, 0xe3, 0xc9, 0xa0, 0x57, 0xfb, 0x30, 0x70, 0x4a, + 0x2d, 0xf6, 0xec, 0x84, 0x76, 0x31, 0x63, 0x2e, 0x8b, 0x57, 0xd8, 0x93, 0x9e, 0xfb, 0x3d, 0x6f, + 0x65, 0xf8, 0x30, 0xc1, 0x73, 0x73, 0x97, 0xe7, 0xb3, 0x78, 0x7a, 0x47, 0x7f, 0x3a, 0x2f, 0xda, + 0x23, 0x78, 0x29, 0x16, 0x9c, 0xd0, 0xa7, 0x60, 0x6a, 0x47, 0xbe, 0xa3, 0xba, 0xbc, 0x90, 0xc5, + 0xbe, 0x98, 0x78, 0x12, 0x38, 0xf2, 0x4c, 0x15, 0x00, 0x47, 0x2c, 0xd1, 0x63, 0x30, 0x7d, 0x69, + 0xab, 0xa2, 0xa4, 0x70, 0x91, 0xcd, 0x7e, 0x81, 0x56, 0xc1, 0x3a, 0x80, 0xae, 0x30, 0x65, 0x2f, + 0x21, 0x36, 0xc5, 0xd1, 0x7e, 0xdb, 0x6f, 0xfe, 0x50, 0x6c, 0x16, 0x69, 0xc3, 0xb5, 0xe5, 0x13, + 0x09, 0x6c, 0x51, 0x8e, 0x15, 0x06, 0x7a, 0x09, 0xa6, 0xc5, 0x7e, 0xc1, 0x74, 0xd3, 0xd2, 0xd1, + 0x2e, 0xfd, 0xe0, 0x88, 0x04, 0xd6, 0xe9, 0xa1, 0xa7, 0x60, 0xba, 0xcd, 0x9e, 0x97, 0x24, 0x17, + 0x3b, 0x8e, 0xb3, 0x7c, 0x92, 0xe9, 0x4d, 0x15, 0x82, 0xd8, 0x8a, 0x40, 0x58, 0xc7, 0x43, 0x4f, + 0xc8, 0x70, 0xfa, 0xdb, 0x62, 0x11, 0x25, 0x15, 0x4e, 0x57, 0x56, 0xee, 0x80, 0x6c, 0xcf, 0x53, + 0xf7, 0x88, 0x63, 0xef, 0xc0, 0x69, 0x69, 0x62, 0xf5, 0x2f, 0x92, 0xe5, 0xe5, 0xd8, 0x29, 0xc1, + 0xe9, 0x1b, 0x03, 0x31, 0xf1, 0x21, 0x54, 0xd0, 0x0e, 0xe4, 0x2d, 0x67, 0x67, 0xf9, 0xc1, 0x2c, + 0x6c, 0x45, 0xf5, 0x6d, 0x3a, 0x9e, 0xa1, 0x51, 0xd9, 0xa8, 0x62, 0x4a, 0xdc, 0x7c, 0x35, 0x3a, + 0xee, 0x56, 0x8f, 0xb2, 0x7d, 0x52, 0x97, 0x6a, 0x23, 0x8b, 0x6f, 0x2f, 0xf5, 0x3d, 0x36, 0xcc, + 0x37, 0xa4, 0x54, 0x99, 0x6e, 0xab, 0x75, 0x9c, 0xc9, 0x3d, 0xff, 0xf8, 0x83, 0x73, 0xdc, 0x9b, + 0x8b, 0xaf, 0x62, 0xf3, 0xc7, 0x05, 0x75, 0x08, 0x95, 0x88, 0x72, 0xfb, 0x50, 0xb4, 0x83, 0xd0, + 0xf6, 0x32, 0xbc, 0xcb, 0x93, 0x78, 0xa9, 0x8d, 0x65, 0x35, 0x32, 0x00, 0xe6, 0xac, 0x28, 0x4f, + 0xb7, 0x69, 0xbb, 0x77, 0x44, 0xf7, 0xaf, 0x65, 0x1e, 0xbe, 0xe6, 0x3c, 0x19, 0x00, 0x73, 0x56, + 0xe8, 0x26, 0x97, 0xb4, 0x6c, 0xbe, 0xb3, 0x95, 0xfc, 0x7c, 0x5e, 0x5c, 0xe2, 0x28, 0xaf, 0xa0, + 0x65, 0x0b, 0x1b, 0x66, 0x4c, 0x5e, 0xb5, 0xcd, 0xf5, 0x34, 0x5e, 0xb5, 0xcd, 0x75, 0x4c, 0x99, + 0xa0, 0xd7, 0x0d, 0x00, 0x4b, 0x7d, 0x47, 0x2e, 0x9b, 0x97, 0xb9, 0x07, 0x7d, 0x97, 0x8e, 0x27, + 0x22, 0x45, 0x50, 0xac, 0x71, 0x36, 0xff, 0xd9, 0x00, 0xed, 0xe3, 0x3b, 0x51, 0x16, 0x8c, 0x31, + 0x74, 0x16, 0x4c, 0x6e, 0xc4, 0x2c, 0x98, 0xfc, 0x48, 0x59, 0x30, 0x85, 0xd1, 0xb3, 0x60, 0x8a, + 0x83, 0xb3, 0x60, 0xcc, 0x37, 0x0c, 0x58, 0xec, 0x9b, 0x9b, 0xe4, 0x47, 0x0e, 0x8d, 0x21, 0x3f, + 0x72, 0xb8, 0x06, 0x0b, 0xe2, 0xe9, 0xc2, 0x5a, 0xdb, 0xb1, 0x53, 0xaf, 0xff, 0x6d, 0x27, 0xe0, + 0xb8, 0xaf, 0x86, 0xf9, 0xc7, 0x06, 0x4c, 0x6b, 0xb7, 0x15, 0x68, 0x3f, 0xd8, 0xad, 0x0e, 0xd1, + 0x8c, 0xe8, 0xd5, 0x46, 0x76, 0xcc, 0xc8, 0x61, 0xfc, 0xc4, 0xbb, 0xa9, 0x3d, 0xce, 0x15, 0x9d, + 0x78, 0xd3, 0x52, 0x2c, 0xa0, 0xfc, 0xd9, 0x25, 0xc2, 0x3f, 0x60, 0x99, 0xd7, 0x9f, 0x5d, 0x22, + 0x6d, 0xcc, 0x20, 0x8c, 0x1d, 0xdd, 0xd3, 0x44, 0x82, 0x94, 0xf6, 0x48, 0xa4, 0x45, 0x3d, 0x17, + 0x06, 0x43, 0x67, 0x20, 0x4f, 0xdc, 0x86, 0x30, 0xc0, 0xd5, 0x27, 0x03, 0x2e, 0xb8, 0x0d, 0x4c, + 0xcb, 0xcd, 0xab, 0x30, 0x53, 0x23, 0x75, 0x9f, 0x84, 0xcf, 0x93, 0x83, 0xa1, 0xbf, 0x41, 0x70, + 0x8b, 0x1c, 0x24, 0xbf, 0x41, 0x40, 0xab, 0xd3, 0x72, 0xf3, 0x77, 0x0c, 0x48, 0xbc, 0xd9, 0xa9, + 0x9d, 0x7e, 0x19, 0x83, 0x4e, 0xbf, 0x62, 0xe7, 0x34, 0xb9, 0x43, 0xcf, 0x69, 0x2e, 0x03, 0x6a, + 0x59, 0x61, 0x7d, 0x2f, 0xf6, 0xa2, 0xac, 0xf0, 0x7d, 0xa2, 0xbb, 0x51, 0x7d, 0x18, 0x38, 0xa5, + 0x96, 0xf9, 0x8a, 0x01, 0x7d, 0xdf, 0x9f, 0xa4, 0x3b, 0x36, 0x11, 0xcf, 0xbb, 0x73, 0x97, 0x50, + 0xed, 0xd8, 0xf2, 0x55, 0x77, 0x09, 0xa7, 0x7e, 0x83, 0x3c, 0x79, 0x92, 0x7e, 0x3c, 0xbf, 0x45, + 0xa2, 0xfc, 0x86, 0xb5, 0x38, 0x18, 0x27, 0xf1, 0xcd, 0x17, 0xa0, 0x24, 0xaf, 0xda, 0xb1, 0xfb, + 0x2a, 0xd2, 0x13, 0xd5, 0xef, 0xab, 0x50, 0x47, 0x94, 0x41, 0xe8, 0x30, 0x05, 0xae, 0x7d, 0xc9, + 0x0b, 0x42, 0x79, 0x3f, 0x90, 0x9f, 0x37, 0x5d, 0x59, 0x67, 0x65, 0x58, 0x41, 0xcd, 0x45, 0x98, + 0x57, 0x07, 0x49, 0x5c, 0xe8, 0xcd, 0x6f, 0xe7, 0x61, 0x26, 0xf6, 0x55, 0xa1, 0x7b, 0x4f, 0xf6, + 0xf0, 0xd3, 0x92, 0x72, 0x20, 0x94, 0x1f, 0xf1, 0x40, 0x48, 0x3f, 0x81, 0x2b, 0x1c, 0xef, 0x09, + 0x5c, 0x31, 0x9b, 0x13, 0xb8, 0x10, 0x26, 0xc5, 0x17, 0x57, 0x45, 0x9a, 0xed, 0x66, 0x46, 0xf7, + 0xe4, 0xc5, 0x85, 0x53, 0x96, 0x59, 0x2c, 0x15, 0x98, 0x64, 0x65, 0x7e, 0xb3, 0x08, 0x73, 0xf1, + 0x9b, 0xf3, 0x43, 0xcc, 0xe4, 0xbb, 0xfa, 0x66, 0x72, 0x44, 0x87, 0x38, 0x3f, 0xae, 0x43, 0x5c, + 0x18, 0xd7, 0x21, 0x2e, 0x1e, 0xc1, 0x21, 0xee, 0x77, 0x67, 0x27, 0x86, 0x76, 0x67, 0x3f, 0xa0, + 0xa2, 0xb9, 0x93, 0xb1, 0xf0, 0x47, 0x14, 0xcd, 0x45, 0xf1, 0x69, 0x58, 0xf5, 0x1a, 0xa9, 0x51, + 0xf1, 0xd2, 0x3d, 0x0c, 0x7f, 0x3f, 0x35, 0xf8, 0x3a, 0xfa, 0x99, 0xdb, 0xdb, 0x46, 0x08, 0xbc, + 0x46, 0x1f, 0x15, 0x66, 0x9b, 0x1f, 0xc4, 0x37, 0xce, 0x5a, 0x04, 0xc2, 0x3a, 0x1e, 0xfb, 0x9c, + 0x4c, 0xfc, 0xfb, 0x39, 0xec, 0x7c, 0x41, 0xff, 0x9c, 0x4c, 0xe2, 0x7b, 0x3b, 0x49, 0x7c, 0xf3, + 0x1b, 0x79, 0x98, 0x8b, 0x3f, 0x07, 0x8e, 0x6e, 0x2b, 0xfb, 0x3c, 0x13, 0xd7, 0x80, 0x93, 0xd5, + 0xee, 0x8e, 0x0f, 0x74, 0xb6, 0xf9, 0xa7, 0x6e, 0x77, 0xd4, 0x45, 0xf6, 0xe3, 0x63, 0x2c, 0xbc, + 0x5c, 0xc1, 0x8e, 0xbd, 0x20, 0x1e, 0x65, 0x6a, 0x8a, 0x08, 0x6e, 0xe6, 0xdc, 0xa3, 0xdc, 0x4b, + 0xc5, 0x0a, 0x6b, 0x6c, 0xa9, 0x7a, 0xdf, 0x27, 0xbe, 0xbd, 0x6b, 0xab, 0x4f, 0x99, 0x30, 0xe5, + 0xf9, 0x82, 0x28, 0xc3, 0x0a, 0x6a, 0xbe, 0x92, 0x83, 0xe8, 0xc3, 0x4d, 0xec, 0x65, 0xe2, 0x40, + 0x33, 0x1b, 0xc4, 0xb4, 0x5d, 0x1e, 0xf7, 0xf9, 0xef, 0x88, 0xa2, 0x48, 0x76, 0xd1, 0x4a, 0x70, + 0x8c, 0xe3, 0xcf, 0xe1, 0x83, 0x4d, 0x16, 0xcc, 0x27, 0x6e, 0x60, 0x64, 0x9e, 0xaa, 0xf7, 0x95, + 0x3c, 0x4c, 0xa9, 0x3b, 0x2c, 0xe8, 0x7d, 0xec, 0x51, 0xd1, 0x3d, 0x4f, 0x3e, 0xf5, 0xfa, 0x76, + 0xed, 0xe9, 0xcf, 0x3d, 0xaf, 0x71, 0xb7, 0x5b, 0x9e, 0x57, 0xc8, 0xbc, 0x08, 0x8b, 0x0a, 0xd4, + 0x48, 0xeb, 0xf8, 0x4e, 0xd2, 0x48, 0xbb, 0x8e, 0x37, 0x30, 0x2d, 0x47, 0x77, 0x60, 0x72, 0x8f, + 0x58, 0x0d, 0xe2, 0xcb, 0xdc, 0x81, 0xcd, 0x8c, 0xee, 0xdd, 0x5c, 0x62, 0x54, 0xa3, 0x61, 0xe0, + 0xff, 0x03, 0x2c, 0xd9, 0xd1, 0x8d, 0x6a, 0xc7, 0x6b, 0x1c, 0x24, 0x9f, 0x0a, 0xad, 0x7a, 0x8d, + 0x03, 0xcc, 0x20, 0xe8, 0x59, 0x98, 0x0b, 0xed, 0x16, 0xf1, 0x3a, 0xa1, 0xfe, 0x59, 0x9c, 0x7c, + 0x74, 0x78, 0xbc, 0x1d, 0x83, 0xe2, 0x04, 0x36, 0xdd, 0xe8, 0x6e, 0x06, 0x9e, 0xcb, 0x9e, 0x29, + 0x99, 0x88, 0x9f, 0x34, 0x5d, 0xae, 0x5d, 0xbd, 0xc2, 0x5e, 0x29, 0x51, 0x18, 0x14, 0xdb, 0x66, + 0x89, 0xf2, 0x3e, 0x11, 0xb1, 0x9b, 0x85, 0xe8, 0x3a, 0x23, 0x2f, 0xc7, 0x0a, 0xc3, 0xbc, 0x0e, + 0xf3, 0x89, 0xae, 0x4a, 0x73, 0xd8, 0x48, 0x37, 0x87, 0x87, 0x7b, 0x97, 0xf3, 0x0f, 0x0c, 0x58, + 0xec, 0x5b, 0xbc, 0xc3, 0xe6, 0x90, 0x26, 0x35, 0x79, 0xee, 0xe8, 0x9a, 0x3c, 0x3f, 0x9a, 0x26, + 0xaf, 0xae, 0x7c, 0xe7, 0xcd, 0xb3, 0x0f, 0x7c, 0xf7, 0xcd, 0xb3, 0x0f, 0x7c, 0xff, 0xcd, 0xb3, + 0x0f, 0xbc, 0xd2, 0x3b, 0x6b, 0x7c, 0xa7, 0x77, 0xd6, 0xf8, 0x6e, 0xef, 0xac, 0xf1, 0xfd, 0xde, + 0x59, 0xe3, 0xc7, 0xbd, 0xb3, 0xc6, 0x1b, 0x3f, 0x39, 0xfb, 0xc0, 0x8b, 0x25, 0x29, 0x26, 0xff, + 0x19, 0x00, 0x00, 0xff, 0xff, 0xd5, 0x66, 0xee, 0x39, 0xa9, 0x82, 0x00, 0x00, } func (m *ALBStatus) Marshal() (dAtA []byte, err error) { @@ -7150,18 +7150,20 @@ func (m *RolloutStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - { - size, err := m.ALB.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + if m.ALB != nil { + { + size, err := m.ALB.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xca } - i-- - dAtA[i] = 0x1 - i-- - dAtA[i] = 0xca i -= len(m.WorkloadObservedGeneration) copy(dAtA[i:], m.WorkloadObservedGeneration) i = encodeVarintGenerated(dAtA, i, uint64(len(m.WorkloadObservedGeneration))) @@ -9735,8 +9737,10 @@ func (m *RolloutStatus) Size() (n int) { n += 2 + l + sovGenerated(uint64(l)) l = len(m.WorkloadObservedGeneration) n += 2 + l + sovGenerated(uint64(l)) - l = m.ALB.Size() - n += 2 + l + sovGenerated(uint64(l)) + if m.ALB != nil { + l = m.ALB.Size() + n += 2 + l + sovGenerated(uint64(l)) + } return n } @@ -11224,7 +11228,7 @@ func (this *RolloutStatus) String() string { `Phase:` + fmt.Sprintf("%v", this.Phase) + `,`, `Message:` + fmt.Sprintf("%v", this.Message) + `,`, `WorkloadObservedGeneration:` + fmt.Sprintf("%v", this.WorkloadObservedGeneration) + `,`, - `ALB:` + strings.Replace(strings.Replace(this.ALB.String(), "ALBStatus", "ALBStatus", 1), `&`, ``, 1) + `,`, + `ALB:` + strings.Replace(this.ALB.String(), "ALBStatus", "ALBStatus", 1) + `,`, `}`, }, "") return s @@ -24921,6 +24925,9 @@ func (m *RolloutStatus) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } + if m.ALB == nil { + m.ALB = &ALBStatus{} + } if err := m.ALB.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index 7e24562d25..b420c0f355 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -3795,7 +3795,6 @@ func schema_pkg_apis_rollouts_v1alpha1_RolloutStatus(ref common.ReferenceCallbac "alb": { SchemaProps: spec.SchemaProps{ Description: "/ ALB keeps information regarding the ALB and TargetGroups", - Default: map[string]interface{}{}, Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ALBStatus"), }, }, diff --git a/pkg/apis/rollouts/v1alpha1/types.go b/pkg/apis/rollouts/v1alpha1/types.go index 44a2a9c21f..b2810665ad 100644 --- a/pkg/apis/rollouts/v1alpha1/types.go +++ b/pkg/apis/rollouts/v1alpha1/types.go @@ -753,7 +753,7 @@ type RolloutStatus struct { // +optional WorkloadObservedGeneration string `json:"workloadObservedGeneration,omitempty" protobuf:"bytes,24,opt,name=workloadObservedGeneration"` /// ALB keeps information regarding the ALB and TargetGroups - ALB ALBStatus `json:"alb,omitempty" protobuf:"bytes,25,opt,name=alb"` + ALB *ALBStatus `json:"alb,omitempty" protobuf:"bytes,25,opt,name=alb"` } // BlueGreenStatus status fields that only pertain to the blueGreen rollout diff --git a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go index e7ff0ab8d5..c5dbb72bd8 100644 --- a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go @@ -1988,7 +1988,11 @@ func (in *RolloutStatus) DeepCopyInto(out *RolloutStatus) { in, out := &in.RestartedAt, &out.RestartedAt *out = (*in).DeepCopy() } - out.ALB = in.ALB + if in.ALB != nil { + in, out := &in.ALB, &out.ALB + *out = new(ALBStatus) + **out = **in + } return } diff --git a/rollout/trafficrouting/alb/alb.go b/rollout/trafficrouting/alb/alb.go index f3830a9c49..e7ced03efb 100644 --- a/rollout/trafficrouting/alb/alb.go +++ b/rollout/trafficrouting/alb/alb.go @@ -121,8 +121,12 @@ func (r *Reconciler) shouldVerifyWeight() bool { func (r *Reconciler) VerifyWeight(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) (*bool, error) { if !r.shouldVerifyWeight() { + r.cfg.Status.ALB = nil return nil, nil } + if r.cfg.Status.ALB == nil { + r.cfg.Status.ALB = &v1alpha1.ALBStatus{} + } ctx := context.TODO() rollout := r.cfg.Rollout ingressName := rollout.Spec.Strategy.Canary.TrafficRouting.ALB.Ingress diff --git a/rollout/trafficrouting/alb/alb_test.go b/rollout/trafficrouting/alb/alb_test.go index 7afb8aa7a6..deca405037 100644 --- a/rollout/trafficrouting/alb/alb_test.go +++ b/rollout/trafficrouting/alb/alb_test.go @@ -464,7 +464,8 @@ func TestVerifyWeight(t *testing.T) { // LoadBalancer not found { - r, _ := newFakeReconciler(nil) + var status v1alpha1.RolloutStatus + r, _ := newFakeReconciler(&status) weightVerified, err := r.VerifyWeight(10) assert.NoError(t, err) assert.False(t, *weightVerified) @@ -505,7 +506,7 @@ func TestVerifyWeight(t *testing.T) { weightVerified, err := r.VerifyWeight(10) assert.NoError(t, err) assert.False(t, *weightVerified) - assert.Equal(t, status.ALB, *fakeClient.getAlbStatus()) + assert.Equal(t, *status.ALB, *fakeClient.getAlbStatus()) } // LoadBalancer found, at weight @@ -543,7 +544,7 @@ func TestVerifyWeight(t *testing.T) { weightVerified, err := r.VerifyWeight(10) assert.NoError(t, err) assert.True(t, *weightVerified) - assert.Equal(t, status.ALB, *fakeClient.getAlbStatus()) + assert.Equal(t, *status.ALB, *fakeClient.getAlbStatus()) } } @@ -677,7 +678,7 @@ func TestVerifyWeightWithAdditionalDestinations(t *testing.T) { weightVerified, err := r.VerifyWeight(10, weightDestinations...) assert.NoError(t, err) assert.False(t, *weightVerified) - assert.Equal(t, status.ALB, *fakeClient.getAlbStatus()) + assert.Equal(t, *status.ALB, *fakeClient.getAlbStatus()) } // LoadBalancer found, with incorrect weights @@ -735,7 +736,7 @@ func TestVerifyWeightWithAdditionalDestinations(t *testing.T) { weightVerified, err := r.VerifyWeight(10, weightDestinations...) assert.NoError(t, err) assert.False(t, *weightVerified) - assert.Equal(t, status.ALB, *fakeClient.getAlbStatus()) + assert.Equal(t, *status.ALB, *fakeClient.getAlbStatus()) } // LoadBalancer found, with all correct weights @@ -793,6 +794,6 @@ func TestVerifyWeightWithAdditionalDestinations(t *testing.T) { weightVerified, err := r.VerifyWeight(10, weightDestinations...) assert.NoError(t, err) assert.True(t, *weightVerified) - assert.Equal(t, status.ALB, *fakeClient.getAlbStatus()) + assert.Equal(t, *status.ALB, *fakeClient.getAlbStatus()) } } From 4ee03654642c90e8970a9524d5da1623d6777399 Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Fri, 14 Jan 2022 13:52:24 -0800 Subject: [PATCH 044/175] chore: upgrade k8s libraries to v1.22 (#1773) Signed-off-by: Jesse Suen --- .github/workflows/e2e.yaml | 4 + .../features/kustomize/rollout_cr_schema.json | 9 + go.mod | 95 ++- go.sum | 551 +++++++----------- hack/gen-crd-spec/main.go | 8 +- hack/installers/install-codegen-go-tools.sh | 2 +- manifests/crds/analysis-run-crd.yaml | 11 +- manifests/crds/analysis-template-crd.yaml | 11 +- .../crds/cluster-analysis-template-crd.yaml | 11 +- manifests/crds/experiment-crd.yaml | 11 +- manifests/crds/rollout-crd.yaml | 11 +- manifests/install.yaml | 55 +- manifests/namespace-install.yaml | 55 +- metricproviders/prometheus/mock_test.go | 4 + pkg/apiclient/rollout/rollout.swagger.json | 58 +- pkg/apis/rollouts/v1alpha1/generated.pb.go | 458 +++------------ .../rollouts/v1alpha1/openapi_generated.go | 2 +- pkg/apis/rollouts/validation/validation.go | 19 +- .../versioned/fake/clientset_generated.go | 5 +- .../options/fake/fakeoptions.go | 14 +- 20 files changed, 585 insertions(+), 809 deletions(-) diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 1854019cc7..bec5015c09 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -21,6 +21,10 @@ jobs: name: Run end-to-end tests runs-on: ubuntu-latest steps: + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.16 - uses: actions/checkout@v2 - name: Setup k3s run: | diff --git a/docs/features/kustomize/rollout_cr_schema.json b/docs/features/kustomize/rollout_cr_schema.json index 2f27f6f557..d0cfd53991 100644 --- a/docs/features/kustomize/rollout_cr_schema.json +++ b/docs/features/kustomize/rollout_cr_schema.json @@ -871,6 +871,9 @@ "gmsaCredentialSpecName": { "type": "string" }, + "hostProcess": { + "type": "boolean" + }, "runAsUserName": { "type": "string" } @@ -1727,6 +1730,9 @@ "gmsaCredentialSpecName": { "type": "string" }, + "hostProcess": { + "type": "boolean" + }, "runAsUserName": { "type": "string" } @@ -2623,6 +2629,9 @@ "gmsaCredentialSpecName": { "type": "string" }, + "hostProcess": { + "type": "boolean" + }, "runAsUserName": { "type": "string" } diff --git a/go.mod b/go.mod index 8e580b61b9..9517a6affd 100644 --- a/go.mod +++ b/go.mod @@ -12,78 +12,75 @@ require ( github.com/blang/semver v3.5.1+incompatible github.com/evanphx/json-patch/v5 v5.6.0 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 - github.com/go-openapi/spec v0.19.5 github.com/gogo/protobuf v1.3.2 github.com/golang/mock v1.4.4 - github.com/golang/protobuf v1.4.3 + github.com/golang/protobuf v1.5.2 github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 - github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a github.com/lunixbochs/vtclean v1.0.0 // indirect github.com/mitchellh/mapstructure v1.3.3 github.com/newrelic/newrelic-client-go v0.49.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.10.0 + github.com/prometheus/client_golang v1.11.0 github.com/prometheus/client_model v0.2.0 - github.com/prometheus/common v0.21.0 + github.com/prometheus/common v0.26.0 github.com/servicemeshinterface/smi-sdk-go v0.4.1 - github.com/sirupsen/logrus v1.7.0 - github.com/soheilhy/cmux v0.1.4 + github.com/sirupsen/logrus v1.8.1 + github.com/soheilhy/cmux v0.1.5 github.com/spaceapegames/go-wavefront v1.8.1 github.com/spf13/cobra v1.1.3 github.com/stretchr/testify v1.7.0 github.com/tj/assert v0.0.3 github.com/valyala/fasttemplate v1.2.1 golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect - google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a - google.golang.org/grpc v1.33.1 - google.golang.org/grpc/examples v0.0.0-20210331235824-f6bb3972ed15 // indirect - google.golang.org/protobuf v1.25.0 + google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c + google.golang.org/grpc v1.38.0 + google.golang.org/protobuf v1.26.0 gopkg.in/yaml.v2 v2.4.0 - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect - k8s.io/api v0.21.0 + k8s.io/api v0.22.5 k8s.io/apiextensions-apiserver v0.21.0 - k8s.io/apimachinery v0.21.0 - k8s.io/apiserver v0.21.0 - k8s.io/cli-runtime v0.21.0 - k8s.io/client-go v0.21.0 - k8s.io/code-generator v0.21.0 - k8s.io/component-base v0.21.0 - k8s.io/klog/v2 v2.8.0 - k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 + k8s.io/apimachinery v0.22.5 + k8s.io/apiserver v0.22.5 + k8s.io/cli-runtime v0.22.5 + k8s.io/client-go v0.22.5 + k8s.io/code-generator v0.22.5 + k8s.io/component-base v0.22.5 + k8s.io/klog/v2 v2.9.0 + k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c k8s.io/kubectl v0.21.0 - k8s.io/kubernetes v1.21.0 - k8s.io/utils v0.0.0-20201110183641-67b214c5f920 + k8s.io/kubernetes v1.22.5 + k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a ) replace ( github.com/go-check/check => github.com/go-check/check v0.0.0-20180628173108-788fd7840127 github.com/grpc-ecosystem/grpc-gateway => github.com/grpc-ecosystem/grpc-gateway v1.16.0 - k8s.io/api => k8s.io/api v0.21.0 - k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.21.0 - k8s.io/apimachinery => k8s.io/apimachinery v0.21.0 - k8s.io/apiserver => k8s.io/apiserver v0.21.0 - k8s.io/cli-runtime => k8s.io/cli-runtime v0.21.0 - k8s.io/client-go => k8s.io/client-go v0.21.0 - k8s.io/cloud-provider => k8s.io/cloud-provider v0.21.0 - k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.21.0 - k8s.io/code-generator => k8s.io/code-generator v0.20.5-rc.0 - k8s.io/component-base => k8s.io/component-base v0.21.0 - k8s.io/component-helpers => k8s.io/component-helpers v0.21.0 - k8s.io/controller-manager => k8s.io/controller-manager v0.21.0 - k8s.io/cri-api => k8s.io/cri-api v0.20.5-rc.0 - k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.21.0 - k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.21.0 - k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.21.0 - k8s.io/kube-proxy => k8s.io/kube-proxy v0.21.0 - k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.21.0 - k8s.io/kubectl => k8s.io/kubectl v0.21.0 - k8s.io/kubelet => k8s.io/kubelet v0.21.0 - k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.21.0 - k8s.io/metrics => k8s.io/metrics v0.21.0 - k8s.io/mount-utils => k8s.io/mount-utils v0.20.5-rc.0 - k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.21.0 - k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.21.0 - k8s.io/sample-controller => k8s.io/sample-controller v0.21.0 + k8s.io/api => k8s.io/api v0.22.5 + k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.22.5 + k8s.io/apimachinery => k8s.io/apimachinery v0.22.6-rc.0 + k8s.io/apiserver => k8s.io/apiserver v0.22.5 + k8s.io/cli-runtime => k8s.io/cli-runtime v0.22.5 + k8s.io/client-go => k8s.io/client-go v0.22.5 + k8s.io/cloud-provider => k8s.io/cloud-provider v0.22.5 + k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.22.5 + k8s.io/code-generator => k8s.io/code-generator v0.22.6-rc.0 + k8s.io/component-base => k8s.io/component-base v0.22.5 + k8s.io/component-helpers => k8s.io/component-helpers v0.22.5 + k8s.io/controller-manager => k8s.io/controller-manager v0.22.5 + k8s.io/cri-api => k8s.io/cri-api v0.22.6-rc.0 + k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.22.5 + k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.22.5 + k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.22.5 + k8s.io/kube-proxy => k8s.io/kube-proxy v0.22.5 + k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.22.5 + k8s.io/kubectl => k8s.io/kubectl v0.22.5 + k8s.io/kubelet => k8s.io/kubelet v0.22.5 + k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.22.5 + k8s.io/metrics => k8s.io/metrics v0.22.5 + k8s.io/mount-utils => k8s.io/mount-utils v0.22.6-rc.0 + k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.22.5 + k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.22.5 + k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.22.5 + k8s.io/sample-controller => k8s.io/sample-controller v0.22.5 ) diff --git a/go.sum b/go.sum index 80a4c87956..232f101410 100644 --- a/go.sum +++ b/go.sum @@ -51,25 +51,27 @@ github.com/Azure/azure-amqp-common-go/v3 v3.0.0/go.mod h1:SY08giD/XbhTz07tJdpw1S github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= github.com/Azure/azure-sdk-for-go v37.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v43.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v55.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-service-bus-go v0.10.1/go.mod h1:E/FOceuKAFUfpbIJDKWz/May6guE+eGibfGT6q+n1to= github.com/Azure/azure-storage-blob-go v0.9.0/go.mod h1:8UBPbiOhrMQ4pLPi3gA1tXnpjrS76UYE/fo5A40vf4g= github.com/Azure/go-amqp v0.12.6/go.mod h1:qApuH6OFTSKZFmCOxccvAv5rLizBQf4v8pRmG138DPo= github.com/Azure/go-amqp v0.12.7/go.mod h1:qApuH6OFTSKZFmCOxccvAv5rLizBQf4v8pRmG138DPo= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= -github.com/Azure/go-autorest/autorest v0.11.12 h1:gI8ytXbxMfI+IVbI9mP2JGCTXIuhHLgRlvQ9X4PsnHE= -github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= +github.com/Azure/go-autorest/autorest v0.11.18 h1:90Y4srNYrwOtAgVo3ndrQkTYn6kf1Eg/AjTFJ8Is2aM= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= github.com/Azure/go-autorest/autorest/adal v0.8.3/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= -github.com/Azure/go-autorest/autorest/adal v0.9.5 h1:Y3bBUV4rTuxenJJs41HU3qmqsb+auo+a3Lz+PlJPpL0= -github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/adal v0.9.13 h1:Mp5hbtOePIzM8pJVRa3YLrWWmZtoxRXqUEzCfJt3+/Q= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM= github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= @@ -81,13 +83,13 @@ github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxB github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/logger v0.2.0 h1:e4RVHVZKC5p6UANLJHkM4OfR1UKZPj8Wt8Pcx+3oqrE= -github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= @@ -100,7 +102,6 @@ github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20200415212048-7901bc82 github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5hodBMJ5+l/7J4xAyMeuM2PNuepvHlGs8yilUCA= github.com/Jeffail/gabs v1.4.0 h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo= github.com/Jeffail/gabs v1.4.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= -github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= @@ -120,19 +121,13 @@ github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMo github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM= -github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60 h1:prBTRx78AQnXzivNT9Crhu564W/zPPr3ibSlpT9xKcE= github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60/go.mod h1:rjP7sIipbZcagro/6TCk6X0ZeFT2eyudH5+fve/cbBA= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= -github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= -github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= @@ -141,14 +136,11 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antonmedv/expr v1.8.9 h1:O9stiHmHHww9b4ozhPx7T6BK7fXfOCHJ8ybxf0833zw= github.com/antonmedv/expr v1.8.9/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmHhwGEk8= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA= github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= @@ -163,19 +155,15 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= -github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/auth0/go-jwt-middleware v0.0.0-20170425171159-5493cabe49f7/go.mod h1:LWMyo4iOLWXHGdBki7NIht1kHru/0wM179h+d3g8ATM= -github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/auth0/go-jwt-middleware v1.0.1/go.mod h1:YSeUX3z6+TF2H+7padiEqNJ73Zy9vXW72U//IgN0BIM= github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.13/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.33.16/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.35.24/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k= -github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/aws/aws-sdk-go v1.38.49/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go-v2 v1.7.0/go.mod h1:tb9wi5s61kTDA5qCkcDbt3KRVV74GGslQkl/DRdX/P4= github.com/aws/aws-sdk-go-v2 v1.8.1/go.mod h1:xEFuWz+3TYdlPRuo+CqATbeDWIWyaT5uAPwPaWtgse0= github.com/aws/aws-sdk-go-v2 v1.9.0 h1:+S+dSqQCN3MSU5vJRu1HqHrq00cJn6heIMU7X9hcsoo= @@ -204,12 +192,13 @@ github.com/aws/smithy-go v1.8.0 h1:AEwwwXQZtUwP5Mz506FeXXrKBe0jA8gVM+1gEcSRooc= github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= +github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bifurcation/mint v0.0.0-20180715133206-93c51c6ce115/go.mod h1:zVt7zX3K/aDCk9Tj+VM7YymsX66ERvzCJzw8rFCX2JU= +github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= @@ -221,38 +210,38 @@ github.com/bradleyfalzon/ghinstallation v1.1.1 h1:pmBXkxgM1WeF8QYvDLT5kuQiHMcmf+ github.com/bradleyfalzon/ghinstallation v1.1.1/go.mod h1:vyCmHTciHx/uuyN82Zc3rXN3X2KTK8nUTCrTMwAhcug= github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q= github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw= -github.com/caddyserver/caddy v1.0.3/go.mod h1:G+ouvOY32gENkJC+jhgl62TyhvqEsFaDiZ4uw0RzP1E= github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo= -github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= -github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= -github.com/cheekybits/genny v0.0.0-20170328200008-9127e812e1e9/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= +github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= -github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= -github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313/go.mod h1:P1wt9Z3DP8O6W3rvwCt0REIlshg1InHImaLW0t3ObY0= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= +github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27/go.mod h1:VQx0hjo2oUeQkQUET7wRwradO6f+fN5jzXgB/zROxxE= -github.com/container-storage-interface/spec v1.3.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4= +github.com/container-storage-interface/spec v1.5.0/go.mod h1:8K96oQNkJ7pFcC2R9Z1ynGGBB1I93kcS6PGg3SsOk8s= github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= -github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.4.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= @@ -262,26 +251,26 @@ github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDG github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= -github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= -github.com/coredns/corefile-migration v1.0.11/go.mod h1:RMy/mXdeDlYwzt0vdMEJvT2hGJ2I86/eO0UdXmH9XNI= +github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/coredns/caddy v1.1.0/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4= +github.com/coredns/corefile-migration v1.0.12/go.mod h1:NJOI8ceUF/NTgEwtjD+TUq3/BnH/GF7WAM3RzCa3hBo= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/go-systemd/v22 v22.3.1/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/daixiang0/gci v0.0.0-20200727065011-66f1df783cb2/go.mod h1:+AV8KmHTGxxwp/pY84TLQfFKp2vuKXXJVzF3kD/hfR4= github.com/daixiang0/gci v0.2.4/go.mod h1:+AV8KmHTGxxwp/pY84TLQfFKp2vuKXXJVzF3kD/hfR4= @@ -303,15 +292,9 @@ github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BU github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v20.10.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= @@ -319,15 +302,15 @@ github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emirpasic/gods v1.9.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= -github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdRwPr2TU5ThnS43puaKEMpja1uw= -github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= -github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= +github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= @@ -344,28 +327,24 @@ github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/flosch/pongo2 v0.0.0-20181225140029-79872a7b2769/go.mod h1:tbAXHifHQWNSpWbiJHpJTZH5fi3XHhDMdP//vuz9WS4= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= -github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew= github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= github.com/git-chglog/git-chglog v0.0.0-20200414013904-db796966b373/go.mod h1:Dcsy1kii/xFyNad5JqY/d0GO5mu91sungp5xotbm3Yk= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/go-acme/lego v2.5.0+incompatible/go.mod h1:yzMNe9CasVUhkquNvti5nAtPmG94USbYxYrZfTkIn0M= -github.com/go-bindata/go-bindata v3.1.1+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-critic/go-critic v0.5.0/go.mod h1:4jeRh3ZAVnRYhuWdOEvwzVqLUpxMSoAT0xZ74JsTPlo= github.com/go-critic/go-critic v0.5.2/go.mod h1:cc0+HvdE3lFpqLecgqMaJcvWWH77sLdBp+wLGPM1Yyo= @@ -383,7 +362,7 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -394,51 +373,15 @@ github.com/go-logr/logr v0.3.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTg github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= -github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= -github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= -github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= -github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= -github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= -github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= -github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= -github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= -github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= -github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= -github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/spec v0.19.5 h1:Xm0Ao53uqnk9QE/LlYV5DEU09UAgpliA85QoT9LzqPw= -github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= -github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= -github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= -github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= -github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= +github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= -github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= -github.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= +github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= @@ -463,14 +406,13 @@ github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2 github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -478,12 +420,12 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -505,9 +447,11 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0= @@ -527,9 +471,10 @@ github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunE github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/cadvisor v0.39.0/go.mod h1:rjQFmK4jPCpxeUdLq9bYhNFFsjgGOtpnDmDeap0+nsw= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/cadvisor v0.39.2/go.mod h1:kN93gpdevu+bpS227TyHVZyCU5bbqCzTj5T9drl34MI= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -539,6 +484,7 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM= @@ -578,14 +524,16 @@ github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I= -github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= +github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gookit/color v1.2.5/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg= github.com/gookit/color v1.3.1/go.mod h1:R3ogXq2B9rTbXoSHJ1HyUVAZ3poOJHpd9nQmyGZsfvQ= github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4 h1:4EZlYQIiyecYJlUbVkFXCXHz1QPhVXcHnQKAzBTPfQo= github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4/go.mod h1:lEO7XoHJ/xNRBCxrn4h/CEB67h0kW1B0t4ooP2yrjUA= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/goreleaser/chglog v0.1.1/go.mod h1:xSDa/73C0TxBcLvoT2JHh47QyXpCx5rrNVzJKyeFGPw= github.com/goreleaser/chglog v0.1.2/go.mod h1:tTZsFuSZK4epDXfjMkxzcGbrIOXprf0JFp47BjIr3B8= github.com/goreleaser/fileglob v0.3.0/go.mod h1:kNcPrPzjCp+Ox3jmXLU5QEsjhqrtLBm6OnXAif8KRl8= @@ -593,11 +541,8 @@ github.com/goreleaser/goreleaser v0.143.0/go.mod h1:/zq84GQ8WZFnspGTONdZO0Kgf5Bz github.com/goreleaser/goreleaser v0.147.0/go.mod h1:AkI3X+mBaAEc99RDZgUGvjbUEqh/+t+EjNMaqUbd+3w= github.com/goreleaser/nfpm v1.7.0/go.mod h1:V6xp021JRvYdBYpGFoP6m6YsuedzgB6IO2ub2NNBohs= github.com/goreleaser/nfpm v1.10.1/go.mod h1:G0vvOjif+gnnTTWBtvYqMBh8nMGM7eNkrZU/W2gdM6o= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -611,14 +556,12 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= @@ -641,17 +584,14 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/heketi/heketi v10.2.0+incompatible/go.mod h1:bB9ly3RchcQqsQ9CpyaQwvva7RS5ytVoSoholZQON6o= +github.com/heketi/heketi v10.3.0+incompatible/go.mod h1:bB9ly3RchcQqsQ9CpyaQwvva7RS5ytVoSoholZQON6o= github.com/heketi/tests v0.0.0-20151005000721-f3775cbcefd6/go.mod h1:xGMAM8JLi7UkZt1i4FQeQy0R2T8GLUwQhOP5M1gBhy4= github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= @@ -660,7 +600,6 @@ github.com/huandu/xstrings v1.3.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= @@ -669,13 +608,11 @@ github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/ishidawataru/sctp v0.0.0-20190723014705-7c296d48a2b5/go.mod h1:DM4VvS+hD/kDi1U1QsX2fnZowwBhqD0Dk3bRPKF/Oc8= github.com/jarcoal/httpmock v1.0.6/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8= github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a/go.mod h1:xRskid8CManxVta/ALEhJha/pweKBaVG6fWgc0yH25s= github.com/jirfag/go-printf-func-name v0.0.0-20191110105641-45db9963cdd3/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -689,14 +626,16 @@ github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhB github.com/jmoiron/sqlx v1.2.1-0.20190826204134-d7d95172beb5/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -722,7 +661,6 @@ github.com/klauspost/compress v1.10.5/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.0/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -731,49 +669,38 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kyoh86/exportloopref v0.1.7/go.mod h1:h1rDl2Kdj97+Kwh4gdz3ujE7XHmH51Q0lUiZ1z4NLj8= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/libopenstorage/openstorage v1.0.0/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= -github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= github.com/llorllale/go-gitlint v0.0.0-20190914155841-58c0b8cef0e5/go.mod h1:omoASPlaaf3ECEhTMfLZVS6o550eBWI2YsM/saGEbVA= github.com/llorllale/go-gitlint v0.0.0-20200802191503-5984945d4b80/go.mod h1:omoASPlaaf3ECEhTMfLZVS6o550eBWI2YsM/saGEbVA= github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lpabon/godbc v0.1.1/go.mod h1:Jo9QV0cf3U6jZABgiJ2skINAXb9j8m51r07g4KI92ZA= -github.com/lucas-clemente/aes12 v0.0.0-20171027163421-cd47fb39b79f/go.mod h1:JpH9J1c9oX6otFSgdUHwUBUizmKlrMjxWnIAjff4m04= -github.com/lucas-clemente/quic-clients v0.1.0/go.mod h1:y5xVIEoObKqULIKivu+gD/LU90pL73bTdtQjPBvtCBk= -github.com/lucas-clemente/quic-go v0.10.2/go.mod h1:hvaRS9IHjFLMq76puFJeWNfmn+H70QZ/CXoxqw9bzao= -github.com/lucas-clemente/quic-go-certificates v0.0.0-20160823095156-d2f86524cced/go.mod h1:NCcRLrOTZbzhZvixZLlERbJtDtYsmMw8Jc4vS8Z0g58= github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5/go.mod h1:c2mYKRyMb1BPkO5St0c/ps62L4S0W2NAkaTXj9qEI+0= github.com/lusis/slack-test v0.0.0-20190426140909-c40012f20018/go.mod h1:sFlOUpQL1YcjhFVXhg1CG8ZASEs/Mf1oVb6H75JL/zg= -github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailgun/mailgun-go v2.0.0+incompatible/go.mod h1:NWTyU+O4aczg/nsGhQnvHL6v2n5Gy6Sv5tNDVvC6FbU= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpApTE5fXSKAqwDU= -github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= -github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= @@ -787,14 +714,12 @@ github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HN github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= @@ -808,10 +733,7 @@ github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182aff github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mbilski/exhaustivestruct v1.1.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= -github.com/mholt/certmagic v0.6.2-0.20190624175158-6a42ef9fe8c2/go.mod h1:g4cOPxcjV0oFq3qwpjSA30LReKD8AoIfwAY9VvG35NY= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/mindprince/gonvml v0.0.0-20190828220739-9ebdce4bb989/go.mod h1:2eu9pRWp8mo84xCg6KswZ+USQHjwgRhNp06sozOdsTY= github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= github.com/minio/minio-go/v7 v7.0.2/go.mod h1:dJ80Mv2HeGkYLH1sqS/ksz07ON6csH3S6JUMSQ2zAns= @@ -839,9 +761,10 @@ github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx github.com/moby/ipvs v1.0.1/go.mod h1:2pngiyseZbIKXNv7hsKj3O9UEz30c53MT9005gt2hxQ= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= -github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk= +github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= +github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 h1:yH0SvLzcbZxcJXho2yh7CqdENGMQe73Cw3woZBpPli0= +github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -864,15 +787,6 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nakabonne/nestif v0.3.0/go.mod h1:dI314BppzXjJ4HsCnbo7XzrJHPszZsjnk5wEBSYHI2c= -github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= -github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= -github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= -github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= -github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= -github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= -github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= github.com/newrelic/newrelic-client-go v0.49.0 h1:MnAK89AcdOqapfPGcsUzLdzTUmeIojBz1W9VbC4Llag= github.com/newrelic/newrelic-client-go v0.49.0/go.mod h1://vEwOJWDi1nsSnmmdZrB8Kab9ibSfGcF0UmnwzoSNQ= @@ -885,26 +799,20 @@ github.com/nishanths/exhaustive v0.1.0/go.mod h1:S1j9110vxV1ECdCudXRkeMnFQ/DQk9a github.com/nlopes/slack v0.5.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= -github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852/go.mod h1:eqOVx5Vwu4gd2mmMZvVZsgIqNSaW3xxRThUJ0k/TPk4= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4= github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= @@ -915,38 +823,29 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= +github.com/opencontainers/runc v1.0.0-rc95/go.mod h1:z+bZxa/+Tz/FmYVWkhUajJdzFeOqjc5vrqskhVyHGUM= +github.com/opencontainers/runc v1.0.2 h1:opHZMaswlyxz1OuGpBE53Dwe4/xF7EZTY0A2L/FpCOg= +github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= -github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= -github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/opsgenie/opsgenie-go-sdk-v2 v1.0.5 h1:AnS8ZCC5dle8P4X4FZ+IOlX9v0jAkCMiZDIzRnYwBbs= github.com/opsgenie/opsgenie-go-sdk-v2 v1.0.5/go.mod h1:f0ezb0R/mrB9Hpm5RrIS6EX3ydjsR2nAB88nYYXZcNY= -github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= -github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= -github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -955,36 +854,27 @@ github.com/polyfloyd/go-errorlint v0.0.0-20201006195004-351e25ade6e3/go.mod h1:w github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.10.0 h1:/o0BDeWzLWXNZ+4q5gXltUvaMpJqckTa+jTNoB+z4cg= -github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= +github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.21.0 h1:SMvI2JVldvfUvRVlP64jkIJEC6WiGHJcN2e5tB+ztF8= -github.com/prometheus/common v0.21.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= @@ -996,11 +886,10 @@ github.com/quasilyte/go-ruleguard v0.1.2-0.20200318202121-b00d7a75d3d8/go.mod h1 github.com/quasilyte/go-ruleguard v0.2.0/go.mod h1:2RT/tf0Ce0UDj5y243iWKosQogJd8+1G3Rs2fxmlYnw= github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= github.com/quobyte/api v0.1.8/go.mod h1:jL7lIHrmqQ7yh05OJ+eEEdHr0u/kmT1Ff9iHd+4H6VI= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= github.com/rivo/tview v0.0.0-20200219210816-cd38d7432498/go.mod h1:6lkG1x+13OShEf0EaOCaTQYyB7d5nSbb181KtjlS+84= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/robfig/cron v1.1.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -1009,17 +898,14 @@ github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rogpeppe/go-internal v1.6.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rubiojr/go-vhd v0.0.0-20200706105327-02e210299021/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= -github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryancurrah/gomodguard v1.1.0/go.mod h1:4O8tr7hBODaGE6VIhfJDHcwzh5GUccKSJBU0UMXJFVM= github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0KCtEdgEkHwDbigdA= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sanity-io/litter v1.2.0/go.mod h1:JF6pZUFgu2Q0sBZ+HSV35P8TVPI1TTzEwyu9FXAw2W4= github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b/go.mod h1:am+Fp8Bt506lA3Rk3QCmSqmYmLMnPDhdDUcosQCAx+I= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= @@ -1040,21 +926,23 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/slack-go/slack v0.6.6 h1:ln0fO794CudStSJEfhZ08Ok5JanMjvW6/k2xBuHqedU= github.com/slack-go/slack v0.6.6/go.mod h1:FGqNzJBmxIsZURAxh2a8D21AnOVvvXZvGligs4npPUM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= -github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4lqBjiZI= -github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/sony/sonyflake v1.0.0 h1:MpU6Ro7tfXwgn2l5eluf9xQvQJDROTBImNCfRXn/YeM= github.com/sony/sonyflake v1.0.0/go.mod h1:Jv3cfhf/UFtolOTTRd3q4Nl6ENqM+KfyZ5PseKfZGF4= github.com/sourcegraph/go-diff v0.5.3/go.mod h1:v9JDtjCE4HHHCZGId75rg8gkKKa98RVjBcBGsVmMmak= @@ -1078,7 +966,6 @@ github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSW github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -1089,10 +976,8 @@ github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jW github.com/ssgreg/nlreturn/v2 v2.0.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= github.com/ssgreg/nlreturn/v2 v2.1.0/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/storageos/go-api v2.2.0+incompatible/go.mod h1:ZrLn+e0ZuF3Y65PNF6dIwbJPZqfmtCXxFm9ckv0agOY= -github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= @@ -1113,8 +998,6 @@ github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQ github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= github.com/tetafro/godot v0.4.8/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0= github.com/tetafro/godot v0.4.9/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0= -github.com/thecodeteam/goscaleio v0.1.0/go.mod h1:68sdkZAsK8bvEwBlbQnlLS+xU+hvLYM/iQ8KXej1AwM= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= @@ -1123,8 +1006,8 @@ github.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tomarrell/wrapcheck v0.0.0-20200807122107-df9e8bcb914d/go.mod h1:yiFB6fFoV7saXirUGfuK+cPtUh4NX/Hf5y2WC2lehu0= github.com/tommy-muehle/go-mnd v1.3.1-0.20200224220436-e6f9a994e8fa/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= @@ -1136,7 +1019,6 @@ github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oW github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= @@ -1152,7 +1034,6 @@ github.com/valyala/quicktemplate v1.5.1/go.mod h1:v7yYWpBEiutDyNfVaph6oC/yKwejzV github.com/valyala/quicktemplate v1.6.2/go.mod h1:mtEJpQtUiBV0SHhMX6RtiJtqxncgrfmjcUy5T68X8TM= github.com/valyala/quicktemplate v1.6.3/go.mod h1:fwPzK2fHuYEODzJ9pkw0ipCPNHZ2tD5KW4lOuSdPKzY= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= @@ -1174,31 +1055,42 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= -go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= +go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= +go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= +go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= +go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= +go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= +go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= +go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= +go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= +go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= +go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= gocloud.dev v0.20.0/go.mod h1:+Y/RpSXrJthIOM8uFNzWp6MRu9pFPNFEEZrQMxpkfIc= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1206,17 +1098,12 @@ golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1257,6 +1144,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= @@ -1267,22 +1155,19 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449 h1:xUIPaMhvROX9dhPvRCenIJtU78+lbEenGbgqB5hfHCQ= golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190328230028-74de082e2cca/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -1295,7 +1180,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1318,9 +1202,11 @@ golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 h1:OgUuv8lsRpBibGNbSizVwKWlysjaNzmC9gYMhPVfqFM= -golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1339,6 +1225,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1348,29 +1235,23 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1380,14 +1261,12 @@ golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1406,16 +1285,19 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201109165425-215b40eba54c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -1427,25 +1309,25 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190221204921-83362c3779f5/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -1462,8 +1344,6 @@ golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -1472,7 +1352,6 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1481,10 +1360,8 @@ golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -1514,7 +1391,6 @@ golang.org/x/tools v0.0.0-20200519015757-0d0afa43d58a/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200601175630-2caf76543d99/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200606014950-c42cb6316fb6/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200608174601-1b747fd94509/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200624225443-88f3c62a19ff/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200625211823-6506e20df31f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -1530,8 +1406,8 @@ golang.org/x/tools v0.0.0-20201007032633-0806396f153e/go.mod h1:z6u4i615ZeAfBE4X golang.org/x/tools v0.0.0-20201011145850-ed2f50202694/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201013201025-64a9e34f3752/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1547,7 +1423,6 @@ gonum.org/v1/gonum v0.6.2/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -1565,7 +1440,6 @@ google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.26.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1599,6 +1473,7 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200317114155-1f3552e48f24/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200325114520-5b2d0af7952b/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -1606,16 +1481,14 @@ google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1m google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200603110839-e855014d5736/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a h1:pOwg4OoaRYScjmR4LlLgdtnyoHYTSAVhhqe5uPdpII8= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= @@ -1624,11 +1497,11 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1 h1:DGeFlSan2f+WEtCERJ4J9GJWk15TxUi8QGagfI87Xyc= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc/examples v0.0.0-20210331235824-f6bb3972ed15 h1:5zzARWGVJhfHEHNuN5Irypt6oKD506IgclKOta6InM0= -google.golang.org/grpc/examples v0.0.0-20210331235824-f6bb3972ed15/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1638,8 +1511,10 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/AlecAivazis/survey.v1 v1.8.7/go.mod h1:iBNOmqKz/NUbZx3bA+4hAGLRC7fSK7tgtVDT4tB22XA= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= @@ -1649,11 +1524,9 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= @@ -1662,7 +1535,6 @@ gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/kyokomi/emoji.v1 v1.5.1/go.mod h1:N9AZ6hi1jHOPn34PsbpufQZUcKftSD7WgS2pgpmH4Lg= -gopkg.in/mcuadros/go-syslog.v2 v2.2.1/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= @@ -1678,13 +1550,13 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= @@ -1693,7 +1565,6 @@ gotest.tools/gotestsum v0.6.0/go.mod h1:LEX+ioCVdeWhZc8GYfiBRag360eBhwixWJ62R9eD gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1703,60 +1574,59 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.6/go.mod h1:pyyisuGw24ruLjrr1ddx39WE0y9OooInRzEYLhQB2YY= -k8s.io/api v0.21.0 h1:gu5iGF4V6tfVCQ/R+8Hc0h7H1JuEhzyEi9S4R5LM8+Y= -k8s.io/api v0.21.0/go.mod h1:+YbrhBBGgsxbF6o6Kj4KJPJnBmAKuXDeS3E18bgHNVU= -k8s.io/apiextensions-apiserver v0.21.0 h1:Nd4uBuweg6ImzbxkC1W7xUNZcCV/8Vt10iTdTIVF3hw= -k8s.io/apiextensions-apiserver v0.21.0/go.mod h1:gsQGNtGkc/YoDG9loKI0V+oLZM4ljRPjc/sql5tmvzc= -k8s.io/apimachinery v0.21.0 h1:3Fx+41if+IRavNcKOz09FwEXDBG6ORh6iMsTSelhkMA= -k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY= -k8s.io/apiserver v0.21.0 h1:1hWMfsz+cXxB77k6/y0XxWxwl6l9OF26PC9QneUVn1Q= -k8s.io/apiserver v0.21.0/go.mod h1:w2YSn4/WIwYuxG5zJmcqtRdtqgW/J2JRgFAqps3bBpg= -k8s.io/cli-runtime v0.21.0 h1:/V2Kkxtf6x5NI2z+Sd/mIrq4FQyQ8jzZAUD6N5RnN7Y= -k8s.io/cli-runtime v0.21.0/go.mod h1:XoaHP93mGPF37MkLbjGVYqg3S1MnsFdKtiA/RZzzxOo= -k8s.io/client-go v0.21.0 h1:n0zzzJsAQmJngpC0IhgFcApZyoGXPrDIAD601HD09ag= -k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA= -k8s.io/cloud-provider v0.21.0/go.mod h1:z17TQgu3JgUFjcgby8sj5X86YdVK5Pbt+jm/eYMZU9M= -k8s.io/cluster-bootstrap v0.21.0 h1:9CfnWrvXm12k6fP3WR3ist76rrqGq6H5pRVEUvEc4Ws= -k8s.io/cluster-bootstrap v0.21.0/go.mod h1:rs7i1JpBCa56YNmnYxFJuoUghIwpMzDidY8ZmqiRnrQ= -k8s.io/code-generator v0.20.5-rc.0 h1:t1T/nu5/kZtZp61BSgj+TucDp5hBg0/JcbaIZufxRMg= -k8s.io/code-generator v0.20.5-rc.0/go.mod h1:UsqdF+VX4PU2g46NC2JRs4gc+IfrctnwHb76RNbWHJg= -k8s.io/component-base v0.21.0 h1:tLLGp4BBjQaCpS/KiuWh7m2xqvAdsxLm4ATxHSe5Zpg= -k8s.io/component-base v0.21.0/go.mod h1:qvtjz6X0USWXbgmbfXR+Agik4RZ3jv2Bgr5QnZzdPYw= -k8s.io/component-helpers v0.21.0 h1:SoWLsd63LI5uwofcHVSO4jtlmZEJRycfwNBKU4eAGPQ= -k8s.io/component-helpers v0.21.0/go.mod h1:tezqefP7lxfvJyR+0a+6QtVrkZ/wIkyMLK4WcQ3Cj8U= -k8s.io/controller-manager v0.21.0/go.mod h1:Ohy0GRNRKPVjB8C8G+dV+4aPn26m8HYUI6ejloUBvUA= -k8s.io/cri-api v0.20.5-rc.0/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= -k8s.io/csi-translation-lib v0.21.0/go.mod h1:edq+UMpgqEx3roTuGF/03uIuSOsI986jtu65+ytLlkA= +k8s.io/api v0.22.5 h1:xk7C+rMjF/EGELiD560jdmwzrB788mfcHiNbMQLIVI8= +k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs= +k8s.io/apiextensions-apiserver v0.22.5 h1:ML0QqT7FIlmZHN+9+2EtARJ3cJVHeoizt6GCteFRE0o= +k8s.io/apiextensions-apiserver v0.22.5/go.mod h1:tIXeZ0BrDxUb1PoAz+tgOz43Zi1Bp4BEEqVtUccMJbE= +k8s.io/apimachinery v0.22.6-rc.0 h1:7fsM4YnKNmb3qLznaIPFJ6Rk7hjo8TxbHv2FS3I7804= +k8s.io/apimachinery v0.22.6-rc.0/go.mod h1:xziclGKwuuJ2RM5/rSFQSYAj0zdbci3DH8kj+WvyN0U= +k8s.io/apiserver v0.22.5 h1:71krQxCUz218ecb+nPhfDsNB6QgP1/4EMvi1a2uYBlg= +k8s.io/apiserver v0.22.5/go.mod h1:s2WbtgZAkTKt679sYtSudEQrTGWUSQAPe6MupLnlmaQ= +k8s.io/cli-runtime v0.22.5 h1:bZqLgx1INiPgXyMk/Hu3o5NFmdfvlvtsoE+wHJuKA2U= +k8s.io/cli-runtime v0.22.5/go.mod h1:12ah4O0kaevIYHsRcFGt8RKER0wlTN2yCgHp1c4Uxp4= +k8s.io/client-go v0.22.5 h1:I8Zn/UqIdi2r02aZmhaJ1hqMxcpfJ3t5VqvHtctHYFo= +k8s.io/client-go v0.22.5/go.mod h1:cs6yf/61q2T1SdQL5Rdcjg9J1ElXSwbjSrW2vFImM4Y= +k8s.io/cloud-provider v0.22.5/go.mod h1:nBjHLzOB4VNvGTskv4N6SHKmd+jUJYtOg1PxUi+eoL4= +k8s.io/cluster-bootstrap v0.22.5 h1:vCALIBnbpL9DRPpqSffqQfTftQxK4raMn+DbNJzcZ/M= +k8s.io/cluster-bootstrap v0.22.5/go.mod h1:apRzF71o+erN4FmzaHVuaFj2RtTI44nqZFBTrB7zJNg= +k8s.io/code-generator v0.22.6-rc.0 h1:yy0LyeCSlUNF011N8a9Uy62F1CcKBb/umYGaBCPSPhc= +k8s.io/code-generator v0.22.6-rc.0/go.mod h1:sbdWCOVob+KaQ5O7xs8PNNaCTpbWVqNgA6EPwLOmRNk= +k8s.io/component-base v0.22.5 h1:U0eHqZm7mAFE42hFwYhY6ze/MmVaW00JpMrzVsQmzYE= +k8s.io/component-base v0.22.5/go.mod h1:VK3I+TjuF9eaa+Ln67dKxhGar5ynVbwnGrUiNF4MqCI= +k8s.io/component-helpers v0.22.5 h1:DbON3tctKjVJyV1XALj85ZKU1NRpWKc3CrpAJ4Nb07k= +k8s.io/component-helpers v0.22.5/go.mod h1:UK4H16PcV6pTInkhAOfkPbN/aXHPXPX2/ZI4lfCXH4I= +k8s.io/controller-manager v0.22.5/go.mod h1:Ad1qlS+ygzKgxImZ6ccExOMutfmGprodopbIzrHKgJw= +k8s.io/cri-api v0.22.6-rc.0/go.mod h1:uAw9CICQq20/1yB4ZnWT2TjJyMMROl4typFfWaURLwQ= +k8s.io/csi-translation-lib v0.22.5/go.mod h1:vqSdiDUFMdo0WT5TuO4j3ZVrODoYkzGjTLluKEqs2eQ= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027 h1:Uusb3oh8XcdzDF/ndlI4ToKTYVlkCSJP39SRY2mfRAw= k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/heapster v1.2.0-beta.1/go.mod h1:h1uhptVXMwC8xtZBYsPXKVi8fpdlYkTs6k949KozGrM= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.5.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts= -k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/kube-aggregator v0.21.0/go.mod h1:sIaa9L4QCBo9gjPyoGJns4cBjYVLq3s49FxF7m/1A0A= -k8s.io/kube-controller-manager v0.21.0/go.mod h1:QGJ1P7eU4FQq8evpCHN5e4QwPpcr2sbWFJBO/DKBUrw= -k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= -k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0= -k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= -k8s.io/kube-proxy v0.21.0/go.mod h1:36jW3e6+5iQql9tHrLjVrmwpPsbhTywoI6OCFL7MWRs= -k8s.io/kube-scheduler v0.21.0/go.mod h1:wf1oi1NHSsFYfG7lKwxJVmnQNBnhL9vOMXztcKQu5IU= -k8s.io/kubectl v0.21.0 h1:WZXlnG/yjcE4LWO2g6ULjFxtzK6H1TKzsfaBFuVIhNg= -k8s.io/kubectl v0.21.0/go.mod h1:EU37NukZRXn1TpAkMUoy8Z/B2u6wjHDS4aInsDzVvks= -k8s.io/kubelet v0.21.0/go.mod h1:G5ZxMTVev9t4bhmsSxDAWhH6wXDYEVHVVFyYsw4laR4= -k8s.io/kubernetes v1.21.0 h1:LUUQgdFsKB+wVgKPUapmXjkvvJHSLN53CuQwre4c+mM= -k8s.io/kubernetes v1.21.0/go.mod h1:Yx6XZ8zalyqEk7but+j4+5SvLzdyH1eeqZ4cwO+5dD4= -k8s.io/legacy-cloud-providers v0.21.0/go.mod h1:bNxo7gDg+PGkBmT/MFZswLTWdSWK9kAlS1s8DJca5q4= -k8s.io/metrics v0.21.0/go.mod h1:L3Ji9EGPP1YBbfm9sPfEXSpnj8i24bfQbAFAsW0NueQ= -k8s.io/mount-utils v0.20.5-rc.0/go.mod h1:Jv9NRZ5L2LF87A17GaGlArD+r3JAJdZFvo4XD1cG4Kc= -k8s.io/sample-apiserver v0.21.0/go.mod h1:yMffYq14yQZtuVPVBGaBJ+3Scb2xHT6QeqFfk3v+AEY= -k8s.io/system-validators v1.4.0/go.mod h1:bPldcLgkIUK22ALflnsXk8pvkTEndYdNuaHH6gRrl0Q= -k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw= +k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM= +k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/kube-aggregator v0.22.5/go.mod h1:UhgfJb/mvIvfjc+d0pY2GP8S9+zHquxDzQAuWRxqzq8= +k8s.io/kube-controller-manager v0.22.5/go.mod h1:/ND3VocEUJifrOUSreSZksNx0GL+Bcd1ht2MF/GMenQ= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= +k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c h1:jvamsI1tn9V0S8jicyX82qaFC0H/NKxv2e5mbqsgR80= +k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= +k8s.io/kube-proxy v0.22.5/go.mod h1:0XigADqqbYWE23zIs8JpBZGJcGCKYFIJ5uqh1CBZRxU= +k8s.io/kube-scheduler v0.22.5/go.mod h1:JEeZKTpcr07eIxrcW9DptOtgylMu6KnQPAQ+Ew45Ask= +k8s.io/kubectl v0.22.5 h1:diivOcs6dyDjpBqOpy9iiI3srZnW1khJDWwsFSapFt8= +k8s.io/kubectl v0.22.5/go.mod h1:uwKSKhaC6HOwnbk1cVLxVPYwfvazj9x06oZAOsL43N8= +k8s.io/kubelet v0.22.5/go.mod h1:f/f0+phP4j+JZirY3twlszp3Re3q/NRPIhdU4bashIk= +k8s.io/kubernetes v1.22.5 h1:DfYHZkWXDra2xKEKb7C96cq4vQuxjn4j0YthK2naLRo= +k8s.io/kubernetes v1.22.5/go.mod h1:ejAVRNlNOIWvq0c5m3qAnzEdizuFlWBKXRf/HV6Z2zA= +k8s.io/legacy-cloud-providers v0.22.5/go.mod h1:a+nO87Q1eJjGpBcfmv1llCMufHF6sRpKSoXFMp1tj+s= +k8s.io/metrics v0.22.5/go.mod h1:dCqOkoZQWLSfBhUtPFMiDrzJaPtXJlVePVuJbEx0hW8= +k8s.io/mount-utils v0.22.6-rc.0/go.mod h1:dHl6c2P60T5LHUnZxVslyly9EDCMzvhtISO5aY+Z4sk= +k8s.io/pod-security-admission v0.22.5/go.mod h1:2a1JSU7b+CHFoSGIr8FwZBBeAJFau41srx08/qEy+NI= +k8s.io/sample-apiserver v0.22.5/go.mod h1:0/GPEcsJQg4ljzx+mTv3yhj6c+aZ7KPo4BkQ++KlT4Q= +k8s.io/system-validators v1.5.0/go.mod h1:bPldcLgkIUK22ALflnsXk8pvkTEndYdNuaHH6gRrl0Q= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= @@ -1772,18 +1642,17 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= -sigs.k8s.io/kustomize/api v0.8.5 h1:bfCXGXDAbFbb/Jv5AhMj2BB8a5VAJuuQ5/KU69WtDjQ= -sigs.k8s.io/kustomize/api v0.8.5/go.mod h1:M377apnKT5ZHJS++6H4rQoCHmWtt6qTpp3mbe7p6OLY= -sigs.k8s.io/kustomize/cmd/config v0.9.7/go.mod h1:MvXCpHs77cfyxRmCNUQjIqCmZyYsbn5PyQpWiq44nW0= -sigs.k8s.io/kustomize/kustomize/v4 v4.0.5/go.mod h1:C7rYla7sI8EnxHE/xEhRBSHMNfcL91fx0uKmUlUhrBk= -sigs.k8s.io/kustomize/kyaml v0.10.15 h1:dSLgG78KyaxN4HylPXdK+7zB3k7sW6q3IcCmcfKA+aI= -sigs.k8s.io/kustomize/kyaml v0.10.15/go.mod h1:mlQFagmkm1P+W4lZJbJ/yaxMd8PqMRSC4cPcfUVt5Hg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/kustomize/api v0.8.11 h1:LzQzlq6Z023b+mBtc6v72N2mSHYmN8x7ssgbf/hv0H8= +sigs.k8s.io/kustomize/api v0.8.11/go.mod h1:a77Ls36JdfCWojpUqR6m60pdGY1AYFix4AH83nJtY1g= +sigs.k8s.io/kustomize/cmd/config v0.9.13/go.mod h1:7547FLF8W/lTaDf0BDqFTbZxM9zqwEJqCKN9sSR0xSs= +sigs.k8s.io/kustomize/kustomize/v4 v4.2.0/go.mod h1:MOkR6fmhwG7hEDRXBYELTi5GSFcLwfqwzTRHW3kv5go= +sigs.k8s.io/kustomize/kyaml v0.11.0 h1:9KhiCPKaVyuPcgOLJXkvytOvjMJLoxpjodiycb4gHsA= +sigs.k8s.io/kustomize/kyaml v0.11.0/go.mod h1:GNMwjim4Ypgp/MueD3zXHLRJEjz7RvtPae0AwlvEMFM= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.0 h1:C4r9BgJ98vrKnnVCjwCSXcWjWe0NKcUQkmzDXZXGwH8= -sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= -sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/hack/gen-crd-spec/main.go b/hack/gen-crd-spec/main.go index 8ed5f46ede..193de108d7 100644 --- a/hack/gen-crd-spec/main.go +++ b/hack/gen-crd-spec/main.go @@ -14,9 +14,9 @@ import ( "github.com/blang/semver" "github.com/ghodss/yaml" - "github.com/go-openapi/spec" extensionsobj "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + spec "k8s.io/kube-openapi/pkg/validation/spec" ) const metadataValidation = `properties: @@ -79,12 +79,6 @@ func NewCustomResourceDefinition() []*extensionsobj.CustomResourceDefinition { crdYamlBytes, err := exec.Command( "controller-gen", "paths=./pkg/apis/rollouts/...", - "crd:trivialVersions=true", - // The only possible value is 'false' since 'apiextensions.k8s.io/v1' - // https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#field-pruning - // It is possible though to opt-out of pruning for specifc sub-trees of fields by adding x-kubernetes-preserve-unknown-fields: true - // by using the 'setValidationOverride' function in this file. - "crd:preserveUnknownFields=false", "crd:crdVersions=v1", "crd:maxDescLen=0", "output:crd:stdout", diff --git a/hack/installers/install-codegen-go-tools.sh b/hack/installers/install-codegen-go-tools.sh index b74ef32753..435838126c 100755 --- a/hack/installers/install-codegen-go-tools.sh +++ b/hack/installers/install-codegen-go-tools.sh @@ -45,7 +45,7 @@ go_mod_install k8s.io/code-generator/cmd/lister-gen go_mod_install k8s.io/kube-openapi/cmd/openapi-gen # controller-gen is run by ./hack/gen-crd-spec to generate the CRDs -go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.5.0 +go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.7.0 # swagger cli is used to generate swagger docs go install github.com/go-swagger/go-swagger/cmd/swagger@v0.28.0 diff --git a/manifests/crds/analysis-run-crd.yaml b/manifests/crds/analysis-run-crd.yaml index 51d86d0e51..eae64e49ed 100644 --- a/manifests/crds/analysis-run-crd.yaml +++ b/manifests/crds/analysis-run-crd.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.5.0 + controller-gen.kubebuilder.io/version: v0.7.0 name: analysisruns.argoproj.io spec: group: argoproj.io @@ -1045,6 +1045,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -1608,6 +1610,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -2179,6 +2183,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -2305,6 +2311,7 @@ spec: additionalProperties: type: string type: object + x-kubernetes-map-type: atomic overhead: additionalProperties: anyOf: @@ -2393,6 +2400,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object diff --git a/manifests/crds/analysis-template-crd.yaml b/manifests/crds/analysis-template-crd.yaml index 0677555741..0210a582a8 100644 --- a/manifests/crds/analysis-template-crd.yaml +++ b/manifests/crds/analysis-template-crd.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.5.0 + controller-gen.kubebuilder.io/version: v0.7.0 name: analysistemplates.argoproj.io spec: group: argoproj.io @@ -1041,6 +1041,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -1604,6 +1606,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -2175,6 +2179,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -2301,6 +2307,7 @@ spec: additionalProperties: type: string type: object + x-kubernetes-map-type: atomic overhead: additionalProperties: anyOf: @@ -2389,6 +2396,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object diff --git a/manifests/crds/cluster-analysis-template-crd.yaml b/manifests/crds/cluster-analysis-template-crd.yaml index 6a25750124..e7d358b497 100644 --- a/manifests/crds/cluster-analysis-template-crd.yaml +++ b/manifests/crds/cluster-analysis-template-crd.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.5.0 + controller-gen.kubebuilder.io/version: v0.7.0 name: clusteranalysistemplates.argoproj.io spec: group: argoproj.io @@ -1041,6 +1041,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -1604,6 +1606,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -2175,6 +2179,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -2301,6 +2307,7 @@ spec: additionalProperties: type: string type: object + x-kubernetes-map-type: atomic overhead: additionalProperties: anyOf: @@ -2389,6 +2396,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object diff --git a/manifests/crds/experiment-crd.yaml b/manifests/crds/experiment-crd.yaml index 90d56c1410..e2301e1dcd 100644 --- a/manifests/crds/experiment-crd.yaml +++ b/manifests/crds/experiment-crd.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.5.0 + controller-gen.kubebuilder.io/version: v0.7.0 name: experiments.argoproj.io spec: group: argoproj.io @@ -934,6 +934,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -1497,6 +1499,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -2068,6 +2072,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -2194,6 +2200,7 @@ spec: additionalProperties: type: string type: object + x-kubernetes-map-type: atomic overhead: additionalProperties: anyOf: @@ -2282,6 +2289,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object diff --git a/manifests/crds/rollout-crd.yaml b/manifests/crds/rollout-crd.yaml index 8c258e1405..ba19354ff0 100644 --- a/manifests/crds/rollout-crd.yaml +++ b/manifests/crds/rollout-crd.yaml @@ -2,7 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.5.0 + controller-gen.kubebuilder.io/version: v0.7.0 name: rollouts.argoproj.io spec: group: argoproj.io @@ -1457,6 +1457,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -2020,6 +2022,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -2591,6 +2595,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -2717,6 +2723,7 @@ spec: additionalProperties: type: string type: object + x-kubernetes-map-type: atomic overhead: additionalProperties: anyOf: @@ -2805,6 +2812,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object diff --git a/manifests/install.yaml b/manifests/install.yaml index 89f4621d96..cae614a930 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.5.0 + controller-gen.kubebuilder.io/version: v0.7.0 name: analysisruns.argoproj.io spec: group: argoproj.io @@ -1046,6 +1046,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -1609,6 +1611,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -2180,6 +2184,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -2306,6 +2312,7 @@ spec: additionalProperties: type: string type: object + x-kubernetes-map-type: atomic overhead: additionalProperties: anyOf: @@ -2394,6 +2401,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -2757,7 +2766,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.5.0 + controller-gen.kubebuilder.io/version: v0.7.0 name: analysistemplates.argoproj.io spec: group: argoproj.io @@ -3796,6 +3805,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -4359,6 +4370,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -4930,6 +4943,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -5056,6 +5071,7 @@ spec: additionalProperties: type: string type: object + x-kubernetes-map-type: atomic overhead: additionalProperties: anyOf: @@ -5144,6 +5160,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -5397,7 +5415,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.5.0 + controller-gen.kubebuilder.io/version: v0.7.0 name: clusteranalysistemplates.argoproj.io spec: group: argoproj.io @@ -6436,6 +6454,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -6999,6 +7019,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -7570,6 +7592,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -7696,6 +7720,7 @@ spec: additionalProperties: type: string type: object + x-kubernetes-map-type: atomic overhead: additionalProperties: anyOf: @@ -7784,6 +7809,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -8037,7 +8064,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.5.0 + controller-gen.kubebuilder.io/version: v0.7.0 name: experiments.argoproj.io spec: group: argoproj.io @@ -8969,6 +8996,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -9532,6 +9561,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -10103,6 +10134,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -10229,6 +10262,7 @@ spec: additionalProperties: type: string type: object + x-kubernetes-map-type: atomic overhead: additionalProperties: anyOf: @@ -10317,6 +10351,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -10513,7 +10549,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.5.0 + controller-gen.kubebuilder.io/version: v0.7.0 name: rollouts.argoproj.io spec: group: argoproj.io @@ -11968,6 +12004,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -12531,6 +12569,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -13102,6 +13142,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -13228,6 +13270,7 @@ spec: additionalProperties: type: string type: object + x-kubernetes-map-type: atomic overhead: additionalProperties: anyOf: @@ -13316,6 +13359,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 7b74516558..6592d72d85 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.5.0 + controller-gen.kubebuilder.io/version: v0.7.0 name: analysisruns.argoproj.io spec: group: argoproj.io @@ -1046,6 +1046,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -1609,6 +1611,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -2180,6 +2184,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -2306,6 +2312,7 @@ spec: additionalProperties: type: string type: object + x-kubernetes-map-type: atomic overhead: additionalProperties: anyOf: @@ -2394,6 +2401,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -2757,7 +2766,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.5.0 + controller-gen.kubebuilder.io/version: v0.7.0 name: analysistemplates.argoproj.io spec: group: argoproj.io @@ -3796,6 +3805,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -4359,6 +4370,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -4930,6 +4943,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -5056,6 +5071,7 @@ spec: additionalProperties: type: string type: object + x-kubernetes-map-type: atomic overhead: additionalProperties: anyOf: @@ -5144,6 +5160,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -5397,7 +5415,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.5.0 + controller-gen.kubebuilder.io/version: v0.7.0 name: clusteranalysistemplates.argoproj.io spec: group: argoproj.io @@ -6436,6 +6454,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -6999,6 +7019,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -7570,6 +7592,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -7696,6 +7720,7 @@ spec: additionalProperties: type: string type: object + x-kubernetes-map-type: atomic overhead: additionalProperties: anyOf: @@ -7784,6 +7809,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -8037,7 +8064,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.5.0 + controller-gen.kubebuilder.io/version: v0.7.0 name: experiments.argoproj.io spec: group: argoproj.io @@ -8969,6 +8996,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -9532,6 +9561,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -10103,6 +10134,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -10229,6 +10262,7 @@ spec: additionalProperties: type: string type: object + x-kubernetes-map-type: atomic overhead: additionalProperties: anyOf: @@ -10317,6 +10351,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -10513,7 +10549,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.5.0 + controller-gen.kubebuilder.io/version: v0.7.0 name: rollouts.argoproj.io spec: group: argoproj.io @@ -11968,6 +12004,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -12531,6 +12569,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -13102,6 +13142,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object @@ -13228,6 +13270,7 @@ spec: additionalProperties: type: string type: object + x-kubernetes-map-type: atomic overhead: additionalProperties: anyOf: @@ -13316,6 +13359,8 @@ spec: type: string gmsaCredentialSpecName: type: string + hostProcess: + type: boolean runAsUserName: type: string type: object diff --git a/metricproviders/prometheus/mock_test.go b/metricproviders/prometheus/mock_test.go index 7aa6ed6f95..a93c285244 100644 --- a/metricproviders/prometheus/mock_test.go +++ b/metricproviders/prometheus/mock_test.go @@ -95,3 +95,7 @@ func (m mockAPI) TSDB(ctx context.Context) (v1.TSDBResult, error) { func (m mockAPI) Buildinfo(ctx context.Context) (v1.BuildinfoResult, error) { panic("Not used") } + +func (m mockAPI) QueryExemplars(ctx context.Context, query string, startTime time.Time, endTime time.Time) ([]v1.ExemplarQueryResult, error) { + panic("Not used") +} diff --git a/pkg/apiclient/rollout/rollout.swagger.json b/pkg/apiclient/rollout/rollout.swagger.json index 5aa648723a..e6ae65bc49 100644 --- a/pkg/apiclient/rollout/rollout.swagger.json +++ b/pkg/apiclient/rollout/rollout.swagger.json @@ -1813,7 +1813,7 @@ "title": "Specify whether the ConfigMap or its key must be defined\n+optional" } }, - "description": "Selects a key from a ConfigMap." + "title": "Selects a key from a ConfigMap.\n+structType=atomic" }, "k8s.io.api.core.v1.ConfigMapProjection": { "type": "object", @@ -1876,14 +1876,14 @@ "items": { "type": "string" }, - "title": "Entrypoint array. Not executed within a shell.\nThe docker image's ENTRYPOINT is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax\ncan be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded,\nregardless of whether the variable exists or not.\nCannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional" + "title": "Entrypoint array. Not executed within a shell.\nThe docker image's ENTRYPOINT is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will\nproduce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless\nof whether the variable exists or not. Cannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional" }, "args": { "type": "array", "items": { "type": "string" }, - "title": "Arguments to the entrypoint.\nThe docker image's CMD is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax\ncan be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded,\nregardless of whether the variable exists or not.\nCannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional" + "title": "Arguments to the entrypoint.\nThe docker image's CMD is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will\nproduce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless\nof whether the variable exists or not. Cannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional" }, "workingDir": { "type": "string", @@ -1958,7 +1958,7 @@ }, "securityContext": { "$ref": "#/definitions/k8s.io.api.core.v1.SecurityContext", - "title": "Security options the pod should run with.\nMore info: https://kubernetes.io/docs/concepts/policy/security-context/\nMore info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/\n+optional" + "title": "SecurityContext defines the security options the container should be run with.\nIf set, the fields of SecurityContext override the equivalent fields of PodSecurityContext.\nMore info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/\n+optional" }, "stdin": { "type": "boolean", @@ -2098,7 +2098,7 @@ }, "value": { "type": "string", - "title": "Variable references $(VAR_NAME) are expanded\nusing the previous defined environment variables in the container and\nany service environment variables. If a variable cannot be resolved,\nthe reference in the input string will be unchanged. The $(VAR_NAME)\nsyntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped\nreferences will never be expanded, regardless of whether the variable\nexists or not.\nDefaults to \"\".\n+optional" + "title": "Variable references $(VAR_NAME) are expanded\nusing the previously defined environment variables in the container and\nany service environment variables. If a variable cannot be resolved,\nthe reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e.\n\"$$(VAR_NAME)\" will produce the string literal \"$(VAR_NAME)\".\nEscaped references will never be expanded, regardless of whether the variable\nexists or not.\nDefaults to \"\".\n+optional" }, "valueFrom": { "$ref": "#/definitions/k8s.io.api.core.v1.EnvVarSource", @@ -2159,14 +2159,14 @@ "items": { "type": "string" }, - "title": "Entrypoint array. Not executed within a shell.\nThe docker image's ENTRYPOINT is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax\ncan be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded,\nregardless of whether the variable exists or not.\nCannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional" + "title": "Entrypoint array. Not executed within a shell.\nThe docker image's ENTRYPOINT is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will\nproduce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless\nof whether the variable exists or not. Cannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional" }, "args": { "type": "array", "items": { "type": "string" }, - "title": "Arguments to the entrypoint.\nThe docker image's CMD is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax\ncan be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded,\nregardless of whether the variable exists or not.\nCannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional" + "title": "Arguments to the entrypoint.\nThe docker image's CMD is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will\nproduce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless\nof whether the variable exists or not. Cannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional" }, "workingDir": { "type": "string", @@ -2241,7 +2241,7 @@ }, "securityContext": { "$ref": "#/definitions/k8s.io.api.core.v1.SecurityContext", - "title": "SecurityContext is not allowed for ephemeral containers.\n+optional" + "title": "Optional: SecurityContext defines the security options the ephemeral container should be run with.\nIf set, the fields of SecurityContext override the equivalent fields of PodSecurityContext.\n+optional" }, "stdin": { "type": "boolean", @@ -2603,7 +2603,7 @@ "title": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\nTODO: Add other useful fields. apiVersion, kind, uid?\n+optional" } }, - "description": "LocalObjectReference contains enough information to let you locate the\nreferenced object inside the same namespace." + "title": "LocalObjectReference contains enough information to let you locate the\nreferenced object inside the same namespace.\n+structType=atomic" }, "k8s.io.api.core.v1.NFSVolumeSource": { "type": "object", @@ -2651,7 +2651,7 @@ "description": "Required. A list of node selector terms. The terms are ORed." } }, - "description": "A node selector represents the union of the results of one or more label queries\nover a set of nodes; that is, it represents the OR of the selectors represented\nby the node selector terms." + "title": "A node selector represents the union of the results of one or more label queries\nover a set of nodes; that is, it represents the OR of the selectors represented\nby the node selector terms.\n+structType=atomic" }, "k8s.io.api.core.v1.NodeSelectorRequirement": { "type": "object", @@ -2692,7 +2692,7 @@ "title": "A list of node selector requirements by node's fields.\n+optional" } }, - "description": "A null or empty node selector term matches no objects. The requirements of\nthem are ANDed.\nThe TopologySelectorTerm type implements a subset of the NodeSelectorTerm." + "title": "A null or empty node selector term matches no objects. The requirements of\nthem are ANDed.\nThe TopologySelectorTerm type implements a subset of the NodeSelectorTerm.\n+structType=atomic" }, "k8s.io.api.core.v1.ObjectFieldSelector": { "type": "object", @@ -2706,7 +2706,7 @@ "description": "Path of the field to select in the specified API version." } }, - "description": "ObjectFieldSelector selects an APIVersioned field of an object." + "title": "ObjectFieldSelector selects an APIVersioned field of an object.\n+structType=atomic" }, "k8s.io.api.core.v1.PersistentVolumeClaimSpec": { "type": "object", @@ -2740,7 +2740,11 @@ }, "dataSource": { "$ref": "#/definitions/k8s.io.api.core.v1.TypedLocalObjectReference", - "title": "This field can be used to specify either:\n* An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot)\n* An existing PVC (PersistentVolumeClaim)\n* An existing custom resource that implements data population (Alpha)\nIn order to use custom resource types that implement data population,\nthe AnyVolumeDataSource feature gate must be enabled.\nIf the provisioner or an external controller can support the specified data source,\nit will create a new volume based on the contents of the specified data source.\n+optional" + "title": "This field can be used to specify either:\n* An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot)\n* An existing PVC (PersistentVolumeClaim)\nIf the provisioner or an external controller can support the specified data source,\nit will create a new volume based on the contents of the specified data source.\nIf the AnyVolumeDataSource feature gate is enabled, this field will always have\nthe same contents as the DataSourceRef field.\n+optional" + }, + "dataSourceRef": { + "$ref": "#/definitions/k8s.io.api.core.v1.TypedLocalObjectReference", + "title": "Specifies the object from which to populate the volume with data, if a non-empty\nvolume is desired. This may be any local object from a non-empty API group (non\ncore object) or a PersistentVolumeClaim object.\nWhen this field is specified, volume binding will only succeed if the type of\nthe specified object matches some installed volume populator or dynamic\nprovisioner.\nThis field will replace the functionality of the DataSource field and as such\nif both fields are non-empty, they must have the same value. For backwards\ncompatibility, both fields (DataSource and DataSourceRef) will be set to the same\nvalue automatically if one of them is empty and the other is non-empty.\nThere are two important differences between DataSource and DataSourceRef:\n* While DataSource only allows two specific types of objects, DataSourceRef\n allows any non-core object, as well as PersistentVolumeClaim objects.\n* While DataSource ignores disallowed values (dropping them), DataSourceRef\n preserves all values, and generates an error if a disallowed value is\n specified.\n(Alpha) Using this field requires the AnyVolumeDataSource feature gate to be enabled.\n+optional" } }, "title": "PersistentVolumeClaimSpec describes the common attributes of storage devices\nand allows a Source for provider-specific attributes" @@ -2827,7 +2831,7 @@ }, "namespaceSelector": { "$ref": "#/definitions/k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector", - "title": "A label query over the set of namespaces that the term applies to.\nThe term is applied to the union of the namespaces selected by this field\nand the ones listed in the namespaces field.\nnull selector and null or empty namespaces list means \"this pod's namespace\".\nAn empty selector ({}) matches all namespaces.\nThis field is alpha-level and is only honored when PodAffinityNamespaceSelector feature is enabled.\n+optional" + "title": "A label query over the set of namespaces that the term applies to.\nThe term is applied to the union of the namespaces selected by this field\nand the ones listed in the namespaces field.\nnull selector and null or empty namespaces list means \"this pod's namespace\".\nAn empty selector ({}) matches all namespaces.\nThis field is beta-level and is only honored when PodAffinityNamespaceSelector feature is enabled.\n+optional" } }, "title": "Defines a set of pods (namely those matching the labelSelector\nrelative to the given namespace(s)) that this pod should be\nco-located (affinity) or not co-located (anti-affinity) with,\nwhere co-located is defined as running on a node whose value of\nthe label with key \u003ctopologyKey\u003e matches that of any node on which\na pod of the set of pods is running" @@ -3014,7 +3018,7 @@ "additionalProperties": { "type": "string" }, - "title": "NodeSelector is a selector which must be true for the pod to fit on a node.\nSelector which must match a node's labels for the pod to be scheduled on that node.\nMore info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/\n+optional" + "title": "NodeSelector is a selector which must be true for the pod to fit on a node.\nSelector which must match a node's labels for the pod to be scheduled on that node.\nMore info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/\n+optional\n+mapType=atomic" }, "serviceAccountName": { "type": "string", @@ -3107,11 +3111,11 @@ "items": { "$ref": "#/definitions/k8s.io.api.core.v1.PodReadinessGate" }, - "title": "If specified, all readiness gates will be evaluated for pod readiness.\nA pod is ready when all its containers are ready AND\nall conditions specified in the readiness gates have status equal to \"True\"\nMore info: https://git.k8s.io/enhancements/keps/sig-network/0007-pod-ready%2B%2B.md\n+optional" + "title": "If specified, all readiness gates will be evaluated for pod readiness.\nA pod is ready when all its containers are ready AND\nall conditions specified in the readiness gates have status equal to \"True\"\nMore info: https://git.k8s.io/enhancements/keps/sig-network/580-pod-readiness-gates\n+optional" }, "runtimeClassName": { "type": "string", - "title": "RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used\nto run this pod. If no RuntimeClass resource matches the named class, the pod will not be run.\nIf unset or empty, the \"legacy\" RuntimeClass will be used, which is an implicit class with an\nempty definition that uses the default runtime handler.\nMore info: https://git.k8s.io/enhancements/keps/sig-node/runtime-class.md\nThis is a beta feature as of Kubernetes v1.14.\n+optional" + "title": "RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used\nto run this pod. If no RuntimeClass resource matches the named class, the pod will not be run.\nIf unset or empty, the \"legacy\" RuntimeClass will be used, which is an implicit class with an\nempty definition that uses the default runtime handler.\nMore info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class\nThis is a beta feature as of Kubernetes v1.14.\n+optional" }, "enableServiceLinks": { "type": "boolean", @@ -3126,7 +3130,7 @@ "additionalProperties": { "$ref": "#/definitions/k8s.io.apimachinery.pkg.api.resource.Quantity" }, - "title": "Overhead represents the resource overhead associated with running a pod for a given RuntimeClass.\nThis field will be autopopulated at admission time by the RuntimeClass admission controller. If\nthe RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests.\nThe RuntimeClass admission controller will reject Pod create requests which have the overhead already\nset. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value\ndefined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero.\nMore info: https://git.k8s.io/enhancements/keps/sig-node/20190226-pod-overhead.md\nThis field is alpha-level as of Kubernetes v1.16, and is only honored by servers that enable the PodOverhead feature.\n+optional" + "title": "Overhead represents the resource overhead associated with running a pod for a given RuntimeClass.\nThis field will be autopopulated at admission time by the RuntimeClass admission controller. If\nthe RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests.\nThe RuntimeClass admission controller will reject Pod create requests which have the overhead already\nset. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value\ndefined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero.\nMore info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead/README.md\nThis field is beta-level as of Kubernetes v1.18, and is only honored by servers that enable the PodOverhead feature.\n+optional" }, "topologySpreadConstraints": { "type": "array", @@ -3224,7 +3228,7 @@ "terminationGracePeriodSeconds": { "type": "string", "format": "int64", - "title": "Optional duration in seconds the pod needs to terminate gracefully upon probe failure.\nThe grace period is the duration in seconds after the processes running in the pod are sent\na termination signal and the time when the processes are forcibly halted with a kill signal.\nSet this value longer than the expected cleanup time for your process.\nIf this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this\nvalue overrides the value provided by the pod spec.\nValue must be non-negative integer. The value zero indicates stop immediately via\nthe kill signal (no opportunity to shut down).\nThis is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate.\n+optional" + "title": "Optional duration in seconds the pod needs to terminate gracefully upon probe failure.\nThe grace period is the duration in seconds after the processes running in the pod are sent\na termination signal and the time when the processes are forcibly halted with a kill signal.\nSet this value longer than the expected cleanup time for your process.\nIf this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this\nvalue overrides the value provided by the pod spec.\nValue must be non-negative integer. The value zero indicates stop immediately via\nthe kill signal (no opportunity to shut down).\nThis is a beta field and requires enabling ProbeTerminationGracePeriod feature gate.\nMinimum value is 1. spec.terminationGracePeriodSeconds is used if unset.\n+optional" } }, "description": "Probe describes a health check to be performed against a container to determine whether it is\nalive or ready to receive traffic." @@ -3334,7 +3338,7 @@ "title": "Specifies the output format of the exposed resources, defaults to \"1\"\n+optional" } }, - "title": "ResourceFieldSelector represents container resources (cpu, memory) and their output format" + "title": "ResourceFieldSelector represents container resources (cpu, memory) and their output format\n+structType=atomic" }, "k8s.io.api.core.v1.ResourceRequirements": { "type": "object", @@ -3469,7 +3473,7 @@ "title": "Specify whether the Secret or its key must be defined\n+optional" } }, - "description": "SecretKeySelector selects a key of a Secret." + "title": "SecretKeySelector selects a key of a Secret.\n+structType=atomic" }, "k8s.io.api.core.v1.SecretProjection": { "type": "object", @@ -3708,7 +3712,7 @@ "title": "Name is the name of resource being referenced" } }, - "description": "TypedLocalObjectReference contains enough information to let you locate the\ntyped referenced object inside the same namespace." + "title": "TypedLocalObjectReference contains enough information to let you locate the\ntyped referenced object inside the same namespace.\n+structType=atomic" }, "k8s.io.api.core.v1.Volume": { "type": "object", @@ -3963,6 +3967,10 @@ "runAsUserName": { "type": "string", "title": "The UserName in Windows to run the entrypoint of the container process.\nDefaults to the user specified in image metadata if unspecified.\nMay also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\n+optional" + }, + "hostProcess": { + "type": "boolean", + "title": "HostProcess determines if a container should be run as a 'Host Process' container.\nThis field is alpha-level and will only be honored by components that enable the\nWindowsHostProcessContainers feature flag. Setting this field without the feature\nflag will result in errors when validating the Pod. All of a Pod's containers must\nhave the same effective HostProcess value (it is not allowed to have a mix of HostProcess\ncontainers and non-HostProcess containers). In addition, if HostProcess is true\nthen HostNetwork must also be set to true.\n+optional" } }, "description": "WindowsSecurityContextOptions contain Windows-specific options and credentials." @@ -4054,6 +4062,10 @@ "fieldsV1": { "$ref": "#/definitions/k8s.io.apimachinery.pkg.apis.meta.v1.FieldsV1", "title": "FieldsV1 holds the first JSON version format as described in the \"FieldsV1\" type.\n+optional" + }, + "subresource": { + "type": "string", + "description": "Subresource is the name of the subresource used to update that object, or\nempty string if the object was updated through the main resource. The\nvalue of this field is used to distinguish between managers, even if they\nshare the same name. For example, a status update will be distinct from a\nregular update using the same manager name.\nNote that the APIVersion field is not related to the Subresource field and\nit always corresponds to the version of the main resource." } }, "description": "ManagedFieldsEntry is a workflow-id, a FieldSet and the group version of the resource\nthat the fieldset applies to." @@ -4173,7 +4185,7 @@ "title": "If true, AND if the owner has the \"foregroundDeletion\" finalizer, then\nthe owner cannot be deleted from the key-value store until this\nreference is removed.\nDefaults to false.\nTo set this field, a user needs \"delete\" permission of the owner,\notherwise 422 (Unprocessable Entity) will be returned.\n+optional" } }, - "description": "OwnerReference contains enough information to let you identify an owning\nobject. An owning object must be in the same namespace as the dependent, or\nbe cluster-scoped, so there is no namespace field." + "title": "OwnerReference contains enough information to let you identify an owning\nobject. An owning object must be in the same namespace as the dependent, or\nbe cluster-scoped, so there is no namespace field.\n+structType=atomic" }, "k8s.io.apimachinery.pkg.apis.meta.v1.Time": { "type": "object", diff --git a/pkg/apis/rollouts/v1alpha1/generated.pb.go b/pkg/apis/rollouts/v1alpha1/generated.pb.go index b3fb258963..1a6ad9dc4e 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.pb.go +++ b/pkg/apis/rollouts/v1alpha1/generated.pb.go @@ -11612,10 +11612,7 @@ func (m *ALBStatus) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -11816,10 +11813,7 @@ func (m *ALBTrafficRouting) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -11901,10 +11895,7 @@ func (m *AmbassadorTrafficRouting) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -12053,10 +12044,7 @@ func (m *AnalysisRun) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -12206,10 +12194,7 @@ func (m *AnalysisRunArgument) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -12326,10 +12311,7 @@ func (m *AnalysisRunList) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -12535,10 +12517,7 @@ func (m *AnalysisRunSpec) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -12791,10 +12770,7 @@ func (m *AnalysisRunStatus) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -12884,10 +12860,7 @@ func (m *AnalysisRunStrategy) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -13003,10 +12976,7 @@ func (m *AnalysisTemplate) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -13123,10 +13093,7 @@ func (m *AnalysisTemplateList) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -13312,10 +13279,7 @@ func (m *AnalysisTemplateSpec) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -13437,10 +13401,7 @@ func (m *AntiAffinity) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -13591,10 +13552,7 @@ func (m *Argument) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -13713,10 +13671,7 @@ func (m *ArgumentValueFrom) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -13830,10 +13785,7 @@ func (m *AwsResourceRef) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -14039,10 +13991,7 @@ func (m *BlueGreenStatus) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -14492,10 +14441,7 @@ func (m *BlueGreenStrategy) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -14685,10 +14631,7 @@ func (m *CanaryStatus) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -14902,10 +14845,7 @@ func (m *CanaryStep) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -15385,10 +15325,7 @@ func (m *CanaryStrategy) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -15504,10 +15441,7 @@ func (m *CloudWatchMetric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -15748,10 +15682,7 @@ func (m *CloudWatchMetricDataQuery) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -15931,10 +15862,7 @@ func (m *CloudWatchMetricStat) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -16083,10 +16011,7 @@ func (m *CloudWatchMetricStatMetric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -16200,10 +16125,7 @@ func (m *CloudWatchMetricStatMetricDimension) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -16319,10 +16241,7 @@ func (m *ClusterAnalysisTemplate) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -16439,10 +16358,7 @@ func (m *ClusterAnalysisTemplateList) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -16556,10 +16472,7 @@ func (m *DatadogMetric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -16641,10 +16554,7 @@ func (m *DryRun) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -16793,10 +16703,7 @@ func (m *Experiment) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -16974,10 +16881,7 @@ func (m *ExperimentAnalysisRunStatus) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -17165,10 +17069,7 @@ func (m *ExperimentAnalysisTemplateRef) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -17412,10 +17313,7 @@ func (m *ExperimentCondition) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -17532,10 +17430,7 @@ func (m *ExperimentList) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -17779,10 +17674,7 @@ func (m *ExperimentSpec) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -18034,10 +17926,7 @@ func (m *ExperimentStatus) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -18119,10 +18008,7 @@ func (m *FieldRef) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -18236,10 +18122,7 @@ func (m *GraphiteMetric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -18385,10 +18268,7 @@ func (m *IstioDestinationRule) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -18544,10 +18424,7 @@ func (m *IstioTrafficRouting) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -18695,10 +18572,7 @@ func (m *IstioVirtualService) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -18814,10 +18688,7 @@ func (m *JobMetric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -19126,10 +18997,7 @@ func (m *KayentaMetric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -19277,10 +19145,7 @@ func (m *KayentaScope) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -19368,10 +19233,7 @@ func (m *KayentaThreshold) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -19699,7 +19561,7 @@ func (m *Measurement) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > postIndex { @@ -19752,10 +19614,7 @@ func (m *Measurement) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -19856,10 +19715,7 @@ func (m *MeasurementRetention) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -20246,10 +20102,7 @@ func (m *Metric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -20623,10 +20476,7 @@ func (m *MetricProvider) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -20940,10 +20790,7 @@ func (m *MetricResult) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -21057,10 +20904,7 @@ func (m *NewRelicMetric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -21284,7 +21128,7 @@ func (m *NginxTrafficRouting) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > postIndex { @@ -21301,10 +21145,7 @@ func (m *NginxTrafficRouting) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -21450,10 +21291,7 @@ func (m *ObjectRef) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -21568,10 +21406,7 @@ func (m *PauseCondition) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -21731,7 +21566,7 @@ func (m *PodTemplateMetadata) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > postIndex { @@ -21858,7 +21693,7 @@ func (m *PodTemplateMetadata) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > postIndex { @@ -21875,10 +21710,7 @@ func (m *PodTemplateMetadata) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -21947,10 +21779,7 @@ func (m *PreferredDuringSchedulingIgnoredDuringExecution) Unmarshal(dAtA []byte) if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -22064,10 +21893,7 @@ func (m *PrometheusMetric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -22117,10 +21943,7 @@ func (m *RequiredDuringSchedulingIgnoredDuringExecution) Unmarshal(dAtA []byte) if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -22269,10 +22092,7 @@ func (m *Rollout) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -22424,10 +22244,7 @@ func (m *RolloutAnalysis) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -22530,10 +22347,7 @@ func (m *RolloutAnalysisBackground) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -22679,10 +22493,7 @@ func (m *RolloutAnalysisRunStatus) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -22784,10 +22595,7 @@ func (m *RolloutAnalysisTemplate) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -23031,10 +22839,7 @@ func (m *RolloutCondition) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -23184,10 +22989,7 @@ func (m *RolloutExperimentStep) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -23375,10 +23177,7 @@ func (m *RolloutExperimentStepAnalysisTemplateRef) Unmarshal(dAtA []byte) error if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -23601,10 +23400,7 @@ func (m *RolloutExperimentTemplate) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -23721,10 +23517,7 @@ func (m *RolloutList) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -23810,10 +23603,7 @@ func (m *RolloutPause) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -24192,10 +23982,7 @@ func (m *RolloutSpec) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -24938,10 +24725,7 @@ func (m *RolloutStatus) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -25063,10 +24847,7 @@ func (m *RolloutStrategy) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -25296,10 +25077,7 @@ func (m *RolloutTrafficRouting) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -25444,10 +25222,7 @@ func (m *RunSummary) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -25561,10 +25336,7 @@ func (m *SMITrafficRouting) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -25761,10 +25533,7 @@ func (m *ScopeDetail) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -25878,10 +25647,7 @@ func (m *SecretKeyRef) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -25991,10 +25757,7 @@ func (m *SetCanaryScale) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -26083,10 +25846,7 @@ func (m *StickinessConfig) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -26187,10 +25947,7 @@ func (m *TLSRoute) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -26240,10 +25997,7 @@ func (m *TemplateService) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -26469,10 +26223,7 @@ func (m *TemplateSpec) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -26814,10 +26565,7 @@ func (m *TemplateStatus) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -26988,10 +26736,7 @@ func (m *TrafficWeights) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -27113,10 +26858,7 @@ func (m *ValueFrom) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -27230,10 +26972,7 @@ func (m *WavefrontMetric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -27484,10 +27223,7 @@ func (m *WebMetric) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -27601,10 +27337,7 @@ func (m *WebMetricHeader) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { @@ -27737,10 +27470,7 @@ func (m *WeightDestination) Unmarshal(dAtA []byte) error { if err != nil { return err } - if skippy < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } if (iNdEx + skippy) > l { diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index b420c0f355..08a3842f96 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -23,8 +23,8 @@ limitations under the License. package v1alpha1 import ( - spec "github.com/go-openapi/spec" common "k8s.io/kube-openapi/pkg/common" + spec "k8s.io/kube-openapi/pkg/validation/spec" ) func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { diff --git a/pkg/apis/rollouts/validation/validation.go b/pkg/apis/rollouts/validation/validation.go index da03a1fd95..4a56c0fa30 100644 --- a/pkg/apis/rollouts/validation/validation.go +++ b/pkg/apis/rollouts/validation/validation.go @@ -64,6 +64,19 @@ const ( InvalidCanaryDynamicStableScaleWithScaleDownDelay = "Canary dynamicStableScale cannot be used with scaleDownDelaySeconds" ) +// allowAllPodValidationOptions allows all pod options to be true for the purposes of rollout pod +// spec validation. We allow everything because we don't know what is truly allowed in the cluster +// and rely on ReplicaSet/Pod creation to enforce if these options are truly allowed. +// NOTE: this variable may need to be updated whenever we update our k8s libraries as new options +// are introduced or removed. +var allowAllPodValidationOptions = apivalidation.PodValidationOptions{ + AllowDownwardAPIHugePages: true, + AllowInvalidPodDeletionCost: true, + AllowIndivisibleHugePagesValues: true, + AllowWindowsHostProcessField: true, + AllowExpandedDNSConfig: true, +} + func ValidateRollout(rollout *v1alpha1.Rollout) field.ErrorList { allErrs := field.ErrorList{} allErrs = append(allErrs, ValidateRolloutSpec(rollout, field.NewPath("spec"))...) @@ -124,14 +137,10 @@ func ValidateRolloutSpec(rollout *v1alpha1.Rollout, fldPath *field.Path) field.E } template.ObjectMeta = spec.Template.ObjectMeta removeSecurityContextPrivileged(&template) - opts := apivalidation.PodValidationOptions{ - AllowMultipleHugePageResources: true, - AllowDownwardAPIHugePages: true, - } // Skip validating empty template for rollout resolved from ref if rollout.Spec.TemplateResolvedFromRef || spec.WorkloadRef == nil { - allErrs = append(allErrs, validation.ValidatePodTemplateSpecForReplicaSet(&template, selector, replicas, fldPath.Child("template"), opts)...) + allErrs = append(allErrs, validation.ValidatePodTemplateSpecForReplicaSet(&template, selector, replicas, fldPath.Child("template"), allowAllPodValidationOptions)...) } } allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(spec.MinReadySeconds), fldPath.Child("minReadySeconds"))...) diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index 0ce58818ea..1a5e6bb353 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -74,7 +74,10 @@ func (c *Clientset) Tracker() testing.ObjectTracker { return c.tracker } -var _ clientset.Interface = &Clientset{} +var ( + _ clientset.Interface = &Clientset{} + _ testing.FakeClient = &Clientset{} +) // ArgoprojV1alpha1 retrieves the ArgoprojV1alpha1Client func (c *Clientset) ArgoprojV1alpha1() argoprojv1alpha1.ArgoprojV1alpha1Interface { diff --git a/pkg/kubectl-argo-rollouts/options/fake/fakeoptions.go b/pkg/kubectl-argo-rollouts/options/fake/fakeoptions.go index 2379897d33..17c02fffd9 100644 --- a/pkg/kubectl-argo-rollouts/options/fake/fakeoptions.go +++ b/pkg/kubectl-argo-rollouts/options/fake/fakeoptions.go @@ -3,15 +3,17 @@ package options import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/cli-runtime/pkg/genericclioptions" dynamicfake "k8s.io/client-go/dynamic/fake" k8sfake "k8s.io/client-go/kubernetes/fake" + "k8s.io/client-go/kubernetes/scheme" cmdtesting "k8s.io/kubectl/pkg/cmd/testing" + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" fakeroclient "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned/fake" "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/options" - "k8s.io/client-go/kubernetes/scheme" ) // NewFakeArgoRolloutsOptions returns a options.ArgoRolloutsOptions suitable for testing @@ -71,6 +73,14 @@ func NewFakeArgoRolloutsOptions(obj ...runtime.Object) (*cmdtesting.TestFactory, if err != nil { panic(err) } - o.DynamicClient = dynamicfake.NewSimpleDynamicClient(scheme.Scheme, allObjs...) + listMapping := map[schema.GroupVersionResource]string{ + v1alpha1.RolloutGVR: rollouts.RolloutKind + "List", + v1alpha1.AnalysisTemplateGVR: rollouts.AnalysisTemplateKind + "List", + v1alpha1.AnalysisRunGVR: rollouts.AnalysisRunKind + "List", + v1alpha1.ExperimentGVR: rollouts.ExperimentKind + "List", + v1alpha1.ClusterAnalysisTemplateGVR: rollouts.ClusterAnalysisTemplateKind + "List", + } + + o.DynamicClient = dynamicfake.NewSimpleDynamicClientWithCustomListKinds(scheme.Scheme, listMapping, allObjs...) return tf, o } From 0f93f9b82ed4fd49f107914b6d4c62eed93dbff7 Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Fri, 14 Jan 2022 13:58:11 -0800 Subject: [PATCH 045/175] fix!: improve basic canary approximation accuracy and honor maxSurge (#1759) Signed-off-by: Jesse Suen --- rollout/analysis_test.go | 8 +- rollout/experiment_test.go | 4 +- utils/replicaset/canary.go | 147 +++++++++++++++++--------------- utils/replicaset/canary_test.go | 137 ++++++++++++++++++++++++++++- 4 files changed, 221 insertions(+), 75 deletions(-) diff --git a/rollout/analysis_test.go b/rollout/analysis_test.go index 61ce7d6991..4e36e37b66 100644 --- a/rollout/analysis_test.go +++ b/rollout/analysis_test.go @@ -735,7 +735,7 @@ func TestDoNothingWithAnalysisRunsWhileBackgroundAnalysisRunRunning(t *testing.T SetWeight: pointer.Int32Ptr(10), }} - r1 := newCanaryRollout("foo", 1, nil, steps, pointer.Int32Ptr(0), intstr.FromInt(0), intstr.FromInt(1)) + r1 := newCanaryRollout("foo", 1, nil, steps, pointer.Int32Ptr(0), intstr.FromInt(1), intstr.FromInt(1)) r2 := bumpVersion(r1) r2.Spec.Strategy.Canary.Analysis = &v1alpha1.RolloutAnalysisBackground{ RolloutAnalysis: v1alpha1.RolloutAnalysis{ @@ -792,7 +792,7 @@ func TestDoNothingWhileStepBasedAnalysisRunRunning(t *testing.T) { }, }} - r1 := newCanaryRollout("foo", 1, nil, steps, pointer.Int32Ptr(0), intstr.FromInt(0), intstr.FromInt(1)) + r1 := newCanaryRollout("foo", 1, nil, steps, pointer.Int32Ptr(0), intstr.FromInt(1), intstr.FromInt(1)) r2 := bumpVersion(r1) ar := analysisRun(at, v1alpha1.RolloutTypeStepLabel, r2) ar.Status.Phase = v1alpha1.AnalysisPhaseRunning @@ -1067,7 +1067,7 @@ func TestPausedOnInconclusiveBackgroundAnalysisRun(t *testing.T) { {SetWeight: pointer.Int32Ptr(30)}, } - r1 := newCanaryRollout("foo", 1, nil, steps, pointer.Int32Ptr(0), intstr.FromInt(0), intstr.FromInt(1)) + r1 := newCanaryRollout("foo", 1, nil, steps, pointer.Int32Ptr(0), intstr.FromInt(1), intstr.FromInt(1)) r2 := bumpVersion(r1) ar := analysisRun(at, v1alpha1.RolloutTypeBackgroundRunLabel, r2) r2.Spec.Strategy.Canary.Analysis = &v1alpha1.RolloutAnalysisBackground{ @@ -1447,7 +1447,7 @@ func TestDoNotCreateBackgroundAnalysisRunAfterInconclusiveRun(t *testing.T) { {SetWeight: pointer.Int32Ptr(10)}, } - r1 := newCanaryRollout("foo", 1, nil, steps, pointer.Int32Ptr(0), intstr.FromInt(0), intstr.FromInt(1)) + r1 := newCanaryRollout("foo", 1, nil, steps, pointer.Int32Ptr(0), intstr.FromInt(1), intstr.FromInt(1)) r2 := bumpVersion(r1) r2.Spec.Strategy.Canary.Analysis = &v1alpha1.RolloutAnalysisBackground{ RolloutAnalysis: v1alpha1.RolloutAnalysis{ diff --git a/rollout/experiment_test.go b/rollout/experiment_test.go index 6c96080c3b..b002913d0f 100644 --- a/rollout/experiment_test.go +++ b/rollout/experiment_test.go @@ -322,7 +322,7 @@ func TestPauseRolloutAfterInconclusiveExperiment(t *testing.T) { Experiment: &v1alpha1.RolloutExperimentStep{}, }} - r1 := newCanaryRollout("foo", 1, nil, steps, pointer.Int32Ptr(0), intstr.FromInt(0), intstr.FromInt(1)) + r1 := newCanaryRollout("foo", 1, nil, steps, pointer.Int32Ptr(0), intstr.FromInt(1), intstr.FromInt(1)) r2 := bumpVersion(r1) rs1 := newReplicaSetWithStatus(r1, 1, 1) @@ -373,7 +373,7 @@ func TestRolloutExperimentScaleDownExperimentFromPreviousStep(t *testing.T) { {SetWeight: pointer.Int32Ptr(1)}, } - r1 := newCanaryRollout("foo", 1, nil, steps, pointer.Int32Ptr(1), intstr.FromInt(0), intstr.FromInt(1)) + r1 := newCanaryRollout("foo", 1, nil, steps, pointer.Int32Ptr(1), intstr.FromInt(1), intstr.FromInt(1)) r2 := bumpVersion(r1) rs1 := newReplicaSetWithStatus(r1, 1, 1) diff --git a/utils/replicaset/canary.go b/utils/replicaset/canary.go index 01055d1931..8a3835eb31 100644 --- a/utils/replicaset/canary.go +++ b/utils/replicaset/canary.go @@ -43,56 +43,6 @@ func AtDesiredReplicaCountsForCanary(ro *v1alpha1.Rollout, newRS, stableRS *apps return true } -/* -// AtDesiredReplicaCountsForCanary indicates if the rollout is at the desired state for the current step -func AtDesiredReplicaCountsForCanary(rollout *v1alpha1.Rollout, newRS, stableRS *appsv1.ReplicaSet, olderRSs []*appsv1.ReplicaSet) bool { - desiredNewRSReplicaCount, desiredStableRSReplicaCount := DesiredReplicaCountsForCanary(rollout, newRS, stableRS) - if newRS == nil || desiredNewRSReplicaCount != *newRS.Spec.Replicas || desiredNewRSReplicaCount != newRS.Status.AvailableReplicas { - return false - } - if stableRS == nil || desiredStableRSReplicaCount != *stableRS.Spec.Replicas || desiredStableRSReplicaCount != stableRS.Status.AvailableReplicas { - return false - } - if GetAvailableReplicaCountForReplicaSets(olderRSs) != int32(0) { - return false - } - return true -} -*/ - -/* -//DesiredReplicaCountsForCanary calculates the desired endstate replica count for the new and stable replicasets -func DesiredReplicaCountsForCanary(rollout *v1alpha1.Rollout, newRS, stableRS *appsv1.ReplicaSet) (int32, int32) { - rolloutSpecReplica := defaults.GetReplicasOrDefault(rollout.Spec.Replicas) - replicas, weight := GetCanaryReplicasOrWeight(rollout) - - desiredNewRSReplicaCount := int32(0) - desiredStableRSReplicaCount := int32(0) - if replicas != nil { - desiredNewRSReplicaCount = *replicas - desiredStableRSReplicaCount = rolloutSpecReplica - } else { - desiredNewRSReplicaCount = int32(math.Ceil(float64(rolloutSpecReplica) * (float64(weight) / 100))) - desiredStableRSReplicaCount = int32(math.Ceil(float64(rolloutSpecReplica) * (1 - (float64(weight) / 100)))) - } - - if !CheckStableRSExists(newRS, stableRS) { - // If there is no stableRS or it is the same as the newRS, then the rollout does not follow the canary steps. - // Instead the controller tries to get the newRS to 100% traffic. - desiredNewRSReplicaCount = rolloutSpecReplica - desiredStableRSReplicaCount = 0 - } - // Unlike the ReplicaSet based weighted canary, a service mesh/ingress - // based canary leaves the stable as 100% scaled until the rollout completes. - if rollout.Spec.Strategy.Canary.TrafficRouting != nil { - desiredStableRSReplicaCount = rolloutSpecReplica - } - - return desiredNewRSReplicaCount, desiredStableRSReplicaCount - -} -*/ - // CalculateReplicaCountsForBasicCanary calculates the number of replicas for the newRS and the stableRS // when using the basic canary strategy. The function calculates the desired number of replicas for // the new and stable RS using the following equations: @@ -131,9 +81,9 @@ func DesiredReplicaCountsForCanary(rollout *v1alpha1.Rollout, newRS, stableRS *a func CalculateReplicaCountsForBasicCanary(rollout *v1alpha1.Rollout, newRS *appsv1.ReplicaSet, stableRS *appsv1.ReplicaSet, oldRSs []*appsv1.ReplicaSet) (int32, int32) { rolloutSpecReplica := defaults.GetReplicasOrDefault(rollout.Spec.Replicas) _, desiredWeight := GetCanaryReplicasOrWeight(rollout) + maxSurge := MaxSurge(rollout) - desiredStableRSReplicaCount := int32(math.Ceil(float64(rolloutSpecReplica) * (1 - (float64(desiredWeight) / 100)))) - desiredNewRSReplicaCount := int32(math.Ceil(float64(rolloutSpecReplica) * (float64(desiredWeight) / 100))) + desiredNewRSReplicaCount, desiredStableRSReplicaCount := approximateWeightedCanaryStableReplicaCounts(rolloutSpecReplica, desiredWeight, maxSurge) stableRSReplicaCount := int32(0) newRSReplicaCount := int32(0) @@ -151,13 +101,6 @@ func CalculateReplicaCountsForBasicCanary(rollout *v1alpha1.Rollout, newRS *apps desiredStableRSReplicaCount = 0 } - maxSurge := MaxSurge(rollout) - - if extraReplicaAdded(rolloutSpecReplica, desiredWeight) { - // In the case where the weight of the stable and canary replica counts cannot be divided evenly, - // the controller needs to surges by one to account for both replica counts being rounded up. - maxSurge = maxSurge + 1 - } maxReplicaCountAllowed := rolloutSpecReplica + maxSurge allRSs := append(oldRSs, newRS) @@ -223,6 +166,84 @@ func CalculateReplicaCountsForBasicCanary(rollout *v1alpha1.Rollout, newRS *apps return newRSReplicaCount, stableRSReplicaCount } +// approximateWeightedCanaryStableReplicaCounts approximates the desired canary weight and returns +// the closest replica count values for the canary and stable to reach the desired weight. The +// canary/stable replica counts might sum to either spec.replicas or spec.replicas + 1 but will not +// exceed spec.replicas if maxSurge is 0. If the canary weight is between 1-99, and spec.replicas is > 1, +// we will always return a minimum of 1 for stable and canary as to not return 0. +func approximateWeightedCanaryStableReplicaCounts(specReplicas, desiredWeight, maxSurge int32) (int32, int32) { + if specReplicas == 0 { + return 0, 0 + } + // canaryOption is one potential return value of this function. We will evaluate multiple options + // for the canary count in order to best approximate the desired weight. + type canaryOption struct { + canary int32 + total int32 + } + var options []canaryOption + + ceilWeightedCanaryCount := int32(math.Ceil(float64(specReplicas*desiredWeight) / 100.0)) + floorWeightedCanaryCount := int32(math.Floor(float64(specReplicas*desiredWeight) / 100.0)) + + tied := floorCeilingTied(desiredWeight, specReplicas) + + // zeroAllowed indicates if are allowed to return the floored value if it is zero. We don't allow + // the value to be zero if when user has a weight from 1-99, and they run 2+ replicas (surge included) + zeroAllowed := desiredWeight == 100 || desiredWeight == 0 || (specReplicas == 1 && maxSurge == 0) + + if ceilWeightedCanaryCount < specReplicas || zeroAllowed { + options = append(options, canaryOption{ceilWeightedCanaryCount, specReplicas}) + } + + if !tied && (floorWeightedCanaryCount != 0 || zeroAllowed) { + options = append(options, canaryOption{floorWeightedCanaryCount, specReplicas}) + } + + // check if we are allowed to surge. if we are, we can also consider rounding up to spec.replicas + 1 + // in order to achieve a closer canary weight + if maxSurge > 0 { + options = append(options, canaryOption{ceilWeightedCanaryCount, specReplicas + 1}) + surgeIsTied := floorCeilingTied(desiredWeight, specReplicas+1) + if !surgeIsTied && (floorWeightedCanaryCount != 0 || zeroAllowed) { + options = append(options, canaryOption{floorWeightedCanaryCount, specReplicas + 1}) + } + } + + if len(options) == 0 { + // should not get here + return 0, specReplicas + } + + bestOption := options[0] + bestDelta := weightDelta(desiredWeight, bestOption.canary, bestOption.total) + for i := 1; i < len(options); i++ { + currOption := options[i] + currDelta := weightDelta(desiredWeight, currOption.canary, currOption.total) + if currDelta < bestDelta { + bestOption = currOption + bestDelta = currDelta + } + } + return bestOption.canary, bestOption.total - bestOption.canary +} + +// floorCeilingTied indicates if the ceiling and floor values are equidistant from the desired weight +// For example: replicas: 3, desiredWeight: 50% +// A canary count of 1 (33.33%) or 2 (66.66%) are both equidistant from desired weight of 50%. +// When this happens, we will pick the larger canary count +func floorCeilingTied(desiredWeight, totalReplicas int32) bool { + _, frac := math.Modf(float64(totalReplicas) * (float64(desiredWeight) / 100)) + return frac == 0.5 +} + +// weightDelta calculates the difference that the canary replicas will be from the desired weight +// This is used to pick the closest approximation of canary counts. +func weightDelta(desiredWeight, canaryReplicas, totalReplicas int32) float64 { + actualWeight := float64(canaryReplicas*100) / float64(totalReplicas) + return math.Abs(actualWeight - float64(desiredWeight)) +} + // calculateScaleDownReplicaCount calculates drainRSReplicaCount // drainRSReplicaCount can be either stableRS count or canaryRS count // drainRSReplicaCount corresponds to RS whose availability is not considered in calculating replicasToScaleDown @@ -397,14 +418,6 @@ func GetReplicasForScaleDown(rs *appsv1.ReplicaSet, ignoreAvailability bool) int return rs.Status.AvailableReplicas } -// extraReplicaAdded checks if an extra replica is added because the stable and canary replicas count are both -// rounded up. The controller rounds both of the replica counts when the setWeight does not distribute evenly -// in order to prevent either from having a 0 replica count. -func extraReplicaAdded(replicas int32, setWeight int32) bool { - _, frac := math.Modf(float64(replicas) * (float64(setWeight) / 100)) - return frac != 0.0 -} - // GetCurrentCanaryStep returns the current canary step. If there are no steps or the rollout // has already executed the last step, the func returns nil func GetCurrentCanaryStep(rollout *v1alpha1.Rollout) (*v1alpha1.CanaryStep, *int32) { diff --git a/utils/replicaset/canary_test.go b/utils/replicaset/canary_test.go index 3b817ad96b..66631fe9f3 100644 --- a/utils/replicaset/canary_test.go +++ b/utils/replicaset/canary_test.go @@ -1,6 +1,7 @@ package replicaset import ( + "fmt" "testing" "github.com/stretchr/testify/assert" @@ -374,7 +375,7 @@ func TestCalculateReplicaCountsForCanary(t *testing.T) { olderRS: newRS("older", 3, 3), }, { - name: "Add an extra replica to surge when the setWeight rounding adds another instance", + name: "Do not round past maxSurge with uneven setWeight divisor", rolloutSpecReplicas: 10, setWeight: 5, maxSurge: intstr.FromInt(0), @@ -386,7 +387,23 @@ func TestCalculateReplicaCountsForCanary(t *testing.T) { canarySpecReplica: 0, canaryAvailableReplica: 0, - expectedStableReplicaCount: 10, + expectedStableReplicaCount: 9, + expectedCanaryReplicaCount: 0, + }, + { + name: "Do not round past maxSurge with uneven setWeight divisor (part 2)", + rolloutSpecReplicas: 10, + setWeight: 5, + maxSurge: intstr.FromInt(0), + maxUnavailable: intstr.FromInt(1), + + stableSpecReplica: 9, + stableAvailableReplica: 9, + + canarySpecReplica: 0, + canaryAvailableReplica: 0, + + expectedStableReplicaCount: 9, expectedCanaryReplicaCount: 1, }, { @@ -487,6 +504,37 @@ func TestCalculateReplicaCountsForCanary(t *testing.T) { expectedCanaryReplicaCount: 1, // should only surge by 1 to honor maxSurge: 1 }, { + name: "scale down to maxunavailable without exceeding maxSurge", + rolloutSpecReplicas: 3, + setWeight: 99, + maxSurge: intstr.FromInt(0), + maxUnavailable: intstr.FromInt(2), + + stableSpecReplica: 3, + stableAvailableReplica: 3, + + canarySpecReplica: 0, + canaryAvailableReplica: 0, + + expectedStableReplicaCount: 1, + expectedCanaryReplicaCount: 0, + }, + { + name: "scale down to maxunavailable without exceeding maxSurge (part 2)", + rolloutSpecReplicas: 3, + setWeight: 99, + maxSurge: intstr.FromInt(0), + maxUnavailable: intstr.FromInt(2), + + stableSpecReplica: 1, + stableAvailableReplica: 1, + + canarySpecReplica: 0, + canaryAvailableReplica: 0, + + expectedStableReplicaCount: 1, + expectedCanaryReplicaCount: 2, + }, { // verify we scale down stableRS while honoring maxUnavailable even when stableRS unavailable name: "honor maxUnavailable during scale down stableRS unavailable", rolloutSpecReplicas: 4, @@ -648,6 +696,91 @@ func TestCalculateReplicaCountsForCanary(t *testing.T) { } } +func TestApproximateWeightedNewStableReplicaCounts(t *testing.T) { + tests := []struct { + replicas int32 + weight int32 + maxSurge int32 + expCanary int32 + expStable int32 + }{ + {replicas: 0, weight: 0, maxSurge: 0, expCanary: 0, expStable: 0}, // 0% + {replicas: 0, weight: 50, maxSurge: 0, expCanary: 0, expStable: 0}, // 0% + {replicas: 0, weight: 100, maxSurge: 0, expCanary: 0, expStable: 0}, // 0% + + {replicas: 0, weight: 0, maxSurge: 1, expCanary: 0, expStable: 0}, // 0% + {replicas: 0, weight: 50, maxSurge: 1, expCanary: 0, expStable: 0}, // 0% + {replicas: 0, weight: 100, maxSurge: 1, expCanary: 0, expStable: 0}, // 0% + + {replicas: 1, weight: 0, maxSurge: 0, expCanary: 0, expStable: 1}, // 0% + {replicas: 1, weight: 1, maxSurge: 0, expCanary: 0, expStable: 1}, // 0% + {replicas: 1, weight: 49, maxSurge: 0, expCanary: 0, expStable: 1}, // 0% + {replicas: 1, weight: 50, maxSurge: 0, expCanary: 1, expStable: 0}, // 100% + {replicas: 1, weight: 99, maxSurge: 0, expCanary: 1, expStable: 0}, // 100% + {replicas: 1, weight: 100, maxSurge: 0, expCanary: 1, expStable: 0}, // 100% + + {replicas: 1, weight: 0, maxSurge: 1, expCanary: 0, expStable: 1}, // 0% + {replicas: 1, weight: 1, maxSurge: 1, expCanary: 1, expStable: 1}, // 50% + {replicas: 1, weight: 49, maxSurge: 1, expCanary: 1, expStable: 1}, // 50% + {replicas: 1, weight: 50, maxSurge: 1, expCanary: 1, expStable: 1}, // 50% + {replicas: 1, weight: 99, maxSurge: 1, expCanary: 1, expStable: 1}, // 50% + {replicas: 1, weight: 100, maxSurge: 1, expCanary: 1, expStable: 0}, // 100% + + {replicas: 2, weight: 0, maxSurge: 0, expCanary: 0, expStable: 2}, // 0% + {replicas: 2, weight: 1, maxSurge: 0, expCanary: 1, expStable: 1}, // 50% + {replicas: 2, weight: 50, maxSurge: 0, expCanary: 1, expStable: 1}, // 50% + {replicas: 2, weight: 99, maxSurge: 0, expCanary: 1, expStable: 1}, // 50% + {replicas: 2, weight: 100, maxSurge: 0, expCanary: 2, expStable: 0}, // 100% + + {replicas: 2, weight: 0, maxSurge: 1, expCanary: 0, expStable: 2}, // 0% + {replicas: 2, weight: 1, maxSurge: 1, expCanary: 1, expStable: 2}, // 33.3% + {replicas: 2, weight: 50, maxSurge: 1, expCanary: 1, expStable: 1}, // 50% + {replicas: 2, weight: 99, maxSurge: 1, expCanary: 2, expStable: 1}, // 66.6% + {replicas: 2, weight: 100, maxSurge: 1, expCanary: 2, expStable: 0}, // 100% + + {replicas: 3, weight: 10, maxSurge: 0, expCanary: 1, expStable: 2}, // 33.3% + {replicas: 3, weight: 25, maxSurge: 0, expCanary: 1, expStable: 2}, // 33.3% + {replicas: 3, weight: 33, maxSurge: 0, expCanary: 1, expStable: 2}, // 33.3% + {replicas: 3, weight: 34, maxSurge: 0, expCanary: 1, expStable: 2}, // 33.3% + {replicas: 3, weight: 49, maxSurge: 0, expCanary: 1, expStable: 2}, // 33.3% + {replicas: 3, weight: 50, maxSurge: 0, expCanary: 2, expStable: 1}, // 66.6% + + {replicas: 3, weight: 10, maxSurge: 1, expCanary: 1, expStable: 3}, // 25% + {replicas: 3, weight: 25, maxSurge: 1, expCanary: 1, expStable: 3}, // 25% + {replicas: 3, weight: 33, maxSurge: 1, expCanary: 1, expStable: 2}, // 33.3% + {replicas: 3, weight: 34, maxSurge: 1, expCanary: 1, expStable: 2}, // 33.3% + {replicas: 3, weight: 49, maxSurge: 1, expCanary: 2, expStable: 2}, // 50% + {replicas: 3, weight: 50, maxSurge: 1, expCanary: 2, expStable: 2}, // 50% + + {replicas: 10, weight: 0, maxSurge: 1, expCanary: 0, expStable: 10}, // 0% + {replicas: 10, weight: 1, maxSurge: 0, expCanary: 1, expStable: 9}, // 10% + {replicas: 10, weight: 14, maxSurge: 0, expCanary: 1, expStable: 9}, // 10% + {replicas: 10, weight: 15, maxSurge: 0, expCanary: 2, expStable: 8}, // 20% + {replicas: 10, weight: 16, maxSurge: 0, expCanary: 2, expStable: 8}, // 20% + {replicas: 10, weight: 99, maxSurge: 0, expCanary: 9, expStable: 1}, // 90% + {replicas: 10, weight: 100, maxSurge: 1, expCanary: 10, expStable: 0}, // 100% + + {replicas: 10, weight: 0, maxSurge: 1, expCanary: 0, expStable: 10}, // 0% + {replicas: 10, weight: 1, maxSurge: 1, expCanary: 1, expStable: 10}, // 9.1% + {replicas: 10, weight: 18, maxSurge: 1, expCanary: 2, expStable: 9}, // 18.1% + {replicas: 10, weight: 19, maxSurge: 1, expCanary: 2, expStable: 9}, // 18.1% + {replicas: 10, weight: 20, maxSurge: 1, expCanary: 2, expStable: 8}, // 20% + {replicas: 10, weight: 23, maxSurge: 1, expCanary: 2, expStable: 8}, // 20% + {replicas: 10, weight: 24, maxSurge: 1, expCanary: 3, expStable: 8}, // 27.2% + {replicas: 10, weight: 25, maxSurge: 1, expCanary: 3, expStable: 8}, // 27.2% + {replicas: 10, weight: 99, maxSurge: 1, expCanary: 10, expStable: 1}, // 90.9% + {replicas: 10, weight: 100, maxSurge: 1, expCanary: 10, expStable: 0}, // 100% + + } + for i := range tests { + test := tests[i] + t.Run(fmt.Sprintf("%s_replicas:%d_weight:%d_surge:%d", t.Name(), test.replicas, test.weight, test.maxSurge), func(t *testing.T) { + newRSReplicaCount, stableRSReplicaCount := approximateWeightedCanaryStableReplicaCounts(test.replicas, test.weight, test.maxSurge) + assert.Equal(t, test.expCanary, newRSReplicaCount, "check canary replica count") + assert.Equal(t, test.expStable, stableRSReplicaCount, "check stable replica count") + }) + } +} func TestCalculateReplicaCountsForNewDeployment(t *testing.T) { rollout := newRollout(10, 10, intstr.FromInt(0), intstr.FromInt(1), "canary", "stable", nil, nil) stableRS := newRS("stable", 10, 0) From bf06d7e7e926ce7f64f6a7bc94681044d649434f Mon Sep 17 00:00:00 2001 From: Mubarak Jama <83465122+mubarak-j@users.noreply.github.com> Date: Fri, 14 Jan 2022 15:03:28 -0700 Subject: [PATCH 046/175] docs: Add Ibotta to the list of users (#1744) Signed-off-by: Mubarak Jama --- USERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/USERS.md b/USERS.md index 97897944aa..95a14d607d 100644 --- a/USERS.md +++ b/USERS.md @@ -13,6 +13,7 @@ Organizations below are **officially** using Argo Rollouts. Please send a PR wit 1. [Databricks](https://github.com/databricks) 1. [Devtron Labs](https://github.com/devtron-labs/devtron) 1. [Farfetch](https://www.farfetch.com/) +1. [Ibotta](https://home.ibotta.com/) 1. [Intuit](https://www.intuit.com/) 1. [New Relic](https://newrelic.com/) 1. [Nitro](https://www.gonitro.com) From eb4630208f5c57229a5f71531a8fda5abb520cb8 Mon Sep 17 00:00:00 2001 From: icecoffee531 <51080110+icecoffee531@users.noreply.github.com> Date: Sat, 15 Jan 2022 06:04:42 +0800 Subject: [PATCH 047/175] docs: Add Gllue to list of users (#1745) Signed-off-by: icecoffee <2335250710@qq.com> --- USERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/USERS.md b/USERS.md index 95a14d607d..9c29b73a7f 100644 --- a/USERS.md +++ b/USERS.md @@ -13,6 +13,7 @@ Organizations below are **officially** using Argo Rollouts. Please send a PR wit 1. [Databricks](https://github.com/databricks) 1. [Devtron Labs](https://github.com/devtron-labs/devtron) 1. [Farfetch](https://www.farfetch.com/) +1. [Gllue](https://gllue.com) 1. [Ibotta](https://home.ibotta.com/) 1. [Intuit](https://www.intuit.com/) 1. [New Relic](https://newrelic.com/) From c77f9b54ddfac872550e58a14c1bf1767ad4dcd6 Mon Sep 17 00:00:00 2001 From: cskh Date: Tue, 18 Jan 2022 18:08:45 -0500 Subject: [PATCH 048/175] fix: continue update process in middle of update if spec.replicas is 0 (#1764) Signed-off-by: Hui Kang --- rollout/canary.go | 25 ++++-- rollout/canary_test.go | 8 +- .../istio-host-split-update-in-middle.yaml | 86 +++++++++++++++++++ test/e2e/istio_test.go | 41 ++++++--- 4 files changed, 140 insertions(+), 20 deletions(-) create mode 100644 test/e2e/istio/istio-host-split-update-in-middle.yaml diff --git a/rollout/canary.go b/rollout/canary.go index 3d04707cb8..4aca373efe 100644 --- a/rollout/canary.go +++ b/rollout/canary.go @@ -216,15 +216,11 @@ func (c *rolloutContext) scaleDownOldReplicaSetsForCanary(oldRSs []*appsv1.Repli // and doesn't yet have scale down deadline. This happens when a user changes their // mind in the middle of an V1 -> V2 update, and then applies a V3. We are deciding // what to do with the defunct, intermediate V2 ReplicaSet right now. - if replicasetutil.IsReplicaSetReady(c.newRS) && replicasetutil.IsReplicaSetReady(c.stableRS) { - // If the both new and old RS are available, we can infer that it is safe to - // scale down this ReplicaSet, since traffic should have shifted away from this RS. - // TODO: instead of checking availability of canary/stable, a better way to determine - // if it is safe to scale this down, is to check if traffic is directed to the RS. - // In other words, we can check c.rollout.Status.Canary.Weights to see if this - // ReplicaSet hash is still referenced, and scale it down otherwise. + if !c.replicaSetReferencedByCanaryTraffic(targetRS) { + // It is safe to scale the intermediate RS down, if no traffic is directed to it. c.log.Infof("scaling down intermediate RS '%s'", targetRS.Name) } else { + c.log.Infof("DEBUG CANNOT scaling down intermediate RS '%s'", targetRS.Name) // The current and stable ReplicaSets have not reached readiness. This implies // we might not have shifted traffic away from this ReplicaSet so we need to // keep this scaled up. @@ -249,6 +245,21 @@ func (c *rolloutContext) scaleDownOldReplicaSetsForCanary(oldRSs []*appsv1.Repli return totalScaledDown, nil } +func (c *rolloutContext) replicaSetReferencedByCanaryTraffic(rs *appsv1.ReplicaSet) bool { + rsPodHash := replicasetutil.GetPodTemplateHash(rs) + ro := c.rollout + + if ro.Status.Canary.Weights == nil { + return false + } + + if ro.Status.Canary.Weights.Canary.PodTemplateHash == rsPodHash || ro.Status.Canary.Weights.Stable.PodTemplateHash == rsPodHash { + return true + } + + return false +} + // canProceedWithScaleDownAnnotation returns whether or not it is safe to proceed with annotating // old replicasets with the scale-down-deadline in the traffic-routed canary strategy. // This method only matters with ALB canary + the target group verification feature. diff --git a/rollout/canary_test.go b/rollout/canary_test.go index 6ec62ba50d..754a916660 100644 --- a/rollout/canary_test.go +++ b/rollout/canary_test.go @@ -24,6 +24,7 @@ import ( "github.com/argoproj/argo-rollouts/utils/conditions" logutil "github.com/argoproj/argo-rollouts/utils/log" "github.com/argoproj/argo-rollouts/utils/record" + replicasetutil "github.com/argoproj/argo-rollouts/utils/replicaset" rolloututil "github.com/argoproj/argo-rollouts/utils/rollout" timeutil "github.com/argoproj/argo-rollouts/utils/time" ) @@ -738,6 +739,11 @@ func TestCanaryDontScaleDownOldRsDuringInterruptedUpdate(t *testing.T) { rs1 := newReplicaSetWithStatus(r1, 5, 5) rs2 := newReplicaSetWithStatus(r2, 5, 5) rs3 := newReplicaSetWithStatus(r3, 5, 0) + r3.Status.Canary.Weights = &v1alpha1.TrafficWeights{ + Canary: v1alpha1.WeightDestination{ + PodTemplateHash: replicasetutil.GetPodTemplateHash(rs2), + }, + } f.objects = append(f.objects, r3) f.kubeobjects = append(f.kubeobjects, rs1, rs2, rs3, canarySvc, stableSvc) @@ -751,7 +757,7 @@ func TestCanaryDontScaleDownOldRsDuringInterruptedUpdate(t *testing.T) { // TestCanaryScaleDownOldRsDuringInterruptedUpdate tests that we proceed with scale down of an // intermediate V2 ReplicaSet when applying a V3 spec in the middle of updating a traffic routed // canary going from V1 -> V2 (i.e. after we have shifted traffic away from V2). This test is the -// same as TestCanaryDontScaleDownOldRsDuringUpdate but rs3 is fully available +// same as TestCanaryDontScaleDownOldRsDuringInterruptedUpdate but rs3 is fully available func TestCanaryScaleDownOldRsDuringInterruptedUpdate(t *testing.T) { f := newFixture(t) defer f.Close() diff --git a/test/e2e/istio/istio-host-split-update-in-middle.yaml b/test/e2e/istio/istio-host-split-update-in-middle.yaml new file mode 100644 index 0000000000..f1d6821b18 --- /dev/null +++ b/test/e2e/istio/istio-host-split-update-in-middle.yaml @@ -0,0 +1,86 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-canary +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-stable +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: istio-host-split-vsvc +spec: + hosts: + - istio-host-split + http: + - name: primary + route: + - destination: + host: istio-host-split-stable + weight: 100 + - destination: + host: istio-host-split-canary + weight: 0 + +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: istio-host-split +spec: + replicas: 2 + strategy: + canary: + canaryService: istio-host-split-canary + stableService: istio-host-split-stable + trafficRouting: + istio: + virtualService: + name: istio-host-split-vsvc + routes: + - primary + steps: + - setWeight: 0 + - setCanaryScale: + replicas: 1 + - pause: {} + selector: + matchLabels: + app: istio-host-split + template: + metadata: + labels: + app: istio-host-split + spec: + containers: + - name: istio-host-split + image: nginx:1.19-alpine + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m diff --git a/test/e2e/istio_test.go b/test/e2e/istio_test.go index 47710b5110..478d7eca05 100644 --- a/test/e2e/istio_test.go +++ b/test/e2e/istio_test.go @@ -257,6 +257,25 @@ func (s *IstioSuite) TestIstioAbortUpdate() { ExpectRevisionPodCount("2", 1) } +func (s *IstioSuite) TestIstioUpdateInMiddleZeroCanaryReplicas() { + s.Given(). + RolloutObjects("@istio/istio-host-split-update-in-middle.yaml"). + When(). + ApplyManifests(). + WaitForRolloutStatus("Healthy"). + Then(). + When(). + UpdateSpec(). + WaitForRolloutStatus("Paused"). + Then(). + ExpectRevisionPodCount("2", 1). + When(). + UpdateSpec(). + WaitForRolloutStatus("Paused"). + Then(). + ExpectRevisionPodCount("3", 1) +} + func (s *IstioSuite) TestIstioAbortUpdateDeleteAllCanaryPods() { s.Given(). RolloutObjects("@istio/istio-rollout-abort-delete-all-canary-pods.yaml"). @@ -361,17 +380,17 @@ func (s *IstioSuite) TestIstioSubsetSplitExperimentStep() { WaitForRolloutStatus("Healthy"). Then(). Assert(func(t *fixtures.Then) { - vsvc := t.GetVirtualService() - assert.Equal(s.T(), int64(100), vsvc.Spec.HTTP[0].Route[0].Weight) // stable - assert.Equal(s.T(), int64(0), vsvc.Spec.HTTP[0].Route[1].Weight) // canary + vsvc := t.GetVirtualService() + assert.Equal(s.T(), int64(100), vsvc.Spec.HTTP[0].Route[0].Weight) // stable + assert.Equal(s.T(), int64(0), vsvc.Spec.HTTP[0].Route[1].Weight) // canary - rs1 := t.GetReplicaSetByRevision("1") - destrule := t.GetDestinationRule() - assert.Len(s.T(), destrule.Spec.Subsets, 2) - assert.Equal(s.T(), rs1.Spec.Template.Labels[v1alpha1.DefaultRolloutUniqueLabelKey], destrule.Spec.Subsets[0].Labels[v1alpha1.DefaultRolloutUniqueLabelKey]) // stable - assert.Equal(s.T(), rs1.Spec.Template.Labels[v1alpha1.DefaultRolloutUniqueLabelKey], destrule.Spec.Subsets[1].Labels[v1alpha1.DefaultRolloutUniqueLabelKey]) // canary + rs1 := t.GetReplicaSetByRevision("1") + destrule := t.GetDestinationRule() + assert.Len(s.T(), destrule.Spec.Subsets, 2) + assert.Equal(s.T(), rs1.Spec.Template.Labels[v1alpha1.DefaultRolloutUniqueLabelKey], destrule.Spec.Subsets[0].Labels[v1alpha1.DefaultRolloutUniqueLabelKey]) // stable + assert.Equal(s.T(), rs1.Spec.Template.Labels[v1alpha1.DefaultRolloutUniqueLabelKey], destrule.Spec.Subsets[1].Labels[v1alpha1.DefaultRolloutUniqueLabelKey]) // canary - }). + }). When(). UpdateSpec(). WaitForRolloutCanaryStepIndex(1). @@ -401,7 +420,7 @@ func (s *IstioSuite) TestIstioSubsetSplitExperimentStep() { Assert(func(t *fixtures.Then) { vsvc := t.GetVirtualService() assert.Equal(s.T(), int64(100), vsvc.Spec.HTTP[0].Route[0].Weight) // stable - assert.Equal(s.T(), int64(0), vsvc.Spec.HTTP[0].Route[1].Weight) // canary + assert.Equal(s.T(), int64(0), vsvc.Spec.HTTP[0].Route[1].Weight) // canary destrule := t.GetDestinationRule() rs2 := t.GetReplicaSetByRevision("2") @@ -413,5 +432,3 @@ func (s *IstioSuite) TestIstioSubsetSplitExperimentStep() { s.TearDownSuite() } - - From 71d746cf30144da0a34e61b66bd1f2f94033562e Mon Sep 17 00:00:00 2001 From: Rohit Agrawal Date: Wed, 19 Jan 2022 05:31:56 +0530 Subject: [PATCH 049/175] feat(rollout): AnalysisRuns created by Rollouts can limit retention of metrics (#1780) Signed-off-by: Rohit Agrawal --- docs/features/analysis.md | 20 + .../features/kustomize/rollout_cr_schema.json | 63 ++ experiments/experiment.go | 4 +- manifests/crds/rollout-crd.yaml | 52 + manifests/install.yaml | 52 + manifests/namespace-install.yaml | 52 + pkg/apiclient/rollout/rollout.swagger.json | 22 + pkg/apis/api-rules/violation_exceptions.list | 1 + pkg/apis/rollouts/v1alpha1/generated.pb.go | 914 ++++++++++-------- pkg/apis/rollouts/v1alpha1/generated.proto | 6 + .../rollouts/v1alpha1/openapi_generated.go | 44 +- pkg/apis/rollouts/v1alpha1/types.go | 5 + .../v1alpha1/zz_generated.deepcopy.go | 5 + .../validation/validation_references.go | 2 +- rollout/analysis.go | 2 +- rollout/analysis_test.go | 12 +- utils/analysis/helpers.go | 68 +- utils/analysis/helpers_test.go | 65 +- 18 files changed, 938 insertions(+), 451 deletions(-) diff --git a/docs/features/analysis.md b/docs/features/analysis.md index acffd7f04f..87bd932267 100644 --- a/docs/features/analysis.md +++ b/docs/features/analysis.md @@ -756,6 +756,26 @@ example, the controller will retain the latest twenty run results for all the me )) ``` +### Measurements Retention for Rollouts Analysis + +If a rollout wants to retain more results of its analysis metrics, it simply needs to specify the `measurementRetention` +field to its `analysis` stanza. In the following example, all the metrics from `random-fail` and `always-pass` get +merged, and their latest twenty measurements get retained instead of the default ten. + +```yaml hl_lines="9 10 11" +kind: Rollout +spec: +... + steps: + - analysis: + templates: + - templateName: random-fail + - templateName: always-pass + measurementRetention: + - metricName: .* + limit: 20 +``` + ## Inconclusive Runs Analysis runs can also be considered `Inconclusive`, which indicates the run was neither successful, diff --git a/docs/features/kustomize/rollout_cr_schema.json b/docs/features/kustomize/rollout_cr_schema.json index d0cfd53991..8b397aa5f0 100644 --- a/docs/features/kustomize/rollout_cr_schema.json +++ b/docs/features/kustomize/rollout_cr_schema.json @@ -63,6 +63,27 @@ "type": "array", "x-kubernetes-patch-merge-key": "metricName", "x-kubernetes-patch-strategy": "merge" + }, + "measurementRetention": { + "items": { + "properties": { + "limit": { + "format": "int32", + "type": "integer" + }, + "metricName": { + "type": "string" + } + }, + "required": [ + "limit", + "metricName" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge" } }, "type": "object" @@ -122,6 +143,27 @@ "type": "array", "x-kubernetes-patch-merge-key": "metricName", "x-kubernetes-patch-strategy": "merge" + }, + "measurementRetention": { + "items": { + "properties": { + "limit": { + "format": "int32", + "type": "integer" + }, + "metricName": { + "type": "string" + } + }, + "required": [ + "limit", + "metricName" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge" } }, "type": "object" @@ -189,6 +231,27 @@ "type": "array", "x-kubernetes-patch-merge-key": "metricName", "x-kubernetes-patch-strategy": "merge" + }, + "measurementRetention": { + "items": { + "properties": { + "limit": { + "format": "int32", + "type": "integer" + }, + "metricName": { + "type": "string" + } + }, + "required": [ + "limit", + "metricName" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge" } }, "type": "object" diff --git a/experiments/experiment.go b/experiments/experiment.go index 6c24c74091..ee0cf51964 100644 --- a/experiments/experiment.go +++ b/experiments/experiment.go @@ -626,7 +626,7 @@ func (ec *experimentContext) newAnalysisRun(analysis v1alpha1.ExperimentAnalysis name := fmt.Sprintf("%s-%s", ec.ex.Name, analysis.Name) clusterAnalysisTemplates := []*v1alpha1.ClusterAnalysisTemplate{clusterTemplate} - run, err := analysisutil.NewAnalysisRunFromTemplates(nil, clusterAnalysisTemplates, args, dryRunMetrics, name, "", ec.ex.Namespace) + run, err := analysisutil.NewAnalysisRunFromTemplates(nil, clusterAnalysisTemplates, args, dryRunMetrics, []v1alpha1.MeasurementRetention{}, name, "", ec.ex.Namespace) if err != nil { return nil, err } @@ -644,7 +644,7 @@ func (ec *experimentContext) newAnalysisRun(analysis v1alpha1.ExperimentAnalysis name := fmt.Sprintf("%s-%s", ec.ex.Name, analysis.Name) analysisTemplates := []*v1alpha1.AnalysisTemplate{template} - run, err := analysisutil.NewAnalysisRunFromTemplates(analysisTemplates, nil, args, dryRunMetrics, name, "", ec.ex.Namespace) + run, err := analysisutil.NewAnalysisRunFromTemplates(analysisTemplates, nil, args, dryRunMetrics, []v1alpha1.MeasurementRetention{}, name, "", ec.ex.Namespace) if err != nil { return nil, err } diff --git a/manifests/crds/rollout-crd.yaml b/manifests/crds/rollout-crd.yaml index ba19354ff0..27ed952f64 100644 --- a/manifests/crds/rollout-crd.yaml +++ b/manifests/crds/rollout-crd.yaml @@ -179,6 +179,19 @@ spec: - metricName type: object type: array + measurementRetention: + items: + properties: + limit: + format: int32 + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array templates: items: properties: @@ -223,6 +236,19 @@ spec: - metricName type: object type: array + measurementRetention: + items: + properties: + limit: + format: int32 + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array templates: items: properties: @@ -297,6 +323,19 @@ spec: - metricName type: object type: array + measurementRetention: + items: + properties: + limit: + format: int32 + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array startingStep: format: int32 type: integer @@ -404,6 +443,19 @@ spec: - metricName type: object type: array + measurementRetention: + items: + properties: + limit: + format: int32 + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array templates: items: properties: diff --git a/manifests/install.yaml b/manifests/install.yaml index cae614a930..51ef4c808a 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -10726,6 +10726,19 @@ spec: - metricName type: object type: array + measurementRetention: + items: + properties: + limit: + format: int32 + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array templates: items: properties: @@ -10770,6 +10783,19 @@ spec: - metricName type: object type: array + measurementRetention: + items: + properties: + limit: + format: int32 + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array templates: items: properties: @@ -10844,6 +10870,19 @@ spec: - metricName type: object type: array + measurementRetention: + items: + properties: + limit: + format: int32 + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array startingStep: format: int32 type: integer @@ -10951,6 +10990,19 @@ spec: - metricName type: object type: array + measurementRetention: + items: + properties: + limit: + format: int32 + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array templates: items: properties: diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 6592d72d85..d5714a1aef 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -10726,6 +10726,19 @@ spec: - metricName type: object type: array + measurementRetention: + items: + properties: + limit: + format: int32 + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array templates: items: properties: @@ -10770,6 +10783,19 @@ spec: - metricName type: object type: array + measurementRetention: + items: + properties: + limit: + format: int32 + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array templates: items: properties: @@ -10844,6 +10870,19 @@ spec: - metricName type: object type: array + measurementRetention: + items: + properties: + limit: + format: int32 + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array startingStep: format: int32 type: integer @@ -10951,6 +10990,19 @@ spec: - metricName type: object type: array + measurementRetention: + items: + properties: + limit: + format: int32 + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array templates: items: properties: diff --git a/pkg/apiclient/rollout/rollout.swagger.json b/pkg/apiclient/rollout/rollout.swagger.json index e6ae65bc49..3008334089 100644 --- a/pkg/apiclient/rollout/rollout.swagger.json +++ b/pkg/apiclient/rollout/rollout.swagger.json @@ -915,6 +915,21 @@ }, "title": "IstioVirtualService holds information on the virtual service the rollout needs to modify" }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MeasurementRetention": { + "type": "object", + "properties": { + "metricName": { + "type": "string", + "description": "MetricName is the name of the metric on which this retention policy should be applied." + }, + "limit": { + "type": "integer", + "format": "int32", + "description": "Limit is the maximum number of measurements to be retained for this given metric." + } + }, + "description": "MeasurementRetention defines the settings for retaining the number of measurements during the analysis." + }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.NginxTrafficRouting": { "type": "object", "properties": { @@ -1039,6 +1054,13 @@ "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.DryRun" }, "title": "DryRun object contains the settings for running the analysis in Dry-Run mode\n+patchMergeKey=metricName\n+patchStrategy=merge\n+optional" + }, + "measurementRetention": { + "type": "array", + "items": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MeasurementRetention" + }, + "title": "MeasurementRetention object contains the settings for retaining the number of measurements during the analysis\n+patchMergeKey=metricName\n+patchStrategy=merge\n+optional" } }, "title": "RolloutAnalysis defines a template that is used to create a analysisRun" diff --git a/pkg/apis/api-rules/violation_exceptions.list b/pkg/apis/api-rules/violation_exceptions.list index a4930858ab..6b08b1daf0 100644 --- a/pkg/apis/api-rules/violation_exceptions.list +++ b/pkg/apis/api-rules/violation_exceptions.list @@ -25,6 +25,7 @@ API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,MetricResult,Measurements API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutAnalysis,Args API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutAnalysis,DryRun +API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutAnalysis,MeasurementRetention API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutAnalysis,Templates API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutExperimentStep,Analyses API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutExperimentStep,Templates diff --git a/pkg/apis/rollouts/v1alpha1/generated.pb.go b/pkg/apis/rollouts/v1alpha1/generated.pb.go index 1a6ad9dc4e..86c45cf571 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.pb.go +++ b/pkg/apis/rollouts/v1alpha1/generated.pb.go @@ -2679,433 +2679,433 @@ var fileDescriptor_e0e705f843545fab = []byte{ // 6861 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x5d, 0x8c, 0x24, 0x57, 0x75, 0xb0, 0xab, 0x7f, 0x66, 0x7a, 0xce, 0xfc, 0xdf, 0x9d, 0x65, 0xc7, 0x6b, 0xef, 0xb6, 0x29, - 0x23, 0x7f, 0xe6, 0xfb, 0x60, 0x16, 0xd6, 0xf6, 0xf7, 0x19, 0x8c, 0xac, 0xaf, 0x7b, 0x66, 0xd7, - 0x3b, 0xeb, 0x99, 0xdd, 0xd9, 0xdb, 0xb3, 0x5e, 0x30, 0x98, 0x50, 0xd3, 0x7d, 0xa7, 0xa7, 0x76, - 0xab, 0xab, 0x9a, 0xaa, 0xea, 0xd9, 0x1d, 0x83, 0xc0, 0x0e, 0xb2, 0x43, 0x22, 0x10, 0x4e, 0x80, - 0x87, 0x28, 0x22, 0x42, 0x11, 0x0f, 0x51, 0xc8, 0x43, 0x84, 0x12, 0xe5, 0x05, 0x29, 0x51, 0x02, - 0x12, 0x79, 0x48, 0x44, 0xa4, 0x24, 0x40, 0x04, 0x1d, 0xdc, 0x24, 0x0f, 0x89, 0x22, 0x45, 0x91, - 0x88, 0x22, 0x56, 0x8a, 0x14, 0xdd, 0xdf, 0xba, 0x55, 0x5d, 0x3d, 0xdb, 0x3d, 0x5d, 0xb3, 0x58, - 0x49, 0xde, 0xba, 0xef, 0x39, 0xf7, 0x9c, 0xfb, 0x73, 0xee, 0xb9, 0xe7, 0xdc, 0x73, 0xee, 0x2d, - 0xd8, 0x68, 0xda, 0xe1, 0x5e, 0x67, 0x67, 0xa5, 0xee, 0xb5, 0xce, 0x59, 0x7e, 0xd3, 0x6b, 0xfb, - 0xde, 0x4d, 0xf6, 0xe3, 0xdd, 0xbe, 0xe7, 0x38, 0x5e, 0x27, 0x0c, 0xce, 0xb5, 0x6f, 0x35, 0xcf, - 0x59, 0x6d, 0x3b, 0x38, 0xa7, 0x4a, 0xf6, 0xdf, 0x6b, 0x39, 0xed, 0x3d, 0xeb, 0xbd, 0xe7, 0x9a, - 0xc4, 0x25, 0xbe, 0x15, 0x92, 0xc6, 0x4a, 0xdb, 0xf7, 0x42, 0x0f, 0x7d, 0x20, 0xa2, 0xb6, 0x22, - 0xa9, 0xb1, 0x1f, 0xbf, 0x20, 0xeb, 0xae, 0xb4, 0x6f, 0x35, 0x57, 0x28, 0xb5, 0x15, 0x55, 0x22, - 0xa9, 0x9d, 0x7e, 0xb7, 0xd6, 0x96, 0xa6, 0xd7, 0xf4, 0xce, 0x31, 0xa2, 0x3b, 0x9d, 0x5d, 0xf6, - 0x8f, 0xfd, 0x61, 0xbf, 0x38, 0xb3, 0xd3, 0x8f, 0xde, 0x7a, 0x3a, 0x58, 0xb1, 0x3d, 0xda, 0xb6, - 0x73, 0x3b, 0x56, 0x58, 0xdf, 0x3b, 0xb7, 0xdf, 0xd7, 0xa2, 0xd3, 0xa6, 0x86, 0x54, 0xf7, 0x7c, - 0x92, 0x86, 0xf3, 0x64, 0x84, 0xd3, 0xb2, 0xea, 0x7b, 0xb6, 0x4b, 0xfc, 0x83, 0xa8, 0xd7, 0x2d, - 0x12, 0x5a, 0x69, 0xb5, 0xce, 0x0d, 0xaa, 0xe5, 0x77, 0xdc, 0xd0, 0x6e, 0x91, 0xbe, 0x0a, 0xff, - 0xf7, 0x5e, 0x15, 0x82, 0xfa, 0x1e, 0x69, 0x59, 0x7d, 0xf5, 0x9e, 0x18, 0x54, 0xaf, 0x13, 0xda, - 0xce, 0x39, 0xdb, 0x0d, 0x83, 0xd0, 0x4f, 0x56, 0x32, 0xbf, 0x95, 0x87, 0xa9, 0xca, 0x46, 0xb5, - 0x16, 0x5a, 0x61, 0x27, 0x40, 0xaf, 0x1b, 0x30, 0xe3, 0x78, 0x56, 0xa3, 0x6a, 0x39, 0x96, 0x5b, - 0x27, 0xfe, 0xb2, 0xf1, 0x88, 0xf1, 0xf8, 0xf4, 0xf9, 0x8d, 0x95, 0x71, 0xe6, 0x6b, 0xa5, 0x72, - 0x3b, 0xc0, 0x24, 0xf0, 0x3a, 0x7e, 0x9d, 0x60, 0xb2, 0x5b, 0x5d, 0xfa, 0x4e, 0xb7, 0xfc, 0x40, - 0xaf, 0x5b, 0x9e, 0xd9, 0xd0, 0x38, 0xe1, 0x18, 0x5f, 0xf4, 0x65, 0x03, 0x16, 0xeb, 0x96, 0x6b, - 0xf9, 0x07, 0xdb, 0x96, 0xdf, 0x24, 0xe1, 0x73, 0xbe, 0xd7, 0x69, 0x2f, 0xe7, 0x8e, 0xa1, 0x35, - 0x0f, 0x8a, 0xd6, 0x2c, 0xae, 0x26, 0xd9, 0xe1, 0xfe, 0x16, 0xb0, 0x76, 0x05, 0xa1, 0xb5, 0xe3, - 0x10, 0xbd, 0x5d, 0xf9, 0xe3, 0x6c, 0x57, 0x2d, 0xc9, 0x0e, 0xf7, 0xb7, 0xc0, 0x7c, 0x2d, 0x0f, - 0x8b, 0x95, 0x8d, 0xea, 0xb6, 0x6f, 0xed, 0xee, 0xda, 0x75, 0xec, 0x75, 0x42, 0xdb, 0x6d, 0xa2, - 0x77, 0xc2, 0xa4, 0xed, 0x36, 0x7d, 0x12, 0x04, 0x6c, 0x22, 0xa7, 0xaa, 0xf3, 0x82, 0xe8, 0xe4, - 0x3a, 0x2f, 0xc6, 0x12, 0x8e, 0x9e, 0x82, 0xe9, 0x80, 0xf8, 0xfb, 0x76, 0x9d, 0x6c, 0x79, 0x7e, - 0xc8, 0x46, 0xba, 0x58, 0x3d, 0x21, 0xd0, 0xa7, 0x6b, 0x11, 0x08, 0xeb, 0x78, 0xb4, 0x9a, 0xef, - 0x79, 0xa1, 0x80, 0xb3, 0x81, 0x98, 0x8a, 0xaa, 0xe1, 0x08, 0x84, 0x75, 0x3c, 0xf4, 0x86, 0x01, - 0x0b, 0x41, 0x68, 0xd7, 0x6f, 0xd9, 0x2e, 0x09, 0x82, 0x55, 0xcf, 0xdd, 0xb5, 0x9b, 0xcb, 0x45, - 0x36, 0x8a, 0x57, 0xc6, 0x1b, 0xc5, 0x5a, 0x82, 0x6a, 0x75, 0xa9, 0xd7, 0x2d, 0x2f, 0x24, 0x4b, - 0x71, 0x1f, 0x77, 0xb4, 0x06, 0x0b, 0x96, 0xeb, 0x7a, 0xa1, 0x15, 0xda, 0x9e, 0xbb, 0xe5, 0x93, - 0x5d, 0xfb, 0xce, 0x72, 0x81, 0x75, 0x67, 0x59, 0x74, 0x67, 0xa1, 0x92, 0x80, 0xe3, 0xbe, 0x1a, - 0xe6, 0x1a, 0x2c, 0x57, 0x5a, 0x3b, 0x56, 0x10, 0x58, 0x0d, 0xcf, 0x4f, 0xcc, 0xc6, 0xe3, 0x50, - 0x6a, 0x59, 0xed, 0xb6, 0xed, 0x36, 0xe9, 0x74, 0xe4, 0x1f, 0x9f, 0xaa, 0xce, 0xf4, 0xba, 0xe5, - 0xd2, 0xa6, 0x28, 0xc3, 0x0a, 0x6a, 0xfe, 0x20, 0x07, 0xd3, 0x15, 0xd7, 0x72, 0x0e, 0x02, 0x3b, - 0xc0, 0x1d, 0x17, 0x7d, 0x0c, 0x4a, 0x54, 0xbb, 0x34, 0xac, 0xd0, 0x12, 0x2b, 0xf2, 0x3d, 0x2b, - 0x7c, 0xb1, 0xaf, 0xe8, 0x8b, 0x3d, 0x1a, 0x17, 0x8a, 0xbd, 0xb2, 0xff, 0xde, 0x95, 0xab, 0x3b, - 0x37, 0x49, 0x3d, 0xdc, 0x24, 0xa1, 0x55, 0x45, 0xa2, 0x17, 0x10, 0x95, 0x61, 0x45, 0x15, 0x79, - 0x50, 0x08, 0xda, 0xa4, 0x2e, 0x56, 0xd8, 0xe6, 0x98, 0x92, 0x1c, 0x35, 0xbd, 0xd6, 0x26, 0xf5, - 0xea, 0x8c, 0x60, 0x5d, 0xa0, 0xff, 0x30, 0x63, 0x84, 0x6e, 0xc3, 0x44, 0xc0, 0x74, 0x8e, 0x58, - 0x3c, 0x57, 0xb3, 0x63, 0xc9, 0xc8, 0x56, 0xe7, 0x04, 0xd3, 0x09, 0xfe, 0x1f, 0x0b, 0x76, 0xe6, - 0xdf, 0x1a, 0x70, 0x42, 0xc3, 0xae, 0xf8, 0xcd, 0x4e, 0x8b, 0xb8, 0x21, 0x7a, 0x04, 0x0a, 0xae, - 0xd5, 0x22, 0x62, 0xa1, 0xa8, 0x26, 0x5f, 0xb1, 0x5a, 0x04, 0x33, 0x08, 0x7a, 0x14, 0x8a, 0xfb, - 0x96, 0xd3, 0x21, 0x6c, 0x90, 0xa6, 0xaa, 0xb3, 0x02, 0xa5, 0xf8, 0x02, 0x2d, 0xc4, 0x1c, 0x86, - 0x3e, 0x09, 0x53, 0xec, 0xc7, 0x45, 0xdf, 0x6b, 0x65, 0xd4, 0x35, 0xd1, 0xc2, 0x17, 0x24, 0xd9, - 0xea, 0x6c, 0xaf, 0x5b, 0x9e, 0x52, 0x7f, 0x71, 0xc4, 0xd0, 0xfc, 0x3b, 0x03, 0xe6, 0xb5, 0xce, - 0x6d, 0xd8, 0x41, 0x88, 0x3e, 0xd2, 0x27, 0x3c, 0x2b, 0xc3, 0x09, 0x0f, 0xad, 0xcd, 0x44, 0x67, - 0x41, 0xf4, 0xb4, 0x24, 0x4b, 0x34, 0xc1, 0x71, 0xa1, 0x68, 0x87, 0xa4, 0x15, 0x2c, 0xe7, 0x1e, - 0xc9, 0x3f, 0x3e, 0x7d, 0x7e, 0x3d, 0xb3, 0x69, 0x8c, 0xc6, 0x77, 0x9d, 0xd2, 0xc7, 0x9c, 0x8d, - 0xf9, 0x8d, 0x42, 0xac, 0x87, 0x54, 0xa2, 0x90, 0x07, 0x93, 0x2d, 0x12, 0xfa, 0x76, 0x9d, 0xaf, - 0xab, 0xe9, 0xf3, 0x6b, 0xe3, 0xb5, 0x62, 0x93, 0x11, 0x8b, 0x94, 0x25, 0xff, 0x1f, 0x60, 0xc9, - 0x05, 0xed, 0x41, 0xc1, 0xf2, 0x9b, 0xb2, 0xcf, 0x17, 0xb3, 0x99, 0xdf, 0x48, 0xe6, 0x2a, 0x7e, - 0x33, 0xc0, 0x8c, 0x03, 0x3a, 0x07, 0x53, 0x21, 0xf1, 0x5b, 0xb6, 0x6b, 0x85, 0x5c, 0xbb, 0x96, - 0xaa, 0x8b, 0x02, 0x6d, 0x6a, 0x5b, 0x02, 0x70, 0x84, 0x83, 0x1c, 0x98, 0x68, 0xf8, 0x07, 0xb8, - 0xe3, 0x2e, 0x17, 0xb2, 0x18, 0x8a, 0x35, 0x46, 0x2b, 0x5a, 0x4c, 0xfc, 0x3f, 0x16, 0x3c, 0xd0, - 0xd7, 0x0c, 0x58, 0x6a, 0x11, 0x2b, 0xe8, 0xf8, 0x84, 0x76, 0x01, 0x93, 0x90, 0xb8, 0x54, 0x1b, - 0x2e, 0x17, 0x19, 0x73, 0x3c, 0xee, 0x3c, 0xf4, 0x53, 0xae, 0x3e, 0x2c, 0x9a, 0xb2, 0x94, 0x06, - 0xc5, 0xa9, 0xad, 0x31, 0x7f, 0x50, 0x80, 0xc5, 0x3e, 0x0d, 0x81, 0x9e, 0x84, 0x62, 0x7b, 0xcf, - 0x0a, 0xe4, 0x92, 0x3f, 0x2b, 0xe5, 0x6d, 0x8b, 0x16, 0xde, 0xed, 0x96, 0x67, 0x65, 0x15, 0x56, - 0x80, 0x39, 0x32, 0xdd, 0x53, 0x5b, 0x24, 0x08, 0xac, 0xa6, 0xd4, 0x03, 0x9a, 0x98, 0xb0, 0x62, - 0x2c, 0xe1, 0xe8, 0x97, 0x0c, 0x98, 0xe5, 0x22, 0x83, 0x49, 0xd0, 0x71, 0x42, 0xaa, 0xeb, 0xe8, - 0xb0, 0x5c, 0xce, 0x42, 0x3c, 0x39, 0xc9, 0xea, 0x49, 0xc1, 0x7d, 0x56, 0x2f, 0x0d, 0x70, 0x9c, - 0x2f, 0xba, 0x01, 0x53, 0x41, 0x68, 0xf9, 0x21, 0x69, 0x54, 0x42, 0xb6, 0xab, 0x4d, 0x9f, 0xff, - 0xdf, 0xc3, 0x29, 0x81, 0x6d, 0xbb, 0x45, 0xb8, 0xc2, 0xa9, 0x49, 0x02, 0x38, 0xa2, 0x85, 0x3e, - 0x09, 0xe0, 0x77, 0xdc, 0x5a, 0xa7, 0xd5, 0xb2, 0xfc, 0x03, 0xb1, 0x83, 0x5f, 0x1a, 0xaf, 0x7b, - 0x58, 0xd1, 0x8b, 0xf6, 0xac, 0xa8, 0x0c, 0x6b, 0xfc, 0xd0, 0xab, 0x06, 0xcc, 0x72, 0x49, 0x94, - 0x2d, 0x98, 0xc8, 0xb8, 0x05, 0x8b, 0x74, 0x68, 0xd7, 0x74, 0x16, 0x38, 0xce, 0xd1, 0xfc, 0xeb, - 0xf8, 0x7e, 0x52, 0x0b, 0xa9, 0x75, 0xdd, 0x3c, 0x40, 0x1f, 0x86, 0x07, 0x83, 0x4e, 0xbd, 0x4e, - 0x82, 0x60, 0xb7, 0xe3, 0xe0, 0x8e, 0x7b, 0xc9, 0x0e, 0x42, 0xcf, 0x3f, 0xd8, 0xb0, 0x5b, 0x76, - 0xc8, 0x24, 0xae, 0x58, 0x3d, 0xd3, 0xeb, 0x96, 0x1f, 0xac, 0x0d, 0x42, 0xc2, 0x83, 0xeb, 0x23, - 0x0b, 0x1e, 0xea, 0xb8, 0x83, 0xc9, 0x73, 0xeb, 0xad, 0xdc, 0xeb, 0x96, 0x1f, 0xba, 0x3e, 0x18, - 0x0d, 0x1f, 0x46, 0xc3, 0xfc, 0x27, 0x03, 0x16, 0x64, 0xbf, 0xb6, 0x49, 0xab, 0xed, 0x50, 0xed, - 0x72, 0xfc, 0x86, 0x48, 0x18, 0x33, 0x44, 0x70, 0x36, 0xdb, 0x89, 0x6c, 0xff, 0x20, 0x6b, 0xc4, - 0xfc, 0x47, 0x03, 0x96, 0x92, 0xc8, 0xf7, 0x61, 0xf3, 0x0c, 0xe2, 0x9b, 0xe7, 0x95, 0x6c, 0x7b, - 0x3b, 0x60, 0x07, 0x7d, 0xbd, 0xd0, 0xdf, 0xd7, 0xff, 0xea, 0xdb, 0x68, 0xb4, 0x2b, 0xe6, 0x7f, - 0x9e, 0xbb, 0x62, 0xe1, 0x2d, 0xb5, 0x2b, 0xfe, 0x76, 0x01, 0x66, 0x2a, 0x6e, 0x68, 0x57, 0x76, - 0x77, 0x6d, 0xd7, 0x0e, 0x0f, 0xd0, 0xe7, 0x72, 0x70, 0xae, 0xed, 0x93, 0x5d, 0xe2, 0xfb, 0xa4, - 0xb1, 0xd6, 0xf1, 0x6d, 0xb7, 0x59, 0xab, 0xef, 0x91, 0x46, 0xc7, 0xb1, 0xdd, 0xe6, 0x7a, 0xd3, - 0xf5, 0x54, 0xf1, 0x85, 0x3b, 0xa4, 0xde, 0x61, 0x5d, 0xe2, 0x8b, 0xa2, 0x35, 0x5e, 0x97, 0xb6, - 0x46, 0x63, 0x5a, 0x7d, 0xa2, 0xd7, 0x2d, 0x9f, 0x1b, 0xb1, 0x12, 0x1e, 0xb5, 0x6b, 0xe8, 0xb3, - 0x39, 0x58, 0xf1, 0xc9, 0xc7, 0x3b, 0xf6, 0xf0, 0xa3, 0xc1, 0xb5, 0x96, 0x33, 0xe6, 0xf6, 0x33, - 0x12, 0xcf, 0xea, 0xf9, 0x5e, 0xb7, 0x3c, 0x62, 0x1d, 0x3c, 0x62, 0xbf, 0xcc, 0x3f, 0x35, 0xa0, - 0x34, 0x82, 0xa7, 0x54, 0x8e, 0x7b, 0x4a, 0x53, 0x7d, 0x5e, 0x52, 0xd8, 0xef, 0x25, 0x3d, 0x37, - 0xde, 0xa0, 0x0d, 0xe3, 0x1d, 0xfd, 0x8b, 0x01, 0x8b, 0x7d, 0xde, 0x14, 0xda, 0x83, 0xa5, 0xb6, - 0xd7, 0x90, 0x9a, 0xf0, 0x92, 0x15, 0xec, 0x31, 0x98, 0xe8, 0xde, 0x93, 0x74, 0x51, 0x6d, 0xa5, - 0xc0, 0xef, 0x76, 0xcb, 0xcb, 0x8a, 0x48, 0x02, 0x01, 0xa7, 0x52, 0x44, 0x6d, 0x28, 0xed, 0xda, - 0xc4, 0x69, 0x60, 0xb2, 0x2b, 0x24, 0x65, 0x4c, 0x9d, 0x77, 0x51, 0x50, 0xe3, 0x07, 0x09, 0xf2, - 0x1f, 0x56, 0x5c, 0xcc, 0x6b, 0x30, 0x17, 0x3f, 0x56, 0x1a, 0x62, 0xf2, 0xce, 0x40, 0xde, 0xf2, - 0x5d, 0x31, 0x75, 0xd3, 0x02, 0x21, 0x5f, 0xc1, 0x57, 0x30, 0x2d, 0x37, 0x7f, 0x56, 0x80, 0xf9, - 0xaa, 0xd3, 0x21, 0xcf, 0xf9, 0x84, 0x48, 0x4b, 0xba, 0x02, 0xf3, 0x6d, 0x9f, 0xec, 0xdb, 0xe4, - 0x76, 0x8d, 0x38, 0xa4, 0x1e, 0x7a, 0xbe, 0xa0, 0x7f, 0x4a, 0x54, 0x9f, 0xdf, 0x8a, 0x83, 0x71, - 0x12, 0x1f, 0x3d, 0x0b, 0x73, 0x56, 0x3d, 0xb4, 0xf7, 0x89, 0xa2, 0xc0, 0x1b, 0xf0, 0x36, 0x41, - 0x61, 0xae, 0x12, 0x83, 0xe2, 0x04, 0x36, 0xfa, 0x08, 0x2c, 0x07, 0x75, 0xcb, 0x21, 0xd7, 0xdb, - 0x82, 0xd5, 0xea, 0x1e, 0xa9, 0xdf, 0xda, 0xf2, 0x6c, 0x37, 0x14, 0x7e, 0xd3, 0x23, 0x82, 0xd2, - 0x72, 0x6d, 0x00, 0x1e, 0x1e, 0x48, 0x01, 0xfd, 0x91, 0x01, 0x67, 0xda, 0x3e, 0xd9, 0xf2, 0xbd, - 0x96, 0x47, 0x17, 0x44, 0x9f, 0x33, 0x21, 0x8c, 0xea, 0x17, 0xc6, 0x5c, 0xf9, 0xbc, 0xa4, 0xff, - 0x30, 0xe3, 0xed, 0xbd, 0x6e, 0xf9, 0xcc, 0xd6, 0x61, 0x0d, 0xc0, 0x87, 0xb7, 0x0f, 0xfd, 0x89, - 0x01, 0x67, 0xdb, 0x5e, 0x10, 0x1e, 0xd2, 0x85, 0xe2, 0xb1, 0x76, 0xc1, 0xec, 0x75, 0xcb, 0x67, - 0xb7, 0x0e, 0x6d, 0x01, 0xbe, 0x47, 0x0b, 0xcd, 0xde, 0x34, 0x2c, 0x6a, 0xb2, 0x27, 0x2c, 0xed, - 0x67, 0x60, 0x56, 0x0a, 0x03, 0x3f, 0x85, 0xe4, 0xb2, 0xa7, 0x3c, 0xa3, 0x8a, 0x0e, 0xc4, 0x71, - 0x5c, 0x2a, 0x77, 0x4a, 0x14, 0x79, 0xed, 0x84, 0xdc, 0x6d, 0xc5, 0xa0, 0x38, 0x81, 0x8d, 0xd6, - 0xe1, 0x84, 0x28, 0xc1, 0xa4, 0xed, 0xd8, 0x75, 0x6b, 0xd5, 0xeb, 0x08, 0x91, 0x2b, 0x56, 0x4f, - 0xf5, 0xba, 0xe5, 0x13, 0x5b, 0xfd, 0x60, 0x9c, 0x56, 0x07, 0x6d, 0xc0, 0x92, 0xd5, 0x09, 0x3d, - 0xd5, 0xff, 0x0b, 0xae, 0xb5, 0xe3, 0x90, 0x06, 0x13, 0xad, 0x52, 0x75, 0x99, 0x2a, 0xa2, 0x4a, - 0x0a, 0x1c, 0xa7, 0xd6, 0x42, 0x5b, 0x09, 0x6a, 0x35, 0x52, 0xf7, 0xdc, 0x06, 0x9f, 0xe5, 0x62, - 0x64, 0x2f, 0x54, 0x52, 0x70, 0x70, 0x6a, 0x4d, 0xe4, 0xc0, 0x5c, 0xcb, 0xba, 0x73, 0xdd, 0xb5, - 0xf6, 0x2d, 0xdb, 0xa1, 0x4c, 0x84, 0xb7, 0x35, 0xd8, 0x05, 0xe8, 0x84, 0xb6, 0xb3, 0xc2, 0x03, - 0x0f, 0x2b, 0xeb, 0x6e, 0x78, 0xd5, 0xaf, 0x85, 0x74, 0x5f, 0xa9, 0x22, 0x3a, 0xb0, 0x9b, 0x31, - 0x5a, 0x38, 0x41, 0x1b, 0x5d, 0x85, 0x93, 0x6c, 0x39, 0xae, 0x79, 0xb7, 0xdd, 0x35, 0xe2, 0x58, - 0x07, 0xb2, 0x03, 0x93, 0xac, 0x03, 0x0f, 0xf6, 0xba, 0xe5, 0x93, 0xb5, 0x34, 0x04, 0x9c, 0x5e, - 0x8f, 0xfa, 0x4c, 0x71, 0x00, 0x26, 0xfb, 0x76, 0x60, 0x7b, 0x2e, 0xf7, 0x99, 0x4a, 0x91, 0xcf, - 0x54, 0x1b, 0x8c, 0x86, 0x0f, 0xa3, 0x81, 0x7e, 0xc3, 0x80, 0xa5, 0xb4, 0x65, 0xb8, 0x3c, 0x95, - 0xc5, 0xb1, 0x6a, 0x62, 0x69, 0x71, 0x89, 0x48, 0x55, 0x0a, 0xa9, 0x8d, 0x40, 0xaf, 0x18, 0x30, - 0x63, 0x69, 0xf6, 0xde, 0x32, 0xb0, 0x56, 0x5d, 0x1e, 0xd7, 0xeb, 0x88, 0x28, 0x56, 0x17, 0x7a, - 0xdd, 0x72, 0xcc, 0xa6, 0xc4, 0x31, 0x8e, 0xe8, 0x37, 0x0d, 0x38, 0x99, 0xba, 0xc6, 0x97, 0xa7, - 0x8f, 0x63, 0x84, 0x98, 0x90, 0xa4, 0xeb, 0x9c, 0xf4, 0x66, 0xa0, 0x37, 0x0c, 0xb5, 0x95, 0x6d, - 0x4a, 0xbf, 0x6f, 0x86, 0x35, 0xed, 0xda, 0x98, 0x26, 0x6e, 0x64, 0x10, 0x48, 0xc2, 0xd5, 0x13, - 0xda, 0xce, 0x28, 0x0b, 0x71, 0x92, 0x3d, 0xfa, 0xbc, 0x21, 0xb7, 0x46, 0xd5, 0xa2, 0xd9, 0xe3, - 0x6a, 0x11, 0x8a, 0x76, 0x5a, 0xd5, 0xa0, 0x04, 0x73, 0xf4, 0x51, 0x38, 0x6d, 0xed, 0x78, 0x7e, - 0x98, 0xba, 0xf8, 0x96, 0xe7, 0xd8, 0x32, 0x3a, 0xdb, 0xeb, 0x96, 0x4f, 0x57, 0x06, 0x62, 0xe1, - 0x43, 0x28, 0x98, 0x3f, 0x2c, 0xc0, 0x0c, 0x8f, 0xc5, 0x89, 0xad, 0xeb, 0x9b, 0x06, 0x3c, 0x5c, - 0xef, 0xf8, 0x3e, 0x71, 0xc3, 0x5a, 0x48, 0xda, 0xfd, 0x1b, 0x97, 0x71, 0xac, 0x1b, 0xd7, 0x23, - 0xbd, 0x6e, 0xf9, 0xe1, 0xd5, 0x43, 0xf8, 0xe3, 0x43, 0x5b, 0x87, 0xfe, 0xc2, 0x00, 0x53, 0x20, - 0x54, 0xad, 0xfa, 0xad, 0xa6, 0xef, 0x75, 0xdc, 0x46, 0x7f, 0x27, 0x72, 0xc7, 0xda, 0x89, 0xc7, - 0x7a, 0xdd, 0xb2, 0xb9, 0x7a, 0xcf, 0x56, 0xe0, 0x21, 0x5a, 0x8a, 0x9e, 0x83, 0x45, 0x81, 0x75, - 0xe1, 0x4e, 0x9b, 0xf8, 0x36, 0x35, 0xa7, 0x45, 0xe4, 0x2f, 0x0a, 0xa6, 0x26, 0x11, 0x70, 0x7f, - 0x1d, 0x14, 0xc0, 0xe4, 0x6d, 0x62, 0x37, 0xf7, 0x42, 0x69, 0x3e, 0x8d, 0x19, 0x41, 0x15, 0xf1, - 0xb6, 0x1b, 0x9c, 0x66, 0x75, 0xba, 0xd7, 0x2d, 0x4f, 0x8a, 0x3f, 0x58, 0x72, 0x32, 0x7f, 0xaf, - 0x00, 0x20, 0xc5, 0x8b, 0xb4, 0xd1, 0xff, 0x81, 0xa9, 0x80, 0x84, 0x1c, 0x4b, 0x1c, 0xcb, 0xf1, - 0xd3, 0x4e, 0x59, 0x88, 0x23, 0x38, 0xba, 0x05, 0xc5, 0xb6, 0xd5, 0x09, 0x88, 0x98, 0xac, 0xcb, - 0x99, 0x4c, 0xd6, 0x16, 0xa5, 0xc8, 0x7d, 0x24, 0xf6, 0x13, 0x73, 0x1e, 0xe8, 0x33, 0x06, 0x00, - 0x89, 0x0f, 0xf0, 0xf4, 0xf9, 0x5a, 0x26, 0x2c, 0xa3, 0x39, 0xa0, 0x63, 0x50, 0x9d, 0xeb, 0x75, - 0xcb, 0xa0, 0x4d, 0x95, 0xc6, 0x16, 0xdd, 0x86, 0x92, 0x25, 0x75, 0x74, 0xe1, 0x38, 0x74, 0x34, - 0x73, 0x5d, 0x94, 0x90, 0x29, 0x66, 0xe8, 0xb3, 0x06, 0xcc, 0x05, 0x24, 0x14, 0x53, 0x45, 0x35, - 0x85, 0x30, 0x50, 0xc7, 0x14, 0x92, 0x5a, 0x8c, 0x26, 0xd7, 0x78, 0xf1, 0x32, 0x9c, 0xe0, 0x6b, - 0xfe, 0x70, 0x1a, 0xe6, 0xa4, 0xc8, 0x44, 0x36, 0x27, 0x4f, 0x0e, 0x18, 0x60, 0x73, 0xae, 0xea, - 0x40, 0x1c, 0xc7, 0xa5, 0x95, 0x79, 0x04, 0x3f, 0x6e, 0x72, 0xaa, 0xca, 0x35, 0x1d, 0x88, 0xe3, - 0xb8, 0xa8, 0x05, 0xc5, 0x20, 0x24, 0x6d, 0x19, 0x4b, 0x18, 0xf3, 0xa8, 0x3b, 0x5a, 0x09, 0xd1, - 0x69, 0x21, 0xfd, 0x17, 0x60, 0xce, 0x05, 0x7d, 0xc1, 0x80, 0xb9, 0x30, 0x16, 0xc7, 0x16, 0x62, - 0x90, 0x8d, 0x24, 0xc6, 0x43, 0xe4, 0x7c, 0x36, 0xe2, 0x65, 0x38, 0xc1, 0x3e, 0xc5, 0x0c, 0x2d, - 0x1e, 0xa3, 0x19, 0xfa, 0x22, 0x94, 0x5a, 0xd6, 0x9d, 0x5a, 0xc7, 0x6f, 0x1e, 0xdd, 0xdc, 0x15, - 0x61, 0x7e, 0x4e, 0x05, 0x2b, 0x7a, 0xe8, 0x55, 0x43, 0x5b, 0x5c, 0x93, 0x8c, 0xf8, 0x8d, 0x6c, - 0x17, 0x97, 0xd2, 0xe2, 0x03, 0x97, 0x59, 0x9f, 0x51, 0x58, 0xba, 0xef, 0x46, 0x21, 0x35, 0x70, - 0xf8, 0x02, 0x51, 0x06, 0xce, 0xd4, 0xb1, 0x1a, 0x38, 0xab, 0x31, 0x66, 0x38, 0xc1, 0x9c, 0xb5, - 0x87, 0xaf, 0x39, 0xd5, 0x1e, 0x38, 0xd6, 0xf6, 0xd4, 0x62, 0xcc, 0x70, 0x82, 0xf9, 0x60, 0x4f, - 0x68, 0xfa, 0x78, 0x3c, 0xa1, 0x99, 0x0c, 0x3c, 0xa1, 0xc3, 0x8d, 0xc4, 0xd9, 0x71, 0x8d, 0x44, - 0x74, 0x19, 0x50, 0xe3, 0xc0, 0xb5, 0x5a, 0x76, 0x5d, 0x28, 0x4b, 0xb6, 0x41, 0xcc, 0x31, 0x4f, - 0xf9, 0xb4, 0x50, 0x64, 0x68, 0xad, 0x0f, 0x03, 0xa7, 0xd4, 0x32, 0xff, 0xcd, 0x80, 0x85, 0x55, - 0xc7, 0xeb, 0x34, 0x6e, 0x58, 0x61, 0x7d, 0x8f, 0x47, 0x29, 0xd0, 0xb3, 0x50, 0xb2, 0xdd, 0x90, - 0xf8, 0xfb, 0x96, 0x23, 0x74, 0xbb, 0x29, 0x03, 0x39, 0xeb, 0xa2, 0xfc, 0x6e, 0xb7, 0x3c, 0xb7, - 0xd6, 0xf1, 0x59, 0xfa, 0x0f, 0x5f, 0xe9, 0x58, 0xd5, 0x41, 0x5f, 0x35, 0x60, 0x91, 0xc7, 0x39, - 0xd6, 0xac, 0xd0, 0xba, 0xd6, 0x21, 0xbe, 0x4d, 0x64, 0xa4, 0x63, 0xcc, 0x45, 0x9e, 0x6c, 0xab, - 0x64, 0x70, 0x10, 0x99, 0x5f, 0x9b, 0x49, 0xce, 0xb8, 0xbf, 0x31, 0xe6, 0x17, 0xf3, 0xf0, 0xe0, - 0x40, 0x5a, 0xe8, 0x34, 0xe4, 0xec, 0x86, 0xe8, 0x3a, 0x08, 0xba, 0xb9, 0xf5, 0x06, 0xce, 0xd9, - 0x0d, 0xb4, 0xc2, 0x2c, 0x13, 0x9f, 0x04, 0x81, 0x3c, 0xf4, 0x9e, 0x52, 0x46, 0x84, 0x28, 0xc5, - 0x1a, 0x06, 0x2a, 0x43, 0xd1, 0xb1, 0x76, 0x88, 0x23, 0xac, 0x44, 0x66, 0xeb, 0x6c, 0xd0, 0x02, - 0xcc, 0xcb, 0xd1, 0x2f, 0x1a, 0x00, 0xbc, 0x81, 0xd4, 0xc6, 0x14, 0x3b, 0x0c, 0xce, 0x76, 0x98, - 0x28, 0x65, 0xde, 0xca, 0xe8, 0x3f, 0xd6, 0xb8, 0xa2, 0x6d, 0x98, 0xa0, 0x66, 0x8f, 0xd7, 0x38, - 0xf2, 0x86, 0x02, 0xbd, 0x6e, 0x79, 0x62, 0x8b, 0xd1, 0xc0, 0x82, 0x16, 0x1d, 0x2b, 0x9f, 0x84, - 0x1d, 0xdf, 0xa5, 0x43, 0xcb, 0xb6, 0x90, 0x12, 0x6f, 0x05, 0x56, 0xa5, 0x58, 0xc3, 0x30, 0xff, - 0x30, 0x07, 0x4b, 0x69, 0x4d, 0xa7, 0x9a, 0x7a, 0x82, 0xb7, 0x56, 0x38, 0x3c, 0x1f, 0xcc, 0x7e, - 0x7c, 0x44, 0xc8, 0x4e, 0x05, 0xb6, 0x44, 0x52, 0x81, 0xe0, 0x8b, 0x3e, 0xa8, 0x46, 0x28, 0x77, - 0xc4, 0x11, 0x52, 0x94, 0x13, 0xa3, 0xf4, 0x08, 0x14, 0x02, 0x3a, 0xf3, 0xf9, 0xf8, 0xb1, 0x34, - 0x9b, 0x23, 0x06, 0xa1, 0x18, 0x1d, 0xd7, 0x0e, 0x45, 0x4e, 0x9e, 0xc2, 0xb8, 0xee, 0xda, 0x21, - 0x66, 0x10, 0xf3, 0xcb, 0x39, 0x38, 0x3d, 0xb8, 0x53, 0xe8, 0xcb, 0x06, 0x40, 0x83, 0x1a, 0xb5, - 0x54, 0x24, 0x65, 0x88, 0xd3, 0x3a, 0xae, 0x31, 0x5c, 0x93, 0x9c, 0xa2, 0x78, 0xb7, 0x2a, 0x0a, - 0xb0, 0xd6, 0x10, 0x74, 0x5e, 0x8a, 0xfe, 0x15, 0xab, 0x25, 0x4d, 0x41, 0x55, 0x67, 0x53, 0x41, - 0xb0, 0x86, 0x45, 0xbd, 0x16, 0xd7, 0x6a, 0x91, 0xa0, 0x6d, 0xa9, 0xa4, 0x4b, 0xe6, 0xb5, 0x5c, - 0x91, 0x85, 0x38, 0x82, 0x9b, 0x0e, 0x3c, 0x3a, 0x44, 0x3b, 0x33, 0x4a, 0x80, 0x33, 0xff, 0xd5, - 0x80, 0x53, 0xab, 0x4e, 0x27, 0x08, 0x89, 0xff, 0xdf, 0x26, 0x7d, 0xe0, 0xdf, 0x0d, 0x78, 0x68, - 0x40, 0x9f, 0xef, 0x43, 0x16, 0xc1, 0xcb, 0xf1, 0x2c, 0x82, 0xeb, 0xe3, 0x8a, 0x74, 0x6a, 0x3f, - 0x06, 0x24, 0x13, 0x84, 0x30, 0x4b, 0xb5, 0x56, 0xc3, 0x6b, 0x66, 0xb4, 0x6f, 0x3e, 0x0a, 0xc5, - 0x8f, 0xd3, 0xfd, 0x27, 0x29, 0x63, 0x6c, 0x53, 0xc2, 0x1c, 0x66, 0x7e, 0x00, 0x44, 0xc8, 0x3d, - 0xb1, 0x78, 0x8c, 0x61, 0x16, 0x8f, 0xf9, 0x37, 0x39, 0xd0, 0xbc, 0xdd, 0xfb, 0x20, 0x94, 0x6e, - 0x4c, 0x28, 0xc7, 0xf4, 0x5f, 0x35, 0xdf, 0x7d, 0x50, 0x6e, 0xed, 0x7e, 0x22, 0xb7, 0xf6, 0x4a, - 0x66, 0x1c, 0x0f, 0x4f, 0xad, 0xfd, 0x9e, 0x01, 0x0f, 0x45, 0xc8, 0xfd, 0x07, 0x47, 0xf7, 0xd6, - 0x30, 0x4f, 0xc1, 0xb4, 0x15, 0x55, 0x13, 0x32, 0xa0, 0xd2, 0xc9, 0x35, 0x8a, 0x58, 0xc7, 0x8b, - 0x32, 0xf9, 0xf2, 0x47, 0xcc, 0xe4, 0x2b, 0x1c, 0x9e, 0xc9, 0x67, 0xfe, 0x34, 0x07, 0x67, 0xfa, - 0x7b, 0x26, 0xd7, 0xc6, 0x70, 0x71, 0xd5, 0xa7, 0x61, 0x26, 0x14, 0x15, 0x34, 0x4d, 0xaf, 0x2e, - 0x43, 0x6c, 0x6b, 0x30, 0x1c, 0xc3, 0xa4, 0x35, 0xeb, 0x7c, 0x55, 0xd6, 0xea, 0x5e, 0x5b, 0xe6, - 0x81, 0xaa, 0x9a, 0xab, 0x1a, 0x0c, 0xc7, 0x30, 0x55, 0x86, 0x4d, 0xe1, 0xd8, 0x33, 0x6c, 0x6a, - 0x70, 0x52, 0xe6, 0x14, 0x5c, 0xf4, 0xfc, 0x55, 0xaf, 0xd5, 0x76, 0x88, 0xc8, 0x04, 0xa5, 0x8d, - 0x3d, 0x23, 0xaa, 0x9c, 0xc4, 0x69, 0x48, 0x38, 0xbd, 0xae, 0xf9, 0xbd, 0x3c, 0x9c, 0x88, 0x86, - 0x7d, 0xd5, 0x73, 0x1b, 0x36, 0xcb, 0xcc, 0x78, 0x06, 0x0a, 0xe1, 0x41, 0x5b, 0x0e, 0xf6, 0xff, - 0x92, 0xcd, 0xd9, 0x3e, 0x68, 0xd3, 0xd9, 0x3e, 0x95, 0x52, 0x85, 0x82, 0x30, 0xab, 0x84, 0x36, - 0xd4, 0xea, 0xe0, 0x33, 0xf0, 0x64, 0x5c, 0x9a, 0xef, 0x76, 0xcb, 0x29, 0x77, 0x81, 0x56, 0x14, - 0xa5, 0xb8, 0xcc, 0xa3, 0x9b, 0x30, 0xe7, 0x58, 0x41, 0x78, 0xbd, 0xdd, 0xb0, 0x42, 0xb2, 0x6d, - 0xb7, 0x88, 0x58, 0x73, 0xa3, 0xa4, 0x57, 0xaa, 0x58, 0xe3, 0x46, 0x8c, 0x12, 0x4e, 0x50, 0x46, - 0xfb, 0x80, 0x68, 0xc9, 0xb6, 0x6f, 0xb9, 0x01, 0xef, 0x15, 0xe5, 0x37, 0x7a, 0x3a, 0xa7, 0x72, - 0x90, 0x36, 0xfa, 0xa8, 0xe1, 0x14, 0x0e, 0xe8, 0x31, 0x98, 0xf0, 0x89, 0x15, 0x88, 0xc9, 0x9c, - 0x8a, 0xd6, 0x3f, 0x66, 0xa5, 0x58, 0x40, 0xf5, 0x05, 0x35, 0x71, 0x8f, 0x05, 0xf5, 0x23, 0x03, - 0xe6, 0xa2, 0x69, 0xba, 0x0f, 0x9b, 0x64, 0x2b, 0xbe, 0x49, 0x5e, 0xca, 0x4a, 0x25, 0x0e, 0xd8, - 0x17, 0xbf, 0x5a, 0xd4, 0xfb, 0xc7, 0xd2, 0xeb, 0x3e, 0x01, 0x53, 0x72, 0x55, 0x4b, 0xeb, 0x73, - 0xcc, 0x53, 0x96, 0x98, 0x5d, 0xa2, 0xa5, 0x85, 0x0b, 0x26, 0x38, 0xe2, 0x47, 0xb7, 0xe5, 0x86, - 0xd8, 0x72, 0x85, 0xd8, 0xab, 0x6d, 0x59, 0x6e, 0xc5, 0x69, 0xdb, 0xb2, 0xac, 0x83, 0xae, 0xc3, - 0xa9, 0xb6, 0xef, 0xb1, 0xab, 0x42, 0x6b, 0xc4, 0x6a, 0x38, 0xb6, 0x4b, 0xa4, 0x33, 0xcf, 0x43, - 0xdd, 0x0f, 0xf5, 0xba, 0xe5, 0x53, 0x5b, 0xe9, 0x28, 0x78, 0x50, 0xdd, 0x78, 0x7a, 0x7b, 0x61, - 0x88, 0xf4, 0xf6, 0x5f, 0x56, 0x47, 0x66, 0x24, 0x10, 0x49, 0xe6, 0x1f, 0xce, 0x6a, 0x2a, 0x53, - 0xd4, 0x7a, 0x24, 0x52, 0x15, 0xc1, 0x14, 0x2b, 0xf6, 0x83, 0xcf, 0x65, 0x26, 0x8e, 0x78, 0x2e, - 0x13, 0x65, 0x29, 0x4e, 0x1e, 0x7f, 0x96, 0xa2, 0xf9, 0x5a, 0x11, 0x16, 0x92, 0x5b, 0xfb, 0xf1, - 0xe7, 0xc4, 0xff, 0x9a, 0x01, 0x0b, 0x52, 0x2c, 0x39, 0x4f, 0x22, 0x8f, 0xb2, 0x37, 0x32, 0x5a, - 0x0d, 0xdc, 0x48, 0x51, 0xb7, 0xb6, 0xb6, 0x13, 0xdc, 0x70, 0x1f, 0x7f, 0xf4, 0x12, 0x4c, 0xab, - 0x13, 0xdf, 0x23, 0x25, 0xc8, 0xcf, 0x33, 0xf3, 0x24, 0x22, 0x81, 0x75, 0x7a, 0xe8, 0x35, 0x03, - 0xa0, 0x2e, 0xf7, 0x0f, 0x29, 0xb6, 0xd7, 0xb2, 0x12, 0x5b, 0xb5, 0x33, 0x45, 0x56, 0xa8, 0x2a, - 0x0a, 0xb0, 0xc6, 0x18, 0x7d, 0x91, 0x9d, 0xf5, 0x2a, 0xb3, 0x89, 0x0a, 0x2a, 0x6d, 0xc9, 0x87, - 0xb2, 0x5e, 0x40, 0x51, 0xd8, 0x51, 0xd9, 0x28, 0x1a, 0x28, 0xc0, 0xb1, 0x46, 0x98, 0xcf, 0x80, - 0xca, 0x5c, 0xa3, 0xfa, 0x80, 0xe5, 0xae, 0x6d, 0x59, 0xe1, 0x9e, 0x10, 0x41, 0xa5, 0x0f, 0x2e, - 0x4a, 0x00, 0x8e, 0x70, 0xcc, 0x8f, 0xc1, 0xdc, 0x73, 0xbe, 0xd5, 0xde, 0xb3, 0xd9, 0x99, 0x2a, - 0x75, 0x40, 0xde, 0x09, 0x93, 0x56, 0xa3, 0x91, 0x76, 0xe7, 0xb1, 0xc2, 0x8b, 0xb1, 0x84, 0x0f, - 0xe7, 0x6b, 0x7c, 0xcb, 0x80, 0xa5, 0xf5, 0x20, 0xb4, 0xbd, 0x35, 0x12, 0x84, 0x54, 0x09, 0x51, - 0x7b, 0xa5, 0xe3, 0x90, 0x21, 0x2c, 0xbe, 0x35, 0x58, 0x10, 0x81, 0x9f, 0xce, 0x4e, 0x40, 0x42, - 0xcd, 0xea, 0x53, 0xc2, 0xb9, 0x9a, 0x80, 0xe3, 0xbe, 0x1a, 0x94, 0x8a, 0x88, 0x00, 0x45, 0x54, - 0xf2, 0x71, 0x2a, 0xb5, 0x04, 0x1c, 0xf7, 0xd5, 0x30, 0xbf, 0x9b, 0x87, 0x13, 0xac, 0x1b, 0x89, - 0x4b, 0x89, 0x9f, 0x37, 0x60, 0x6e, 0xdf, 0xf6, 0xc3, 0x8e, 0xe5, 0xe8, 0xa1, 0xac, 0xb1, 0xe5, - 0x93, 0xf1, 0x7a, 0x21, 0x46, 0x98, 0x1f, 0x76, 0xc7, 0xcb, 0x70, 0x82, 0x39, 0xfa, 0x55, 0x03, - 0xe6, 0x1b, 0xf1, 0x91, 0xce, 0xc6, 0x99, 0x4f, 0x9b, 0x43, 0x9e, 0x81, 0x91, 0x28, 0xc4, 0x49, - 0xfe, 0xe8, 0x4b, 0x06, 0xcc, 0xc7, 0x9b, 0x29, 0x55, 0xd6, 0x31, 0x0c, 0x92, 0x4a, 0x99, 0x8c, - 0x97, 0x07, 0x38, 0xd9, 0x04, 0xf3, 0xaf, 0x0c, 0x31, 0xa5, 0x71, 0xcc, 0x21, 0x04, 0xd3, 0x84, - 0x09, 0xdf, 0xeb, 0x84, 0xe2, 0x40, 0x7a, 0x8a, 0x9f, 0x5b, 0x62, 0x56, 0x82, 0x05, 0x04, 0xdd, - 0x86, 0xa9, 0xd0, 0x09, 0x78, 0xa1, 0xe8, 0xed, 0x98, 0xfe, 0xc3, 0xf6, 0x46, 0x8d, 0x91, 0xd3, - 0xb6, 0x78, 0x51, 0x42, 0x4d, 0x15, 0xc9, 0xcb, 0xfc, 0xba, 0x01, 0x53, 0x97, 0xbd, 0x1d, 0xb1, - 0x9c, 0x3f, 0x9a, 0x81, 0x77, 0xae, 0x36, 0x71, 0x15, 0x62, 0x89, 0xec, 0xc2, 0x67, 0x63, 0xbe, - 0xf9, 0xc3, 0x1a, 0xed, 0x15, 0xf6, 0x56, 0x00, 0x25, 0x75, 0xd9, 0xdb, 0x19, 0x78, 0xf4, 0xf3, - 0x5b, 0x45, 0x98, 0x7d, 0xde, 0x3a, 0x20, 0x6e, 0x68, 0x8d, 0xae, 0x80, 0xa8, 0xbb, 0xdb, 0x66, - 0x19, 0x80, 0x9a, 0x61, 0x16, 0xb9, 0xbb, 0x11, 0x08, 0xeb, 0x78, 0x91, 0x5e, 0xe1, 0x57, 0x97, - 0xd3, 0x34, 0xc2, 0x6a, 0x02, 0x8e, 0xfb, 0x6a, 0xa0, 0xcb, 0x80, 0xc4, 0x45, 0x8c, 0x4a, 0xbd, - 0xee, 0x75, 0x5c, 0xae, 0x59, 0xb8, 0x27, 0xac, 0x3c, 0x84, 0xcd, 0x3e, 0x0c, 0x9c, 0x52, 0x0b, - 0x7d, 0x04, 0x96, 0xeb, 0x8c, 0xb2, 0xb0, 0x17, 0x75, 0x8a, 0xdc, 0x67, 0x50, 0xd9, 0xb7, 0xab, - 0x03, 0xf0, 0xf0, 0x40, 0x0a, 0xb4, 0xa5, 0x41, 0xe8, 0xf9, 0x56, 0x93, 0xe8, 0x74, 0x27, 0xe2, - 0x2d, 0xad, 0xf5, 0x61, 0xe0, 0x94, 0x5a, 0xe8, 0xd3, 0x30, 0x15, 0xee, 0xf9, 0x24, 0xd8, 0xf3, - 0x9c, 0x86, 0x88, 0xb9, 0x8e, 0x79, 0x3c, 0x22, 0x66, 0x7f, 0x5b, 0x52, 0xd5, 0xc4, 0x5b, 0x16, - 0xe1, 0x88, 0x27, 0xf2, 0x61, 0x22, 0xa0, 0xbe, 0x79, 0xb0, 0x5c, 0xca, 0xc2, 0x07, 0x10, 0xdc, - 0x99, 0xbb, 0xaf, 0x1d, 0xcc, 0x30, 0x0e, 0x58, 0x70, 0x32, 0xbf, 0x9d, 0x83, 0x19, 0x1d, 0x71, - 0x08, 0x15, 0xf1, 0x19, 0x03, 0x66, 0xea, 0x9e, 0x1b, 0xfa, 0x9e, 0xc3, 0x0f, 0x1d, 0xf8, 0x02, - 0x19, 0xf3, 0x7e, 0x2f, 0x23, 0xb5, 0x46, 0x42, 0xcb, 0x76, 0xb4, 0xf3, 0x0b, 0x8d, 0x0d, 0x8e, - 0x31, 0x45, 0x9f, 0x33, 0x60, 0x3e, 0x4a, 0x46, 0x89, 0x4e, 0x3f, 0x32, 0x6d, 0x88, 0xd2, 0xb8, - 0x17, 0xe2, 0x9c, 0x70, 0x92, 0xb5, 0xb9, 0x03, 0x0b, 0xc9, 0xd9, 0xa6, 0x43, 0xd9, 0xb6, 0xc4, - 0x5a, 0xcf, 0x47, 0x43, 0xb9, 0x65, 0x05, 0x01, 0x66, 0x10, 0xf4, 0x2e, 0x28, 0xb5, 0x2c, 0xbf, - 0x69, 0xbb, 0x96, 0xc3, 0x46, 0x31, 0xaf, 0x29, 0x24, 0x51, 0x8e, 0x15, 0x86, 0xf9, 0x93, 0x02, - 0x4c, 0x6b, 0x97, 0x78, 0x8e, 0xdf, 0x22, 0x8f, 0xdd, 0x0d, 0xcd, 0x67, 0x78, 0x37, 0xf4, 0x45, - 0x80, 0x5d, 0xdb, 0xb5, 0x83, 0xbd, 0x23, 0xde, 0x3a, 0x65, 0x51, 0xb2, 0x8b, 0x8a, 0x02, 0xd6, - 0xa8, 0x45, 0xa1, 0x88, 0xe2, 0x21, 0x77, 0xf1, 0x5f, 0x33, 0xb4, 0xcd, 0x63, 0x22, 0x8b, 0xd0, - 0xab, 0x36, 0x31, 0x2b, 0x72, 0x33, 0xb9, 0xe0, 0x86, 0xfe, 0xc1, 0xa1, 0x7b, 0xcc, 0x36, 0x94, - 0x7c, 0x12, 0x74, 0x5a, 0xd4, 0xb7, 0x98, 0x1c, 0x79, 0x18, 0x58, 0xe6, 0x06, 0x16, 0xf5, 0xb1, - 0xa2, 0x74, 0xfa, 0x19, 0x98, 0x8d, 0x35, 0x01, 0x2d, 0x40, 0xfe, 0x16, 0x39, 0xe0, 0x72, 0x82, - 0xe9, 0x4f, 0xb4, 0x14, 0x0b, 0xd8, 0x88, 0x61, 0x79, 0x7f, 0xee, 0x69, 0xc3, 0xf4, 0x20, 0xf5, - 0xa6, 0xd8, 0x51, 0xce, 0xd3, 0xe9, 0x5c, 0x38, 0xda, 0xb5, 0x53, 0x35, 0x17, 0x3c, 0x4d, 0x80, - 0xc3, 0xcc, 0x9f, 0x4e, 0x80, 0x88, 0x26, 0x0e, 0xa1, 0x7c, 0xf4, 0x20, 0x42, 0xee, 0x08, 0x41, - 0x84, 0xcb, 0x30, 0x63, 0xbb, 0x76, 0x68, 0x5b, 0x0e, 0xf3, 0xaf, 0xc5, 0xe6, 0xf8, 0x98, 0x54, - 0x38, 0xeb, 0x1a, 0x2c, 0x85, 0x4e, 0xac, 0x2e, 0xba, 0x06, 0x45, 0xb6, 0x7b, 0x08, 0x01, 0x1e, - 0x3d, 0xe4, 0xc9, 0xa2, 0xdd, 0x3c, 0xed, 0x9f, 0x53, 0x62, 0x16, 0x3d, 0xbf, 0x77, 0xab, 0x1c, - 0x35, 0x21, 0xc7, 0x91, 0x45, 0x9f, 0x80, 0xe3, 0xbe, 0x1a, 0x94, 0xca, 0xae, 0x65, 0x3b, 0x1d, - 0x9f, 0x44, 0x54, 0x26, 0xe2, 0x54, 0x2e, 0x26, 0xe0, 0xb8, 0xaf, 0x06, 0xda, 0x85, 0x19, 0x51, - 0xc6, 0x93, 0x3f, 0x26, 0x8f, 0xd8, 0x4b, 0x96, 0xe4, 0x73, 0x51, 0xa3, 0x84, 0x63, 0x74, 0x51, - 0x07, 0x16, 0x6d, 0xb7, 0xee, 0xb9, 0x75, 0xa7, 0x13, 0xd8, 0xfb, 0x24, 0xca, 0xb9, 0x3f, 0x0a, - 0xb3, 0x93, 0xbd, 0x6e, 0x79, 0x71, 0x3d, 0x49, 0x0e, 0xf7, 0x73, 0x40, 0xaf, 0x1a, 0x70, 0xb2, - 0xee, 0xb9, 0x01, 0xbb, 0xc8, 0xb6, 0x4f, 0x2e, 0xf8, 0xbe, 0xe7, 0x73, 0xde, 0x53, 0x47, 0xe4, - 0xcd, 0x8e, 0x75, 0x56, 0xd3, 0x48, 0xe2, 0x74, 0x4e, 0xe8, 0x65, 0x28, 0xb5, 0x7d, 0x6f, 0xdf, - 0x6e, 0x10, 0x5f, 0x24, 0x12, 0x6d, 0x64, 0x71, 0xb1, 0x76, 0x4b, 0xd0, 0x8c, 0x54, 0x8f, 0x2c, - 0xc1, 0x8a, 0x9f, 0xf9, 0xbb, 0x25, 0x98, 0x8b, 0xa3, 0xa3, 0x4f, 0x01, 0xb4, 0x7d, 0xaf, 0x45, - 0xc2, 0x3d, 0xa2, 0x72, 0xa7, 0xaf, 0x8c, 0x7b, 0x7f, 0x53, 0xd2, 0x93, 0x09, 0x04, 0x54, 0x5d, - 0x44, 0xa5, 0x58, 0xe3, 0x88, 0x7c, 0x98, 0xbc, 0xc5, 0x37, 0x51, 0x61, 0x53, 0x3c, 0x9f, 0x89, - 0x05, 0x24, 0x38, 0xb3, 0xa4, 0x5f, 0x51, 0x84, 0x25, 0x23, 0xb4, 0x03, 0xf9, 0xdb, 0x64, 0x27, - 0x9b, 0x9b, 0x86, 0x37, 0x88, 0xf0, 0x4d, 0xaa, 0x93, 0xbd, 0x6e, 0x39, 0x7f, 0x83, 0xec, 0x60, - 0x4a, 0x9c, 0xf6, 0xab, 0xc1, 0x43, 0xa1, 0x42, 0x55, 0x8c, 0xd9, 0xaf, 0x58, 0x5c, 0x95, 0xf7, - 0x4b, 0x14, 0x61, 0xc9, 0x08, 0xbd, 0x0c, 0x53, 0xb7, 0xad, 0x7d, 0xb2, 0xeb, 0x7b, 0x6e, 0x28, - 0xb2, 0x56, 0xc6, 0x4c, 0xcf, 0xbd, 0x21, 0xc9, 0x09, 0xbe, 0x6c, 0x7b, 0x57, 0x85, 0x38, 0x62, - 0x87, 0xf6, 0xa1, 0xe4, 0x92, 0xdb, 0x98, 0x38, 0x76, 0x5d, 0x64, 0x46, 0x8e, 0x29, 0xd6, 0x57, - 0x04, 0x35, 0xc1, 0x99, 0xed, 0x7b, 0xb2, 0x0c, 0x2b, 0x5e, 0x74, 0x2e, 0x6f, 0x7a, 0x3b, 0x42, - 0x51, 0x8d, 0x39, 0x97, 0xca, 0xcf, 0xe4, 0x73, 0x79, 0xd9, 0xdb, 0xc1, 0x94, 0x38, 0x5d, 0x23, - 0x75, 0x95, 0x32, 0x21, 0xd4, 0xd4, 0x95, 0x6c, 0x53, 0x45, 0xf8, 0x1a, 0x89, 0x4a, 0xb1, 0xc6, - 0x91, 0x8e, 0x6d, 0x53, 0x1c, 0x6b, 0x09, 0x45, 0x35, 0xe6, 0xd8, 0xc6, 0x0f, 0xc9, 0xf8, 0xd8, - 0xca, 0x32, 0xac, 0x78, 0x99, 0xff, 0x50, 0x80, 0x19, 0xfd, 0x21, 0x91, 0x21, 0xf6, 0x6a, 0x65, - 0x9f, 0xe6, 0x46, 0xb1, 0x4f, 0xa9, 0x7b, 0xa1, 0x5d, 0x4a, 0x97, 0x27, 0x0c, 0xeb, 0x99, 0x99, - 0x67, 0x91, 0x7b, 0xa1, 0x15, 0x06, 0x38, 0xc6, 0x74, 0x84, 0x08, 0x30, 0x35, 0x72, 0xb8, 0x19, - 0x50, 0x8c, 0x1b, 0x39, 0xb1, 0x8d, 0xfd, 0x3c, 0x40, 0xf4, 0xa0, 0x86, 0x08, 0x03, 0x28, 0xeb, - 0x49, 0x7b, 0xe8, 0x43, 0xc3, 0x42, 0x8f, 0xc1, 0x04, 0xdd, 0x28, 0x49, 0x43, 0x5c, 0x6c, 0x53, - 0x3e, 0xdc, 0x45, 0x56, 0x8a, 0x05, 0x14, 0x3d, 0x4d, 0x6d, 0x9a, 0x68, 0x7b, 0x13, 0xf7, 0xd5, - 0x96, 0x22, 0x9b, 0x26, 0x82, 0xe1, 0x18, 0x26, 0x6d, 0x3a, 0xa1, 0xbb, 0x11, 0x93, 0x24, 0xad, - 0xe9, 0x6c, 0x8b, 0xc2, 0x1c, 0xc6, 0xce, 0x14, 0x12, 0xbb, 0x17, 0xdb, 0xac, 0x8a, 0xda, 0x99, - 0x42, 0x02, 0x8e, 0xfb, 0x6a, 0xd0, 0xce, 0x88, 0x08, 0xc6, 0x34, 0x4f, 0x74, 0x1b, 0x10, 0x7b, - 0xf8, 0x18, 0xcc, 0xc5, 0x57, 0x3b, 0x9d, 0x8a, 0xb6, 0xef, 0xed, 0xda, 0x0e, 0x49, 0x9e, 0x9a, - 0x6c, 0xf1, 0x62, 0x2c, 0xe1, 0xc3, 0x1d, 0xdb, 0xfe, 0x59, 0x1e, 0x4e, 0x5c, 0x69, 0xda, 0xee, - 0x9d, 0xc4, 0x79, 0x67, 0xda, 0x33, 0x6f, 0xc6, 0xa8, 0xcf, 0xbc, 0x45, 0x19, 0xfc, 0xe2, 0x1d, - 0xbd, 0xf4, 0x0c, 0x7e, 0xf9, 0xc8, 0x5e, 0x1c, 0x17, 0xfd, 0xc8, 0x80, 0x87, 0xad, 0x06, 0xb7, - 0xbf, 0x2c, 0x47, 0x94, 0x46, 0x4c, 0xe5, 0x5a, 0x08, 0xc6, 0xd4, 0xa6, 0xfd, 0x9d, 0x5f, 0xa9, - 0x1c, 0xc2, 0x95, 0xbb, 0x31, 0xef, 0x10, 0x3d, 0x78, 0xf8, 0x30, 0x54, 0x7c, 0x68, 0xf3, 0x4f, - 0x5f, 0x85, 0xb7, 0xdf, 0x93, 0xd1, 0x48, 0xce, 0xca, 0x67, 0x0c, 0x98, 0xe2, 0xc7, 0x79, 0x98, - 0xec, 0xd2, 0x45, 0x66, 0xb5, 0xed, 0x17, 0x88, 0x1f, 0xc8, 0xf7, 0x27, 0x34, 0x17, 0xa5, 0xb2, - 0xb5, 0x2e, 0x20, 0x58, 0xc3, 0xa2, 0x6a, 0xec, 0x96, 0xed, 0x36, 0xc4, 0x34, 0x29, 0x35, 0xf6, - 0xbc, 0xed, 0x36, 0x30, 0x83, 0x28, 0x45, 0x97, 0x1f, 0xa4, 0xe8, 0xcc, 0xaf, 0x19, 0x30, 0xc7, - 0x2e, 0xe8, 0x44, 0xc6, 0xf3, 0x53, 0x2a, 0x30, 0xce, 0x9b, 0x71, 0x26, 0x1e, 0x18, 0xbf, 0xdb, - 0x2d, 0x4f, 0xf3, 0x2b, 0x3d, 0xf1, 0x38, 0xf9, 0x87, 0x85, 0xc7, 0xcd, 0xc2, 0xf7, 0xb9, 0x91, - 0x1d, 0x42, 0x75, 0xbe, 0x54, 0x93, 0x44, 0x70, 0x44, 0xcf, 0xfc, 0xfd, 0x3c, 0x9c, 0x48, 0xc9, - 0x34, 0xa7, 0xce, 0xf0, 0x04, 0x4b, 0xb6, 0x95, 0xc1, 0xe7, 0x97, 0x32, 0xcf, 0x66, 0x5f, 0x61, - 0x39, 0xbd, 0x42, 0x92, 0xd4, 0xd2, 0xe7, 0x85, 0x58, 0x30, 0x47, 0xbf, 0x6e, 0xc0, 0xb4, 0xa5, - 0x09, 0x3b, 0x8f, 0xc7, 0xef, 0x64, 0xdf, 0x98, 0x3e, 0xd9, 0xd6, 0xf2, 0x88, 0x22, 0x51, 0xd6, - 0xdb, 0x72, 0xfa, 0x7d, 0x30, 0xad, 0x75, 0x61, 0x14, 0x19, 0x3d, 0xfd, 0x2c, 0x2c, 0x8c, 0x25, - 0xe3, 0x1f, 0x82, 0x51, 0x1f, 0x34, 0xa1, 0xca, 0xf6, 0xb6, 0x7e, 0x6f, 0x4d, 0x8d, 0xb8, 0xb8, - 0xb8, 0x26, 0xa0, 0xe6, 0x0e, 0x2c, 0x24, 0x0d, 0xf4, 0xcc, 0xa3, 0x64, 0xef, 0x81, 0x11, 0x9f, - 0x20, 0x31, 0xff, 0x3c, 0x07, 0x93, 0xe2, 0xba, 0xca, 0x7d, 0x48, 0xc1, 0xbb, 0x15, 0x3b, 0xe6, - 0x5f, 0xcf, 0xe4, 0x96, 0xcd, 0xc0, 0xfc, 0xbb, 0x20, 0x91, 0x7f, 0xf7, 0x7c, 0x36, 0xec, 0x0e, - 0x4f, 0xbe, 0xfb, 0x8f, 0x1c, 0xcc, 0x27, 0xae, 0xff, 0xa0, 0xd7, 0x8d, 0xfe, 0x9c, 0x93, 0xeb, - 0x99, 0xde, 0x30, 0x52, 0xe9, 0xa1, 0x87, 0xa7, 0x9f, 0x04, 0xb1, 0x97, 0x9e, 0xae, 0x65, 0xf6, - 0x48, 0xe4, 0x5b, 0xe7, 0xd1, 0x27, 0xf3, 0xef, 0x0d, 0x78, 0x70, 0xe0, 0xf5, 0x2b, 0x76, 0xaf, - 0xdc, 0x8f, 0x43, 0x85, 0xa4, 0x67, 0x7c, 0x9d, 0x52, 0x1d, 0x66, 0x27, 0xaf, 0x02, 0x27, 0xd9, - 0xa3, 0x27, 0x61, 0x86, 0xed, 0x1a, 0x74, 0xb1, 0x86, 0xa4, 0x2d, 0x4e, 0xef, 0xd8, 0x39, 0x4e, - 0x4d, 0x2b, 0xc7, 0x31, 0x2c, 0xf3, 0xab, 0x06, 0x2c, 0x0f, 0xba, 0x65, 0x3c, 0x84, 0xb7, 0xf0, - 0xff, 0x12, 0xc9, 0x77, 0xe5, 0xbe, 0xe4, 0xbb, 0x84, 0xbf, 0x20, 0xf3, 0xec, 0x34, 0x53, 0x3d, - 0x7f, 0x8f, 0xdc, 0xb2, 0xcf, 0x1b, 0x70, 0x6a, 0x80, 0x98, 0xf6, 0x25, 0x61, 0x1a, 0x47, 0x4e, - 0xc2, 0xcc, 0x0d, 0x9b, 0x84, 0x69, 0xfe, 0x65, 0x1e, 0x16, 0x44, 0x7b, 0x22, 0xd3, 0xe1, 0xe9, - 0x58, 0x0a, 0xe3, 0x3b, 0x12, 0x29, 0x8c, 0x4b, 0x49, 0xfc, 0xff, 0xc9, 0x5f, 0x7c, 0x6b, 0xe5, - 0x2f, 0xfe, 0x2c, 0x07, 0x27, 0x53, 0x2f, 0x53, 0xa3, 0xcf, 0xa6, 0xe8, 0xdc, 0x1b, 0x19, 0xdf, - 0xda, 0x1e, 0x52, 0xeb, 0x8e, 0x9b, 0xf4, 0xf7, 0x25, 0x3d, 0xd9, 0x8e, 0xeb, 0xd0, 0xdd, 0x63, - 0xb8, 0x7f, 0x3e, 0x62, 0xde, 0x9d, 0xf9, 0x2b, 0x79, 0x78, 0x7c, 0x58, 0x42, 0x6f, 0xd1, 0xbc, - 0xec, 0x20, 0x96, 0x97, 0x7d, 0x9f, 0xf6, 0xc3, 0x63, 0x49, 0xd1, 0xfe, 0x7a, 0x5e, 0x6d, 0x7b, - 0xfd, 0xf2, 0x39, 0x54, 0xa8, 0x67, 0x92, 0xda, 0x4c, 0xf2, 0x49, 0xb4, 0x48, 0x15, 0x4e, 0xd6, - 0x78, 0xf1, 0xdd, 0x6e, 0x79, 0x51, 0x3c, 0x93, 0x54, 0x23, 0xa1, 0x28, 0xc4, 0xb2, 0x12, 0x7a, - 0x1c, 0x4a, 0x3e, 0x87, 0xca, 0x4c, 0x54, 0x11, 0x2f, 0xe3, 0x65, 0x58, 0x41, 0xd1, 0xa7, 0x35, - 0x23, 0xb3, 0x70, 0x5c, 0xf7, 0x79, 0x0f, 0x0b, 0x03, 0xbe, 0x04, 0xa5, 0x40, 0x3e, 0x6e, 0xc6, - 0xcf, 0x6a, 0x9f, 0x18, 0x32, 0xc1, 0x99, 0xfa, 0x24, 0xf2, 0xa5, 0x33, 0xde, 0x3f, 0xf5, 0x0e, - 0x9a, 0x22, 0x89, 0x4c, 0xe5, 0x0e, 0xf0, 0x83, 0x27, 0x48, 0x71, 0x05, 0xbe, 0x67, 0xc0, 0xb4, - 0x98, 0xad, 0xfb, 0x90, 0x73, 0x7d, 0x33, 0x9e, 0x73, 0x7d, 0x21, 0x13, 0xdd, 0x31, 0x20, 0xe1, - 0xfa, 0x26, 0xcc, 0xe8, 0xef, 0x69, 0xa0, 0x17, 0x35, 0xdd, 0x67, 0x8c, 0x73, 0x6f, 0x5f, 0x6a, - 0xc7, 0x48, 0x2f, 0x9a, 0x5f, 0x29, 0xa9, 0x51, 0x64, 0x99, 0xdd, 0xba, 0x0c, 0x1a, 0x87, 0xca, - 0xa0, 0x2e, 0x02, 0xb9, 0xec, 0x45, 0xe0, 0x1a, 0x94, 0xa4, 0x82, 0x12, 0xdb, 0xf8, 0xa3, 0x7a, - 0x42, 0x13, 0xb5, 0x05, 0x28, 0x31, 0x4d, 0x70, 0x99, 0x0f, 0xa3, 0xe6, 0x50, 0x29, 0x4e, 0x45, - 0x06, 0xbd, 0x0c, 0xd3, 0xb7, 0x3d, 0xff, 0x96, 0xe3, 0x59, 0xec, 0xd9, 0x42, 0xc8, 0xe2, 0xd4, - 0x5d, 0x9d, 0xe5, 0xf0, 0xbc, 0xd9, 0x1b, 0x11, 0x7d, 0xac, 0x33, 0x43, 0x15, 0x98, 0x6f, 0xd9, - 0x2e, 0x26, 0x56, 0x43, 0xa5, 0x56, 0x17, 0xf8, 0xbb, 0x6a, 0xd2, 0xc8, 0xdd, 0x8c, 0x83, 0x71, - 0x12, 0x1f, 0x7d, 0x02, 0x4a, 0x81, 0x78, 0xb3, 0x23, 0x9b, 0xf8, 0x88, 0x72, 0xc6, 0x38, 0xd1, - 0x68, 0xec, 0x64, 0x09, 0x56, 0x0c, 0xd1, 0x06, 0x2c, 0xf9, 0xe2, 0x56, 0x7c, 0xec, 0x79, 0x66, - 0xbe, 0x3e, 0xd9, 0xf3, 0x5d, 0x38, 0x05, 0x8e, 0x53, 0x6b, 0x51, 0x2b, 0x86, 0x3d, 0x0c, 0xc3, - 0x0f, 0x8a, 0xb5, 0xb3, 0x55, 0x26, 0xf0, 0x0d, 0x2c, 0xa0, 0x87, 0xa5, 0xea, 0x97, 0xc6, 0x48, - 0xd5, 0xaf, 0xc1, 0xc9, 0x24, 0x88, 0xdd, 0xdd, 0x67, 0xcf, 0x05, 0x68, 0xbb, 0xc7, 0x56, 0x1a, - 0x12, 0x4e, 0xaf, 0x8b, 0x6e, 0xc0, 0x94, 0x4f, 0x98, 0x7f, 0x51, 0x91, 0x11, 0xd9, 0x91, 0x73, - 0x4f, 0xb0, 0x24, 0x80, 0x23, 0x5a, 0x74, 0xde, 0xad, 0xf8, 0xd3, 0x62, 0xd7, 0x32, 0xfc, 0xc0, - 0x84, 0x98, 0xfb, 0x01, 0x6f, 0x6a, 0x98, 0x6f, 0xce, 0xc1, 0x6c, 0xcc, 0x69, 0x47, 0x8f, 0x42, - 0x91, 0x3d, 0x66, 0xc0, 0xd4, 0x43, 0x29, 0x52, 0x61, 0x7c, 0x70, 0x38, 0x0c, 0x7d, 0xc1, 0x80, - 0xf9, 0x76, 0xec, 0x80, 0x51, 0x6a, 0xce, 0x31, 0x83, 0x3f, 0xf1, 0x53, 0x4b, 0xed, 0x51, 0xce, - 0x38, 0x33, 0x9c, 0xe4, 0x4e, 0x17, 0xa0, 0x48, 0xc7, 0x72, 0x88, 0xcf, 0xb0, 0x85, 0x8d, 0xa3, - 0x48, 0xac, 0xc6, 0xc1, 0x38, 0x89, 0x4f, 0x67, 0x98, 0xf5, 0x6e, 0x9c, 0x97, 0xe7, 0x2b, 0x92, - 0x00, 0x8e, 0x68, 0xa1, 0x67, 0x61, 0x4e, 0xbc, 0x28, 0xb5, 0xe5, 0x35, 0x2e, 0x59, 0xc1, 0x9e, - 0x30, 0xee, 0x95, 0x33, 0xb2, 0x1a, 0x83, 0xe2, 0x04, 0x36, 0xeb, 0x5b, 0xf4, 0x6c, 0x17, 0x23, - 0x30, 0x11, 0x7f, 0xb3, 0x74, 0x35, 0x0e, 0xc6, 0x49, 0x7c, 0xf4, 0x2e, 0x4d, 0xef, 0xf3, 0xe0, - 0x8d, 0xd2, 0x06, 0x29, 0xba, 0xbf, 0x02, 0xf3, 0x1d, 0xe6, 0x0b, 0x35, 0x24, 0x50, 0xac, 0x47, - 0xc5, 0xf0, 0x7a, 0x1c, 0x8c, 0x93, 0xf8, 0xe8, 0x19, 0x98, 0xf5, 0xa9, 0x76, 0x53, 0x04, 0x78, - 0x44, 0x47, 0x85, 0x1d, 0xb0, 0x0e, 0xc4, 0x71, 0x5c, 0xf4, 0x1c, 0x2c, 0x46, 0xcf, 0xdc, 0x48, - 0x02, 0x3c, 0xc4, 0xa3, 0xde, 0x8d, 0xa8, 0x24, 0x11, 0x70, 0x7f, 0x1d, 0xf4, 0xff, 0x61, 0x41, - 0x1b, 0x89, 0x75, 0xb7, 0x41, 0xee, 0x88, 0xa7, 0x48, 0xd8, 0xb7, 0x76, 0x56, 0x13, 0x30, 0xdc, - 0x87, 0x8d, 0xde, 0x0f, 0x73, 0x75, 0xcf, 0x71, 0x98, 0x8e, 0xe3, 0xef, 0x65, 0xf2, 0x37, 0x47, - 0xf8, 0xeb, 0x2c, 0x31, 0x08, 0x4e, 0x60, 0xa2, 0xcb, 0x80, 0xbc, 0x9d, 0x80, 0xf8, 0xfb, 0xa4, - 0xf1, 0x1c, 0xff, 0x96, 0x15, 0xdd, 0xe2, 0x67, 0xe3, 0xc9, 0xa0, 0x57, 0xfb, 0x30, 0x70, 0x4a, - 0x2d, 0xf6, 0xec, 0x84, 0x76, 0x31, 0x63, 0x2e, 0x8b, 0x57, 0xd8, 0x93, 0x9e, 0xfb, 0x3d, 0x6f, - 0x65, 0xf8, 0x30, 0xc1, 0x73, 0x73, 0x97, 0xe7, 0xb3, 0x78, 0x7a, 0x47, 0x7f, 0x3a, 0x2f, 0xda, - 0x23, 0x78, 0x29, 0x16, 0x9c, 0xd0, 0xa7, 0x60, 0x6a, 0x47, 0xbe, 0xa3, 0xba, 0xbc, 0x90, 0xc5, - 0xbe, 0x98, 0x78, 0x12, 0x38, 0xf2, 0x4c, 0x15, 0x00, 0x47, 0x2c, 0xd1, 0x63, 0x30, 0x7d, 0x69, - 0xab, 0xa2, 0xa4, 0x70, 0x91, 0xcd, 0x7e, 0x81, 0x56, 0xc1, 0x3a, 0x80, 0xae, 0x30, 0x65, 0x2f, - 0x21, 0x36, 0xc5, 0xd1, 0x7e, 0xdb, 0x6f, 0xfe, 0x50, 0x6c, 0x16, 0x69, 0xc3, 0xb5, 0xe5, 0x13, - 0x09, 0x6c, 0x51, 0x8e, 0x15, 0x06, 0x7a, 0x09, 0xa6, 0xc5, 0x7e, 0xc1, 0x74, 0xd3, 0xd2, 0xd1, - 0x2e, 0xfd, 0xe0, 0x88, 0x04, 0xd6, 0xe9, 0xa1, 0xa7, 0x60, 0xba, 0xcd, 0x9e, 0x97, 0x24, 0x17, - 0x3b, 0x8e, 0xb3, 0x7c, 0x92, 0xe9, 0x4d, 0x15, 0x82, 0xd8, 0x8a, 0x40, 0x58, 0xc7, 0x43, 0x4f, - 0xc8, 0x70, 0xfa, 0xdb, 0x62, 0x11, 0x25, 0x15, 0x4e, 0x57, 0x56, 0xee, 0x80, 0x6c, 0xcf, 0x53, - 0xf7, 0x88, 0x63, 0xef, 0xc0, 0x69, 0x69, 0x62, 0xf5, 0x2f, 0x92, 0xe5, 0xe5, 0xd8, 0x29, 0xc1, - 0xe9, 0x1b, 0x03, 0x31, 0xf1, 0x21, 0x54, 0xd0, 0x0e, 0xe4, 0x2d, 0x67, 0x67, 0xf9, 0xc1, 0x2c, - 0x6c, 0x45, 0xf5, 0x6d, 0x3a, 0x9e, 0xa1, 0x51, 0xd9, 0xa8, 0x62, 0x4a, 0xdc, 0x7c, 0x35, 0x3a, - 0xee, 0x56, 0x8f, 0xb2, 0x7d, 0x52, 0x97, 0x6a, 0x23, 0x8b, 0x6f, 0x2f, 0xf5, 0x3d, 0x36, 0xcc, - 0x37, 0xa4, 0x54, 0x99, 0x6e, 0xab, 0x75, 0x9c, 0xc9, 0x3d, 0xff, 0xf8, 0x83, 0x73, 0xdc, 0x9b, - 0x8b, 0xaf, 0x62, 0xf3, 0xc7, 0x05, 0x75, 0x08, 0x95, 0x88, 0x72, 0xfb, 0x50, 0xb4, 0x83, 0xd0, - 0xf6, 0x32, 0xbc, 0xcb, 0x93, 0x78, 0xa9, 0x8d, 0x65, 0x35, 0x32, 0x00, 0xe6, 0xac, 0x28, 0x4f, - 0xb7, 0x69, 0xbb, 0x77, 0x44, 0xf7, 0xaf, 0x65, 0x1e, 0xbe, 0xe6, 0x3c, 0x19, 0x00, 0x73, 0x56, - 0xe8, 0x26, 0x97, 0xb4, 0x6c, 0xbe, 0xb3, 0x95, 0xfc, 0x7c, 0x5e, 0x5c, 0xe2, 0x28, 0xaf, 0xa0, - 0x65, 0x0b, 0x1b, 0x66, 0x4c, 0x5e, 0xb5, 0xcd, 0xf5, 0x34, 0x5e, 0xb5, 0xcd, 0x75, 0x4c, 0x99, - 0xa0, 0xd7, 0x0d, 0x00, 0x4b, 0x7d, 0x47, 0x2e, 0x9b, 0x97, 0xb9, 0x07, 0x7d, 0x97, 0x8e, 0x27, - 0x22, 0x45, 0x50, 0xac, 0x71, 0x36, 0xff, 0xd9, 0x00, 0xed, 0xe3, 0x3b, 0x51, 0x16, 0x8c, 0x31, - 0x74, 0x16, 0x4c, 0x6e, 0xc4, 0x2c, 0x98, 0xfc, 0x48, 0x59, 0x30, 0x85, 0xd1, 0xb3, 0x60, 0x8a, - 0x83, 0xb3, 0x60, 0xcc, 0x37, 0x0c, 0x58, 0xec, 0x9b, 0x9b, 0xe4, 0x47, 0x0e, 0x8d, 0x21, 0x3f, - 0x72, 0xb8, 0x06, 0x0b, 0xe2, 0xe9, 0xc2, 0x5a, 0xdb, 0xb1, 0x53, 0xaf, 0xff, 0x6d, 0x27, 0xe0, - 0xb8, 0xaf, 0x86, 0xf9, 0xc7, 0x06, 0x4c, 0x6b, 0xb7, 0x15, 0x68, 0x3f, 0xd8, 0xad, 0x0e, 0xd1, - 0x8c, 0xe8, 0xd5, 0x46, 0x76, 0xcc, 0xc8, 0x61, 0xfc, 0xc4, 0xbb, 0xa9, 0x3d, 0xce, 0x15, 0x9d, - 0x78, 0xd3, 0x52, 0x2c, 0xa0, 0xfc, 0xd9, 0x25, 0xc2, 0x3f, 0x60, 0x99, 0xd7, 0x9f, 0x5d, 0x22, - 0x6d, 0xcc, 0x20, 0x8c, 0x1d, 0xdd, 0xd3, 0x44, 0x82, 0x94, 0xf6, 0x48, 0xa4, 0x45, 0x3d, 0x17, - 0x06, 0x43, 0x67, 0x20, 0x4f, 0xdc, 0x86, 0x30, 0xc0, 0xd5, 0x27, 0x03, 0x2e, 0xb8, 0x0d, 0x4c, - 0xcb, 0xcd, 0xab, 0x30, 0x53, 0x23, 0x75, 0x9f, 0x84, 0xcf, 0x93, 0x83, 0xa1, 0xbf, 0x41, 0x70, - 0x8b, 0x1c, 0x24, 0xbf, 0x41, 0x40, 0xab, 0xd3, 0x72, 0xf3, 0x77, 0x0c, 0x48, 0xbc, 0xd9, 0xa9, - 0x9d, 0x7e, 0x19, 0x83, 0x4e, 0xbf, 0x62, 0xe7, 0x34, 0xb9, 0x43, 0xcf, 0x69, 0x2e, 0x03, 0x6a, - 0x59, 0x61, 0x7d, 0x2f, 0xf6, 0xa2, 0xac, 0xf0, 0x7d, 0xa2, 0xbb, 0x51, 0x7d, 0x18, 0x38, 0xa5, - 0x96, 0xf9, 0x8a, 0x01, 0x7d, 0xdf, 0x9f, 0xa4, 0x3b, 0x36, 0x11, 0xcf, 0xbb, 0x73, 0x97, 0x50, - 0xed, 0xd8, 0xf2, 0x55, 0x77, 0x09, 0xa7, 0x7e, 0x83, 0x3c, 0x79, 0x92, 0x7e, 0x3c, 0xbf, 0x45, - 0xa2, 0xfc, 0x86, 0xb5, 0x38, 0x18, 0x27, 0xf1, 0xcd, 0x17, 0xa0, 0x24, 0xaf, 0xda, 0xb1, 0xfb, - 0x2a, 0xd2, 0x13, 0xd5, 0xef, 0xab, 0x50, 0x47, 0x94, 0x41, 0xe8, 0x30, 0x05, 0xae, 0x7d, 0xc9, - 0x0b, 0x42, 0x79, 0x3f, 0x90, 0x9f, 0x37, 0x5d, 0x59, 0x67, 0x65, 0x58, 0x41, 0xcd, 0x45, 0x98, - 0x57, 0x07, 0x49, 0x5c, 0xe8, 0xcd, 0x6f, 0xe7, 0x61, 0x26, 0xf6, 0x55, 0xa1, 0x7b, 0x4f, 0xf6, - 0xf0, 0xd3, 0x92, 0x72, 0x20, 0x94, 0x1f, 0xf1, 0x40, 0x48, 0x3f, 0x81, 0x2b, 0x1c, 0xef, 0x09, - 0x5c, 0x31, 0x9b, 0x13, 0xb8, 0x10, 0x26, 0xc5, 0x17, 0x57, 0x45, 0x9a, 0xed, 0x66, 0x46, 0xf7, - 0xe4, 0xc5, 0x85, 0x53, 0x96, 0x59, 0x2c, 0x15, 0x98, 0x64, 0x65, 0x7e, 0xb3, 0x08, 0x73, 0xf1, - 0x9b, 0xf3, 0x43, 0xcc, 0xe4, 0xbb, 0xfa, 0x66, 0x72, 0x44, 0x87, 0x38, 0x3f, 0xae, 0x43, 0x5c, - 0x18, 0xd7, 0x21, 0x2e, 0x1e, 0xc1, 0x21, 0xee, 0x77, 0x67, 0x27, 0x86, 0x76, 0x67, 0x3f, 0xa0, - 0xa2, 0xb9, 0x93, 0xb1, 0xf0, 0x47, 0x14, 0xcd, 0x45, 0xf1, 0x69, 0x58, 0xf5, 0x1a, 0xa9, 0x51, - 0xf1, 0xd2, 0x3d, 0x0c, 0x7f, 0x3f, 0x35, 0xf8, 0x3a, 0xfa, 0x99, 0xdb, 0xdb, 0x46, 0x08, 0xbc, - 0x46, 0x1f, 0x15, 0x66, 0x9b, 0x1f, 0xc4, 0x37, 0xce, 0x5a, 0x04, 0xc2, 0x3a, 0x1e, 0xfb, 0x9c, - 0x4c, 0xfc, 0xfb, 0x39, 0xec, 0x7c, 0x41, 0xff, 0x9c, 0x4c, 0xe2, 0x7b, 0x3b, 0x49, 0x7c, 0xf3, - 0x1b, 0x79, 0x98, 0x8b, 0x3f, 0x07, 0x8e, 0x6e, 0x2b, 0xfb, 0x3c, 0x13, 0xd7, 0x80, 0x93, 0xd5, - 0xee, 0x8e, 0x0f, 0x74, 0xb6, 0xf9, 0xa7, 0x6e, 0x77, 0xd4, 0x45, 0xf6, 0xe3, 0x63, 0x2c, 0xbc, - 0x5c, 0xc1, 0x8e, 0xbd, 0x20, 0x1e, 0x65, 0x6a, 0x8a, 0x08, 0x6e, 0xe6, 0xdc, 0xa3, 0xdc, 0x4b, - 0xc5, 0x0a, 0x6b, 0x6c, 0xa9, 0x7a, 0xdf, 0x27, 0xbe, 0xbd, 0x6b, 0xab, 0x4f, 0x99, 0x30, 0xe5, - 0xf9, 0x82, 0x28, 0xc3, 0x0a, 0x6a, 0xbe, 0x92, 0x83, 0xe8, 0xc3, 0x4d, 0xec, 0x65, 0xe2, 0x40, - 0x33, 0x1b, 0xc4, 0xb4, 0x5d, 0x1e, 0xf7, 0xf9, 0xef, 0x88, 0xa2, 0x48, 0x76, 0xd1, 0x4a, 0x70, - 0x8c, 0xe3, 0xcf, 0xe1, 0x83, 0x4d, 0x16, 0xcc, 0x27, 0x6e, 0x60, 0x64, 0x9e, 0xaa, 0xf7, 0x95, - 0x3c, 0x4c, 0xa9, 0x3b, 0x2c, 0xe8, 0x7d, 0xec, 0x51, 0xd1, 0x3d, 0x4f, 0x3e, 0xf5, 0xfa, 0x76, - 0xed, 0xe9, 0xcf, 0x3d, 0xaf, 0x71, 0xb7, 0x5b, 0x9e, 0x57, 0xc8, 0xbc, 0x08, 0x8b, 0x0a, 0xd4, - 0x48, 0xeb, 0xf8, 0x4e, 0xd2, 0x48, 0xbb, 0x8e, 0x37, 0x30, 0x2d, 0x47, 0x77, 0x60, 0x72, 0x8f, - 0x58, 0x0d, 0xe2, 0xcb, 0xdc, 0x81, 0xcd, 0x8c, 0xee, 0xdd, 0x5c, 0x62, 0x54, 0xa3, 0x61, 0xe0, - 0xff, 0x03, 0x2c, 0xd9, 0xd1, 0x8d, 0x6a, 0xc7, 0x6b, 0x1c, 0x24, 0x9f, 0x0a, 0xad, 0x7a, 0x8d, - 0x03, 0xcc, 0x20, 0xe8, 0x59, 0x98, 0x0b, 0xed, 0x16, 0xf1, 0x3a, 0xa1, 0xfe, 0x59, 0x9c, 0x7c, - 0x74, 0x78, 0xbc, 0x1d, 0x83, 0xe2, 0x04, 0x36, 0xdd, 0xe8, 0x6e, 0x06, 0x9e, 0xcb, 0x9e, 0x29, - 0x99, 0x88, 0x9f, 0x34, 0x5d, 0xae, 0x5d, 0xbd, 0xc2, 0x5e, 0x29, 0x51, 0x18, 0x14, 0xdb, 0x66, - 0x89, 0xf2, 0x3e, 0x11, 0xb1, 0x9b, 0x85, 0xe8, 0x3a, 0x23, 0x2f, 0xc7, 0x0a, 0xc3, 0xbc, 0x0e, - 0xf3, 0x89, 0xae, 0x4a, 0x73, 0xd8, 0x48, 0x37, 0x87, 0x87, 0x7b, 0x97, 0xf3, 0x0f, 0x0c, 0x58, - 0xec, 0x5b, 0xbc, 0xc3, 0xe6, 0x90, 0x26, 0x35, 0x79, 0xee, 0xe8, 0x9a, 0x3c, 0x3f, 0x9a, 0x26, - 0xaf, 0xae, 0x7c, 0xe7, 0xcd, 0xb3, 0x0f, 0x7c, 0xf7, 0xcd, 0xb3, 0x0f, 0x7c, 0xff, 0xcd, 0xb3, - 0x0f, 0xbc, 0xd2, 0x3b, 0x6b, 0x7c, 0xa7, 0x77, 0xd6, 0xf8, 0x6e, 0xef, 0xac, 0xf1, 0xfd, 0xde, - 0x59, 0xe3, 0xc7, 0xbd, 0xb3, 0xc6, 0x1b, 0x3f, 0x39, 0xfb, 0xc0, 0x8b, 0x25, 0x29, 0x26, 0xff, - 0x19, 0x00, 0x00, 0xff, 0xff, 0xd5, 0x66, 0xee, 0x39, 0xa9, 0x82, 0x00, 0x00, + 0x23, 0x7f, 0xe6, 0x0b, 0xcc, 0xc2, 0xda, 0x4e, 0x0c, 0x46, 0x56, 0xba, 0x67, 0x76, 0xbd, 0xb3, + 0x9e, 0xd9, 0x9d, 0xbd, 0x3d, 0xeb, 0x05, 0x83, 0x09, 0x35, 0xdd, 0x77, 0x7a, 0x6a, 0xb7, 0xba, + 0xaa, 0xa9, 0xaa, 0x9e, 0xdd, 0x31, 0x08, 0xec, 0x20, 0x3b, 0x24, 0x02, 0xe1, 0x04, 0x78, 0x88, + 0x22, 0x22, 0x14, 0xf1, 0x10, 0x85, 0x3c, 0x44, 0x28, 0x51, 0x5e, 0x90, 0x12, 0x25, 0x20, 0x91, + 0x87, 0x44, 0x44, 0x4a, 0x02, 0x44, 0xd0, 0xc1, 0x4d, 0xf2, 0x90, 0x28, 0x52, 0x14, 0x89, 0x28, + 0x62, 0x9f, 0xa2, 0xfb, 0x5b, 0xb7, 0xaa, 0xab, 0x67, 0xbb, 0xa7, 0x6b, 0x16, 0x94, 0xf0, 0xd6, + 0x7d, 0xcf, 0xb9, 0xe7, 0xdc, 0xdf, 0x73, 0xcf, 0xb9, 0xe7, 0xdc, 0x53, 0xb0, 0xd1, 0xb4, 0xc3, + 0xbd, 0xce, 0xce, 0x4a, 0xdd, 0x6b, 0x9d, 0xb3, 0xfc, 0xa6, 0xd7, 0xf6, 0xbd, 0x9b, 0xec, 0xc7, + 0x3b, 0x7d, 0xcf, 0x71, 0xbc, 0x4e, 0x18, 0x9c, 0x6b, 0xdf, 0x6a, 0x9e, 0xb3, 0xda, 0x76, 0x70, + 0x4e, 0x95, 0xec, 0xbf, 0xdb, 0x72, 0xda, 0x7b, 0xd6, 0xbb, 0xcf, 0x35, 0x89, 0x4b, 0x7c, 0x2b, + 0x24, 0x8d, 0x95, 0xb6, 0xef, 0x85, 0x1e, 0x7a, 0x5f, 0x44, 0x6d, 0x45, 0x52, 0x63, 0x3f, 0x7e, + 0x45, 0xd6, 0x5d, 0x69, 0xdf, 0x6a, 0xae, 0x50, 0x6a, 0x2b, 0xaa, 0x44, 0x52, 0x3b, 0xfd, 0x4e, + 0xad, 0x2d, 0x4d, 0xaf, 0xe9, 0x9d, 0x63, 0x44, 0x77, 0x3a, 0xbb, 0xec, 0x1f, 0xfb, 0xc3, 0x7e, + 0x71, 0x66, 0xa7, 0x1f, 0xbd, 0xf5, 0x74, 0xb0, 0x62, 0x7b, 0xb4, 0x6d, 0xe7, 0x76, 0xac, 0xb0, + 0xbe, 0x77, 0x6e, 0xbf, 0xaf, 0x45, 0xa7, 0x4d, 0x0d, 0xa9, 0xee, 0xf9, 0x24, 0x0d, 0xe7, 0xc9, + 0x08, 0xa7, 0x65, 0xd5, 0xf7, 0x6c, 0x97, 0xf8, 0x07, 0x51, 0xaf, 0x5b, 0x24, 0xb4, 0xd2, 0x6a, + 0x9d, 0x1b, 0x54, 0xcb, 0xef, 0xb8, 0xa1, 0xdd, 0x22, 0x7d, 0x15, 0x7e, 0xf1, 0x5e, 0x15, 0x82, + 0xfa, 0x1e, 0x69, 0x59, 0x7d, 0xf5, 0x9e, 0x18, 0x54, 0xaf, 0x13, 0xda, 0xce, 0x39, 0xdb, 0x0d, + 0x83, 0xd0, 0x4f, 0x56, 0x32, 0xbf, 0x91, 0x87, 0xa9, 0xca, 0x46, 0xb5, 0x16, 0x5a, 0x61, 0x27, + 0x40, 0xaf, 0x1b, 0x30, 0xe3, 0x78, 0x56, 0xa3, 0x6a, 0x39, 0x96, 0x5b, 0x27, 0xfe, 0xb2, 0xf1, + 0x88, 0xf1, 0xf8, 0xf4, 0xf9, 0x8d, 0x95, 0x71, 0xe6, 0x6b, 0xa5, 0x72, 0x3b, 0xc0, 0x24, 0xf0, + 0x3a, 0x7e, 0x9d, 0x60, 0xb2, 0x5b, 0x5d, 0xfa, 0x56, 0xb7, 0xfc, 0x40, 0xaf, 0x5b, 0x9e, 0xd9, + 0xd0, 0x38, 0xe1, 0x18, 0x5f, 0xf4, 0x45, 0x03, 0x16, 0xeb, 0x96, 0x6b, 0xf9, 0x07, 0xdb, 0x96, + 0xdf, 0x24, 0xe1, 0x73, 0xbe, 0xd7, 0x69, 0x2f, 0xe7, 0x8e, 0xa1, 0x35, 0x0f, 0x8a, 0xd6, 0x2c, + 0xae, 0x26, 0xd9, 0xe1, 0xfe, 0x16, 0xb0, 0x76, 0x05, 0xa1, 0xb5, 0xe3, 0x10, 0xbd, 0x5d, 0xf9, + 0xe3, 0x6c, 0x57, 0x2d, 0xc9, 0x0e, 0xf7, 0xb7, 0xc0, 0x7c, 0x2d, 0x0f, 0x8b, 0x95, 0x8d, 0xea, + 0xb6, 0x6f, 0xed, 0xee, 0xda, 0x75, 0xec, 0x75, 0x42, 0xdb, 0x6d, 0xa2, 0xb7, 0xc3, 0xa4, 0xed, + 0x36, 0x7d, 0x12, 0x04, 0x6c, 0x22, 0xa7, 0xaa, 0xf3, 0x82, 0xe8, 0xe4, 0x3a, 0x2f, 0xc6, 0x12, + 0x8e, 0x9e, 0x82, 0xe9, 0x80, 0xf8, 0xfb, 0x76, 0x9d, 0x6c, 0x79, 0x7e, 0xc8, 0x46, 0xba, 0x58, + 0x3d, 0x21, 0xd0, 0xa7, 0x6b, 0x11, 0x08, 0xeb, 0x78, 0xb4, 0x9a, 0xef, 0x79, 0xa1, 0x80, 0xb3, + 0x81, 0x98, 0x8a, 0xaa, 0xe1, 0x08, 0x84, 0x75, 0x3c, 0xf4, 0x86, 0x01, 0x0b, 0x41, 0x68, 0xd7, + 0x6f, 0xd9, 0x2e, 0x09, 0x82, 0x55, 0xcf, 0xdd, 0xb5, 0x9b, 0xcb, 0x45, 0x36, 0x8a, 0x57, 0xc6, + 0x1b, 0xc5, 0x5a, 0x82, 0x6a, 0x75, 0xa9, 0xd7, 0x2d, 0x2f, 0x24, 0x4b, 0x71, 0x1f, 0x77, 0xb4, + 0x06, 0x0b, 0x96, 0xeb, 0x7a, 0xa1, 0x15, 0xda, 0x9e, 0xbb, 0xe5, 0x93, 0x5d, 0xfb, 0xce, 0x72, + 0x81, 0x75, 0x67, 0x59, 0x74, 0x67, 0xa1, 0x92, 0x80, 0xe3, 0xbe, 0x1a, 0xe6, 0x1a, 0x2c, 0x57, + 0x5a, 0x3b, 0x56, 0x10, 0x58, 0x0d, 0xcf, 0x4f, 0xcc, 0xc6, 0xe3, 0x50, 0x6a, 0x59, 0xed, 0xb6, + 0xed, 0x36, 0xe9, 0x74, 0xe4, 0x1f, 0x9f, 0xaa, 0xce, 0xf4, 0xba, 0xe5, 0xd2, 0xa6, 0x28, 0xc3, + 0x0a, 0x6a, 0x7e, 0x2f, 0x07, 0xd3, 0x15, 0xd7, 0x72, 0x0e, 0x02, 0x3b, 0xc0, 0x1d, 0x17, 0x7d, + 0x04, 0x4a, 0x54, 0xba, 0x34, 0xac, 0xd0, 0x12, 0x3b, 0xf2, 0x5d, 0x2b, 0x7c, 0xb3, 0xaf, 0xe8, + 0x9b, 0x3d, 0x1a, 0x17, 0x8a, 0xbd, 0xb2, 0xff, 0xee, 0x95, 0xab, 0x3b, 0x37, 0x49, 0x3d, 0xdc, + 0x24, 0xa1, 0x55, 0x45, 0xa2, 0x17, 0x10, 0x95, 0x61, 0x45, 0x15, 0x79, 0x50, 0x08, 0xda, 0xa4, + 0x2e, 0x76, 0xd8, 0xe6, 0x98, 0x2b, 0x39, 0x6a, 0x7a, 0xad, 0x4d, 0xea, 0xd5, 0x19, 0xc1, 0xba, + 0x40, 0xff, 0x61, 0xc6, 0x08, 0xdd, 0x86, 0x89, 0x80, 0xc9, 0x1c, 0xb1, 0x79, 0xae, 0x66, 0xc7, + 0x92, 0x91, 0xad, 0xce, 0x09, 0xa6, 0x13, 0xfc, 0x3f, 0x16, 0xec, 0xcc, 0x7f, 0x34, 0xe0, 0x84, + 0x86, 0x5d, 0xf1, 0x9b, 0x9d, 0x16, 0x71, 0x43, 0xf4, 0x08, 0x14, 0x5c, 0xab, 0x45, 0xc4, 0x46, + 0x51, 0x4d, 0xbe, 0x62, 0xb5, 0x08, 0x66, 0x10, 0xf4, 0x28, 0x14, 0xf7, 0x2d, 0xa7, 0x43, 0xd8, + 0x20, 0x4d, 0x55, 0x67, 0x05, 0x4a, 0xf1, 0x05, 0x5a, 0x88, 0x39, 0x0c, 0x7d, 0x1c, 0xa6, 0xd8, + 0x8f, 0x8b, 0xbe, 0xd7, 0xca, 0xa8, 0x6b, 0xa2, 0x85, 0x2f, 0x48, 0xb2, 0xd5, 0xd9, 0x5e, 0xb7, + 0x3c, 0xa5, 0xfe, 0xe2, 0x88, 0xa1, 0xf9, 0x4f, 0x06, 0xcc, 0x6b, 0x9d, 0xdb, 0xb0, 0x83, 0x10, + 0x7d, 0xa8, 0x6f, 0xf1, 0xac, 0x0c, 0xb7, 0x78, 0x68, 0x6d, 0xb6, 0x74, 0x16, 0x44, 0x4f, 0x4b, + 0xb2, 0x44, 0x5b, 0x38, 0x2e, 0x14, 0xed, 0x90, 0xb4, 0x82, 0xe5, 0xdc, 0x23, 0xf9, 0xc7, 0xa7, + 0xcf, 0xaf, 0x67, 0x36, 0x8d, 0xd1, 0xf8, 0xae, 0x53, 0xfa, 0x98, 0xb3, 0x31, 0xbf, 0x56, 0x88, + 0xf5, 0x90, 0xae, 0x28, 0xe4, 0xc1, 0x64, 0x8b, 0x84, 0xbe, 0x5d, 0xe7, 0xfb, 0x6a, 0xfa, 0xfc, + 0xda, 0x78, 0xad, 0xd8, 0x64, 0xc4, 0x22, 0x61, 0xc9, 0xff, 0x07, 0x58, 0x72, 0x41, 0x7b, 0x50, + 0xb0, 0xfc, 0xa6, 0xec, 0xf3, 0xc5, 0x6c, 0xe6, 0x37, 0x5a, 0x73, 0x15, 0xbf, 0x19, 0x60, 0xc6, + 0x01, 0x9d, 0x83, 0xa9, 0x90, 0xf8, 0x2d, 0xdb, 0xb5, 0x42, 0x2e, 0x5d, 0x4b, 0xd5, 0x45, 0x81, + 0x36, 0xb5, 0x2d, 0x01, 0x38, 0xc2, 0x41, 0x0e, 0x4c, 0x34, 0xfc, 0x03, 0xdc, 0x71, 0x97, 0x0b, + 0x59, 0x0c, 0xc5, 0x1a, 0xa3, 0x15, 0x6d, 0x26, 0xfe, 0x1f, 0x0b, 0x1e, 0xe8, 0x2b, 0x06, 0x2c, + 0xb5, 0x88, 0x15, 0x74, 0x7c, 0x42, 0xbb, 0x80, 0x49, 0x48, 0x5c, 0x2a, 0x0d, 0x97, 0x8b, 0x8c, + 0x39, 0x1e, 0x77, 0x1e, 0xfa, 0x29, 0x57, 0x1f, 0x16, 0x4d, 0x59, 0x4a, 0x83, 0xe2, 0xd4, 0xd6, + 0x98, 0xdf, 0x2b, 0xc0, 0x62, 0x9f, 0x84, 0x40, 0x4f, 0x42, 0xb1, 0xbd, 0x67, 0x05, 0x72, 0xcb, + 0x9f, 0x95, 0xeb, 0x6d, 0x8b, 0x16, 0xde, 0xed, 0x96, 0x67, 0x65, 0x15, 0x56, 0x80, 0x39, 0x32, + 0x3d, 0x53, 0x5b, 0x24, 0x08, 0xac, 0xa6, 0x94, 0x03, 0xda, 0x32, 0x61, 0xc5, 0x58, 0xc2, 0xd1, + 0xaf, 0x19, 0x30, 0xcb, 0x97, 0x0c, 0x26, 0x41, 0xc7, 0x09, 0xa9, 0xac, 0xa3, 0xc3, 0x72, 0x39, + 0x8b, 0xe5, 0xc9, 0x49, 0x56, 0x4f, 0x0a, 0xee, 0xb3, 0x7a, 0x69, 0x80, 0xe3, 0x7c, 0xd1, 0x0d, + 0x98, 0x0a, 0x42, 0xcb, 0x0f, 0x49, 0xa3, 0x12, 0xb2, 0x53, 0x6d, 0xfa, 0xfc, 0xff, 0x1f, 0x4e, + 0x08, 0x6c, 0xdb, 0x2d, 0xc2, 0x05, 0x4e, 0x4d, 0x12, 0xc0, 0x11, 0x2d, 0xf4, 0x71, 0x00, 0xbf, + 0xe3, 0xd6, 0x3a, 0xad, 0x96, 0xe5, 0x1f, 0x88, 0x13, 0xfc, 0xd2, 0x78, 0xdd, 0xc3, 0x8a, 0x5e, + 0x74, 0x66, 0x45, 0x65, 0x58, 0xe3, 0x87, 0x5e, 0x35, 0x60, 0x96, 0xaf, 0x44, 0xd9, 0x82, 0x89, + 0x8c, 0x5b, 0xb0, 0x48, 0x87, 0x76, 0x4d, 0x67, 0x81, 0xe3, 0x1c, 0xcd, 0xbf, 0x8f, 0x9f, 0x27, + 0xb5, 0x90, 0x6a, 0xd7, 0xcd, 0x03, 0xf4, 0x41, 0x78, 0x30, 0xe8, 0xd4, 0xeb, 0x24, 0x08, 0x76, + 0x3b, 0x0e, 0xee, 0xb8, 0x97, 0xec, 0x20, 0xf4, 0xfc, 0x83, 0x0d, 0xbb, 0x65, 0x87, 0x6c, 0xc5, + 0x15, 0xab, 0x67, 0x7a, 0xdd, 0xf2, 0x83, 0xb5, 0x41, 0x48, 0x78, 0x70, 0x7d, 0x64, 0xc1, 0x43, + 0x1d, 0x77, 0x30, 0x79, 0xae, 0xbd, 0x95, 0x7b, 0xdd, 0xf2, 0x43, 0xd7, 0x07, 0xa3, 0xe1, 0xc3, + 0x68, 0x98, 0xff, 0x66, 0xc0, 0x82, 0xec, 0xd7, 0x36, 0x69, 0xb5, 0x1d, 0x2a, 0x5d, 0x8e, 0x5f, + 0x11, 0x09, 0x63, 0x8a, 0x08, 0xce, 0xe6, 0x38, 0x91, 0xed, 0x1f, 0xa4, 0x8d, 0x98, 0xff, 0x6a, + 0xc0, 0x52, 0x12, 0xf9, 0x3e, 0x1c, 0x9e, 0x41, 0xfc, 0xf0, 0xbc, 0x92, 0x6d, 0x6f, 0x07, 0x9c, + 0xa0, 0xaf, 0x17, 0xfa, 0xfb, 0xfa, 0xbf, 0xfd, 0x18, 0x8d, 0x4e, 0xc5, 0xfc, 0x4f, 0xf3, 0x54, + 0x2c, 0xfc, 0x4c, 0x9d, 0x8a, 0xbf, 0x5f, 0x80, 0x99, 0x8a, 0x1b, 0xda, 0x95, 0xdd, 0x5d, 0xdb, + 0xb5, 0xc3, 0x03, 0xf4, 0x99, 0x1c, 0x9c, 0x6b, 0xfb, 0x64, 0x97, 0xf8, 0x3e, 0x69, 0xac, 0x75, + 0x7c, 0xdb, 0x6d, 0xd6, 0xea, 0x7b, 0xa4, 0xd1, 0x71, 0x6c, 0xb7, 0xb9, 0xde, 0x74, 0x3d, 0x55, + 0x7c, 0xe1, 0x0e, 0xa9, 0x77, 0x58, 0x97, 0xf8, 0xa6, 0x68, 0x8d, 0xd7, 0xa5, 0xad, 0xd1, 0x98, + 0x56, 0x9f, 0xe8, 0x75, 0xcb, 0xe7, 0x46, 0xac, 0x84, 0x47, 0xed, 0x1a, 0xfa, 0x74, 0x0e, 0x56, + 0x7c, 0xf2, 0xd1, 0x8e, 0x3d, 0xfc, 0x68, 0x70, 0xa9, 0xe5, 0x8c, 0x79, 0xfc, 0x8c, 0xc4, 0xb3, + 0x7a, 0xbe, 0xd7, 0x2d, 0x8f, 0x58, 0x07, 0x8f, 0xd8, 0x2f, 0xf3, 0x2f, 0x0d, 0x28, 0x8d, 0x60, + 0x29, 0x95, 0xe3, 0x96, 0xd2, 0x54, 0x9f, 0x95, 0x14, 0xf6, 0x5b, 0x49, 0xcf, 0x8d, 0x37, 0x68, + 0xc3, 0x58, 0x47, 0xff, 0x61, 0xc0, 0x62, 0x9f, 0x35, 0x85, 0xf6, 0x60, 0xa9, 0xed, 0x35, 0xa4, + 0x24, 0xbc, 0x64, 0x05, 0x7b, 0x0c, 0x26, 0xba, 0xf7, 0x24, 0xdd, 0x54, 0x5b, 0x29, 0xf0, 0xbb, + 0xdd, 0xf2, 0xb2, 0x22, 0x92, 0x40, 0xc0, 0xa9, 0x14, 0x51, 0x1b, 0x4a, 0xbb, 0x36, 0x71, 0x1a, + 0x98, 0xec, 0x8a, 0x95, 0x32, 0xa6, 0xcc, 0xbb, 0x28, 0xa8, 0xf1, 0x8b, 0x04, 0xf9, 0x0f, 0x2b, + 0x2e, 0xe6, 0x35, 0x98, 0x8b, 0x5f, 0x2b, 0x0d, 0x31, 0x79, 0x67, 0x20, 0x6f, 0xf9, 0xae, 0x98, + 0xba, 0x69, 0x81, 0x90, 0xaf, 0xe0, 0x2b, 0x98, 0x96, 0x9b, 0x3f, 0x29, 0xc0, 0x7c, 0xd5, 0xe9, + 0x90, 0xe7, 0x7c, 0x42, 0xa4, 0x26, 0x5d, 0x81, 0xf9, 0xb6, 0x4f, 0xf6, 0x6d, 0x72, 0xbb, 0x46, + 0x1c, 0x52, 0x0f, 0x3d, 0x5f, 0xd0, 0x3f, 0x25, 0xaa, 0xcf, 0x6f, 0xc5, 0xc1, 0x38, 0x89, 0x8f, + 0x9e, 0x85, 0x39, 0xab, 0x1e, 0xda, 0xfb, 0x44, 0x51, 0xe0, 0x0d, 0x78, 0x8b, 0xa0, 0x30, 0x57, + 0x89, 0x41, 0x71, 0x02, 0x1b, 0x7d, 0x08, 0x96, 0x83, 0xba, 0xe5, 0x90, 0xeb, 0x6d, 0xc1, 0x6a, + 0x75, 0x8f, 0xd4, 0x6f, 0x6d, 0x79, 0xb6, 0x1b, 0x0a, 0xbb, 0xe9, 0x11, 0x41, 0x69, 0xb9, 0x36, + 0x00, 0x0f, 0x0f, 0xa4, 0x80, 0xfe, 0xcc, 0x80, 0x33, 0x6d, 0x9f, 0x6c, 0xf9, 0x5e, 0xcb, 0xa3, + 0x1b, 0xa2, 0xcf, 0x98, 0x10, 0x4a, 0xf5, 0x0b, 0x63, 0xee, 0x7c, 0x5e, 0xd2, 0x7f, 0x99, 0xf1, + 0xd6, 0x5e, 0xb7, 0x7c, 0x66, 0xeb, 0xb0, 0x06, 0xe0, 0xc3, 0xdb, 0x87, 0xfe, 0xc2, 0x80, 0xb3, + 0x6d, 0x2f, 0x08, 0x0f, 0xe9, 0x42, 0xf1, 0x58, 0xbb, 0x60, 0xf6, 0xba, 0xe5, 0xb3, 0x5b, 0x87, + 0xb6, 0x00, 0xdf, 0xa3, 0x85, 0x66, 0x6f, 0x1a, 0x16, 0xb5, 0xb5, 0x27, 0x34, 0xed, 0x67, 0x60, + 0x56, 0x2e, 0x06, 0x7e, 0x0b, 0xc9, 0xd7, 0x9e, 0xb2, 0x8c, 0x2a, 0x3a, 0x10, 0xc7, 0x71, 0xe9, + 0xba, 0x53, 0x4b, 0x91, 0xd7, 0x4e, 0xac, 0xbb, 0xad, 0x18, 0x14, 0x27, 0xb0, 0xd1, 0x3a, 0x9c, + 0x10, 0x25, 0x98, 0xb4, 0x1d, 0xbb, 0x6e, 0xad, 0x7a, 0x1d, 0xb1, 0xe4, 0x8a, 0xd5, 0x53, 0xbd, + 0x6e, 0xf9, 0xc4, 0x56, 0x3f, 0x18, 0xa7, 0xd5, 0x41, 0x1b, 0xb0, 0x64, 0x75, 0x42, 0x4f, 0xf5, + 0xff, 0x82, 0x6b, 0xed, 0x38, 0xa4, 0xc1, 0x96, 0x56, 0xa9, 0xba, 0x4c, 0x05, 0x51, 0x25, 0x05, + 0x8e, 0x53, 0x6b, 0xa1, 0xad, 0x04, 0xb5, 0x1a, 0xa9, 0x7b, 0x6e, 0x83, 0xcf, 0x72, 0x31, 0xd2, + 0x17, 0x2a, 0x29, 0x38, 0x38, 0xb5, 0x26, 0x72, 0x60, 0xae, 0x65, 0xdd, 0xb9, 0xee, 0x5a, 0xfb, + 0x96, 0xed, 0x50, 0x26, 0xc2, 0xda, 0x1a, 0x6c, 0x02, 0x74, 0x42, 0xdb, 0x59, 0xe1, 0x8e, 0x87, + 0x95, 0x75, 0x37, 0xbc, 0xea, 0xd7, 0x42, 0x7a, 0xae, 0x54, 0x11, 0x1d, 0xd8, 0xcd, 0x18, 0x2d, + 0x9c, 0xa0, 0x8d, 0xae, 0xc2, 0x49, 0xb6, 0x1d, 0xd7, 0xbc, 0xdb, 0xee, 0x1a, 0x71, 0xac, 0x03, + 0xd9, 0x81, 0x49, 0xd6, 0x81, 0x07, 0x7b, 0xdd, 0xf2, 0xc9, 0x5a, 0x1a, 0x02, 0x4e, 0xaf, 0x47, + 0x6d, 0xa6, 0x38, 0x00, 0x93, 0x7d, 0x3b, 0xb0, 0x3d, 0x97, 0xdb, 0x4c, 0xa5, 0xc8, 0x66, 0xaa, + 0x0d, 0x46, 0xc3, 0x87, 0xd1, 0x40, 0xbf, 0x63, 0xc0, 0x52, 0xda, 0x36, 0x5c, 0x9e, 0xca, 0xe2, + 0x5a, 0x35, 0xb1, 0xb5, 0xf8, 0x8a, 0x48, 0x15, 0x0a, 0xa9, 0x8d, 0x40, 0xaf, 0x18, 0x30, 0x63, + 0x69, 0xfa, 0xde, 0x32, 0xb0, 0x56, 0x5d, 0x1e, 0xd7, 0xea, 0x88, 0x28, 0x56, 0x17, 0x7a, 0xdd, + 0x72, 0x4c, 0xa7, 0xc4, 0x31, 0x8e, 0xe8, 0x77, 0x0d, 0x38, 0x99, 0xba, 0xc7, 0x97, 0xa7, 0x8f, + 0x63, 0x84, 0xd8, 0x22, 0x49, 0x97, 0x39, 0xe9, 0xcd, 0x40, 0x6f, 0x18, 0xea, 0x28, 0xdb, 0x94, + 0x76, 0xdf, 0x0c, 0x6b, 0xda, 0xb5, 0x31, 0x55, 0xdc, 0x48, 0x21, 0x90, 0x84, 0xab, 0x27, 0xb4, + 0x93, 0x51, 0x16, 0xe2, 0x24, 0x7b, 0xf4, 0x59, 0x43, 0x1e, 0x8d, 0xaa, 0x45, 0xb3, 0xc7, 0xd5, + 0x22, 0x14, 0x9d, 0xb4, 0xaa, 0x41, 0x09, 0xe6, 0xe8, 0xc3, 0x70, 0xda, 0xda, 0xf1, 0xfc, 0x30, + 0x75, 0xf3, 0x2d, 0xcf, 0xb1, 0x6d, 0x74, 0xb6, 0xd7, 0x2d, 0x9f, 0xae, 0x0c, 0xc4, 0xc2, 0x87, + 0x50, 0x30, 0xbf, 0x5f, 0x80, 0x19, 0xee, 0x8b, 0x13, 0x47, 0xd7, 0xd7, 0x0d, 0x78, 0xb8, 0xde, + 0xf1, 0x7d, 0xe2, 0x86, 0xb5, 0x90, 0xb4, 0xfb, 0x0f, 0x2e, 0xe3, 0x58, 0x0f, 0xae, 0x47, 0x7a, + 0xdd, 0xf2, 0xc3, 0xab, 0x87, 0xf0, 0xc7, 0x87, 0xb6, 0x0e, 0xfd, 0x8d, 0x01, 0xa6, 0x40, 0xa8, + 0x5a, 0xf5, 0x5b, 0x4d, 0xdf, 0xeb, 0xb8, 0x8d, 0xfe, 0x4e, 0xe4, 0x8e, 0xb5, 0x13, 0x8f, 0xf5, + 0xba, 0x65, 0x73, 0xf5, 0x9e, 0xad, 0xc0, 0x43, 0xb4, 0x14, 0x3d, 0x07, 0x8b, 0x02, 0xeb, 0xc2, + 0x9d, 0x36, 0xf1, 0x6d, 0xaa, 0x4e, 0x0b, 0xcf, 0x5f, 0xe4, 0x4c, 0x4d, 0x22, 0xe0, 0xfe, 0x3a, + 0x28, 0x80, 0xc9, 0xdb, 0xc4, 0x6e, 0xee, 0x85, 0x52, 0x7d, 0x1a, 0xd3, 0x83, 0x2a, 0xfc, 0x6d, + 0x37, 0x38, 0xcd, 0xea, 0x74, 0xaf, 0x5b, 0x9e, 0x14, 0x7f, 0xb0, 0xe4, 0x64, 0xfe, 0x51, 0x01, + 0x40, 0x2e, 0x2f, 0xd2, 0x46, 0xbf, 0x00, 0x53, 0x01, 0x09, 0x39, 0x96, 0xb8, 0x96, 0xe3, 0xb7, + 0x9d, 0xb2, 0x10, 0x47, 0x70, 0x74, 0x0b, 0x8a, 0x6d, 0xab, 0x13, 0x10, 0x31, 0x59, 0x97, 0x33, + 0x99, 0xac, 0x2d, 0x4a, 0x91, 0xdb, 0x48, 0xec, 0x27, 0xe6, 0x3c, 0xd0, 0xa7, 0x0c, 0x00, 0x12, + 0x1f, 0xe0, 0xe9, 0xf3, 0xb5, 0x4c, 0x58, 0x46, 0x73, 0x40, 0xc7, 0xa0, 0x3a, 0xd7, 0xeb, 0x96, + 0x41, 0x9b, 0x2a, 0x8d, 0x2d, 0xba, 0x0d, 0x25, 0x4b, 0xca, 0xe8, 0xc2, 0x71, 0xc8, 0x68, 0x66, + 0xba, 0xa8, 0x45, 0xa6, 0x98, 0xa1, 0x4f, 0x1b, 0x30, 0x17, 0x90, 0x50, 0x4c, 0x15, 0x95, 0x14, + 0x42, 0x41, 0x1d, 0x73, 0x91, 0xd4, 0x62, 0x34, 0xb9, 0xc4, 0x8b, 0x97, 0xe1, 0x04, 0x5f, 0xf3, + 0xfb, 0xd3, 0x30, 0x27, 0x97, 0x4c, 0xa4, 0x73, 0xf2, 0xe0, 0x80, 0x01, 0x3a, 0xe7, 0xaa, 0x0e, + 0xc4, 0x71, 0x5c, 0x5a, 0x99, 0x7b, 0xf0, 0xe3, 0x2a, 0xa7, 0xaa, 0x5c, 0xd3, 0x81, 0x38, 0x8e, + 0x8b, 0x5a, 0x50, 0x0c, 0x42, 0xd2, 0x96, 0xbe, 0x84, 0x31, 0xaf, 0xba, 0xa3, 0x9d, 0x10, 0xdd, + 0x16, 0xd2, 0x7f, 0x01, 0xe6, 0x5c, 0xd0, 0xe7, 0x0c, 0x98, 0x0b, 0x63, 0x7e, 0x6c, 0xb1, 0x0c, + 0xb2, 0x59, 0x89, 0x71, 0x17, 0x39, 0x9f, 0x8d, 0x78, 0x19, 0x4e, 0xb0, 0x4f, 0x51, 0x43, 0x8b, + 0xc7, 0xa8, 0x86, 0xbe, 0x08, 0xa5, 0x96, 0x75, 0xa7, 0xd6, 0xf1, 0x9b, 0x47, 0x57, 0x77, 0x85, + 0x9b, 0x9f, 0x53, 0xc1, 0x8a, 0x1e, 0x7a, 0xd5, 0xd0, 0x36, 0xd7, 0x24, 0x23, 0x7e, 0x23, 0xdb, + 0xcd, 0xa5, 0xa4, 0xf8, 0xc0, 0x6d, 0xd6, 0xa7, 0x14, 0x96, 0xee, 0xbb, 0x52, 0x48, 0x15, 0x1c, + 0xbe, 0x41, 0x94, 0x82, 0x33, 0x75, 0xac, 0x0a, 0xce, 0x6a, 0x8c, 0x19, 0x4e, 0x30, 0x67, 0xed, + 0xe1, 0x7b, 0x4e, 0xb5, 0x07, 0x8e, 0xb5, 0x3d, 0xb5, 0x18, 0x33, 0x9c, 0x60, 0x3e, 0xd8, 0x12, + 0x9a, 0x3e, 0x1e, 0x4b, 0x68, 0x26, 0x03, 0x4b, 0xe8, 0x70, 0x25, 0x71, 0x76, 0x5c, 0x25, 0x11, + 0x5d, 0x06, 0xd4, 0x38, 0x70, 0xad, 0x96, 0x5d, 0x17, 0xc2, 0x92, 0x1d, 0x10, 0x73, 0xcc, 0x52, + 0x3e, 0x2d, 0x04, 0x19, 0x5a, 0xeb, 0xc3, 0xc0, 0x29, 0xb5, 0xcc, 0xff, 0x32, 0x60, 0x61, 0xd5, + 0xf1, 0x3a, 0x8d, 0x1b, 0x56, 0x58, 0xdf, 0xe3, 0x5e, 0x0a, 0xf4, 0x2c, 0x94, 0x6c, 0x37, 0x24, + 0xfe, 0xbe, 0xe5, 0x08, 0xd9, 0x6e, 0x4a, 0x47, 0xce, 0xba, 0x28, 0xbf, 0xdb, 0x2d, 0xcf, 0xad, + 0x75, 0x7c, 0x16, 0xfe, 0xc3, 0x77, 0x3a, 0x56, 0x75, 0xd0, 0x97, 0x0d, 0x58, 0xe4, 0x7e, 0x8e, + 0x35, 0x2b, 0xb4, 0xae, 0x75, 0x88, 0x6f, 0x13, 0xe9, 0xe9, 0x18, 0x73, 0x93, 0x27, 0xdb, 0x2a, + 0x19, 0x1c, 0x44, 0xea, 0xd7, 0x66, 0x92, 0x33, 0xee, 0x6f, 0x8c, 0xf9, 0xf9, 0x3c, 0x3c, 0x38, + 0x90, 0x16, 0x3a, 0x0d, 0x39, 0xbb, 0x21, 0xba, 0x0e, 0x82, 0x6e, 0x6e, 0xbd, 0x81, 0x73, 0x76, + 0x03, 0xad, 0x30, 0xcd, 0xc4, 0x27, 0x41, 0x20, 0x2f, 0xbd, 0xa7, 0x94, 0x12, 0x21, 0x4a, 0xb1, + 0x86, 0x81, 0xca, 0x50, 0x74, 0xac, 0x1d, 0xe2, 0x08, 0x2d, 0x91, 0xe9, 0x3a, 0x1b, 0xb4, 0x00, + 0xf3, 0x72, 0xf4, 0xab, 0x06, 0x00, 0x6f, 0x20, 0xd5, 0x31, 0xc5, 0x09, 0x83, 0xb3, 0x1d, 0x26, + 0x4a, 0x99, 0xb7, 0x32, 0xfa, 0x8f, 0x35, 0xae, 0x68, 0x1b, 0x26, 0xa8, 0xda, 0xe3, 0x35, 0x8e, + 0x7c, 0xa0, 0x40, 0xaf, 0x5b, 0x9e, 0xd8, 0x62, 0x34, 0xb0, 0xa0, 0x45, 0xc7, 0xca, 0x27, 0x61, + 0xc7, 0x77, 0xe9, 0xd0, 0xb2, 0x23, 0xa4, 0xc4, 0x5b, 0x81, 0x55, 0x29, 0xd6, 0x30, 0xcc, 0x3f, + 0xcd, 0xc1, 0x52, 0x5a, 0xd3, 0xa9, 0xa4, 0x9e, 0xe0, 0xad, 0x15, 0x06, 0xcf, 0xfb, 0xb3, 0x1f, + 0x1f, 0xe1, 0xb2, 0x53, 0x8e, 0x2d, 0x11, 0x54, 0x20, 0xf8, 0xa2, 0xf7, 0xab, 0x11, 0xca, 0x1d, + 0x71, 0x84, 0x14, 0xe5, 0xc4, 0x28, 0x3d, 0x02, 0x85, 0x80, 0xce, 0x7c, 0x3e, 0x7e, 0x2d, 0xcd, + 0xe6, 0x88, 0x41, 0x28, 0x46, 0xc7, 0xb5, 0x43, 0x11, 0x93, 0xa7, 0x30, 0xae, 0xbb, 0x76, 0x88, + 0x19, 0xc4, 0xfc, 0x62, 0x0e, 0x4e, 0x0f, 0xee, 0x14, 0xfa, 0xa2, 0x01, 0xd0, 0xa0, 0x4a, 0x2d, + 0x5d, 0x92, 0xd2, 0xc5, 0x69, 0x1d, 0xd7, 0x18, 0xae, 0x49, 0x4e, 0x91, 0xbf, 0x5b, 0x15, 0x05, + 0x58, 0x6b, 0x08, 0x3a, 0x2f, 0x97, 0xfe, 0x15, 0xab, 0x25, 0x55, 0x41, 0x55, 0x67, 0x53, 0x41, + 0xb0, 0x86, 0x45, 0xad, 0x16, 0xd7, 0x6a, 0x91, 0xa0, 0x6d, 0xa9, 0xa0, 0x4b, 0x66, 0xb5, 0x5c, + 0x91, 0x85, 0x38, 0x82, 0x9b, 0x0e, 0x3c, 0x3a, 0x44, 0x3b, 0x33, 0x0a, 0x80, 0x33, 0xff, 0xd3, + 0x80, 0x53, 0xab, 0x4e, 0x27, 0x08, 0x89, 0xff, 0x7f, 0x26, 0x7c, 0xe0, 0xbf, 0x0d, 0x78, 0x68, + 0x40, 0x9f, 0xef, 0x43, 0x14, 0xc1, 0xcb, 0xf1, 0x28, 0x82, 0xeb, 0xe3, 0x2e, 0xe9, 0xd4, 0x7e, + 0x0c, 0x08, 0x26, 0x08, 0x61, 0x96, 0x4a, 0xad, 0x86, 0xd7, 0xcc, 0xe8, 0xdc, 0x7c, 0x14, 0x8a, + 0x1f, 0xa5, 0xe7, 0x4f, 0x72, 0x8d, 0xb1, 0x43, 0x09, 0x73, 0x98, 0xf9, 0x3e, 0x10, 0x2e, 0xf7, + 0xc4, 0xe6, 0x31, 0x86, 0xd9, 0x3c, 0xe6, 0x3f, 0xe4, 0x40, 0xb3, 0x76, 0xef, 0xc3, 0xa2, 0x74, + 0x63, 0x8b, 0x72, 0x4c, 0xfb, 0x55, 0xb3, 0xdd, 0x07, 0xc5, 0xd6, 0xee, 0x27, 0x62, 0x6b, 0xaf, + 0x64, 0xc6, 0xf1, 0xf0, 0xd0, 0xda, 0xef, 0x18, 0xf0, 0x50, 0x84, 0xdc, 0x7f, 0x71, 0x74, 0x6f, + 0x09, 0xf3, 0x14, 0x4c, 0x5b, 0x51, 0x35, 0xb1, 0x06, 0x54, 0x38, 0xb9, 0x46, 0x11, 0xeb, 0x78, + 0x51, 0x24, 0x5f, 0xfe, 0x88, 0x91, 0x7c, 0x85, 0xc3, 0x23, 0xf9, 0xcc, 0x1f, 0xe7, 0xe0, 0x4c, + 0x7f, 0xcf, 0xe4, 0xde, 0x18, 0xce, 0xaf, 0xfa, 0x34, 0xcc, 0x84, 0xa2, 0x82, 0x26, 0xe9, 0xd5, + 0x63, 0x88, 0x6d, 0x0d, 0x86, 0x63, 0x98, 0xb4, 0x66, 0x9d, 0xef, 0xca, 0x5a, 0xdd, 0x6b, 0xcb, + 0x38, 0x50, 0x55, 0x73, 0x55, 0x83, 0xe1, 0x18, 0xa6, 0x8a, 0xb0, 0x29, 0x1c, 0x7b, 0x84, 0x4d, + 0x0d, 0x4e, 0xca, 0x98, 0x82, 0x8b, 0x9e, 0xbf, 0xea, 0xb5, 0xda, 0x0e, 0x11, 0x91, 0xa0, 0xb4, + 0xb1, 0x67, 0x44, 0x95, 0x93, 0x38, 0x0d, 0x09, 0xa7, 0xd7, 0x35, 0xbf, 0x93, 0x87, 0x13, 0xd1, + 0xb0, 0xaf, 0x7a, 0x6e, 0xc3, 0x66, 0x91, 0x19, 0xcf, 0x40, 0x21, 0x3c, 0x68, 0xcb, 0xc1, 0xfe, + 0x7f, 0xb2, 0x39, 0xdb, 0x07, 0x6d, 0x3a, 0xdb, 0xa7, 0x52, 0xaa, 0x50, 0x10, 0x66, 0x95, 0xd0, + 0x86, 0xda, 0x1d, 0x7c, 0x06, 0x9e, 0x8c, 0xaf, 0xe6, 0xbb, 0xdd, 0x72, 0xca, 0x5b, 0xa0, 0x15, + 0x45, 0x29, 0xbe, 0xe6, 0xd1, 0x4d, 0x98, 0x73, 0xac, 0x20, 0xbc, 0xde, 0x6e, 0x58, 0x21, 0xd9, + 0xb6, 0x5b, 0x44, 0xec, 0xb9, 0x51, 0xc2, 0x2b, 0x95, 0xaf, 0x71, 0x23, 0x46, 0x09, 0x27, 0x28, + 0xa3, 0x7d, 0x40, 0xb4, 0x64, 0xdb, 0xb7, 0xdc, 0x80, 0xf7, 0x8a, 0xf2, 0x1b, 0x3d, 0x9c, 0x53, + 0x19, 0x48, 0x1b, 0x7d, 0xd4, 0x70, 0x0a, 0x07, 0xf4, 0x18, 0x4c, 0xf8, 0xc4, 0x0a, 0xc4, 0x64, + 0x4e, 0x45, 0xfb, 0x1f, 0xb3, 0x52, 0x2c, 0xa0, 0xfa, 0x86, 0x9a, 0xb8, 0xc7, 0x86, 0xfa, 0x81, + 0x01, 0x73, 0xd1, 0x34, 0xdd, 0x87, 0x43, 0xb2, 0x15, 0x3f, 0x24, 0x2f, 0x65, 0x25, 0x12, 0x07, + 0x9c, 0x8b, 0x5f, 0x2e, 0xea, 0xfd, 0x63, 0xe1, 0x75, 0x1f, 0x83, 0x29, 0xb9, 0xab, 0xa5, 0xf6, + 0x39, 0xe6, 0x2d, 0x4b, 0x4c, 0x2f, 0xd1, 0xc2, 0xc2, 0x05, 0x13, 0x1c, 0xf1, 0xa3, 0xc7, 0x72, + 0x43, 0x1c, 0xb9, 0x62, 0xd9, 0xab, 0x63, 0x59, 0x1e, 0xc5, 0x69, 0xc7, 0xb2, 0xac, 0x83, 0xae, + 0xc3, 0xa9, 0xb6, 0xef, 0xb1, 0xa7, 0x42, 0x6b, 0xc4, 0x6a, 0x38, 0xb6, 0x4b, 0xa4, 0x31, 0xcf, + 0x5d, 0xdd, 0x0f, 0xf5, 0xba, 0xe5, 0x53, 0x5b, 0xe9, 0x28, 0x78, 0x50, 0xdd, 0x78, 0x78, 0x7b, + 0x61, 0x88, 0xf0, 0xf6, 0x5f, 0x57, 0x57, 0x66, 0x24, 0x10, 0x41, 0xe6, 0x1f, 0xcc, 0x6a, 0x2a, + 0x53, 0xc4, 0x7a, 0xb4, 0xa4, 0x2a, 0x82, 0x29, 0x56, 0xec, 0x07, 0xdf, 0xcb, 0x4c, 0x1c, 0xf1, + 0x5e, 0x26, 0x8a, 0x52, 0x9c, 0x3c, 0xfe, 0x28, 0x45, 0xf3, 0xb5, 0x22, 0x2c, 0x24, 0x8f, 0xf6, + 0xe3, 0x8f, 0x89, 0xff, 0x2d, 0x03, 0x16, 0xe4, 0xb2, 0xe4, 0x3c, 0x89, 0xbc, 0xca, 0xde, 0xc8, + 0x68, 0x37, 0x70, 0x25, 0x45, 0xbd, 0xda, 0xda, 0x4e, 0x70, 0xc3, 0x7d, 0xfc, 0xd1, 0x4b, 0x30, + 0xad, 0x6e, 0x7c, 0x8f, 0x14, 0x20, 0x3f, 0xcf, 0xd4, 0x93, 0x88, 0x04, 0xd6, 0xe9, 0xa1, 0xd7, + 0x0c, 0x80, 0xba, 0x3c, 0x3f, 0xe4, 0xb2, 0xbd, 0x96, 0xd5, 0xb2, 0x55, 0x27, 0x53, 0xa4, 0x85, + 0xaa, 0xa2, 0x00, 0x6b, 0x8c, 0xd1, 0xe7, 0xd9, 0x5d, 0xaf, 0x52, 0x9b, 0xe8, 0x42, 0xa5, 0x2d, + 0xf9, 0x40, 0xd6, 0x1b, 0x28, 0x72, 0x3b, 0x2a, 0x1d, 0x45, 0x03, 0x05, 0x38, 0xd6, 0x08, 0xf3, + 0x19, 0x50, 0x91, 0x6b, 0x54, 0x1e, 0xb0, 0xd8, 0xb5, 0x2d, 0x2b, 0xdc, 0x13, 0x4b, 0x50, 0xc9, + 0x83, 0x8b, 0x12, 0x80, 0x23, 0x1c, 0xf3, 0x23, 0x30, 0xf7, 0x9c, 0x6f, 0xb5, 0xf7, 0x6c, 0x76, + 0xa7, 0x4a, 0x0d, 0x90, 0xb7, 0xc3, 0xa4, 0xd5, 0x68, 0xa4, 0xbd, 0x79, 0xac, 0xf0, 0x62, 0x2c, + 0xe1, 0xc3, 0xd9, 0x1a, 0xdf, 0x30, 0x60, 0x69, 0x3d, 0x08, 0x6d, 0x6f, 0x8d, 0x04, 0x21, 0x15, + 0x42, 0x54, 0x5f, 0xe9, 0x38, 0x64, 0x08, 0x8d, 0x6f, 0x0d, 0x16, 0x84, 0xe3, 0xa7, 0xb3, 0x13, + 0x90, 0x50, 0xd3, 0xfa, 0xd4, 0xe2, 0x5c, 0x4d, 0xc0, 0x71, 0x5f, 0x0d, 0x4a, 0x45, 0x78, 0x80, + 0x22, 0x2a, 0xf9, 0x38, 0x95, 0x5a, 0x02, 0x8e, 0xfb, 0x6a, 0x98, 0xdf, 0xce, 0xc3, 0x09, 0xd6, + 0x8d, 0xc4, 0xa3, 0xc4, 0xcf, 0x1a, 0x30, 0xb7, 0x6f, 0xfb, 0x61, 0xc7, 0x72, 0x74, 0x57, 0xd6, + 0xd8, 0xeb, 0x93, 0xf1, 0x7a, 0x21, 0x46, 0x98, 0x5f, 0x76, 0xc7, 0xcb, 0x70, 0x82, 0x39, 0xfa, + 0x4d, 0x03, 0xe6, 0x1b, 0xf1, 0x91, 0xce, 0xc6, 0x98, 0x4f, 0x9b, 0x43, 0x1e, 0x81, 0x91, 0x28, + 0xc4, 0x49, 0xfe, 0xe8, 0x0b, 0x06, 0xcc, 0xc7, 0x9b, 0x29, 0x45, 0xd6, 0x31, 0x0c, 0x92, 0x0a, + 0x99, 0x8c, 0x97, 0x07, 0x38, 0xd9, 0x04, 0xf3, 0xef, 0x0c, 0x31, 0xa5, 0x71, 0xcc, 0x21, 0x16, + 0xa6, 0x09, 0x13, 0xbe, 0xd7, 0x09, 0xc5, 0x85, 0xf4, 0x14, 0xbf, 0xb7, 0xc4, 0xac, 0x04, 0x0b, + 0x08, 0xba, 0x0d, 0x53, 0xa1, 0x13, 0xf0, 0x42, 0xd1, 0xdb, 0x31, 0xed, 0x87, 0xed, 0x8d, 0x1a, + 0x23, 0xa7, 0x1d, 0xf1, 0xa2, 0x84, 0xaa, 0x2a, 0x92, 0x97, 0xf9, 0x55, 0x03, 0xa6, 0x2e, 0x7b, + 0x3b, 0x62, 0x3b, 0x7f, 0x38, 0x03, 0xeb, 0x5c, 0x1d, 0xe2, 0xca, 0xc5, 0x12, 0xe9, 0x85, 0xcf, + 0xc6, 0x6c, 0xf3, 0x87, 0x35, 0xda, 0x2b, 0x2c, 0x57, 0x00, 0x25, 0x75, 0xd9, 0xdb, 0x19, 0x78, + 0xf5, 0xf3, 0x7b, 0x45, 0x98, 0x7d, 0xde, 0x3a, 0x20, 0x6e, 0x68, 0x8d, 0x2e, 0x80, 0xa8, 0xb9, + 0xdb, 0x66, 0x11, 0x80, 0x9a, 0x62, 0x16, 0x99, 0xbb, 0x11, 0x08, 0xeb, 0x78, 0x91, 0x5c, 0xe1, + 0x4f, 0x97, 0xd3, 0x24, 0xc2, 0x6a, 0x02, 0x8e, 0xfb, 0x6a, 0xa0, 0xcb, 0x80, 0xc4, 0x43, 0x8c, + 0x4a, 0xbd, 0xee, 0x75, 0x5c, 0x2e, 0x59, 0xb8, 0x25, 0xac, 0x2c, 0x84, 0xcd, 0x3e, 0x0c, 0x9c, + 0x52, 0x0b, 0x7d, 0x08, 0x96, 0xeb, 0x8c, 0xb2, 0xd0, 0x17, 0x75, 0x8a, 0xdc, 0x66, 0x50, 0xd1, + 0xb7, 0xab, 0x03, 0xf0, 0xf0, 0x40, 0x0a, 0xb4, 0xa5, 0x41, 0xe8, 0xf9, 0x56, 0x93, 0xe8, 0x74, + 0x27, 0xe2, 0x2d, 0xad, 0xf5, 0x61, 0xe0, 0x94, 0x5a, 0xe8, 0x93, 0x30, 0x15, 0xee, 0xf9, 0x24, + 0xd8, 0xf3, 0x9c, 0x86, 0xf0, 0xb9, 0x8e, 0x79, 0x3d, 0x22, 0x66, 0x7f, 0x5b, 0x52, 0xd5, 0x96, + 0xb7, 0x2c, 0xc2, 0x11, 0x4f, 0xe4, 0xc3, 0x44, 0x40, 0x6d, 0xf3, 0x60, 0xb9, 0x94, 0x85, 0x0d, + 0x20, 0xb8, 0x33, 0x73, 0x5f, 0xbb, 0x98, 0x61, 0x1c, 0xb0, 0xe0, 0x64, 0x7e, 0x33, 0x07, 0x33, + 0x3a, 0xe2, 0x10, 0x22, 0xe2, 0x53, 0x06, 0xcc, 0xd4, 0x3d, 0x37, 0xf4, 0x3d, 0x87, 0x5f, 0x3a, + 0xf0, 0x0d, 0x32, 0xe6, 0xfb, 0x5e, 0x46, 0x6a, 0x8d, 0x84, 0x96, 0xed, 0x68, 0xf7, 0x17, 0x1a, + 0x1b, 0x1c, 0x63, 0x8a, 0x3e, 0x63, 0xc0, 0x7c, 0x14, 0x8c, 0x12, 0xdd, 0x7e, 0x64, 0xda, 0x10, + 0x25, 0x71, 0x2f, 0xc4, 0x39, 0xe1, 0x24, 0x6b, 0x73, 0x07, 0x16, 0x92, 0xb3, 0x4d, 0x87, 0xb2, + 0x6d, 0x89, 0xbd, 0x9e, 0x8f, 0x86, 0x72, 0xcb, 0x0a, 0x02, 0xcc, 0x20, 0xe8, 0x1d, 0x50, 0x6a, + 0x59, 0x7e, 0xd3, 0x76, 0x2d, 0x87, 0x8d, 0x62, 0x5e, 0x13, 0x48, 0xa2, 0x1c, 0x2b, 0x0c, 0xf3, + 0x47, 0x05, 0x98, 0xd6, 0x1e, 0xf1, 0x1c, 0xbf, 0x46, 0x1e, 0x7b, 0x1b, 0x9a, 0xcf, 0xf0, 0x6d, + 0xe8, 0x8b, 0x00, 0xbb, 0xb6, 0x6b, 0x07, 0x7b, 0x47, 0x7c, 0x75, 0xca, 0xbc, 0x64, 0x17, 0x15, + 0x05, 0xac, 0x51, 0x8b, 0x5c, 0x11, 0xc5, 0x43, 0xde, 0xe2, 0xbf, 0x66, 0x68, 0x87, 0xc7, 0x44, + 0x16, 0xae, 0x57, 0x6d, 0x62, 0x56, 0xe4, 0x61, 0x72, 0xc1, 0x0d, 0xfd, 0x83, 0x43, 0xcf, 0x98, + 0x6d, 0x28, 0xf9, 0x24, 0xe8, 0xb4, 0xa8, 0x6d, 0x31, 0x39, 0xf2, 0x30, 0xb0, 0xc8, 0x0d, 0x2c, + 0xea, 0x63, 0x45, 0xe9, 0xf4, 0x33, 0x30, 0x1b, 0x6b, 0x02, 0x5a, 0x80, 0xfc, 0x2d, 0x72, 0xc0, + 0xd7, 0x09, 0xa6, 0x3f, 0xd1, 0x52, 0xcc, 0x61, 0x23, 0x86, 0xe5, 0xbd, 0xb9, 0xa7, 0x0d, 0xd3, + 0x83, 0xd4, 0x97, 0x62, 0x47, 0xb9, 0x4f, 0xa7, 0x73, 0xe1, 0x68, 0xcf, 0x4e, 0xd5, 0x5c, 0xf0, + 0x30, 0x01, 0x0e, 0x33, 0x7f, 0x3c, 0x01, 0xc2, 0x9b, 0x38, 0x84, 0xf0, 0xd1, 0x9d, 0x08, 0xb9, + 0x23, 0x38, 0x11, 0x2e, 0xc3, 0x8c, 0xed, 0xda, 0xa1, 0x6d, 0x39, 0xcc, 0xbe, 0x16, 0x87, 0xe3, + 0x63, 0x52, 0xe0, 0xac, 0x6b, 0xb0, 0x14, 0x3a, 0xb1, 0xba, 0xe8, 0x1a, 0x14, 0xd9, 0xe9, 0x21, + 0x16, 0xf0, 0xe8, 0x2e, 0x4f, 0xe6, 0xed, 0xe6, 0x61, 0xff, 0x9c, 0x12, 0xd3, 0xe8, 0xf9, 0xbb, + 0x5b, 0x65, 0xa8, 0x89, 0x75, 0x1c, 0x69, 0xf4, 0x09, 0x38, 0xee, 0xab, 0x41, 0xa9, 0xec, 0x5a, + 0xb6, 0xd3, 0xf1, 0x49, 0x44, 0x65, 0x22, 0x4e, 0xe5, 0x62, 0x02, 0x8e, 0xfb, 0x6a, 0xa0, 0x5d, + 0x98, 0x11, 0x65, 0x3c, 0xf8, 0x63, 0xf2, 0x88, 0xbd, 0x64, 0x41, 0x3e, 0x17, 0x35, 0x4a, 0x38, + 0x46, 0x17, 0x75, 0x60, 0xd1, 0x76, 0xeb, 0x9e, 0x5b, 0x77, 0x3a, 0x81, 0xbd, 0x4f, 0xa2, 0x98, + 0xfb, 0xa3, 0x30, 0x3b, 0xd9, 0xeb, 0x96, 0x17, 0xd7, 0x93, 0xe4, 0x70, 0x3f, 0x07, 0xf4, 0xaa, + 0x01, 0x27, 0xeb, 0x9e, 0x1b, 0xb0, 0x87, 0x6c, 0xfb, 0xe4, 0x82, 0xef, 0x7b, 0x3e, 0xe7, 0x3d, + 0x75, 0x44, 0xde, 0xec, 0x5a, 0x67, 0x35, 0x8d, 0x24, 0x4e, 0xe7, 0x84, 0x5e, 0x86, 0x52, 0xdb, + 0xf7, 0xf6, 0xed, 0x06, 0xf1, 0x45, 0x20, 0xd1, 0x46, 0x16, 0x0f, 0x6b, 0xb7, 0x04, 0xcd, 0x48, + 0xf4, 0xc8, 0x12, 0xac, 0xf8, 0x99, 0x7f, 0x58, 0x82, 0xb9, 0x38, 0x3a, 0xfa, 0x04, 0x40, 0xdb, + 0xf7, 0x5a, 0x24, 0xdc, 0x23, 0x2a, 0x76, 0xfa, 0xca, 0xb8, 0xef, 0x37, 0x25, 0x3d, 0x19, 0x40, + 0x40, 0xc5, 0x45, 0x54, 0x8a, 0x35, 0x8e, 0xc8, 0x87, 0xc9, 0x5b, 0xfc, 0x10, 0x15, 0x3a, 0xc5, + 0xf3, 0x99, 0x68, 0x40, 0x82, 0x33, 0x0b, 0xfa, 0x15, 0x45, 0x58, 0x32, 0x42, 0x3b, 0x90, 0xbf, + 0x4d, 0x76, 0xb2, 0x79, 0x69, 0x78, 0x83, 0x08, 0xdb, 0xa4, 0x3a, 0xd9, 0xeb, 0x96, 0xf3, 0x37, + 0xc8, 0x0e, 0xa6, 0xc4, 0x69, 0xbf, 0x1a, 0xdc, 0x15, 0x2a, 0x44, 0xc5, 0x98, 0xfd, 0x8a, 0xf9, + 0x55, 0x79, 0xbf, 0x44, 0x11, 0x96, 0x8c, 0xd0, 0xcb, 0x30, 0x75, 0xdb, 0xda, 0x27, 0xbb, 0xbe, + 0xe7, 0x86, 0x22, 0x6a, 0x65, 0xcc, 0xf0, 0xdc, 0x1b, 0x92, 0x9c, 0xe0, 0xcb, 0x8e, 0x77, 0x55, + 0x88, 0x23, 0x76, 0x68, 0x1f, 0x4a, 0x2e, 0xb9, 0x8d, 0x89, 0x63, 0xd7, 0x45, 0x64, 0xe4, 0x98, + 0xcb, 0xfa, 0x8a, 0xa0, 0x26, 0x38, 0xb3, 0x73, 0x4f, 0x96, 0x61, 0xc5, 0x8b, 0xce, 0xe5, 0x4d, + 0x6f, 0x47, 0x08, 0xaa, 0x31, 0xe7, 0x52, 0xd9, 0x99, 0x7c, 0x2e, 0x2f, 0x7b, 0x3b, 0x98, 0x12, + 0xa7, 0x7b, 0xa4, 0xae, 0x42, 0x26, 0x84, 0x98, 0xba, 0x92, 0x6d, 0xa8, 0x08, 0xdf, 0x23, 0x51, + 0x29, 0xd6, 0x38, 0xd2, 0xb1, 0x6d, 0x8a, 0x6b, 0x2d, 0x21, 0xa8, 0xc6, 0x1c, 0xdb, 0xf8, 0x25, + 0x19, 0x1f, 0x5b, 0x59, 0x86, 0x15, 0x2f, 0xf3, 0x5f, 0x0a, 0x30, 0xa3, 0x27, 0x12, 0x19, 0xe2, + 0xac, 0x56, 0xfa, 0x69, 0x6e, 0x14, 0xfd, 0x94, 0x9a, 0x17, 0xda, 0xa3, 0x74, 0x79, 0xc3, 0xb0, + 0x9e, 0x99, 0x7a, 0x16, 0x99, 0x17, 0x5a, 0x61, 0x80, 0x63, 0x4c, 0x47, 0xf0, 0x00, 0x53, 0x25, + 0x87, 0xab, 0x01, 0xc5, 0xb8, 0x92, 0x13, 0x3b, 0xd8, 0xcf, 0x03, 0x44, 0x09, 0x35, 0x84, 0x1b, + 0x40, 0x69, 0x4f, 0x5a, 0xa2, 0x0f, 0x0d, 0x0b, 0x3d, 0x06, 0x13, 0xf4, 0xa0, 0x24, 0x0d, 0xf1, + 0xb0, 0x4d, 0xd9, 0x70, 0x17, 0x59, 0x29, 0x16, 0x50, 0xf4, 0x34, 0xd5, 0x69, 0xa2, 0xe3, 0x4d, + 0xbc, 0x57, 0x5b, 0x8a, 0x74, 0x9a, 0x08, 0x86, 0x63, 0x98, 0xb4, 0xe9, 0x84, 0x9e, 0x46, 0x6c, + 0x25, 0x69, 0x4d, 0x67, 0x47, 0x14, 0xe6, 0x30, 0x76, 0xa7, 0x90, 0x38, 0xbd, 0xd8, 0x61, 0x55, + 0xd4, 0xee, 0x14, 0x12, 0x70, 0xdc, 0x57, 0x83, 0x76, 0x46, 0x78, 0x30, 0xa6, 0x79, 0xa0, 0xdb, + 0x00, 0xdf, 0xc3, 0x47, 0x60, 0x2e, 0xbe, 0xdb, 0xe9, 0x54, 0xb4, 0x7d, 0x6f, 0xd7, 0x76, 0x48, + 0xf2, 0xd6, 0x64, 0x8b, 0x17, 0x63, 0x09, 0x1f, 0xee, 0xda, 0xf6, 0xaf, 0xf2, 0x70, 0xe2, 0x4a, + 0xd3, 0x76, 0xef, 0x24, 0xee, 0x3b, 0xd3, 0xd2, 0xbc, 0x19, 0xa3, 0xa6, 0x79, 0x8b, 0x22, 0xf8, + 0x45, 0x1e, 0xbd, 0xf4, 0x08, 0x7e, 0x99, 0x64, 0x2f, 0x8e, 0x8b, 0x7e, 0x60, 0xc0, 0xc3, 0x56, + 0x83, 0xeb, 0x5f, 0x96, 0x23, 0x4a, 0x23, 0xa6, 0x72, 0x2f, 0x04, 0x63, 0x4a, 0xd3, 0xfe, 0xce, + 0xaf, 0x54, 0x0e, 0xe1, 0xca, 0xcd, 0x98, 0xb7, 0x89, 0x1e, 0x3c, 0x7c, 0x18, 0x2a, 0x3e, 0xb4, + 0xf9, 0xa7, 0xaf, 0xc2, 0x5b, 0xef, 0xc9, 0x68, 0x24, 0x63, 0xe5, 0x53, 0x06, 0x4c, 0xf1, 0xeb, + 0x3c, 0x4c, 0x76, 0xe9, 0x26, 0xb3, 0xda, 0xf6, 0x0b, 0xc4, 0x0f, 0x64, 0xfe, 0x09, 0xcd, 0x44, + 0xa9, 0x6c, 0xad, 0x0b, 0x08, 0xd6, 0xb0, 0xa8, 0x18, 0xbb, 0x65, 0xbb, 0x0d, 0x31, 0x4d, 0x4a, + 0x8c, 0x3d, 0x6f, 0xbb, 0x0d, 0xcc, 0x20, 0x4a, 0xd0, 0xe5, 0x07, 0x09, 0x3a, 0xf3, 0x2b, 0x06, + 0xcc, 0xb1, 0x07, 0x3a, 0x91, 0xf2, 0xfc, 0x94, 0x72, 0x8c, 0xf3, 0x66, 0x9c, 0x89, 0x3b, 0xc6, + 0xef, 0x76, 0xcb, 0xd3, 0xfc, 0x49, 0x4f, 0xdc, 0x4f, 0xfe, 0x41, 0x61, 0x71, 0x33, 0xf7, 0x7d, + 0x6e, 0x64, 0x83, 0x50, 0xdd, 0x2f, 0xd5, 0x24, 0x11, 0x1c, 0xd1, 0x33, 0xff, 0x38, 0x0f, 0x27, + 0x52, 0x22, 0xcd, 0xa9, 0x31, 0x3c, 0xc1, 0x82, 0x6d, 0xa5, 0xf3, 0xf9, 0xa5, 0xcc, 0xa3, 0xd9, + 0x57, 0x58, 0x4c, 0xaf, 0x58, 0x49, 0x6a, 0xeb, 0xf3, 0x42, 0x2c, 0x98, 0xa3, 0xdf, 0x36, 0x60, + 0xda, 0xd2, 0x16, 0x3b, 0xf7, 0xc7, 0xef, 0x64, 0xdf, 0x98, 0xbe, 0xb5, 0xad, 0xc5, 0x11, 0x45, + 0x4b, 0x59, 0x6f, 0xcb, 0xe9, 0xf7, 0xc0, 0xb4, 0xd6, 0x85, 0x51, 0xd6, 0xe8, 0xe9, 0x67, 0x61, + 0x61, 0xac, 0x35, 0xfe, 0x01, 0x18, 0x35, 0xa1, 0x09, 0x15, 0xb6, 0xb7, 0xf5, 0x77, 0x6b, 0x6a, + 0xc4, 0xc5, 0xc3, 0x35, 0x01, 0x35, 0x77, 0x60, 0x21, 0xa9, 0xa0, 0x67, 0xee, 0x25, 0x7b, 0x17, + 0x8c, 0x98, 0x82, 0xc4, 0xfc, 0xeb, 0x1c, 0x4c, 0x8a, 0xe7, 0x2a, 0xf7, 0x21, 0x04, 0xef, 0x56, + 0xec, 0x9a, 0x7f, 0x3d, 0x93, 0x57, 0x36, 0x03, 0xe3, 0xef, 0x82, 0x44, 0xfc, 0xdd, 0xf3, 0xd9, + 0xb0, 0x3b, 0x3c, 0xf8, 0xee, 0x2b, 0x05, 0x98, 0x4f, 0x3c, 0xff, 0x41, 0xaf, 0x1b, 0xfd, 0x31, + 0x27, 0xd7, 0x33, 0x7d, 0x61, 0xa4, 0xc2, 0x43, 0x0f, 0x0f, 0x3f, 0x09, 0x62, 0x99, 0x9e, 0xae, + 0x65, 0x96, 0x24, 0xf2, 0xe7, 0x49, 0x9f, 0x46, 0x4d, 0xfa, 0xf4, 0xcf, 0x06, 0x3c, 0x38, 0xf0, + 0x95, 0x18, 0x7b, 0xfe, 0xee, 0xc7, 0xa1, 0x62, 0x43, 0x66, 0xfc, 0xea, 0x53, 0xdd, 0xb9, 0x27, + 0x5f, 0x2c, 0x27, 0xd9, 0xa3, 0x27, 0x61, 0x86, 0x1d, 0x6e, 0x54, 0xa6, 0x84, 0xa4, 0x2d, 0x2e, + 0x19, 0xd9, 0x75, 0x53, 0x4d, 0x2b, 0xc7, 0x31, 0x2c, 0xf3, 0xcb, 0x06, 0x2c, 0x0f, 0x7a, 0x0c, + 0x3d, 0x84, 0x51, 0xf3, 0x4b, 0x89, 0x18, 0xc1, 0x72, 0x5f, 0x8c, 0x60, 0xc2, 0xac, 0x91, 0xe1, + 0x80, 0x9a, 0x45, 0x91, 0xbf, 0x47, 0x08, 0xdc, 0x67, 0x0d, 0x38, 0x35, 0x60, 0x37, 0xf5, 0xc5, + 0x8a, 0x1a, 0x47, 0x8e, 0x15, 0xcd, 0x0d, 0x1b, 0x2b, 0x6a, 0xfe, 0x6d, 0x1e, 0x16, 0x44, 0x7b, + 0x22, 0x0d, 0xe7, 0xe9, 0x58, 0xa4, 0xe5, 0xdb, 0x12, 0x91, 0x96, 0x4b, 0x49, 0xfc, 0x9f, 0x87, + 0x59, 0xfe, 0x6c, 0x85, 0x59, 0xfe, 0x24, 0x07, 0x27, 0x53, 0xdf, 0x7c, 0xa3, 0x4f, 0xa7, 0x1c, + 0x0d, 0x37, 0x32, 0x7e, 0x5c, 0x3e, 0xe4, 0xe1, 0x30, 0x6e, 0x6c, 0xe2, 0x17, 0xf4, 0x98, 0x40, + 0x2e, 0xea, 0x77, 0x8f, 0xe1, 0x99, 0xfc, 0x88, 0xe1, 0x81, 0xe6, 0x6f, 0xe4, 0xe1, 0xf1, 0x61, + 0x09, 0xfd, 0x8c, 0x86, 0x8f, 0x07, 0xb1, 0xf0, 0xf1, 0xfb, 0x74, 0x6c, 0x1f, 0x4b, 0x24, 0xf9, + 0x57, 0xf3, 0xea, 0xd8, 0xeb, 0x5f, 0x9f, 0x43, 0x79, 0xa4, 0x26, 0xa9, 0x6a, 0x27, 0x33, 0xb7, + 0x45, 0xa2, 0x70, 0xb2, 0xc6, 0x8b, 0xef, 0x76, 0xcb, 0x8b, 0x22, 0x9b, 0x53, 0x8d, 0x84, 0xa2, + 0x10, 0xcb, 0x4a, 0xe8, 0x71, 0x28, 0xf9, 0x1c, 0x2a, 0x03, 0x66, 0x85, 0x5b, 0x8f, 0x97, 0x61, + 0x05, 0x45, 0x9f, 0xd4, 0x74, 0xe1, 0xc2, 0x71, 0x3d, 0x3b, 0x3e, 0xcc, 0x5b, 0xf9, 0x12, 0x94, + 0x02, 0x99, 0x83, 0x8d, 0x5f, 0x29, 0x3f, 0x31, 0x64, 0x1c, 0x36, 0x35, 0x9d, 0x64, 0x42, 0x36, + 0xde, 0x3f, 0x95, 0xae, 0x4d, 0x91, 0x44, 0xa6, 0xb2, 0x5a, 0xf8, 0xfd, 0x18, 0xa4, 0x58, 0x2c, + 0xdf, 0x31, 0x60, 0x5a, 0xcc, 0xd6, 0x7d, 0x08, 0x0d, 0xbf, 0x19, 0x0f, 0x0d, 0xbf, 0x90, 0x89, + 0xec, 0x18, 0x10, 0x17, 0x7e, 0x13, 0x66, 0xf4, 0xb4, 0x1f, 0xe8, 0x45, 0x4d, 0xf6, 0x19, 0xe3, + 0xa4, 0x17, 0x90, 0xd2, 0x31, 0x92, 0x8b, 0xe6, 0x97, 0x4a, 0x6a, 0x14, 0x59, 0x00, 0xba, 0xbe, + 0x06, 0x8d, 0x43, 0xd7, 0xa0, 0xbe, 0x04, 0x72, 0xd9, 0x2f, 0x81, 0x6b, 0x50, 0x92, 0x02, 0x4a, + 0x1c, 0xe3, 0x8f, 0xea, 0x71, 0x57, 0x54, 0x17, 0xa0, 0xc4, 0xb4, 0x85, 0xcb, 0x4c, 0x2d, 0x35, + 0x87, 0x4a, 0x70, 0x2a, 0x32, 0xe8, 0x65, 0x98, 0xbe, 0xed, 0xf9, 0xb7, 0x1c, 0xcf, 0x62, 0xd9, + 0x15, 0x21, 0x0b, 0xe7, 0x80, 0xba, 0x72, 0xe2, 0xe1, 0xbd, 0x37, 0x22, 0xfa, 0x58, 0x67, 0x86, + 0x2a, 0x30, 0xdf, 0xb2, 0x5d, 0x4c, 0xac, 0x86, 0x8a, 0x00, 0x2f, 0xf0, 0xf4, 0x6f, 0x52, 0xc9, + 0xdd, 0x8c, 0x83, 0x71, 0x12, 0x1f, 0x7d, 0x0c, 0x4a, 0x81, 0x48, 0x2d, 0x92, 0x8d, 0x1b, 0x47, + 0xd9, 0x8c, 0x9c, 0x68, 0x34, 0x76, 0xb2, 0x04, 0x2b, 0x86, 0x68, 0x03, 0x96, 0x7c, 0xf1, 0x78, + 0x3f, 0x96, 0x45, 0x9a, 0xef, 0x4f, 0x96, 0x65, 0x0c, 0xa7, 0xc0, 0x71, 0x6a, 0x2d, 0xaa, 0xc5, + 0xb0, 0xfc, 0x35, 0xfc, 0x3e, 0x5b, 0xbb, 0x02, 0x66, 0x0b, 0xbe, 0x81, 0x05, 0xf4, 0xb0, 0x17, + 0x05, 0xa5, 0x31, 0x5e, 0x14, 0xd4, 0xe0, 0x64, 0x12, 0xc4, 0x52, 0x0c, 0xb0, 0xac, 0x06, 0xda, + 0xe9, 0xb1, 0x95, 0x86, 0x84, 0xd3, 0xeb, 0xa2, 0x1b, 0x30, 0xe5, 0x13, 0x66, 0x5f, 0x54, 0xa4, + 0xe3, 0x78, 0xe4, 0x10, 0x19, 0x2c, 0x09, 0xe0, 0x88, 0x16, 0x9d, 0x77, 0x2b, 0x9e, 0x01, 0xed, + 0x5a, 0x86, 0xdf, 0xc1, 0x10, 0x73, 0x3f, 0x20, 0xf5, 0x87, 0xf9, 0xe6, 0x1c, 0xcc, 0xc6, 0xee, + 0x16, 0xd0, 0xa3, 0x50, 0x64, 0x39, 0x17, 0x98, 0x78, 0x28, 0x45, 0x22, 0x8c, 0x0f, 0x0e, 0x87, + 0xa1, 0xcf, 0x19, 0x30, 0xdf, 0x8e, 0xdd, 0x83, 0x4a, 0xc9, 0x39, 0xa6, 0x8f, 0x2a, 0x7e, 0xb9, + 0xaa, 0xe5, 0x0e, 0x8d, 0x33, 0xc3, 0x49, 0xee, 0x74, 0x03, 0x8a, 0xa8, 0x31, 0x87, 0xf8, 0x0c, + 0x5b, 0xe8, 0x38, 0x8a, 0xc4, 0x6a, 0x1c, 0x8c, 0x93, 0xf8, 0x74, 0x86, 0x59, 0xef, 0xc6, 0x49, + 0x90, 0x5f, 0x91, 0x04, 0x70, 0x44, 0x0b, 0x3d, 0x0b, 0x73, 0x22, 0xf1, 0xd5, 0x96, 0xd7, 0xb8, + 0x64, 0x05, 0x7b, 0x42, 0xb9, 0x57, 0xc6, 0xc8, 0x6a, 0x0c, 0x8a, 0x13, 0xd8, 0xac, 0x6f, 0x51, + 0x76, 0x31, 0x46, 0x60, 0x22, 0x9e, 0x5a, 0x75, 0x35, 0x0e, 0xc6, 0x49, 0x7c, 0xf4, 0x0e, 0x4d, + 0xee, 0x73, 0x1f, 0x93, 0x92, 0x06, 0x29, 0xb2, 0xbf, 0x02, 0xf3, 0x1d, 0x66, 0x0b, 0x35, 0x24, + 0x50, 0xec, 0x47, 0xc5, 0xf0, 0x7a, 0x1c, 0x8c, 0x93, 0xf8, 0xe8, 0x19, 0x98, 0xf5, 0xa9, 0x74, + 0x53, 0x04, 0xb8, 0xe3, 0x49, 0x79, 0x47, 0xb0, 0x0e, 0xc4, 0x71, 0x5c, 0xf4, 0x1c, 0x2c, 0x46, + 0xd9, 0x78, 0x24, 0x01, 0xee, 0x89, 0x52, 0xe9, 0x2d, 0x2a, 0x49, 0x04, 0xdc, 0x5f, 0x07, 0xfd, + 0x32, 0x2c, 0x68, 0x23, 0xb1, 0xee, 0x36, 0xc8, 0x1d, 0x91, 0x31, 0x85, 0x7d, 0x12, 0x68, 0x35, + 0x01, 0xc3, 0x7d, 0xd8, 0xe8, 0xbd, 0x30, 0x57, 0xf7, 0x1c, 0x87, 0xc9, 0x38, 0x9e, 0xd6, 0x93, + 0xa7, 0x46, 0xe1, 0x49, 0x64, 0x62, 0x10, 0x9c, 0xc0, 0x44, 0x97, 0x01, 0x79, 0x3b, 0x01, 0xf1, + 0xf7, 0x49, 0xe3, 0x39, 0xfe, 0xc9, 0x2d, 0x7a, 0xc4, 0xcf, 0xc6, 0x63, 0x56, 0xaf, 0xf6, 0x61, + 0xe0, 0x94, 0x5a, 0x2c, 0x3b, 0x86, 0xf6, 0x7e, 0x64, 0x2e, 0x8b, 0x64, 0xf1, 0x49, 0xcb, 0xfd, + 0x9e, 0x8f, 0x47, 0x7c, 0x98, 0xe0, 0x21, 0xc4, 0xcb, 0xf3, 0x59, 0x64, 0x08, 0xd2, 0x33, 0xfc, + 0x45, 0x67, 0x04, 0x2f, 0xc5, 0x82, 0x13, 0xfa, 0x04, 0x4c, 0xed, 0xc8, 0x74, 0xaf, 0xcb, 0x0b, + 0x59, 0x9c, 0x8b, 0x89, 0xcc, 0xc5, 0x91, 0x65, 0xaa, 0x00, 0x38, 0x62, 0x89, 0x1e, 0x83, 0xe9, + 0x4b, 0x5b, 0x15, 0xb5, 0x0a, 0x17, 0xd9, 0xec, 0x17, 0x68, 0x15, 0xac, 0x03, 0xe8, 0x0e, 0x53, + 0xfa, 0x12, 0x62, 0x53, 0x1c, 0x9d, 0xb7, 0xfd, 0xea, 0x0f, 0xc5, 0x66, 0x0e, 0x41, 0x5c, 0x5b, + 0x3e, 0x91, 0xc0, 0x16, 0xe5, 0x58, 0x61, 0xa0, 0x97, 0x60, 0x5a, 0x9c, 0x17, 0x4c, 0x36, 0x2d, + 0x1d, 0xed, 0x6d, 0x12, 0x8e, 0x48, 0x60, 0x9d, 0x1e, 0x7a, 0x0a, 0xa6, 0xdb, 0x2c, 0x0b, 0x26, + 0xb9, 0xd8, 0x71, 0x9c, 0xe5, 0x93, 0x4c, 0x6e, 0x2a, 0x4f, 0xc9, 0x56, 0x04, 0xc2, 0x3a, 0x1e, + 0x7a, 0x42, 0x7a, 0xfd, 0xdf, 0x12, 0x73, 0x7c, 0x29, 0xaf, 0xbf, 0xd2, 0x72, 0x07, 0x04, 0xa5, + 0x9e, 0xba, 0x87, 0xbb, 0x7d, 0x07, 0x4e, 0x4b, 0x15, 0xab, 0x7f, 0x93, 0x2c, 0x2f, 0xc7, 0x6e, + 0x09, 0x4e, 0xdf, 0x18, 0x88, 0x89, 0x0f, 0xa1, 0x82, 0x76, 0x20, 0x6f, 0x39, 0x3b, 0xcb, 0x0f, + 0x66, 0xa1, 0x2b, 0xaa, 0x4f, 0xe8, 0xf1, 0x40, 0x92, 0xca, 0x46, 0x15, 0x53, 0xe2, 0xe6, 0xab, + 0x39, 0x75, 0x2b, 0xaf, 0x72, 0xc7, 0x7d, 0x5c, 0x5f, 0xd5, 0x46, 0x16, 0x9f, 0x88, 0xea, 0xcb, + 0x89, 0xcc, 0x0f, 0xa4, 0xd4, 0x35, 0xdd, 0x56, 0xfb, 0x38, 0x93, 0x74, 0x04, 0xf1, 0xbc, 0x78, + 0xdc, 0x9a, 0x8b, 0xef, 0x62, 0xf3, 0x87, 0x05, 0x75, 0x09, 0x95, 0x70, 0xc6, 0xfb, 0x50, 0xb4, + 0x83, 0xd0, 0xf6, 0x32, 0x7c, 0x72, 0x94, 0x48, 0x28, 0xc7, 0x82, 0x2f, 0x19, 0x00, 0x73, 0x56, + 0x94, 0xa7, 0xdb, 0xb4, 0xdd, 0x3b, 0xa2, 0xfb, 0xd7, 0x32, 0xf7, 0xb2, 0x73, 0x9e, 0x0c, 0x80, + 0x39, 0x2b, 0x74, 0x93, 0xaf, 0xb4, 0x6c, 0x3e, 0x07, 0x96, 0xfc, 0xca, 0x5f, 0x7c, 0xc5, 0x51, + 0x5e, 0x41, 0xcb, 0x16, 0x3a, 0xcc, 0x98, 0xbc, 0x6a, 0x9b, 0xeb, 0x69, 0xbc, 0x6a, 0x9b, 0xeb, + 0x98, 0x32, 0x41, 0xaf, 0x1b, 0x00, 0x96, 0xfa, 0xdc, 0x5d, 0x36, 0x09, 0xc4, 0x07, 0x7d, 0x3e, + 0x8f, 0xc7, 0x4b, 0x45, 0x50, 0xac, 0x71, 0x36, 0xff, 0xdd, 0x00, 0xed, 0x1b, 0x41, 0x51, 0xb0, + 0x8e, 0x31, 0x74, 0xb0, 0x4e, 0x6e, 0xc4, 0x60, 0x9d, 0xfc, 0x48, 0xc1, 0x3a, 0x85, 0xd1, 0x83, + 0x75, 0x8a, 0x83, 0x83, 0x75, 0xcc, 0x37, 0x0c, 0x58, 0xec, 0x9b, 0x9b, 0xe4, 0xb7, 0x18, 0x8d, + 0x21, 0xbf, 0xc5, 0xb8, 0x06, 0x0b, 0x22, 0xc3, 0x62, 0xad, 0xed, 0xd8, 0xa9, 0xaf, 0x14, 0xb7, + 0x13, 0x70, 0xdc, 0x57, 0xc3, 0xfc, 0x73, 0x03, 0xa6, 0xb5, 0x47, 0x15, 0xb4, 0x1f, 0xec, 0xf1, + 0x89, 0x68, 0x46, 0x94, 0x5c, 0x92, 0x5d, 0x33, 0x72, 0x18, 0xbf, 0xf1, 0x6e, 0x6a, 0x39, 0xc4, + 0xa2, 0x1b, 0x6f, 0x5a, 0x8a, 0x05, 0x94, 0x67, 0x87, 0x22, 0xfc, 0x3b, 0x9b, 0x79, 0x3d, 0x3b, + 0x14, 0x69, 0x63, 0x06, 0x61, 0xec, 0xe8, 0x99, 0x26, 0xe2, 0xb8, 0xb4, 0x5c, 0x96, 0x16, 0xb5, + 0x5c, 0x18, 0x0c, 0x9d, 0x81, 0x3c, 0x71, 0x1b, 0x42, 0x01, 0x57, 0x5f, 0x36, 0xb8, 0xe0, 0x36, + 0x30, 0x2d, 0x37, 0xaf, 0xc2, 0x4c, 0x8d, 0xd4, 0x7d, 0x12, 0x3e, 0x4f, 0x0e, 0x86, 0xfe, 0x54, + 0xc2, 0x2d, 0x72, 0x90, 0xfc, 0x54, 0x02, 0xad, 0x4e, 0xcb, 0xcd, 0x3f, 0x30, 0x20, 0x91, 0x5a, + 0x54, 0xbb, 0xfd, 0x32, 0x06, 0xdd, 0x7e, 0xc5, 0xee, 0x69, 0x72, 0x87, 0xde, 0xd3, 0x5c, 0x06, + 0xd4, 0xb2, 0xc2, 0xfa, 0x5e, 0x2c, 0xf1, 0xad, 0xb0, 0x7d, 0xa2, 0x27, 0x5c, 0x7d, 0x18, 0x38, + 0xa5, 0x96, 0xf9, 0x8a, 0x01, 0x7d, 0x9f, 0xc9, 0xa4, 0x27, 0x36, 0x11, 0x59, 0xe8, 0xb9, 0x49, + 0xa8, 0x4e, 0x6c, 0x99, 0x7c, 0x5e, 0xc2, 0xa9, 0xdd, 0x20, 0x6f, 0x9e, 0xa4, 0x1d, 0xcf, 0x1f, + 0xbb, 0x28, 0xbb, 0x61, 0x2d, 0x0e, 0xc6, 0x49, 0x7c, 0xf3, 0x05, 0x28, 0xc9, 0x17, 0x81, 0xec, + 0x59, 0x8d, 0xb4, 0x44, 0xf5, 0x67, 0x35, 0xd4, 0x10, 0x65, 0x10, 0x3a, 0x4c, 0x81, 0x6b, 0x5f, + 0xf2, 0x82, 0x50, 0x3e, 0x63, 0xe4, 0xf7, 0x4d, 0x57, 0xd6, 0x59, 0x19, 0x56, 0x50, 0x73, 0x11, + 0xe6, 0xd5, 0x45, 0x12, 0x5f, 0xf4, 0xe6, 0x37, 0xf3, 0x30, 0x13, 0xfb, 0xf8, 0xd1, 0xbd, 0x27, + 0x7b, 0xf8, 0x69, 0x49, 0xb9, 0x10, 0xca, 0x8f, 0x78, 0x21, 0xa4, 0xdf, 0xc0, 0x15, 0x8e, 0xf7, + 0x06, 0xae, 0x98, 0xcd, 0x0d, 0x5c, 0x08, 0x93, 0xe2, 0xc3, 0xb0, 0x22, 0x1a, 0x78, 0x33, 0xa3, + 0xe7, 0xfc, 0xe2, 0x5d, 0x2c, 0x0b, 0x80, 0x96, 0x02, 0x4c, 0xb2, 0x32, 0xbf, 0x5e, 0x84, 0xb9, + 0xf8, 0x03, 0xff, 0x21, 0x66, 0xf2, 0x1d, 0x7d, 0x33, 0x39, 0xa2, 0x41, 0x9c, 0x1f, 0xd7, 0x20, + 0x2e, 0x8c, 0x6b, 0x10, 0x17, 0x8f, 0x60, 0x10, 0xf7, 0x9b, 0xb3, 0x13, 0x43, 0x9b, 0xb3, 0xef, + 0x53, 0xde, 0xdc, 0xc9, 0x98, 0xfb, 0x23, 0xf2, 0xe6, 0xa2, 0xf8, 0x34, 0xac, 0x7a, 0x8d, 0x54, + 0xaf, 0x78, 0xe9, 0x1e, 0x8a, 0xbf, 0x9f, 0xea, 0x7c, 0x1d, 0xfd, 0xce, 0xed, 0x2d, 0x23, 0x38, + 0x5e, 0xa3, 0x6f, 0x1f, 0xb3, 0xc3, 0x0f, 0xe2, 0x07, 0x67, 0x2d, 0x02, 0x61, 0x1d, 0x8f, 0x7d, + 0xf5, 0x26, 0xfe, 0x99, 0x1f, 0x76, 0xbf, 0xa0, 0x7f, 0xf5, 0x26, 0xf1, 0x59, 0xa0, 0x24, 0xbe, + 0xf9, 0xb5, 0x3c, 0xcc, 0xc5, 0xb3, 0x96, 0xa3, 0xdb, 0x4a, 0x3f, 0xcf, 0xc4, 0x34, 0xe0, 0x64, + 0xb5, 0x27, 0xee, 0x03, 0x8d, 0x6d, 0xfe, 0x45, 0xde, 0x1d, 0xf5, 0xde, 0xfe, 0xf8, 0x18, 0x0b, + 0x2b, 0x57, 0xb0, 0x63, 0x89, 0xce, 0xa3, 0x80, 0x52, 0xe1, 0xc1, 0xcd, 0x9c, 0x7b, 0x14, 0x22, + 0xaa, 0x58, 0x61, 0x8d, 0x2d, 0x15, 0xef, 0xfb, 0xc4, 0xb7, 0x77, 0x6d, 0xf5, 0xc5, 0x15, 0x26, + 0x3c, 0x5f, 0x10, 0x65, 0x58, 0x41, 0xcd, 0x57, 0x72, 0x10, 0x7d, 0x5f, 0x8a, 0x25, 0x50, 0x0e, + 0x34, 0xb5, 0x41, 0x4c, 0xdb, 0xe5, 0x71, 0xb3, 0x94, 0x47, 0x14, 0x45, 0xb0, 0x8b, 0x56, 0x82, + 0x63, 0x1c, 0x7f, 0x0a, 0xdf, 0x95, 0xb2, 0x60, 0x3e, 0xf1, 0x50, 0x24, 0xf3, 0x88, 0xc2, 0x2f, + 0xe5, 0x61, 0x4a, 0x3d, 0xb5, 0x41, 0xef, 0x61, 0xb9, 0x4f, 0xf7, 0x3c, 0x99, 0x91, 0xf6, 0xad, + 0x5a, 0x86, 0xd2, 0x3d, 0xaf, 0x71, 0xb7, 0x5b, 0x9e, 0x57, 0xc8, 0xbc, 0x08, 0x8b, 0x0a, 0x54, + 0x49, 0xeb, 0xf8, 0x4e, 0x52, 0x49, 0xbb, 0x8e, 0x37, 0x30, 0x2d, 0x47, 0x77, 0x60, 0x72, 0x8f, + 0x58, 0x0d, 0xe2, 0xcb, 0xd8, 0x81, 0xcd, 0x8c, 0x9e, 0x07, 0x5d, 0x62, 0x54, 0xa3, 0x61, 0xe0, + 0xff, 0x03, 0x2c, 0xd9, 0xd1, 0x83, 0x6a, 0xc7, 0x6b, 0x1c, 0x24, 0x33, 0x9a, 0x56, 0xbd, 0xc6, + 0x01, 0x66, 0x10, 0xf4, 0x2c, 0xcc, 0x85, 0x76, 0x8b, 0x78, 0x9d, 0x50, 0xff, 0x7a, 0x4f, 0x3e, + 0xba, 0x3c, 0xde, 0x8e, 0x41, 0x71, 0x02, 0x9b, 0x1e, 0x74, 0x37, 0x03, 0xcf, 0x65, 0xd9, 0x54, + 0x26, 0xe2, 0x37, 0x4d, 0x97, 0x6b, 0x57, 0xaf, 0xb0, 0x64, 0x2a, 0x0a, 0x83, 0x62, 0xdb, 0x2c, + 0x9e, 0xdf, 0x27, 0xc2, 0x77, 0xb3, 0x10, 0xbd, 0xba, 0xe4, 0xe5, 0x58, 0x61, 0x98, 0xd7, 0x61, + 0x3e, 0xd1, 0x55, 0xa9, 0x0e, 0x1b, 0xe9, 0xea, 0xf0, 0x70, 0xe9, 0x43, 0xff, 0xc4, 0x80, 0xc5, + 0xbe, 0xcd, 0x3b, 0x6c, 0xa8, 0x6b, 0x52, 0x92, 0xe7, 0x8e, 0x2e, 0xc9, 0xf3, 0xa3, 0x49, 0xf2, + 0xea, 0xca, 0xb7, 0xde, 0x3c, 0xfb, 0xc0, 0xb7, 0xdf, 0x3c, 0xfb, 0xc0, 0x77, 0xdf, 0x3c, 0xfb, + 0xc0, 0x2b, 0xbd, 0xb3, 0xc6, 0xb7, 0x7a, 0x67, 0x8d, 0x6f, 0xf7, 0xce, 0x1a, 0xdf, 0xed, 0x9d, + 0x35, 0x7e, 0xd8, 0x3b, 0x6b, 0xbc, 0xf1, 0xa3, 0xb3, 0x0f, 0xbc, 0x58, 0x92, 0xcb, 0xe4, 0x7f, + 0x02, 0x00, 0x00, 0xff, 0xff, 0x63, 0x35, 0xc7, 0x2a, 0x50, 0x83, 0x00, 0x00, } func (m *ALBStatus) Marshal() (dAtA []byte, err error) { @@ -6519,6 +6519,20 @@ func (m *RolloutAnalysis) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.MeasurementRetention) > 0 { + for iNdEx := len(m.MeasurementRetention) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.MeasurementRetention[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } if len(m.DryRun) > 0 { for iNdEx := len(m.DryRun) - 1; iNdEx >= 0; iNdEx-- { { @@ -9472,6 +9486,12 @@ func (m *RolloutAnalysis) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) } } + if len(m.MeasurementRetention) > 0 { + for _, e := range m.MeasurementRetention { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } return n } @@ -11029,10 +11049,16 @@ func (this *RolloutAnalysis) String() string { repeatedStringForDryRun += strings.Replace(strings.Replace(f.String(), "DryRun", "DryRun", 1), `&`, ``, 1) + "," } repeatedStringForDryRun += "}" + repeatedStringForMeasurementRetention := "[]MeasurementRetention{" + for _, f := range this.MeasurementRetention { + repeatedStringForMeasurementRetention += strings.Replace(strings.Replace(f.String(), "MeasurementRetention", "MeasurementRetention", 1), `&`, ``, 1) + "," + } + repeatedStringForMeasurementRetention += "}" s := strings.Join([]string{`&RolloutAnalysis{`, `Templates:` + repeatedStringForTemplates + `,`, `Args:` + repeatedStringForArgs + `,`, `DryRun:` + repeatedStringForDryRun + `,`, + `MeasurementRetention:` + repeatedStringForMeasurementRetention + `,`, `}`, }, "") return s @@ -22238,6 +22264,40 @@ func (m *RolloutAnalysis) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MeasurementRetention", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MeasurementRetention = append(m.MeasurementRetention, MeasurementRetention{}) + if err := m.MeasurementRetention[len(m.MeasurementRetention)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) diff --git a/pkg/apis/rollouts/v1alpha1/generated.proto b/pkg/apis/rollouts/v1alpha1/generated.proto index 300a6337e3..ad006306fb 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.proto +++ b/pkg/apis/rollouts/v1alpha1/generated.proto @@ -1013,6 +1013,12 @@ message RolloutAnalysis { // +patchStrategy=merge // +optional repeated DryRun dryRun = 3; + + // MeasurementRetention object contains the settings for retaining the number of measurements during the analysis + // +patchMergeKey=metricName + // +patchStrategy=merge + // +optional + repeated MeasurementRetention measurementRetention = 4; } // RolloutAnalysisBackground defines a template that is used to create a background analysisRun diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index 08a3842f96..210ea00906 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -3047,11 +3047,31 @@ func schema_pkg_apis_rollouts_v1alpha1_RolloutAnalysis(ref common.ReferenceCallb }, }, }, + "measurementRetention": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "MeasurementRetention object contains the settings for retaining the number of measurements during the analysis", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.MeasurementRetention"), + }, + }, + }, + }, + }, }, }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisRunArgument", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DryRun", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutAnalysisTemplate"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisRunArgument", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DryRun", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.MeasurementRetention", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutAnalysisTemplate"}, } } @@ -3116,6 +3136,26 @@ func schema_pkg_apis_rollouts_v1alpha1_RolloutAnalysisBackground(ref common.Refe }, }, }, + "measurementRetention": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "MeasurementRetention object contains the settings for retaining the number of measurements during the analysis", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.MeasurementRetention"), + }, + }, + }, + }, + }, "startingStep": { SchemaProps: spec.SchemaProps{ Description: "StartingStep indicates which step the background analysis should start on If not listed, controller defaults to 0", @@ -3127,7 +3167,7 @@ func schema_pkg_apis_rollouts_v1alpha1_RolloutAnalysisBackground(ref common.Refe }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisRunArgument", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DryRun", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutAnalysisTemplate"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisRunArgument", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DryRun", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.MeasurementRetention", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutAnalysisTemplate"}, } } diff --git a/pkg/apis/rollouts/v1alpha1/types.go b/pkg/apis/rollouts/v1alpha1/types.go index b2810665ad..cfa95043a9 100644 --- a/pkg/apis/rollouts/v1alpha1/types.go +++ b/pkg/apis/rollouts/v1alpha1/types.go @@ -540,6 +540,11 @@ type RolloutAnalysis struct { // +patchStrategy=merge // +optional DryRun []DryRun `json:"dryRun,omitempty" patchStrategy:"merge" patchMergeKey:"metricName" protobuf:"bytes,3,rep,name=dryRun"` + // MeasurementRetention object contains the settings for retaining the number of measurements during the analysis + // +patchMergeKey=metricName + // +patchStrategy=merge + // +optional + MeasurementRetention []MeasurementRetention `json:"measurementRetention,omitempty" patchStrategy:"merge" patchMergeKey:"metricName" protobuf:"bytes,4,rep,name=measurementRetention"` } type RolloutAnalysisTemplate struct { diff --git a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go index c5dbb72bd8..79e420ea85 100644 --- a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go @@ -1675,6 +1675,11 @@ func (in *RolloutAnalysis) DeepCopyInto(out *RolloutAnalysis) { *out = make([]DryRun, len(*in)) copy(*out, *in) } + if in.MeasurementRetention != nil { + in, out := &in.MeasurementRetention, &out.MeasurementRetention + *out = make([]MeasurementRetention, len(*in)) + copy(*out, *in) + } return } diff --git a/pkg/apis/rollouts/validation/validation_references.go b/pkg/apis/rollouts/validation/validation_references.go index e570bc7c03..de180e98d7 100644 --- a/pkg/apis/rollouts/validation/validation_references.go +++ b/pkg/apis/rollouts/validation/validation_references.go @@ -121,7 +121,7 @@ func ValidateAnalysisTemplatesWithType(rollout *v1alpha1.Rollout, templates Anal templateNames := GetAnalysisTemplateNames(templates) value := fmt.Sprintf("templateNames: %s", templateNames) - _, err := analysisutil.NewAnalysisRunFromTemplates(templates.AnalysisTemplates, templates.ClusterAnalysisTemplates, buildAnalysisArgs(templates.Args, rollout), []v1alpha1.DryRun{}, "", "", "") + _, err := analysisutil.NewAnalysisRunFromTemplates(templates.AnalysisTemplates, templates.ClusterAnalysisTemplates, buildAnalysisArgs(templates.Args, rollout), []v1alpha1.DryRun{}, []v1alpha1.MeasurementRetention{}, "", "", "") if err != nil { allErrs = append(allErrs, field.Invalid(fldPath, value, err.Error())) return allErrs diff --git a/rollout/analysis.go b/rollout/analysis.go index cc2e66b07d..339aa3fec6 100644 --- a/rollout/analysis.go +++ b/rollout/analysis.go @@ -452,7 +452,7 @@ func (c *rolloutContext) newAnalysisRunFromRollout(rolloutAnalysis *v1alpha1.Rol } } - run, err = analysisutil.NewAnalysisRunFromTemplates(templates, clusterTemplates, args, rolloutAnalysis.DryRun, name, "", c.rollout.Namespace) + run, err = analysisutil.NewAnalysisRunFromTemplates(templates, clusterTemplates, args, rolloutAnalysis.DryRun, rolloutAnalysis.MeasurementRetention, name, "", c.rollout.Namespace) if err != nil { return nil, err } diff --git a/rollout/analysis_test.go b/rollout/analysis_test.go index 4e36e37b66..9f25d1c5f7 100644 --- a/rollout/analysis_test.go +++ b/rollout/analysis_test.go @@ -33,6 +33,12 @@ func analysisTemplate(name string) *v1alpha1.AnalysisTemplate { Metrics: []v1alpha1.Metric{{ Name: "example", }}, + DryRun: []v1alpha1.DryRun{{ + MetricName: "example", + }}, + MeasurementRetention: []v1alpha1.MeasurementRetention{{ + MetricName: "example", + }}, }, } } @@ -106,8 +112,10 @@ func analysisRun(at *v1alpha1.AnalysisTemplate, analysisRunType string, r *v1alp OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(r, controllerKind)}, }, Spec: v1alpha1.AnalysisRunSpec{ - Metrics: at.Spec.Metrics, - Args: at.Spec.Args, + Metrics: at.Spec.Metrics, + DryRun: at.Spec.DryRun, + MeasurementRetention: at.Spec.MeasurementRetention, + Args: at.Spec.Args, }, } } diff --git a/utils/analysis/helpers.go b/utils/analysis/helpers.go index cb25dabcac..067950e776 100644 --- a/utils/analysis/helpers.go +++ b/utils/analysis/helpers.go @@ -187,11 +187,11 @@ func TerminateRun(analysisRunIf argoprojclient.AnalysisRunInterface, name string // IsSemanticallyEqual checks to see if two analysis runs are semantically equal func IsSemanticallyEqual(left, right v1alpha1.AnalysisRunSpec) bool { // NOTE: only consider metrics & args when comparing for semantic equality - leftBytes, err := json.Marshal(v1alpha1.AnalysisRunSpec{Metrics: left.Metrics, DryRun: left.DryRun, Args: left.Args}) + leftBytes, err := json.Marshal(v1alpha1.AnalysisRunSpec{Metrics: left.Metrics, DryRun: left.DryRun, MeasurementRetention: left.MeasurementRetention, Args: left.Args}) if err != nil { panic(err) } - rightBytes, err := json.Marshal(v1alpha1.AnalysisRunSpec{Metrics: right.Metrics, DryRun: right.DryRun, Args: right.Args}) + rightBytes, err := json.Marshal(v1alpha1.AnalysisRunSpec{Metrics: right.Metrics, DryRun: right.DryRun, MeasurementRetention: right.MeasurementRetention, Args: right.Args}) if err != nil { panic(err) } @@ -274,7 +274,7 @@ func CreateWithCollisionCounter(logCtx *log.Entry, analysisRunIf argoprojclient. } } -func NewAnalysisRunFromTemplates(templates []*v1alpha1.AnalysisTemplate, clusterTemplates []*v1alpha1.ClusterAnalysisTemplate, args []v1alpha1.Argument, dryRunMetrics []v1alpha1.DryRun, name, generateName, namespace string) (*v1alpha1.AnalysisRun, error) { +func NewAnalysisRunFromTemplates(templates []*v1alpha1.AnalysisTemplate, clusterTemplates []*v1alpha1.ClusterAnalysisTemplate, args []v1alpha1.Argument, dryRunMetrics []v1alpha1.DryRun, measurementRetentionMetrics []v1alpha1.MeasurementRetention, name, generateName, namespace string) (*v1alpha1.AnalysisRun, error) { template, err := FlattenTemplates(templates, clusterTemplates) if err != nil { return nil, err @@ -287,6 +287,10 @@ func NewAnalysisRunFromTemplates(templates []*v1alpha1.AnalysisTemplate, cluster if err != nil { return nil, err } + measurementRetention, err := mergeMeasurementRetentionMetrics(measurementRetentionMetrics, template.Spec.MeasurementRetention) + if err != nil { + return nil, err + } ar := v1alpha1.AnalysisRun{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -294,9 +298,10 @@ func NewAnalysisRunFromTemplates(templates []*v1alpha1.AnalysisTemplate, cluster Namespace: namespace, }, Spec: v1alpha1.AnalysisRunSpec{ - Metrics: template.Spec.Metrics, - DryRun: dryRun, - Args: newArgs, + Metrics: template.Spec.Metrics, + DryRun: dryRun, + MeasurementRetention: measurementRetention, + Args: newArgs, }, } return &ar, nil @@ -311,15 +316,20 @@ func FlattenTemplates(templates []*v1alpha1.AnalysisTemplate, clusterTemplates [ if err != nil { return nil, err } + measurementRetentionMetrics, err := flattenMeasurementRetentionMetrics(templates, clusterTemplates) + if err != nil { + return nil, err + } args, err := flattenArgs(templates, clusterTemplates) if err != nil { return nil, err } return &v1alpha1.AnalysisTemplate{ Spec: v1alpha1.AnalysisTemplateSpec{ - Metrics: metrics, - DryRun: dryRunMetrics, - Args: args, + Metrics: metrics, + DryRun: dryRunMetrics, + MeasurementRetention: measurementRetentionMetrics, + Args: args, }, }, nil } @@ -395,6 +405,18 @@ func mergeDryRunMetrics(leftDryRunMetrics []v1alpha1.DryRun, rightDryRunMetrics return combinedDryRunMetrics, nil } +func mergeMeasurementRetentionMetrics(leftMeasurementRetentionMetrics []v1alpha1.MeasurementRetention, rightMeasurementRetentionMetrics []v1alpha1.MeasurementRetention) ([]v1alpha1.MeasurementRetention, error) { + var combinedMeasurementRetentionMetrics []v1alpha1.MeasurementRetention + combinedMeasurementRetentionMetrics = append(combinedMeasurementRetentionMetrics, leftMeasurementRetentionMetrics...) + combinedMeasurementRetentionMetrics = append(combinedMeasurementRetentionMetrics, rightMeasurementRetentionMetrics...) + + err := validateMeasurementRetentionMetrics(combinedMeasurementRetentionMetrics) + if err != nil { + return nil, err + } + return combinedMeasurementRetentionMetrics, nil +} + func flattenDryRunMetrics(templates []*v1alpha1.AnalysisTemplate, clusterTemplates []*v1alpha1.ClusterAnalysisTemplate) ([]v1alpha1.DryRun, error) { var combinedDryRunMetrics []v1alpha1.DryRun for _, template := range templates { @@ -412,6 +434,23 @@ func flattenDryRunMetrics(templates []*v1alpha1.AnalysisTemplate, clusterTemplat return combinedDryRunMetrics, nil } +func flattenMeasurementRetentionMetrics(templates []*v1alpha1.AnalysisTemplate, clusterTemplates []*v1alpha1.ClusterAnalysisTemplate) ([]v1alpha1.MeasurementRetention, error) { + var combinedMeasurementRetentionMetrics []v1alpha1.MeasurementRetention + for _, template := range templates { + combinedMeasurementRetentionMetrics = append(combinedMeasurementRetentionMetrics, template.Spec.MeasurementRetention...) + } + + for _, template := range clusterTemplates { + combinedMeasurementRetentionMetrics = append(combinedMeasurementRetentionMetrics, template.Spec.MeasurementRetention...) + } + + err := validateMeasurementRetentionMetrics(combinedMeasurementRetentionMetrics) + if err != nil { + return nil, err + } + return combinedMeasurementRetentionMetrics, nil +} + func validateDryRunMetrics(dryRunMetrics []v1alpha1.DryRun) error { metricMap := map[string]bool{} for _, dryRun := range dryRunMetrics { @@ -423,6 +462,17 @@ func validateDryRunMetrics(dryRunMetrics []v1alpha1.DryRun) error { return nil } +func validateMeasurementRetentionMetrics(measurementRetentionMetrics []v1alpha1.MeasurementRetention) error { + metricMap := map[string]bool{} + for _, measurementRetention := range measurementRetentionMetrics { + if _, ok := metricMap[measurementRetention.MetricName]; ok { + return fmt.Errorf("two Measurement Retention metric rules have the same name '%s'", measurementRetention.MetricName) + } + metricMap[measurementRetention.MetricName] = true + } + return nil +} + func NewAnalysisRunFromUnstructured(obj *unstructured.Unstructured, templateArgs []v1alpha1.Argument, name, generateName, namespace string) (*unstructured.Unstructured, error) { var newArgs []v1alpha1.Argument diff --git a/utils/analysis/helpers_test.go b/utils/analysis/helpers_test.go index 3d73dcb061..5568380e43 100644 --- a/utils/analysis/helpers_test.go +++ b/utils/analysis/helpers_test.go @@ -349,12 +349,24 @@ func TestFlattenTemplates(t *testing.T) { { Spec: v1alpha1.AnalysisTemplateSpec{ Metrics: []v1alpha1.Metric{fooMetric}, - Args: nil, + DryRun: []v1alpha1.DryRun{{ + MetricName: "foo", + }}, + MeasurementRetention: []v1alpha1.MeasurementRetention{{ + MetricName: "foo", + }}, + Args: nil, }, }, { Spec: v1alpha1.AnalysisTemplateSpec{ Metrics: []v1alpha1.Metric{barMetric}, - Args: nil, + DryRun: []v1alpha1.DryRun{{ + MetricName: "bar", + }}, + MeasurementRetention: []v1alpha1.MeasurementRetention{{ + MetricName: "bar", + }}, + Args: nil, }, }, }, []*v1alpha1.ClusterAnalysisTemplate{}) @@ -376,6 +388,11 @@ func TestFlattenTemplates(t *testing.T) { MetricName: "foo", }, }, + MeasurementRetention: []v1alpha1.MeasurementRetention{ + { + MetricName: "foo", + }, + }, Args: nil, }, }, @@ -388,6 +405,11 @@ func TestFlattenTemplates(t *testing.T) { MetricName: "bar", }, }, + MeasurementRetention: []v1alpha1.MeasurementRetention{ + { + MetricName: "bar", + }, + }, Args: nil, }, }, @@ -445,6 +467,35 @@ func TestFlattenTemplates(t *testing.T) { assert.Nil(t, template) assert.Equal(t, err, fmt.Errorf("two Dry-Run metric rules have the same name 'foo'")) }) + t.Run("Merge fail with measurement retention metrics name collision", func(t *testing.T) { + fooMetric := metric("foo", "true") + barMetric := metric("bar", "true") + template, err := FlattenTemplates([]*v1alpha1.AnalysisTemplate{ + { + Spec: v1alpha1.AnalysisTemplateSpec{ + Metrics: []v1alpha1.Metric{fooMetric}, + MeasurementRetention: []v1alpha1.MeasurementRetention{ + { + MetricName: "foo", + }, + }, + Args: nil, + }, + }, { + Spec: v1alpha1.AnalysisTemplateSpec{ + Metrics: []v1alpha1.Metric{barMetric}, + MeasurementRetention: []v1alpha1.MeasurementRetention{ + { + MetricName: "foo", + }, + }, + Args: nil, + }, + }, + }, []*v1alpha1.ClusterAnalysisTemplate{}) + assert.Nil(t, template) + assert.Equal(t, err, fmt.Errorf("two Measurement Retention metric rules have the same name 'foo'")) + }) t.Run("Merge multiple args successfully", func(t *testing.T) { fooArgs := arg("foo", pointer.StringPtr("true")) barArgs := arg("bar", pointer.StringPtr("true")) @@ -547,7 +598,7 @@ func TestNewAnalysisRunFromTemplates(t *testing.T) { } args := []v1alpha1.Argument{arg, secretArg} - run, err := NewAnalysisRunFromTemplates(templates, clusterTemplates, args, []v1alpha1.DryRun{}, "foo-run", "foo-run-generate-", "my-ns") + run, err := NewAnalysisRunFromTemplates(templates, clusterTemplates, args, []v1alpha1.DryRun{}, []v1alpha1.MeasurementRetention{}, "foo-run", "foo-run-generate-", "my-ns") assert.NoError(t, err) assert.Equal(t, "foo-run", run.Name) assert.Equal(t, "foo-run-generate-", run.GenerateName) @@ -560,7 +611,7 @@ func TestNewAnalysisRunFromTemplates(t *testing.T) { // Fail Merge Args unresolvedArg := v1alpha1.Argument{Name: "unresolved"} templates[0].Spec.Args = append(templates[0].Spec.Args, unresolvedArg) - run, err = NewAnalysisRunFromTemplates(templates, clusterTemplates, args, []v1alpha1.DryRun{}, "foo-run", "foo-run-generate-", "my-ns") + run, err = NewAnalysisRunFromTemplates(templates, clusterTemplates, args, []v1alpha1.DryRun{}, []v1alpha1.MeasurementRetention{}, "foo-run", "foo-run-generate-", "my-ns") assert.Nil(t, run) assert.Equal(t, fmt.Errorf("args.unresolved was not resolved"), err) // Fail flatten metric @@ -573,7 +624,7 @@ func TestNewAnalysisRunFromTemplates(t *testing.T) { } // Fail Flatten Templates templates = append(templates, matchingMetric) - run, err = NewAnalysisRunFromTemplates(templates, clusterTemplates, args, []v1alpha1.DryRun{}, "foo-run", "foo-run-generate-", "my-ns") + run, err = NewAnalysisRunFromTemplates(templates, clusterTemplates, args, []v1alpha1.DryRun{}, []v1alpha1.MeasurementRetention{}, "foo-run", "foo-run-generate-", "my-ns") assert.Nil(t, run) assert.Equal(t, fmt.Errorf("two metrics have the same name 'success-rate'"), err) } @@ -754,7 +805,7 @@ func TestCompatibilityNewAnalysisRunFromTemplate(t *testing.T) { }, } analysisTemplates := []*v1alpha1.AnalysisTemplate{&template} - run, err := NewAnalysisRunFromTemplates(analysisTemplates, nil, args, nil, "foo-run", "foo-run-generate-", "my-ns") + run, err := NewAnalysisRunFromTemplates(analysisTemplates, nil, args, nil, nil, "foo-run", "foo-run-generate-", "my-ns") assert.NoError(t, err) assert.Equal(t, "foo-run", run.Name) assert.Equal(t, "foo-run-generate-", run.GenerateName) @@ -789,7 +840,7 @@ func TestCompatibilityNewAnalysisRunFromClusterTemplate(t *testing.T) { }, } clusterAnalysisTemplates := []*v1alpha1.ClusterAnalysisTemplate{&clusterTemplate} - run, err := NewAnalysisRunFromTemplates(nil, clusterAnalysisTemplates, args, nil, "foo-run", "foo-run-generate-", "my-ns") + run, err := NewAnalysisRunFromTemplates(nil, clusterAnalysisTemplates, args, nil, nil, "foo-run", "foo-run-generate-", "my-ns") assert.NoError(t, err) assert.Equal(t, "foo-run", run.Name) assert.Equal(t, "foo-run-generate-", run.GenerateName) From a051f3838bc36a0bcb61f5c0914770883ec3af02 Mon Sep 17 00:00:00 2001 From: harikrongali <81331774+harikrongali@users.noreply.github.com> Date: Tue, 18 Jan 2022 16:06:34 -0800 Subject: [PATCH 050/175] docs: fix doc for valueFrom fields for analysis args (#1763) Signed-off-by: hari rongali --- docs/features/analysis.md | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/docs/features/analysis.md b/docs/features/analysis.md index 87bd932267..f1db6579ff 100644 --- a/docs/features/analysis.md +++ b/docs/features/analysis.md @@ -426,9 +426,9 @@ spec: valueFrom: podTemplateHashValue: Latest ``` -Analysis arguments also support valueFrom for reading any Rollout fields and passing them as arguments to AnalysisTemplate. -An example would be to reference metadata labels like env and region and passing them along to AnalysisTemplate, or any field -from the Rollout status +Analysis arguments also support valueFrom for reading metadata fields and passing them as arguments to AnalysisTemplate. +An example would be to reference metadata labels like env and region and passing them along to AnalysisTemplate. + ```yaml apiVersion: argoproj.io/v1alpha1 kind: Rollout @@ -458,10 +458,38 @@ spec: valueFrom: fieldRef: fieldPath: metadata.labels['region'] - - name: canary-hash +``` + +!!! important + Available since v1.2 +Analysis arguments also support valueFrom for reading any field from Rollout status and passing them as arguments to AnalysisTemplate. +Following example references Rollout status field like aws canaryTargetGroup name and passing them along to AnalysisTemplate + +from the Rollout status +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: guestbook + labels: + appType: demo-app + buildType: nginx-app + ... + env: dev + region: us-west-2 +spec: +... + strategy: + canary: + analysis: + templates: + - templateName: args-example + args: + ... + - name: canary-targetgroup-name valueFrom: fieldRef: - fieldPath: status.canary.weights.canary.podTemplateHash + fieldPath: status.alb.canaryTargetGroup.name ``` ## BlueGreen Pre Promotion Analysis From b0ae59adb3cd59a9575d034f17f1f2ed615c44d3 Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Tue, 18 Jan 2022 16:15:44 -0800 Subject: [PATCH 051/175] fix: retry Experiment ReplicaSet scaling conflict errors (#1778) Signed-off-by: Jesse Suen --- experiments/experiment_test.go | 31 +++++++++++++++++++++++++++++-- experiments/replicaset.go | 12 ++++++++---- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/experiments/experiment_test.go b/experiments/experiment_test.go index 48358a1f7b..60c04e0723 100644 --- a/experiments/experiment_test.go +++ b/experiments/experiment_test.go @@ -7,16 +7,17 @@ import ( "testing" "time" - "k8s.io/utils/pointer" - "github.com/stretchr/testify/assert" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" kubeinformers "k8s.io/client-go/informers" k8sfake "k8s.io/client-go/kubernetes/fake" kubetesting "k8s.io/client-go/testing" + "k8s.io/utils/pointer" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned/fake" @@ -414,6 +415,32 @@ func TestFailAddScaleDownDelay(t *testing.T) { assert.Equal(t, newStatus.Phase, v1alpha1.AnalysisPhaseError) } +func TestFailAddScaleDownDelayIsConflict(t *testing.T) { + templates := generateTemplates("bar") + ex := newExperiment("foo", templates, "") + ex.Spec.ScaleDownDelaySeconds = pointer.Int32Ptr(0) + ex.Status.TemplateStatuses = []v1alpha1.TemplateStatus{ + generateTemplatesStatus("bar", 1, 1, v1alpha1.TemplateStatusRunning, now()), + } + rs := templateToRS(ex, templates[0], 1) + rs.Spec.Replicas = pointer.Int32(0) + + exCtx := newTestContext(ex, rs) + exCtx.templateRSs["bar"] = rs + + fakeClient := exCtx.kubeclientset.(*k8sfake.Clientset) + updateCalled := false + fakeClient.PrependReactor("update", "replicasets", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { + updateCalled = true + return true, nil, k8serrors.NewConflict(schema.GroupResource{}, "guestbook", errors.New("intentional-error")) + }) + newStatus := exCtx.reconcile() + assert.True(t, updateCalled) + assert.Equal(t, v1alpha1.TemplateStatusRunning, newStatus.TemplateStatuses[0].Status) + assert.Equal(t, "", newStatus.TemplateStatuses[0].Message) + assert.Equal(t, newStatus.Phase, v1alpha1.AnalysisPhaseRunning) +} + // TestDeleteOutdatedService verifies that outdated service for Template in templateServices map is deleted and new service is created func TestDeleteOutdatedService(t *testing.T) { templates := generateTemplates("bar") diff --git a/experiments/replicaset.go b/experiments/replicaset.go index 4d0c165425..1b9bd7c16f 100644 --- a/experiments/replicaset.go +++ b/experiments/replicaset.go @@ -6,12 +6,10 @@ import ( "fmt" "time" - "github.com/argoproj/argo-rollouts/utils/defaults" - timeutil "github.com/argoproj/argo-rollouts/utils/time" - log "github.com/sirupsen/logrus" appsv1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/api/errors" + k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" patchtypes "k8s.io/apimachinery/pkg/types" @@ -20,10 +18,12 @@ import ( "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/conditions" + "github.com/argoproj/argo-rollouts/utils/defaults" experimentutil "github.com/argoproj/argo-rollouts/utils/experiment" logutil "github.com/argoproj/argo-rollouts/utils/log" "github.com/argoproj/argo-rollouts/utils/record" replicasetutil "github.com/argoproj/argo-rollouts/utils/replicaset" + timeutil "github.com/argoproj/argo-rollouts/utils/time" ) const ( @@ -268,7 +268,11 @@ func (ec *experimentContext) scaleReplicaSetAndRecordEvent(rs *appsv1.ReplicaSet } scaled, newRS, err := ec.scaleReplicaSet(rs, newScale, scalingOperation) if err != nil { - // TODO(jessesuen): gracefully handle conflict issues + if k8serrors.IsConflict(err) { + ec.log.Warnf("Retrying scaling of ReplicaSet '%s': %s", rs.Name, err) + ec.enqueueExperimentAfter(ec.ex, time.Second) + return false, nil, nil + } msg := fmt.Sprintf("Failed to scale %s %s: %v", rs.Name, scalingOperation, err) ec.recorder.Warnf(ec.ex, record.EventOptions{EventReason: "ReplicaSetUpdateError"}, msg) } else { From 0d3b000c2f13c2d8a4e7498636dcdfc539c0defd Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Tue, 18 Jan 2022 17:59:03 -0800 Subject: [PATCH 052/175] fix: controller could panic in scaling events with analysis (#1699) Signed-off-by: Jesse Suen --- rollout/bluegreen.go | 6 ++++-- rollout/canary.go | 4 ++++ rollout/context.go | 17 +++++++++++++++-- rollout/service.go | 8 ++++++++ rollout/sync.go | 42 +++++------------------------------------- 5 files changed, 36 insertions(+), 41 deletions(-) diff --git a/rollout/bluegreen.go b/rollout/bluegreen.go index ef6df170ee..afcad812eb 100644 --- a/rollout/bluegreen.go +++ b/rollout/bluegreen.go @@ -127,6 +127,8 @@ func (c *rolloutContext) isBlueGreenFastTracked(activeSvc *corev1.Service) bool return false } +// reconcileBlueGreenPause will automatically pause or resume the blue-green rollout +// depending if auto-promotion is enabled and we have passedAutoPromotionSeconds func (c *rolloutContext) reconcileBlueGreenPause(activeSvc, previewSvc *corev1.Service) { if c.rollout.Status.Abort { return @@ -136,8 +138,8 @@ func (c *rolloutContext) reconcileBlueGreenPause(activeSvc, previewSvc *corev1.S c.log.Infof("New RS '%s' is not ready to pause", c.newRS.Name) return } - if c.rollout.Spec.Paused { - c.log.Info("rollout has been paused by user") + if reason := c.haltProgress(); reason != "" { + c.log.Infof("skipping pause reconciliation: %s", reason) return } if c.isBlueGreenFastTracked(activeSvc) { diff --git a/rollout/canary.go b/rollout/canary.go index 4aca373efe..03a4682fb5 100644 --- a/rollout/canary.go +++ b/rollout/canary.go @@ -405,6 +405,10 @@ func (c *rolloutContext) syncRolloutStatusCanary() error { } func (c *rolloutContext) reconcileCanaryReplicaSets() (bool, error) { + if haltReason := c.haltProgress(); haltReason != "" { + c.log.Infof("Skipping canary/stable ReplicaSet reconciliation: %s", haltReason) + return false, nil + } err := c.removeScaleDownDeadlines() if err != nil { return false, err diff --git a/rollout/context.go b/rollout/context.go index 5ebd566409..f8fa5b5f03 100644 --- a/rollout/context.go +++ b/rollout/context.go @@ -74,8 +74,8 @@ func (c *rolloutContext) reconcile() error { return err } - if getPauseCondition(c.rollout, v1alpha1.PauseReasonInconclusiveAnalysis) != nil || c.rollout.Spec.Paused || isScalingEvent { - return c.syncReplicasOnly(isScalingEvent) + if isScalingEvent { + return c.syncReplicasOnly() } if c.rollout.Spec.Strategy.BlueGreen != nil { @@ -141,3 +141,16 @@ func (c *rolloutContext) SetCurrentAnalysisRuns(currARs analysisutil.CurrentAnal } } } + +// haltProgress returns a reason on whether or not we should halt all progress with an update +// to ReplicaSet counts (e.g. due to canary steps or blue-green promotion). This is either because +// user explicitly paused the rollout by setting `spec.paused`, or the analysis was inconclusive +func (c *rolloutContext) haltProgress() string { + if c.rollout.Spec.Paused { + return "user paused" + } + if getPauseCondition(c.rollout, v1alpha1.PauseReasonInconclusiveAnalysis) != nil { + return "inconclusive analysis" + } + return "" +} diff --git a/rollout/service.go b/rollout/service.go index 7a8e77ab05..308cc91497 100644 --- a/rollout/service.go +++ b/rollout/service.go @@ -76,6 +76,10 @@ func (c *rolloutContext) reconcilePreviewService(previewSvc *corev1.Service) err if previewSvc == nil { return nil } + if haltReason := c.haltProgress(); haltReason != "" { + c.log.Infof("Skipping preview service reconciliation: %s", haltReason) + return nil + } newPodHash := c.newRS.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] err := c.switchServiceSelector(previewSvc, newPodHash, c.rollout) if err != nil { @@ -86,6 +90,10 @@ func (c *rolloutContext) reconcilePreviewService(previewSvc *corev1.Service) err } func (c *rolloutContext) reconcileActiveService(activeSvc *corev1.Service) error { + if haltReason := c.haltProgress(); haltReason != "" { + c.log.Infof("Skipping active service reconciliation: %s", haltReason) + return nil + } if !replicasetutil.ReadyForPause(c.rollout, c.newRS, c.allRSs) || !annotations.IsSaturated(c.rollout, c.newRS) { c.log.Infof("skipping active service switch: New RS '%s' is not fully saturated", c.newRS.Name) return nil diff --git a/rollout/sync.go b/rollout/sync.go index ee1da25ef4..337cfa462a 100644 --- a/rollout/sync.go +++ b/rollout/sync.go @@ -266,8 +266,8 @@ func (c *rolloutContext) createDesiredReplicaSet() (*appsv1.ReplicaSet, error) { } // syncReplicasOnly is responsible for reconciling rollouts on scaling events. -func (c *rolloutContext) syncReplicasOnly(isScaling bool) error { - c.log.Infof("Syncing replicas only (userPaused %v, isScaling: %v)", c.rollout.Spec.Paused, isScaling) +func (c *rolloutContext) syncReplicasOnly() error { + c.log.Infof("Syncing replicas only due to scaling event") _, err := c.getAllReplicaSetsAndSyncRevision(false) if err != nil { return err @@ -276,15 +276,9 @@ func (c *rolloutContext) syncReplicasOnly(isScaling bool) error { // NOTE: it is possible for newRS to be nil (e.g. when template and replicas changed at same time) if c.rollout.Spec.Strategy.BlueGreen != nil { previewSvc, activeSvc, err := c.getPreviewAndActiveServices() - // Keep existing analysis runs if the rollout is paused - c.SetCurrentAnalysisRuns(c.currentArs) if err != nil { return nil } - err = c.podRestarter.Reconcile(c) - if err != nil { - return err - } if err := c.reconcileBlueGreenReplicaSets(activeSvc); err != nil { // If we get an error while trying to scale, the rollout will be requeued // so we can abort this resync @@ -295,37 +289,11 @@ func (c *rolloutContext) syncReplicasOnly(isScaling bool) error { // The controller wants to use the rolloutCanary method to reconcile the rollout if the rollout is not paused. // If there are no scaling events, the rollout should only sync its status if c.rollout.Spec.Strategy.Canary != nil { - err = c.podRestarter.Reconcile(c) - if err != nil { - return err - } - - if isScaling { - if _, err := c.reconcileCanaryReplicaSets(); err != nil { - // If we get an error while trying to scale, the rollout will be requeued - // so we can abort this resync - return err - } - } - // Reconciling AnalysisRuns to manage Background AnalysisRun if necessary - err = c.reconcileAnalysisRuns() - if err != nil { - return err - } - - // reconcileCanaryPause will ensure we will requeue this rollout at the appropriate time - // if we are at a pause step with a duration. - c.reconcileCanaryPause() - err = c.reconcileStableAndCanaryService() - if err != nil { - return err - } - - err = c.reconcileTrafficRouting() - if err != nil { + if _, err := c.reconcileCanaryReplicaSets(); err != nil { + // If we get an error while trying to scale, the rollout will be requeued + // so we can abort this resync return err } - return c.syncRolloutStatusCanary() } return fmt.Errorf("no rollout strategy provided") From 19cbe3442b842a6f5c204593347cada6b8e7f44c Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Tue, 18 Jan 2022 18:35:49 -0800 Subject: [PATCH 053/175] fix: delay service injection of selector labels until ReplicaSet available (#1777) Signed-off-by: Jesse Suen --- rollout/canary.go | 7 ++-- rollout/canary_test.go | 12 +++---- rollout/service.go | 23 ++++++++----- rollout/service_test.go | 50 +++++++++++++++++++++++++++++ utils/replicaset/replicaset.go | 8 ++--- utils/replicaset/replicaset_test.go | 38 +++++++++++++++------- 6 files changed, 105 insertions(+), 33 deletions(-) diff --git a/rollout/canary.go b/rollout/canary.go index 03a4682fb5..b666d503e8 100644 --- a/rollout/canary.go +++ b/rollout/canary.go @@ -220,10 +220,9 @@ func (c *rolloutContext) scaleDownOldReplicaSetsForCanary(oldRSs []*appsv1.Repli // It is safe to scale the intermediate RS down, if no traffic is directed to it. c.log.Infof("scaling down intermediate RS '%s'", targetRS.Name) } else { - c.log.Infof("DEBUG CANNOT scaling down intermediate RS '%s'", targetRS.Name) - // The current and stable ReplicaSets have not reached readiness. This implies - // we might not have shifted traffic away from this ReplicaSet so we need to - // keep this scaled up. + c.log.Infof("Skip scaling down intermediate RS '%s': still referenced by service", targetRS.Name) + // This ReplicaSet is still referenced by the service. It is not safe to scale + // this down. continue } } diff --git a/rollout/canary_test.go b/rollout/canary_test.go index 754a916660..0961dad44c 100644 --- a/rollout/canary_test.go +++ b/rollout/canary_test.go @@ -1186,7 +1186,7 @@ func TestCanaryRolloutWithCanaryService(t *testing.T) { func TestCanarySVCSelectors(t *testing.T) { for _, tc := range []struct { canaryReplicas int32 - canaryReadyReplicas int32 + canaryAvailReplicas int32 shouldTargetNewRS bool }{ @@ -1247,7 +1247,7 @@ func TestCanarySVCSelectors(t *testing.T) { Replicas: pointer.Int32Ptr(tc.canaryReplicas), }, Status: v1.ReplicaSetStatus{ - ReadyReplicas: tc.canaryReadyReplicas, + AvailableReplicas: tc.canaryAvailReplicas, }, }, stableRS: &v1.ReplicaSet{ @@ -1267,12 +1267,12 @@ func TestCanarySVCSelectors(t *testing.T) { assert.NoError(t, err, "unable to get updated canary service") if tc.shouldTargetNewRS { assert.Equal(t, selectorNewRSVal, updatedCanarySVC.Spec.Selector[v1alpha1.DefaultRolloutUniqueLabelKey], - "canary SVC should have newRS selector label when newRS has %d replicas and %d ReadyReplicas", - tc.canaryReplicas, tc.canaryReadyReplicas) + "canary SVC should have newRS selector label when newRS has %d replicas and %d AvailableReplicas", + tc.canaryReplicas, tc.canaryAvailReplicas) } else { assert.Empty(t, updatedCanarySVC.Spec.Selector[v1alpha1.DefaultRolloutUniqueLabelKey], - "canary SVC should not have newRS selector label when newRS has %d replicas and %d ReadyReplicas", - tc.canaryReplicas, tc.canaryReadyReplicas) + "canary SVC should not have newRS selector label when newRS has %d replicas and %d AvailableReplicas", + tc.canaryReplicas, tc.canaryAvailReplicas) } } } diff --git a/rollout/service.go b/rollout/service.go index 308cc91497..b0ba6588b1 100644 --- a/rollout/service.go +++ b/rollout/service.go @@ -248,16 +248,15 @@ func (c *rolloutContext) reconcileStableAndCanaryService() error { if err != nil { return err } - - if replicasetutil.IsReplicaSetReady(c.newRS) { - err = c.ensureSVCTargets(c.rollout.Spec.Strategy.Canary.CanaryService, c.newRS) - if err != nil { - return err - } + err = c.ensureSVCTargets(c.rollout.Spec.Strategy.Canary.CanaryService, c.newRS) + if err != nil { + return err } return nil } +// ensureSVCTargets updates the service with the given name to point to the given ReplicaSet, +// but only if that ReplicaSet has full availability. func (c *rolloutContext) ensureSVCTargets(svcName string, rs *appsv1.ReplicaSet) error { if rs == nil || svcName == "" { return nil @@ -266,8 +265,16 @@ func (c *rolloutContext) ensureSVCTargets(svcName string, rs *appsv1.ReplicaSet) if err != nil { return err } - if svc.Spec.Selector[v1alpha1.DefaultRolloutUniqueLabelKey] != rs.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] { - err = c.switchServiceSelector(svc, rs.Labels[v1alpha1.DefaultRolloutUniqueLabelKey], c.rollout) + currSelector := svc.Spec.Selector[v1alpha1.DefaultRolloutUniqueLabelKey] + desiredSelector := rs.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] + if currSelector != desiredSelector { + // ensure ReplicaSet is fully available, otherwise we will point the service to nothing or an underprovisioned ReplicaSet + if !replicasetutil.IsReplicaSetAvailable(rs) { + logCtx := c.log.WithField(logutil.ServiceKey, svc.Name) + logCtx.Infof("delaying service switch from %s to %s: ReplicaSet not fully available", currSelector, desiredSelector) + return nil + } + err = c.switchServiceSelector(svc, desiredSelector, c.rollout) if err != nil { return err } diff --git a/rollout/service_test.go b/rollout/service_test.go index c55be8ef7a..3e0affc53f 100644 --- a/rollout/service_test.go +++ b/rollout/service_test.go @@ -738,3 +738,53 @@ func TestShouldVerifyTargetGroups(t *testing.T) { assert.True(t, roCtx.shouldVerifyTargetGroup(activeSvc)) }) } + +// TestDelayCanaryStableServiceLabelInjection verifies we don't inject pod hash labels to the canary +// or stable service before the pods for them are ready. +func TestDelayCanaryStableServiceLabelInjection(t *testing.T) { + ro1 := newCanaryRollout("foo", 3, nil, nil, nil, intstr.FromInt(1), intstr.FromInt(1)) + ro1.Spec.Strategy.Canary.CanaryService = "canary" + ro1.Spec.Strategy.Canary.StableService = "stable" + canarySvc := newService("canary", 80, ro1.Spec.Selector.MatchLabels, nil) + stableSvc := newService("stable", 80, ro1.Spec.Selector.MatchLabels, nil) + ro2 := bumpVersion(ro1) + + f := newFixture(t) + defer f.Close() + f.kubeobjects = append(f.kubeobjects, canarySvc, stableSvc) + f.serviceLister = append(f.serviceLister, canarySvc, stableSvc) + + { + // first ensure we don't update service because new/stable are both not available + ctrl, _, _ := f.newController(noResyncPeriodFunc) + roCtx, err := ctrl.newRolloutContext(ro1) + assert.NoError(t, err) + + roCtx.newRS = newReplicaSetWithStatus(ro1, 3, 0) + roCtx.stableRS = newReplicaSetWithStatus(ro2, 3, 0) + + err = roCtx.reconcileStableAndCanaryService() + assert.NoError(t, err) + _, canaryInjected := canarySvc.Spec.Selector[v1alpha1.DefaultRolloutUniqueLabelKey] + assert.False(t, canaryInjected) + _, stableInjected := stableSvc.Spec.Selector[v1alpha1.DefaultRolloutUniqueLabelKey] + assert.False(t, stableInjected) + } + { + // next ensure we do update service because new/stable are now available + ctrl, _, _ := f.newController(noResyncPeriodFunc) + roCtx, err := ctrl.newRolloutContext(ro1) + assert.NoError(t, err) + + roCtx.newRS = newReplicaSetWithStatus(ro1, 3, 3) + roCtx.stableRS = newReplicaSetWithStatus(ro2, 3, 3) + + err = roCtx.reconcileStableAndCanaryService() + assert.NoError(t, err) + _, canaryInjected := canarySvc.Spec.Selector[v1alpha1.DefaultRolloutUniqueLabelKey] + assert.True(t, canaryInjected) + _, stableInjected := stableSvc.Spec.Selector[v1alpha1.DefaultRolloutUniqueLabelKey] + assert.True(t, stableInjected) + } + +} diff --git a/utils/replicaset/replicaset.go b/utils/replicaset/replicaset.go index ce72d90e56..2292eaa1bc 100644 --- a/utils/replicaset/replicaset.go +++ b/utils/replicaset/replicaset.go @@ -623,12 +623,12 @@ func GetPodsOwnedByReplicaSet(ctx context.Context, client kubernetes.Interface, return podOwnedByRS, nil } -// IsReplicaSetReady returns if a ReplicaSet is scaled up and its ready count is >= desired count -func IsReplicaSetReady(rs *appsv1.ReplicaSet) bool { +// IsReplicaSetAvailable returns if a ReplicaSet is scaled up and its ready count is >= desired count +func IsReplicaSetAvailable(rs *appsv1.ReplicaSet) bool { if rs == nil { return false } replicas := rs.Spec.Replicas - readyReplicas := rs.Status.ReadyReplicas - return replicas != nil && *replicas != 0 && readyReplicas != 0 && *replicas <= readyReplicas + availableReplicas := rs.Status.AvailableReplicas + return replicas != nil && *replicas != 0 && availableReplicas != 0 && *replicas <= availableReplicas } diff --git a/utils/replicaset/replicaset_test.go b/utils/replicaset/replicaset_test.go index 89c1933d9f..ada18a8c1b 100644 --- a/utils/replicaset/replicaset_test.go +++ b/utils/replicaset/replicaset_test.go @@ -1249,9 +1249,9 @@ spec: assert.True(t, PodTemplateEqualIgnoreHash(&live, &desired)) } -func TestIsReplicaSetReady(t *testing.T) { +func TestIsReplicaSetAvailable(t *testing.T) { { - assert.False(t, IsReplicaSetReady(nil)) + assert.False(t, IsReplicaSetAvailable(nil)) } { rs := appsv1.ReplicaSet{ @@ -1259,10 +1259,11 @@ func TestIsReplicaSetReady(t *testing.T) { Replicas: pointer.Int32Ptr(1), }, Status: appsv1.ReplicaSetStatus{ - ReadyReplicas: 0, + ReadyReplicas: 0, + AvailableReplicas: 0, }, } - assert.False(t, IsReplicaSetReady(&rs)) + assert.False(t, IsReplicaSetAvailable(&rs)) } { rs := appsv1.ReplicaSet{ @@ -1270,10 +1271,11 @@ func TestIsReplicaSetReady(t *testing.T) { Replicas: pointer.Int32Ptr(1), }, Status: appsv1.ReplicaSetStatus{ - ReadyReplicas: 1, + ReadyReplicas: 1, + AvailableReplicas: 1, }, } - assert.True(t, IsReplicaSetReady(&rs)) + assert.True(t, IsReplicaSetAvailable(&rs)) } { rs := appsv1.ReplicaSet{ @@ -1281,10 +1283,11 @@ func TestIsReplicaSetReady(t *testing.T) { Replicas: pointer.Int32Ptr(1), }, Status: appsv1.ReplicaSetStatus{ - ReadyReplicas: 2, + ReadyReplicas: 2, + AvailableReplicas: 2, }, } - assert.True(t, IsReplicaSetReady(&rs)) + assert.True(t, IsReplicaSetAvailable(&rs)) } { rs := appsv1.ReplicaSet{ @@ -1292,10 +1295,23 @@ func TestIsReplicaSetReady(t *testing.T) { Replicas: pointer.Int32Ptr(0), }, Status: appsv1.ReplicaSetStatus{ - ReadyReplicas: 0, + ReadyReplicas: 0, + AvailableReplicas: 0, }, } - // NOTE: currently consider scaled down replicas as not ready - assert.False(t, IsReplicaSetReady(&rs)) + // NOTE: currently consider scaled down replicas as not available + assert.False(t, IsReplicaSetAvailable(&rs)) + } + { + rs := appsv1.ReplicaSet{ + Spec: appsv1.ReplicaSetSpec{ + Replicas: pointer.Int32Ptr(0), + }, + Status: appsv1.ReplicaSetStatus{ + ReadyReplicas: 1, + AvailableReplicas: 0, + }, + } + assert.False(t, IsReplicaSetAvailable(&rs)) } } From e10d151145a857ad0445743f03e82a31e95d02bf Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Tue, 18 Jan 2022 22:03:09 -0800 Subject: [PATCH 054/175] fix: notifications using workloadRef did not have access to pod template (#1786) Signed-off-by: Jesse Suen --- utils/record/record.go | 68 ++++++++++++++++++++++++++++++------- utils/record/record_test.go | 47 +++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 13 deletions(-) diff --git a/utils/record/record.go b/utils/record/record.go index 0b6d063a54..f7e9ad7395 100644 --- a/utils/record/record.go +++ b/utils/record/record.go @@ -3,31 +3,30 @@ package record import ( "context" "encoding/json" - - "github.com/argoproj/notifications-engine/pkg/services" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/client-go/tools/cache" - "regexp" "strings" "time" - k8sinformers "k8s.io/client-go/informers" - "github.com/argoproj/notifications-engine/pkg/api" + "github.com/argoproj/notifications-engine/pkg/services" "github.com/argoproj/notifications-engine/pkg/subscriptions" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" + k8sinformers "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes" k8sfake "k8s.io/client-go/kubernetes/fake" typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1" + "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/record" "k8s.io/kubectl/pkg/scheme" + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" rolloutscheme "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned/scheme" logutil "github.com/argoproj/argo-rollouts/utils/log" ) @@ -235,15 +234,11 @@ func (e *EventRecorderAdapter) sendNotifications(object runtime.Object, opts Eve return nil } - objBytes, err := json.Marshal(object) - if err != nil { - return err - } - var objMap map[string]interface{} - err = json.Unmarshal(objBytes, &objMap) + objMap, err := toObjectMap(object) if err != nil { return err } + for _, dest := range destinations { err = notificationsAPI.Send(objMap, triggerActions[0].Send, dest) if err != nil { @@ -254,6 +249,53 @@ func (e *EventRecorderAdapter) sendNotifications(object runtime.Object, opts Eve return nil } +// toObjectMap converts an object to a map for the purposes of sending to the notification engine +func toObjectMap(object interface{}) (map[string]interface{}, error) { + objBytes, err := json.Marshal(object) + if err != nil { + return nil, err + } + var objMap map[string]interface{} + err = json.Unmarshal(objBytes, &objMap) + if err != nil { + return nil, err + } + + // The JSON marshalling above drops the `spec.template` and `spec.selectors` fields if the rollout + // is using workload referencing. The following restores those fields in the returned object map + // so that notification templates can refer to them (as if workload ref was not used). + if ro, ok := object.(*v1alpha1.Rollout); ok && ro.Spec.WorkloadRef != nil { + templateBytes, err := json.Marshal(ro.Spec.Template) + if err != nil { + return nil, err + } + var templateMap map[string]interface{} + err = json.Unmarshal(templateBytes, &templateMap) + if err != nil { + return nil, err + } + err = unstructured.SetNestedMap(objMap, templateMap, "spec", "template") + if err != nil { + return nil, err + } + + selectorBytes, err := json.Marshal(ro.Spec.Selector) + if err != nil { + return nil, err + } + var selectorMap map[string]interface{} + err = json.Unmarshal(selectorBytes, &selectorMap) + if err != nil { + return nil, err + } + err = unstructured.SetNestedMap(objMap, selectorMap, "spec", "selector") + if err != nil { + return nil, err + } + } + return objMap, nil +} + func translateReasonToTrigger(reason string) string { var matchFirstCap = regexp.MustCompile("(.)([A-Z][a-z]+)") var matchAllCap = regexp.MustCompile("([a-z0-9])([A-Z])") diff --git a/utils/record/record_test.go b/utils/record/record_test.go index 15b89f83dd..c7fe164fd9 100644 --- a/utils/record/record_test.go +++ b/utils/record/record_test.go @@ -16,7 +16,9 @@ import ( dto "github.com/prometheus/client_model/go" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" ) @@ -171,3 +173,48 @@ func TestNewAPIFactorySettings(t *testing.T) { assert.Equal(t, map[string]interface{}{"rollout": rollout}, vars) } + +func TestWorkloadRefObjectMap(t *testing.T) { + ro := v1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Name: "guestbook", + Namespace: "default", + Annotations: map[string]string{"notifications.argoproj.io/subscribe.on-missing-reason.console": "console"}, + }, + Spec: v1alpha1.RolloutSpec{ + TemplateResolvedFromRef: true, + SelectorResolvedFromRef: true, + WorkloadRef: &v1alpha1.ObjectRef{ + Kind: "Deployment", + Name: "foo", + APIVersion: "apps/v1", + }, + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "foo", + }, + }, + }, + }, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "foo": "bar", + }, + }, + }, + } + objMap, err := toObjectMap(&ro) + assert.NoError(t, err) + + templateMap, ok, err := unstructured.NestedMap(objMap, "spec", "template") + assert.NoError(t, err) + assert.True(t, ok) + assert.NotNil(t, templateMap) + + selectorMap, ok, err := unstructured.NestedMap(objMap, "spec", "selector") + assert.NoError(t, err) + assert.True(t, ok) + assert.NotNil(t, selectorMap) +} From 0041d378483887bb39e0ce59de4eb3e93450c32f Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Wed, 19 Jan 2022 14:55:42 -0800 Subject: [PATCH 055/175] fix: plugin did not set deployment image when using workloadRef (#1787) Signed-off-by: Jesse Suen --- manifests/dashboard-install.yaml | 7 ++ .../dashboard-clusterrole.yaml | 7 ++ .../cmd/set/set_image.go | 46 ++++++++--- pkg/kubectl-argo-rollouts/cmd/set/set_test.go | 82 +++++++++++++++++++ server/server.go | 5 +- 5 files changed, 136 insertions(+), 11 deletions(-) diff --git a/manifests/dashboard-install.yaml b/manifests/dashboard-install.yaml index 4ecf48208e..d31c27b37e 100644 --- a/manifests/dashboard-install.yaml +++ b/manifests/dashboard-install.yaml @@ -50,6 +50,13 @@ rules: - get - list - watch +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - update - apiGroups: - apps resources: diff --git a/manifests/dashboard-install/dashboard-clusterrole.yaml b/manifests/dashboard-install/dashboard-clusterrole.yaml index 7523a16ed0..dd541479a0 100644 --- a/manifests/dashboard-install/dashboard-clusterrole.yaml +++ b/manifests/dashboard-install/dashboard-clusterrole.yaml @@ -40,6 +40,13 @@ rules: - get - list - watch + - apiGroups: + - apps + resources: + - deployments + verbs: + - get + - update - apiGroups: - apps resources: diff --git a/pkg/kubectl-argo-rollouts/cmd/set/set_image.go b/pkg/kubectl-argo-rollouts/cmd/set/set_image.go index 4be9989c90..c1a66c935c 100644 --- a/pkg/kubectl-argo-rollouts/cmd/set/set_image.go +++ b/pkg/kubectl-argo-rollouts/cmd/set/set_image.go @@ -9,6 +9,7 @@ import ( k8serr "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" @@ -44,8 +45,10 @@ func NewCmdSetImage(o *options.ArgoRolloutsOptions) *cobra.Command { container := imageSplit[0] image := imageSplit[1] + var un *unstructured.Unstructured + var err error for attempt := 0; attempt < maxAttempts; attempt++ { - err := SetImage(o.DynamicClientset(), o.Namespace(), rollout, container, image) + un, err = SetImage(o.DynamicClientset(), o.Namespace(), rollout, container, image) if err != nil { if k8serr.IsConflict(err) && attempt < maxAttempts { continue @@ -54,33 +57,56 @@ func NewCmdSetImage(o *options.ArgoRolloutsOptions) *cobra.Command { } break } - fmt.Fprintf(o.Out, "rollout \"%s\" image updated\n", rollout) + fmt.Fprintf(o.Out, "%s \"%s\" image updated\n", strings.ToLower(un.GetKind()), un.GetName()) return nil }, } return cmd } +var deploymentGVR = schema.GroupVersionResource{ + Group: "apps", + Version: "v1", + Resource: "deployments", +} + // SetImage updates a rollout's container image // We use a dynamic clientset instead of a rollout clientset in order to allow an older plugin // to still work with a newer version of Rollouts (without dropping newly introduced fields during // the marshalling) -func SetImage(dynamicClient dynamic.Interface, namespace, rollout, container, image string) error { +func SetImage(dynamicClient dynamic.Interface, namespace, rollout, container, image string) (*unstructured.Unstructured, error) { ctx := context.TODO() rolloutIf := dynamicClient.Resource(v1alpha1.RolloutGVR).Namespace(namespace) ro, err := rolloutIf.Get(ctx, rollout, metav1.GetOptions{}) if err != nil { - return err + return nil, err } - newRo, err := newRolloutSetImage(ro, container, image) + workloadRef, ok, err := unstructured.NestedMap(ro.Object, "spec", "workloadRef") if err != nil { - return err + return nil, err } - _, err = rolloutIf.Update(ctx, newRo, metav1.UpdateOptions{}) - if err != nil { - return err + if ok { + deployIf := dynamicClient.Resource(deploymentGVR).Namespace(namespace) + deployName, ok := workloadRef["name"].(string) + if !ok { + return nil, fmt.Errorf("spec.workloadRef.name is not a string: %v", workloadRef["name"]) + } + deployUn, err := deployIf.Get(ctx, deployName, metav1.GetOptions{}) + if err != nil { + return nil, err + } + newDeploy, err := newRolloutSetImage(deployUn, container, image) + if err != nil { + return nil, err + } + return deployIf.Update(ctx, newDeploy, metav1.UpdateOptions{}) + } else { + newRo, err := newRolloutSetImage(ro, container, image) + if err != nil { + return nil, err + } + return rolloutIf.Update(ctx, newRo, metav1.UpdateOptions{}) } - return nil } func newRolloutSetImage(orig *unstructured.Unstructured, container string, image string) (*unstructured.Unstructured, error) { diff --git a/pkg/kubectl-argo-rollouts/cmd/set/set_test.go b/pkg/kubectl-argo-rollouts/cmd/set/set_test.go index 7b116ac66e..3e2baeceed 100644 --- a/pkg/kubectl-argo-rollouts/cmd/set/set_test.go +++ b/pkg/kubectl-argo-rollouts/cmd/set/set_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" k8serr "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -299,3 +300,84 @@ func TestSetImageConflict(t *testing.T) { assert.Empty(t, stderr) assert.True(t, updateCalls > 0) } + +func TestSetImageWorkloadRef(t *testing.T) { + ro := v1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Name: "guestbook", + Namespace: metav1.NamespaceDefault, + }, + Spec: v1alpha1.RolloutSpec{ + WorkloadRef: &v1alpha1.ObjectRef{ + APIVersion: "apps/v1", + Kind: "Deployment", + Name: "guestbook", + }, + }, + } + deploy := appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "guestbook", + Namespace: metav1.NamespaceDefault, + }, + Spec: appsv1.DeploymentSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + InitContainers: []corev1.Container{ + { + Name: "guestbook", + Image: "argoproj/rollouts-demo:blue", + }, + }, + Containers: []corev1.Container{ + { + Name: "foo", + Image: "alpine:3.8", + }, + { + Name: "guestbook", + Image: "argoproj/rollouts-demo:blue", + }, + { + Name: "bar", + Image: "alpine:3.8", + }, + }, + EphemeralContainers: []corev1.EphemeralContainer{ + { + EphemeralContainerCommon: corev1.EphemeralContainerCommon{ + Name: "guestbook", + Image: "argoproj/rollouts-demo:blue", + }, + }, + }, + }, + }, + }, + } + + tf, o := options.NewFakeArgoRolloutsOptions(&ro, &deploy) + defer tf.Cleanup() + + cmd := NewCmdSetImage(o) + cmd.PersistentPreRunE = o.PersistentPreRunE + cmd.SetArgs([]string{"guestbook", "guestbook=argoproj/rollouts-demo:NEWIMAGE"}) + err := cmd.Execute() + assert.NoError(t, err) + + newDeployUn, err := o.DynamicClientset().Resource(deploymentGVR).Namespace(ro.Namespace).Get(context.Background(), "guestbook", metav1.GetOptions{}) + assert.NoError(t, err) + var newDeploy appsv1.Deployment + err = runtime.DefaultUnstructuredConverter.FromUnstructured(newDeployUn.Object, &newDeploy) + assert.NoError(t, err) + assert.Equal(t, "argoproj/rollouts-demo:NEWIMAGE", newDeploy.Spec.Template.Spec.Containers[1].Image) + assert.Equal(t, "alpine:3.8", newDeploy.Spec.Template.Spec.Containers[0].Image) + assert.Equal(t, "alpine:3.8", newDeploy.Spec.Template.Spec.Containers[2].Image) + assert.Equal(t, "argoproj/rollouts-demo:NEWIMAGE", newDeploy.Spec.Template.Spec.InitContainers[0].Image) + assert.Equal(t, "argoproj/rollouts-demo:NEWIMAGE", newDeploy.Spec.Template.Spec.EphemeralContainers[0].Image) + + stdout := o.Out.(*bytes.Buffer).String() + stderr := o.ErrOut.(*bytes.Buffer).String() + assert.Equal(t, stdout, "deployment \"guestbook\" image updated\n") + assert.Empty(t, stderr) +} diff --git a/server/server.go b/server/server.go index 6e4033accb..3079aae0df 100644 --- a/server/server.go +++ b/server/server.go @@ -397,7 +397,10 @@ func (s *ArgoRolloutsServer) getRollout(namespace string, name string) (*v1alpha func (s *ArgoRolloutsServer) SetRolloutImage(ctx context.Context, q *rollout.SetImageRequest) (*v1alpha1.Rollout, error) { imageString := fmt.Sprintf("%s:%s", q.GetImage(), q.GetTag()) - set.SetImage(s.Options.DynamicClientset, q.GetNamespace(), q.GetRollout(), q.GetContainer(), imageString) + _, err := set.SetImage(s.Options.DynamicClientset, q.GetNamespace(), q.GetRollout(), q.GetContainer(), imageString) + if err != nil { + return nil, err + } return s.getRollout(q.GetNamespace(), q.GetRollout()) } From f5c229b5370c924df6c4c62707bcf3736feb5c6a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Jan 2022 16:40:41 -0800 Subject: [PATCH 056/175] chore(deps): bump github.com/antonmedv/expr from 1.8.9 to 1.9.0 (#1712) Bumps [github.com/antonmedv/expr](https://github.com/antonmedv/expr) from 1.8.9 to 1.9.0. - [Release notes](https://github.com/antonmedv/expr/releases) - [Commits](https://github.com/antonmedv/expr/compare/v1.8.9...v1.9.0) --- updated-dependencies: - dependency-name: github.com/antonmedv/expr dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 9517a6affd..3c946eccc8 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/argoproj/argo-rollouts go 1.16 require ( - github.com/antonmedv/expr v1.8.9 + github.com/antonmedv/expr v1.9.0 github.com/argoproj/notifications-engine v0.3.0 github.com/argoproj/pkg v0.9.0 github.com/aws/aws-sdk-go-v2/config v1.8.1 diff --git a/go.sum b/go.sum index 232f101410..ef7d369993 100644 --- a/go.sum +++ b/go.sum @@ -139,8 +139,9 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5 github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/antonmedv/expr v1.8.9 h1:O9stiHmHHww9b4ozhPx7T6BK7fXfOCHJ8ybxf0833zw= github.com/antonmedv/expr v1.8.9/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmHhwGEk8= +github.com/antonmedv/expr v1.9.0 h1:j4HI3NHEdgDnN9p6oI6Ndr0G5QryMY0FNxT4ONrFDGU= +github.com/antonmedv/expr v1.9.0/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmHhwGEk8= github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA= github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= From 05afadb2f3f0b9b76540b9de76e4b492b432f5e2 Mon Sep 17 00:00:00 2001 From: Remington Breeze Date: Thu, 20 Jan 2022 12:59:13 -0800 Subject: [PATCH 057/175] fix(ui): Truncate long container names (#1793) Signed-off-by: Remington Breeze --- ui/src/app/components/rollout/containers.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ui/src/app/components/rollout/containers.tsx b/ui/src/app/components/rollout/containers.tsx index 6c31e7b9a9..051c8c606c 100644 --- a/ui/src/app/components/rollout/containers.tsx +++ b/ui/src/app/components/rollout/containers.tsx @@ -98,8 +98,12 @@ const ContainerWidget = (props: {container: RolloutContainerInfo; images: ImageI return (
{container.name}
-
- {!editing ? : img.image)} placeholder='New Image' {...newImageInput} />} +
+ {!editing ? ( + + ) : ( + img.image)} placeholder='New Image' {...newImageInput} /> + )}
); From 86055eefd022fbbf0b6ff4f0d24d9fbdc491d1d4 Mon Sep 17 00:00:00 2001 From: Remington Breeze Date: Thu, 20 Jan 2022 14:31:54 -0800 Subject: [PATCH 058/175] fix(ui): Show container images in dashboard for rollouts with a WorkloadRef (#1792) Signed-off-by: Remington Breeze --- pkg/kubectl-argo-rollouts/info/info_test.go | 12 ++++++------ pkg/kubectl-argo-rollouts/info/rollout_info.go | 14 +++++++++++--- .../viewcontroller/viewcontroller.go | 13 ++++++++++++- pkg/signals/signal_posix.go | 1 + server/server.go | 6 +++--- 5 files changed, 33 insertions(+), 13 deletions(-) diff --git a/pkg/kubectl-argo-rollouts/info/info_test.go b/pkg/kubectl-argo-rollouts/info/info_test.go index 45c3bac921..2f69d2dd6c 100644 --- a/pkg/kubectl-argo-rollouts/info/info_test.go +++ b/pkg/kubectl-argo-rollouts/info/info_test.go @@ -21,7 +21,7 @@ func TestAge(t *testing.T) { func TestCanaryRolloutInfo(t *testing.T) { rolloutObjs := testdata.NewCanaryRollout() - roInfo := NewRolloutInfo(rolloutObjs.Rollouts[0], rolloutObjs.ReplicaSets, rolloutObjs.Pods, rolloutObjs.Experiments, rolloutObjs.AnalysisRuns) + roInfo := NewRolloutInfo(rolloutObjs.Rollouts[0], rolloutObjs.ReplicaSets, rolloutObjs.Pods, rolloutObjs.Experiments, rolloutObjs.AnalysisRuns, nil) assert.Equal(t, roInfo.ObjectMeta.Name, rolloutObjs.Rollouts[0].Name) assert.Len(t, Revisions(roInfo), 3) @@ -40,7 +40,7 @@ func TestCanaryRolloutInfo(t *testing.T) { func TestBlueGreenRolloutInfo(t *testing.T) { { rolloutObjs := testdata.NewBlueGreenRollout() - roInfo := NewRolloutInfo(rolloutObjs.Rollouts[0], rolloutObjs.ReplicaSets, rolloutObjs.Pods, rolloutObjs.Experiments, rolloutObjs.AnalysisRuns) + roInfo := NewRolloutInfo(rolloutObjs.Rollouts[0], rolloutObjs.ReplicaSets, rolloutObjs.Pods, rolloutObjs.Experiments, rolloutObjs.AnalysisRuns, nil) assert.Equal(t, roInfo.ObjectMeta.Name, rolloutObjs.Rollouts[0].Name) assert.Len(t, Revisions(roInfo), 3) @@ -67,7 +67,7 @@ func TestBlueGreenRolloutInfo(t *testing.T) { inFourHours := timeutil.Now().Add(4 * time.Hour).Truncate(time.Second).UTC().Format(time.RFC3339) rolloutObjs.ReplicaSets[0].Annotations[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey] = inFourHours delayedRs := rolloutObjs.ReplicaSets[0].ObjectMeta.UID - roInfo := NewRolloutInfo(rolloutObjs.Rollouts[0], rolloutObjs.ReplicaSets, rolloutObjs.Pods, rolloutObjs.Experiments, rolloutObjs.AnalysisRuns) + roInfo := NewRolloutInfo(rolloutObjs.Rollouts[0], rolloutObjs.ReplicaSets, rolloutObjs.Pods, rolloutObjs.Experiments, rolloutObjs.AnalysisRuns, nil) assert.Equal(t, roInfo.ReplicaSets[1].ObjectMeta.UID, delayedRs) assert.Equal(t, roInfo.ReplicaSets[1].ScaleDownDeadline, inFourHours) @@ -77,7 +77,7 @@ func TestBlueGreenRolloutInfo(t *testing.T) { func TestExperimentAnalysisRolloutInfo(t *testing.T) { rolloutObjs := testdata.NewExperimentAnalysisRollout() - roInfo := NewRolloutInfo(rolloutObjs.Rollouts[0], rolloutObjs.ReplicaSets, rolloutObjs.Pods, rolloutObjs.Experiments, rolloutObjs.AnalysisRuns) + roInfo := NewRolloutInfo(rolloutObjs.Rollouts[0], rolloutObjs.ReplicaSets, rolloutObjs.Pods, rolloutObjs.Experiments, rolloutObjs.AnalysisRuns, nil) assert.Equal(t, roInfo.ObjectMeta.Name, rolloutObjs.Rollouts[0].Name) assert.Len(t, Revisions(roInfo), 2) @@ -115,14 +115,14 @@ func TestExperimentInfo(t *testing.T) { func TestRolloutStatusInvalidSpec(t *testing.T) { rolloutObjs := testdata.NewInvalidRollout() - roInfo := NewRolloutInfo(rolloutObjs.Rollouts[0], rolloutObjs.ReplicaSets, rolloutObjs.Pods, rolloutObjs.Experiments, rolloutObjs.AnalysisRuns) + roInfo := NewRolloutInfo(rolloutObjs.Rollouts[0], rolloutObjs.ReplicaSets, rolloutObjs.Pods, rolloutObjs.Experiments, rolloutObjs.AnalysisRuns, nil) assert.Equal(t, "Degraded", roInfo.Status) assert.Equal(t, "InvalidSpec: The Rollout \"rollout-invalid\" is invalid: spec.template.metadata.labels: Invalid value: map[string]string{\"app\":\"doesnt-match\"}: `selector` does not match template `labels`", roInfo.Message) } func TestRolloutAborted(t *testing.T) { rolloutObjs := testdata.NewAbortedRollout() - roInfo := NewRolloutInfo(rolloutObjs.Rollouts[0], rolloutObjs.ReplicaSets, rolloutObjs.Pods, rolloutObjs.Experiments, rolloutObjs.AnalysisRuns) + roInfo := NewRolloutInfo(rolloutObjs.Rollouts[0], rolloutObjs.ReplicaSets, rolloutObjs.Pods, rolloutObjs.Experiments, rolloutObjs.AnalysisRuns, nil) assert.Equal(t, "Degraded", roInfo.Status) assert.Equal(t, `RolloutAborted: metric "web" assessed Failed due to failed (1) > failureLimit (0)`, roInfo.Message) } diff --git a/pkg/kubectl-argo-rollouts/info/rollout_info.go b/pkg/kubectl-argo-rollouts/info/rollout_info.go index 08b2194e08..2f67876f2b 100644 --- a/pkg/kubectl-argo-rollouts/info/rollout_info.go +++ b/pkg/kubectl-argo-rollouts/info/rollout_info.go @@ -22,6 +22,7 @@ func NewRolloutInfo( allPods []*corev1.Pod, allExperiments []*v1alpha1.Experiment, allARs []*v1alpha1.AnalysisRun, + workloadRef *appsv1.Deployment, ) *rollout.RolloutInfo { roInfo := rollout.RolloutInfo{ @@ -75,9 +76,16 @@ func NewRolloutInfo( roInfo.Message = message roInfo.Icon = rolloutIcon(roInfo.Status) roInfo.Containers = []*rollout.ContainerInfo{} - for c := range ro.Spec.Template.Spec.Containers { - curContainer := ro.Spec.Template.Spec.Containers[c] - roInfo.Containers = append(roInfo.Containers, &rollout.ContainerInfo{Name: curContainer.Name, Image: curContainer.Image}) + + var containerList []corev1.Container + if workloadRef != nil { + containerList = workloadRef.Spec.Template.Spec.Containers + } else { + containerList = ro.Spec.Template.Spec.Containers + } + + for _, c := range containerList { + roInfo.Containers = append(roInfo.Containers, &rollout.ContainerInfo{Name: c.Name, Image: c.Image}) } if ro.Status.RestartedAt != nil { diff --git a/pkg/kubectl-argo-rollouts/viewcontroller/viewcontroller.go b/pkg/kubectl-argo-rollouts/viewcontroller/viewcontroller.go index 247ca64b39..f8cec8bc0f 100644 --- a/pkg/kubectl-argo-rollouts/viewcontroller/viewcontroller.go +++ b/pkg/kubectl-argo-rollouts/viewcontroller/viewcontroller.go @@ -8,6 +8,7 @@ import ( "github.com/argoproj/argo-rollouts/utils/queue" log "github.com/sirupsen/logrus" + v1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/informers" @@ -39,6 +40,7 @@ type viewController struct { rolloutLister rolloutlisters.RolloutNamespaceLister experimentLister rolloutlisters.ExperimentNamespaceLister analysisRunLister rolloutlisters.AnalysisRunNamespaceLister + deploymentLister appslisters.DeploymentNamespaceLister cacheSyncs []cache.InformerSynced @@ -100,6 +102,7 @@ func newViewController(namespace string, name string, kubeClient kubernetes.Inte rolloutLister: rolloutsInformerFactory.Argoproj().V1alpha1().Rollouts().Lister().Rollouts(namespace), experimentLister: rolloutsInformerFactory.Argoproj().V1alpha1().Experiments().Lister().Experiments(namespace), analysisRunLister: rolloutsInformerFactory.Argoproj().V1alpha1().AnalysisRuns().Lister().AnalysisRuns(namespace), + deploymentLister: kubeInformerFactory.Apps().V1().Deployments().Lister().Deployments(namespace), workqueue: workqueue.NewRateLimitingQueue(queue.DefaultArgoRolloutsRateLimiter()), } @@ -194,7 +197,15 @@ func (c *RolloutViewController) GetRolloutInfo() (*rollout.RolloutInfo, error) { return nil, err } - roInfo := info.NewRolloutInfo(ro, allReplicaSets, allPods, allExps, allAnalysisRuns) + var workloadRef *v1.Deployment + if ro.Spec.WorkloadRef != nil { + workloadRef, err = c.deploymentLister.Get(ro.Spec.WorkloadRef.Name) + if err != nil { + return nil, err + } + } + + roInfo := info.NewRolloutInfo(ro, allReplicaSets, allPods, allExps, allAnalysisRuns, workloadRef) return roInfo, nil } diff --git a/pkg/signals/signal_posix.go b/pkg/signals/signal_posix.go index 808c4489ee..56184b9a3e 100644 --- a/pkg/signals/signal_posix.go +++ b/pkg/signals/signal_posix.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package signals diff --git a/server/server.go b/server/server.go index 3079aae0df..bc9661c5b5 100644 --- a/server/server.go +++ b/server/server.go @@ -269,7 +269,7 @@ func (s *ArgoRolloutsServer) ListRolloutInfos(ctx context.Context, q *rollout.Ro var riList []*rollout.RolloutInfo for i := range rolloutList.Items { cur := rolloutList.Items[i] - ri := info.NewRolloutInfo(&cur, nil, nil, nil, nil) + ri := info.NewRolloutInfo(&cur, nil, nil, nil, nil, nil) ri.ReplicaSets = info.GetReplicaSetInfo(cur.UID, &cur, allReplicaSets, allPods) riList = append(riList, ri) } @@ -346,7 +346,7 @@ func (s *ArgoRolloutsServer) WatchRolloutInfos(q *rollout.RolloutInfoListQuery, } // get shallow rollout info - ri := info.NewRolloutInfo(ro, allReplicaSets, allPods, nil, nil) + ri := info.NewRolloutInfo(ro, allReplicaSets, allPods, nil, nil, nil) send(ri) } } @@ -358,7 +358,7 @@ func (s *ArgoRolloutsServer) RolloutToRolloutInfo(ro *v1alpha1.Rollout) (*rollou if err != nil { return nil, err } - return info.NewRolloutInfo(ro, allReplicaSets, allPods, nil, nil), nil + return info.NewRolloutInfo(ro, allReplicaSets, allPods, nil, nil, nil), nil } func (s *ArgoRolloutsServer) GetNamespace(ctx context.Context, e *empty.Empty) (*rollout.NamespaceInfo, error) { From 12400538a8a4045722b41afae604df2009e63e73 Mon Sep 17 00:00:00 2001 From: Remington Breeze Date: Thu, 20 Jan 2022 14:42:34 -0800 Subject: [PATCH 059/175] fix(ui): Requesting cluster scoped namespaces does not fail gracefully in UI (#1795) Signed-off-by: Remington Breeze --- ui/src/app/App.tsx | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/ui/src/app/App.tsx b/ui/src/app/App.tsx index bbc5bec71f..504878a683 100644 --- a/ui/src/app/App.tsx +++ b/ui/src/app/App.tsx @@ -60,12 +60,23 @@ const App = () => { const [namespace, setNamespace] = React.useState(init); const [availableNamespaces, setAvailableNamespaces] = React.useState([]); React.useEffect(() => { - RolloutAPI.rolloutServiceGetNamespace().then((info) => { - if (!namespace) { - setNamespace(info.namespace); - } - setAvailableNamespaces(info.availableNamespaces); - }); + try { + RolloutAPI.rolloutServiceGetNamespace() + .then((info) => { + if (!info) { + throw new Error(); + } + if (!namespace) { + setNamespace(info.namespace); + } + setAvailableNamespaces(info.availableNamespaces); + }) + .catch((e) => { + setAvailableNamespaces([namespace]); + }); + } catch (e) { + setAvailableNamespaces([namespace]); + } }, []); const changeNamespace = (val: string) => { setNamespace(val); From 4c9adae82f622ae2999bfe16ad3ca3f1bc37bc3c Mon Sep 17 00:00:00 2001 From: Rohit Agrawal Date: Fri, 21 Jan 2022 04:52:05 +0530 Subject: [PATCH 060/175] chore: Fix istio vs reconcile errors (#1460) Signed-off-by: Rohit Agrawal --- rollout/trafficrouting/istio/istio.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/rollout/trafficrouting/istio/istio.go b/rollout/trafficrouting/istio/istio.go index 108ece240c..b4f3e75cdd 100644 --- a/rollout/trafficrouting/istio/istio.go +++ b/rollout/trafficrouting/istio/istio.go @@ -242,16 +242,22 @@ func (r *Reconciler) reconcileVirtualService(obj *unstructured.Unstructured, vsv } } + // Generate Patches patches := r.generateVirtualServicePatches(vsvcRouteNames, httpRoutes, vsvcTLSRoutes, tlsRoutes, int64(desiredWeight), additionalDestinations...) err = patches.patchVirtualService(httpRoutesI, tlsRoutesI) if err != nil { return nil, false, err } - err = unstructured.SetNestedSlice(newObj.Object, httpRoutesI, "spec", Http) - if err != nil { - return newObj, len(patches) > 0, err + // Set HTTP Route Slice + if len(httpRoutes) > 0 { + err = unstructured.SetNestedSlice(newObj.Object, httpRoutesI, "spec", Http) + if err != nil { + return newObj, len(patches) > 0, err + } } + + // Set TLS Route Slice if tlsRoutesI != nil { err = unstructured.SetNestedSlice(newObj.Object, tlsRoutesI, "spec", Tls) } From 030427ec95a89eb58c0df25c6abdfbfc36c39670 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Jan 2022 17:20:56 -0800 Subject: [PATCH 061/175] chore(deps): bump github.com/aws/aws-sdk-go-v2/config (#1791) Bumps [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) from 1.8.1 to 1.13.0. - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.8.1...v1.13.0) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go-v2/config dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 40 ++++++++++++++++++++++------------------ 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/go.mod b/go.mod index 3c946eccc8..20437cfbb8 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/antonmedv/expr v1.9.0 github.com/argoproj/notifications-engine v0.3.0 github.com/argoproj/pkg v0.9.0 - github.com/aws/aws-sdk-go-v2/config v1.8.1 + github.com/aws/aws-sdk-go-v2/config v1.13.0 github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.5.0 github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.6.1 github.com/blang/semver v3.5.1+incompatible diff --git a/go.sum b/go.sum index ef7d369993..f781c3ab8b 100644 --- a/go.sum +++ b/go.sum @@ -167,30 +167,34 @@ github.com/aws/aws-sdk-go v1.35.24/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9 github.com/aws/aws-sdk-go v1.38.49/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go-v2 v1.7.0/go.mod h1:tb9wi5s61kTDA5qCkcDbt3KRVV74GGslQkl/DRdX/P4= github.com/aws/aws-sdk-go-v2 v1.8.1/go.mod h1:xEFuWz+3TYdlPRuo+CqATbeDWIWyaT5uAPwPaWtgse0= -github.com/aws/aws-sdk-go-v2 v1.9.0 h1:+S+dSqQCN3MSU5vJRu1HqHrq00cJn6heIMU7X9hcsoo= -github.com/aws/aws-sdk-go-v2 v1.9.0/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= -github.com/aws/aws-sdk-go-v2/config v1.8.1 h1:AcAenV2NVwOViG+3ts73uT08L1olN4NBNNz7lUlHSUo= -github.com/aws/aws-sdk-go-v2/config v1.8.1/go.mod h1:AQtpYfVYjuuft4Dgh0jGSkPQJ9MvmK9vXfSub7oSXlI= -github.com/aws/aws-sdk-go-v2/credentials v1.4.1 h1:oDiUP50hKRwC6xAgESAj46lgL2prJRZQWnCBzn+TU/c= -github.com/aws/aws-sdk-go-v2/credentials v1.4.1/go.mod h1:dgGR+Qq7Wjcd4AOAW5Rf5Tnv3+x7ed6kETXyS9WCuAY= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.5.0 h1:OxTAgH8Y4BXHD6PGCJ8DHx2kaZPCQfSTqmDsdRZFezE= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.5.0/go.mod h1:CpNzHK9VEFUCknu50kkB8z58AH2B5DvPP7ea1LHve/Y= -github.com/aws/aws-sdk-go-v2/internal/ini v1.2.2 h1:d95cddM3yTm4qffj3P6EnP+TzX1SSkWaQypXSgT/hpA= -github.com/aws/aws-sdk-go-v2/internal/ini v1.2.2/go.mod h1:BQV0agm+JEhqR+2RT5e1XTFIDcAAV0eW6z2trp+iduw= +github.com/aws/aws-sdk-go-v2 v1.13.0 h1:1XIXAfxsEmbhbj5ry3D3vX+6ZcUYvIqSm4CWWEuGZCA= +github.com/aws/aws-sdk-go-v2 v1.13.0/go.mod h1:L6+ZpqHaLbAaxsqV0L4cvxZY7QupWJB4fhkf8LXvC7w= +github.com/aws/aws-sdk-go-v2/config v1.13.0 h1:1ij3YPk13RrIn1h+pH+dArh3lNPD5JSAP+ifOkNhnB0= +github.com/aws/aws-sdk-go-v2/config v1.13.0/go.mod h1:Pjv2OafecIn+4miw9VFDCr06YhKyf/oKOkIcpQOgWKk= +github.com/aws/aws-sdk-go-v2/credentials v1.8.0 h1:8Ow0WcyDesGNL0No11jcgb1JAtE+WtubqXjgxau+S0o= +github.com/aws/aws-sdk-go-v2/credentials v1.8.0/go.mod h1:gnMo58Vwx3Mu7hj1wpcG8DI0s57c9o42UQ6wgTQT5to= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.10.0 h1:NITDuUZO34mqtOwFWZiXo7yAHj7kf+XPE+EiKuCBNUI= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.10.0/go.mod h1:I6/fHT/fH460v09eg2gVrd8B/IqskhNdpcLH0WNO3QI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.4 h1:CRiQJ4E2RhfDdqbie1ZYDo8QtIo75Mk7oTdJSfwJTMQ= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.4/go.mod h1:XHgQ7Hz2WY2GAn//UXHofLfPXWh+s62MbMOijrg12Lw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.2.0 h1:3ADoioDMOtF4uiK59vCpplpCwugEU+v4ZFD29jDL3RQ= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.2.0/go.mod h1:BsCSJHx5DnDXIrOcqB8KN1/B+hXLG/bi4Y6Vjcx/x9E= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.4 h1:0NrDHIwS1LIR750ltj6ciiu4NZLpr9rgq8vHi/4QD4s= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.4/go.mod h1:R3sWUqPcfXSiF/LSFJhjyJmpg9uV6yP2yv3YZZjldVI= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.5.0 h1:XO1uX7dQKWfD0WzycEfz+bL/7rl0SsQ05VJwLPWGzGM= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.5.0/go.mod h1:acH3+MQoiMzozT/ivU+DbRg7Ooo2298RdRaWcOv+4vM= github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.6.1 h1:mGc8UvJS4XJv8Tp7Doxlx2p3vfwPx46K9zg+9s9szPE= github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.6.1/go.mod h1:lGKz4aJbqGX+pgyXG47ZBAJPjwrlA5+TJsAuJ2+aE2g= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.0 h1:VNJ5NLBteVXEwE2F1zEXVmyIH58mZ6kIQGJoC7C+vkg= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.0/go.mod h1:R1KK+vY8AfalhG1AOu5e35pOD2SdoPKQCFLTvnxiohk= -github.com/aws/aws-sdk-go-v2/service/sso v1.4.0 h1:sHXMIKYS6YiLPzmKSvDpPmOpJDHxmAUgbiF49YNVztg= -github.com/aws/aws-sdk-go-v2/service/sso v1.4.0/go.mod h1:+1fpWnL96DL23aXPpMGbsmKe8jLTEfbjuQoA4WS1VaA= -github.com/aws/aws-sdk-go-v2/service/sts v1.7.0 h1:1at4e5P+lvHNl2nUktdM2/v+rpICg/QSEr9TO/uW9vU= -github.com/aws/aws-sdk-go-v2/service/sts v1.7.0/go.mod h1:0qcSMCyASQPN2sk/1KQLQ2Fh6yq8wm0HSDAimPhzCoM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0 h1:4QAOB3KrvI1ApJK14sliGr3Ie2pjyvNypn/lfzDHfUw= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0/go.mod h1:K/qPe6AP2TGYv4l6n7c88zh9jWBDf6nHhvg1fx/EWfU= +github.com/aws/aws-sdk-go-v2/service/sso v1.9.0 h1:1qLJeQGBmNQW3mBNzK2CFmrQNmoXWrscPqsrAaU1aTA= +github.com/aws/aws-sdk-go-v2/service/sso v1.9.0/go.mod h1:vCV4glupK3tR7pw7ks7Y4jYRL86VvxS+g5qk04YeWrU= +github.com/aws/aws-sdk-go-v2/service/sts v1.14.0 h1:ksiDXhvNYg0D2/UFkLejsaz3LqpW5yjNQ8Nx9Sn2c0E= +github.com/aws/aws-sdk-go-v2/service/sts v1.14.0/go.mod h1:u0xMJKDvvfocRjiozsoZglVNXRG19043xzp3r2ivLIk= github.com/aws/smithy-go v1.5.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.7.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= -github.com/aws/smithy-go v1.8.0 h1:AEwwwXQZtUwP5Mz506FeXXrKBe0jA8gVM+1gEcSRooc= -github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/aws/smithy-go v1.10.0 h1:gsoZQMNHnX+PaghNw4ynPsyGP7aUCqx5sY2dlPQsZ0w= +github.com/aws/smithy-go v1.10.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= From 6fabe9d31fce77240404f1a80d5204de68c58bac Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Thu, 20 Jan 2022 20:37:35 -0800 Subject: [PATCH 062/175] fix: plugin panic while watching progress (#1796) Signed-off-by: Jesse Suen --- .../cmd/status/status.go | 27 ++++++++++++------- .../cmd/status/status_test.go | 2 +- .../viewcontroller/viewcontroller.go | 5 ++++ 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/pkg/kubectl-argo-rollouts/cmd/status/status.go b/pkg/kubectl-argo-rollouts/cmd/status/status.go index fe7058f1d5..826debb207 100644 --- a/pkg/kubectl-argo-rollouts/cmd/status/status.go +++ b/pkg/kubectl-argo-rollouts/cmd/status/status.go @@ -72,7 +72,7 @@ func NewCmdStatus(o *options.ArgoRolloutsOptions) *cobra.Command { }) go controller.Run(ctx) statusOptions.WatchStatus(ctx.Done(), rolloutUpdates) - close(rolloutUpdates) + defer close(rolloutUpdates) // the final rollout info after timeout or reach Healthy or Degraded status ri, err = controller.GetRolloutInfo() @@ -98,7 +98,7 @@ func NewCmdStatus(o *options.ArgoRolloutsOptions) *cobra.Command { func (o *StatusOptions) WatchStatus(stopCh <-chan struct{}, rolloutUpdates <-chan *rollout.RolloutInfo) string { timeout := make(chan bool) var roInfo *rollout.RolloutInfo - var preventFlicker time.Time + var prevMessage string if o.Timeout != 0 { go func() { @@ -107,16 +107,25 @@ func (o *StatusOptions) WatchStatus(stopCh <-chan struct{}, rolloutUpdates <-cha }() } + printStatus := func(roInfo rollout.RolloutInfo) { + message := roInfo.Status + if roInfo.Message != "" { + message = fmt.Sprintf("%s - %s", roInfo.Status, roInfo.Message) + } + if message != prevMessage { + fmt.Fprintln(o.Out, message) + prevMessage = message + } + } + for { select { case roInfo = <-rolloutUpdates: - if roInfo != nil && roInfo.Status == "Healthy" || roInfo.Status == "Degraded" { - fmt.Fprintln(o.Out, roInfo.Status) - return roInfo.Status - } - if roInfo != nil && time.Now().After(preventFlicker.Add(200*time.Millisecond)) { - fmt.Fprintf(o.Out, "%s - %s\n", roInfo.Status, roInfo.Message) - preventFlicker = time.Now() + if roInfo != nil { + printStatus(*roInfo) + if roInfo.Status == "Healthy" || roInfo.Status == "Degraded" { + return roInfo.Status + } } case <-stopCh: return "" diff --git a/pkg/kubectl-argo-rollouts/cmd/status/status_test.go b/pkg/kubectl-argo-rollouts/cmd/status/status_test.go index 24c103d584..ddbee9b24e 100644 --- a/pkg/kubectl-argo-rollouts/cmd/status/status_test.go +++ b/pkg/kubectl-argo-rollouts/cmd/status/status_test.go @@ -120,7 +120,7 @@ func TestWatchAbortedRollout(t *testing.T) { assert.Error(t, err) stdout := o.Out.(*bytes.Buffer).String() stderr := o.ErrOut.(*bytes.Buffer).String() - assert.Equal(t, "Degraded\n", stdout) + assert.Equal(t, "Degraded - RolloutAborted: metric \"web\" assessed Failed due to failed (1) > failureLimit (0)\n", stdout) assert.Equal(t, "Error: The rollout is in a degraded state with message: RolloutAborted: metric \"web\" assessed Failed due to failed (1) > failureLimit (0)\n", stderr) } diff --git a/pkg/kubectl-argo-rollouts/viewcontroller/viewcontroller.go b/pkg/kubectl-argo-rollouts/viewcontroller/viewcontroller.go index f8cec8bc0f..157f148d5f 100644 --- a/pkg/kubectl-argo-rollouts/viewcontroller/viewcontroller.go +++ b/pkg/kubectl-argo-rollouts/viewcontroller/viewcontroller.go @@ -147,6 +147,7 @@ func (c *viewController) Run(ctx context.Context) error { } }, time.Second, ctx.Done()) <-ctx.Done() + c.DeregisterCallbacks() return nil } @@ -171,6 +172,10 @@ func (c *viewController) processNextWorkItem() bool { return true } +func (c *viewController) DeregisterCallbacks() { + c.callbacks = nil +} + func (c *RolloutViewController) GetRolloutInfo() (*rollout.RolloutInfo, error) { ro, err := c.rolloutLister.Get(c.name) if err != nil { From a74ad8eb9c3e076e40b9b35d2693f3d9c1a874f8 Mon Sep 17 00:00:00 2001 From: nissy34 <33037628+nissy34@users.noreply.github.com> Date: Fri, 21 Jan 2022 10:26:55 +0200 Subject: [PATCH 063/175] fix: Promote-full with dynamicStableScaling increases weight according to available canary pods. Fixes: #1681 (#1683) Signed-off-by: Nissan Hefetz --- rollout/trafficrouting.go | 9 ++++ rollout/trafficrouting_test.go | 86 ++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/rollout/trafficrouting.go b/rollout/trafficrouting.go index 2f3b549f31..8e194c1e70 100644 --- a/rollout/trafficrouting.go +++ b/rollout/trafficrouting.go @@ -129,6 +129,15 @@ func (c *rolloutContext) reconcileTrafficRouting() error { } else if c.newRS == nil || c.newRS.Status.AvailableReplicas == 0 { // when newRS is not available or replicas num is 0. never weight to canary weightDestinations = append(weightDestinations, c.calculateWeightDestinationsFromExperiment()...) + } else if c.rollout.Status.PromoteFull { + // on a promote full, desired stable weight should be 0 (100% to canary), + // But we can only increase canary weight according to available replica counts of the canary. + // we will need to set the desiredWeight to 0 when the newRS is not available. + if c.rollout.Spec.Strategy.Canary.DynamicStableScale { + desiredWeight = (100 * c.newRS.Status.AvailableReplicas) / *c.rollout.Spec.Replicas + } else if c.rollout.Status.Canary.Weights != nil { + desiredWeight = c.rollout.Status.Canary.Weights.Canary.Weight + } } else if index != nil { atDesiredReplicaCount := replicasetutil.AtDesiredReplicaCountsForCanary(c.rollout, c.newRS, c.stableRS, c.otherRSs, nil) if !atDesiredReplicaCount && !c.rollout.Status.PromoteFull { diff --git a/rollout/trafficrouting_test.go b/rollout/trafficrouting_test.go index 1328276a55..6c6cce6d83 100644 --- a/rollout/trafficrouting_test.go +++ b/rollout/trafficrouting_test.go @@ -58,6 +58,14 @@ func newUnmockedFakeTrafficRoutingReconciler() *[]*mocks.TrafficRoutingReconcile return &reconcilerList } +// newUnmockedSingalFakeTrafficRoutingReconciler returns a fake TrafficRoutingReconciler with unmocked +// methods (except Type() mocked) +func newUnmockedSingalFakeTrafficRoutingReconciler() *mocks.TrafficRoutingReconciler { + trafficRoutingReconciler := mocks.TrafficRoutingReconciler{} + trafficRoutingReconciler.On("Type").Return("fake") + return &trafficRoutingReconciler +} + func newTrafficWeightFixture(t *testing.T) (*fixture, *v1alpha1.Rollout) { f := newFixture(t) defer f.Close() @@ -189,6 +197,7 @@ func TestRolloutUseDesiredWeight(t *testing.T) { }) fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(true, nil) } + f.run(getKey(r2, t)) } @@ -390,6 +399,83 @@ func TestRolloutUsePreviousSetWeight(t *testing.T) { f.run(getKey(r2, t)) } +func TestRolloutUseDynamicWeightOnPromoteFull(t *testing.T) { + f := newFixture(t) + defer f.Close() + + steps := []v1alpha1.CanaryStep{ + { + SetWeight: pointer.Int32Ptr(5), + }, + { + SetWeight: pointer.Int32Ptr(25), + }, + } + r1 := newCanaryRollout("foo", 10, nil, steps, pointer.Int32Ptr(1), intstr.FromInt(1), intstr.FromInt(0)) + r2 := bumpVersion(r1) + r2.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{} + r2.Spec.Strategy.Canary.CanaryService = "canary" + r2.Spec.Strategy.Canary.StableService = "stable" + + rs1 := newReplicaSetWithStatus(r1, 5, 5) + rs2 := newReplicaSetWithStatus(r2, 10, 5) + + rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] + rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] + canarySelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash} + stableSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs1PodHash} + canarySvc := newService("canary", 80, canarySelector, r2) + stableSvc := newService("stable", 80, stableSelector, r2) + + r2.Status.Canary.Weights = &v1alpha1.TrafficWeights{ + Canary: v1alpha1.WeightDestination{ + Weight: 5, + ServiceName: "canary", + PodTemplateHash: rs2PodHash, + }, + Stable: v1alpha1.WeightDestination{ + Weight: 95, + ServiceName: "stable", + PodTemplateHash: rs1PodHash, + }, + } + + f.kubeobjects = append(f.kubeobjects, rs1, rs2, canarySvc, stableSvc) + f.replicaSetLister = append(f.replicaSetLister, rs1, rs2) + + r2 = updateCanaryRolloutStatus(r2, rs1PodHash, 15, 0, 10, false) + r2.Status.PromoteFull = true + f.rolloutLister = append(f.rolloutLister, r2) + f.objects = append(f.objects, r2) + + f.expectUpdateReplicaSetAction(rs2) + f.expectPatchRolloutAction(r2) + + t.Run("DynamicStableScale true", func(t *testing.T) { + r2.Spec.Strategy.Canary.DynamicStableScale = true + f.fakeSingleTrafficRouting = newUnmockedSingalFakeTrafficRoutingReconciler() + f.fakeSingleTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) + f.fakeSingleTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { + assert.Equal(t, int32(50), desiredWeight) + return nil + }) + f.fakeSingleTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) + f.run(getKey(r2, t)) + }) + + t.Run("DynamicStableScale false", func(t *testing.T) { + r2.Spec.Strategy.Canary.DynamicStableScale = false + f.fakeSingleTrafficRouting = newUnmockedSingalFakeTrafficRoutingReconciler() + f.fakeSingleTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) + f.fakeSingleTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { + assert.Equal(t, int32(5), desiredWeight) + return nil + }) + f.fakeSingleTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) + f.run(getKey(r2, t)) + }) +} + func TestRolloutSetWeightToZeroWhenFullyRolledOut(t *testing.T) { f := newFixture(t) defer f.Close() From 937448693cb538c8ae93bb18112b3a47ea298550 Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Tue, 25 Jan 2022 09:48:22 -0800 Subject: [PATCH 064/175] fix: canary replicas/weight could flap during abort with dynamic scaling (#1794) Signed-off-by: Jesse Suen --- rollout/controller_test.go | 10 +- rollout/restart.go | 7 + rollout/trafficrouting.go | 28 ++- rollout/trafficrouting/smi/smi.go | 6 +- rollout/trafficrouting_test.go | 365 +++++++++++++++++++----------- utils/conditions/conditions.go | 11 +- 6 files changed, 275 insertions(+), 152 deletions(-) diff --git a/rollout/controller_test.go b/rollout/controller_test.go index 32ce3b269c..8a71878027 100644 --- a/rollout/controller_test.go +++ b/rollout/controller_test.go @@ -103,9 +103,8 @@ type fixture struct { unfreezeTime func() error // events holds all the K8s Event Reasons emitted during the run - events []string - fakeTrafficRouting []*mocks.TrafficRoutingReconciler - fakeSingleTrafficRouting *mocks.TrafficRoutingReconciler + events []string + fakeTrafficRouting *mocks.TrafficRoutingReconciler } func newFixture(t *testing.T) *fixture { @@ -121,8 +120,7 @@ func newFixture(t *testing.T) *fixture { return nil } - f.fakeTrafficRouting = newFakeTrafficRoutingReconciler() - f.fakeSingleTrafficRouting = newFakeSingleTrafficRoutingReconciler() + f.fakeTrafficRouting = newFakeSingleTrafficRoutingReconciler() return f } @@ -570,7 +568,7 @@ func (f *fixture) newController(resync resyncFunc) (*Controller, informers.Share return nil, nil } var reconcilers = []trafficrouting.TrafficRoutingReconciler{} - reconcilers = append(reconcilers, f.fakeSingleTrafficRouting) + reconcilers = append(reconcilers, f.fakeTrafficRouting) return reconcilers, nil } diff --git a/rollout/restart.go b/rollout/restart.go index be8e49a9b9..a8361bf24f 100644 --- a/rollout/restart.go +++ b/rollout/restart.go @@ -143,6 +143,13 @@ func maxInt(left, right int32) int32 { return right } +func minInt(left, right int32) int32 { + if left < right { + return left + } + return right +} + // getRolloutPods returns all pods associated with a rollout func (p *RolloutPodRestarter) getRolloutPods(ctx context.Context, ro *v1alpha1.Rollout, allRSs []*appsv1.ReplicaSet) ([]*corev1.Pod, error) { pods, err := p.client.CoreV1().Pods(ro.Namespace).List(ctx, metav1.ListOptions{ diff --git a/rollout/trafficrouting.go b/rollout/trafficrouting.go index 8e194c1e70..7c018d7ec5 100644 --- a/rollout/trafficrouting.go +++ b/rollout/trafficrouting.go @@ -1,7 +1,9 @@ package rollout import ( + "fmt" "reflect" + "strings" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/rollout/trafficrouting" @@ -120,11 +122,16 @@ func (c *rolloutContext) reconcileTrafficRouting() error { if rolloututil.IsFullyPromoted(c.rollout) { // when we are fully promoted. desired canary weight should be 0 } else if c.pauseContext.IsAborted() { - // when aborted, desired canary weight should be 0 (100% to stable), *unless* we - // are using dynamic stable scaling. In that case, we can only decrease canary weight - // according to available replica counts of the stable. + // when aborted, desired canary weight should immediately be 0 (100% to stable), *unless* + // we are using dynamic stable scaling. In that case, we are dynamically decreasing the + // weight to the canary according to the availability of the stable (whatever it can support). if c.rollout.Spec.Strategy.Canary.DynamicStableScale { desiredWeight = 100 - ((100 * c.stableRS.Status.AvailableReplicas) / *c.rollout.Spec.Replicas) + if c.rollout.Status.Canary.Weights != nil { + // This ensures that if we are already at a lower weight, then we will not + // increase the weight because stable availability is flapping (e.g. pod restarts) + desiredWeight = minInt(desiredWeight, c.rollout.Status.Canary.Weights.Canary.Weight) + } } } else if c.newRS == nil || c.newRS.Status.AvailableReplicas == 0 { // when newRS is not available or replicas num is 0. never weight to canary @@ -174,6 +181,7 @@ func (c *rolloutContext) reconcileTrafficRouting() error { if modified, newWeights := calculateWeightStatus(c.rollout, canaryHash, stableHash, desiredWeight, weightDestinations...); modified { c.log.Infof("Previous weights: %v", c.rollout.Status.Canary.Weights) c.log.Infof("New weights: %v", newWeights) + c.recorder.Eventf(c.rollout, record.EventOptions{EventReason: conditions.TrafficWeightUpdatedReason}, trafficWeightUpdatedMessage(c.rollout.Status.Canary.Weights, newWeights)) c.newStatus.Canary.Weights = newWeights } @@ -204,6 +212,20 @@ func (c *rolloutContext) reconcileTrafficRouting() error { return nil } +// trafficWeightUpdatedMessage returns a message we emit for the kubernetes event whenever we adjust traffic weights +func trafficWeightUpdatedMessage(prev, new *v1alpha1.TrafficWeights) string { + var details []string + if prev == nil { + details = append(details, fmt.Sprintf("to %d", new.Canary.Weight)) + } else if prev.Canary.Weight != new.Canary.Weight { + details = append(details, fmt.Sprintf("from %d to %d", prev.Canary.Weight, new.Canary.Weight)) + } + if prev != nil && new != nil && !reflect.DeepEqual(prev.Additional, new.Additional) { + details = append(details, fmt.Sprintf("additional: %v", new.Additional)) + } + return fmt.Sprintf(conditions.TrafficWeightUpdatedMessage, strings.Join(details, ", ")) +} + // calculateWeightStatus calculates the Rollout's `status.canary.weights` values. Returns true if // it has changed from previous values (which indicates we should reset status.canary.weights.verified) func calculateWeightStatus(ro *v1alpha1.Rollout, canaryHash, stableHash string, desiredWeight int32, weightDestinations ...v1alpha1.WeightDestination) (bool, *v1alpha1.TrafficWeights) { diff --git a/rollout/trafficrouting/smi/smi.go b/rollout/trafficrouting/smi/smi.go index 8d91bf9579..a1b6c5f7fe 100644 --- a/rollout/trafficrouting/smi/smi.go +++ b/rollout/trafficrouting/smi/smi.go @@ -215,11 +215,7 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 if !isControlledBy { return fmt.Errorf("Rollout does not own TrafficSplit `%s`", trafficSplitName) } - err = r.patchTrafficSplit(existingTrafficSplit, trafficSplits) - if err == nil { - r.cfg.Recorder.Eventf(r.cfg.Rollout, record.EventOptions{EventReason: "TrafficSplitModified"}, "TrafficSplit `%s` modified", trafficSplitName) - } - return err + return r.patchTrafficSplit(existingTrafficSplit, trafficSplits) } func (r *Reconciler) generateTrafficSplits(trafficSplitName string, desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) VersionedTrafficSplits { diff --git a/rollout/trafficrouting_test.go b/rollout/trafficrouting_test.go index 6c6cce6d83..5cfb1b1341 100644 --- a/rollout/trafficrouting_test.go +++ b/rollout/trafficrouting_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/client-go/dynamic/dynamicinformer" "k8s.io/client-go/dynamic/dynamiclister" @@ -26,18 +27,6 @@ import ( timeutil "github.com/argoproj/argo-rollouts/utils/time" ) -// newFakeTrafficRoutingReconciler returns a fake TrafficRoutingReconciler with mocked success return values -func newFakeTrafficRoutingReconciler() []*mocks.TrafficRoutingReconciler { - reconcilerList := []*mocks.TrafficRoutingReconciler{} - for _, trafficRoutingReconciler := range reconcilerList { - trafficRoutingReconciler.On("Type").Return("fake") - trafficRoutingReconciler.On("SetWeight", mock.Anything, mock.Anything).Return(nil) - trafficRoutingReconciler.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) - trafficRoutingReconciler.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) - } - return reconcilerList -} - // newFakeTrafficRoutingReconciler returns a fake TrafficRoutingReconciler with mocked success return values func newFakeSingleTrafficRoutingReconciler() *mocks.TrafficRoutingReconciler { trafficRoutingReconciler := mocks.TrafficRoutingReconciler{} @@ -50,17 +39,7 @@ func newFakeSingleTrafficRoutingReconciler() *mocks.TrafficRoutingReconciler { // newUnmockedFakeTrafficRoutingReconciler returns a fake TrafficRoutingReconciler with unmocked // methods (except Type() mocked) -func newUnmockedFakeTrafficRoutingReconciler() *[]*mocks.TrafficRoutingReconciler { - reconcilerList := []*mocks.TrafficRoutingReconciler{} - for _, trafficRoutingReconciler := range reconcilerList { - trafficRoutingReconciler.On("Type").Return("fake") - } - return &reconcilerList -} - -// newUnmockedSingalFakeTrafficRoutingReconciler returns a fake TrafficRoutingReconciler with unmocked -// methods (except Type() mocked) -func newUnmockedSingalFakeTrafficRoutingReconciler() *mocks.TrafficRoutingReconciler { +func newUnmockedFakeTrafficRoutingReconciler() *mocks.TrafficRoutingReconciler { trafficRoutingReconciler := mocks.TrafficRoutingReconciler{} trafficRoutingReconciler.On("Type").Return("fake") return &trafficRoutingReconciler @@ -103,45 +82,40 @@ func newTrafficWeightFixture(t *testing.T) (*fixture, *v1alpha1.Rollout) { func TestReconcileTrafficRoutingSetWeightErr(t *testing.T) { f, ro := newTrafficWeightFixture(t) defer f.Close() - f.fakeTrafficRouting = *newUnmockedFakeTrafficRoutingReconciler() - for _, fakeTrafficRouting := range f.fakeTrafficRouting { - fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) - fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(errors.New("Error message")) - f.runExpectError(getKey(ro, t), true) - } + f.fakeTrafficRouting = newUnmockedFakeTrafficRoutingReconciler() + f.fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(errors.New("Error message")) + f.runExpectError(getKey(ro, t), true) } // verify error is not returned when VerifyWeight returns error (so that we can continue reconciling) func TestReconcileTrafficRoutingVerifyWeightErr(t *testing.T) { f, ro := newTrafficWeightFixture(t) defer f.Close() - f.fakeTrafficRouting = *newUnmockedFakeTrafficRoutingReconciler() - for _, fakeTrafficRouting := range f.fakeTrafficRouting { - fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) - fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(nil) - fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(false), errors.New("Error message")) - f.runExpectError(getKey(ro, t), true) - } + f.fakeTrafficRouting = newUnmockedFakeTrafficRoutingReconciler() + f.fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(false), errors.New("Error message")) + f.expectPatchRolloutAction(ro) + f.run(getKey(ro, t)) } // verify we requeue when VerifyWeight returns false func TestReconcileTrafficRoutingVerifyWeightFalse(t *testing.T) { f, ro := newTrafficWeightFixture(t) defer f.Close() - f.fakeTrafficRouting = *newUnmockedFakeTrafficRoutingReconciler() - for _, fakeTrafficRouting := range f.fakeTrafficRouting { - fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) - fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(nil) - fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(false), nil) - c, i, k8sI := f.newController(noResyncPeriodFunc) - enqueued := false - c.enqueueRolloutAfter = func(obj interface{}, duration time.Duration) { - enqueued = true - } - f.expectPatchRolloutAction(ro) - f.runController(getKey(ro, t), true, false, c, i, k8sI) - assert.True(t, enqueued) + f.fakeTrafficRouting = newUnmockedFakeTrafficRoutingReconciler() + f.fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(false), nil) + c, i, k8sI := f.newController(noResyncPeriodFunc) + enqueued := false + c.enqueueRolloutAfter = func(obj interface{}, duration time.Duration) { + enqueued = true } + f.expectPatchRolloutAction(ro) + f.runController(getKey(ro, t), true, false, c, i, k8sI) + assert.True(t, enqueued) } func TestRolloutUseDesiredWeight(t *testing.T) { @@ -187,17 +161,14 @@ func TestRolloutUseDesiredWeight(t *testing.T) { f.expectPatchRolloutAction(r2) - f.fakeTrafficRouting = *newUnmockedFakeTrafficRoutingReconciler() - for _, fakeTrafficRouting := range f.fakeTrafficRouting { - fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) - fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { - // make sure SetWeight was called with correct value - assert.Equal(t, int32(10), desiredWeight) - return nil - }) - fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(true, nil) - } - + f.fakeTrafficRouting = newUnmockedFakeTrafficRoutingReconciler() + f.fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { + // make sure SetWeight was called with correct value + assert.Equal(t, int32(10), desiredWeight) + return nil + }) + f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(true, nil) f.run(getKey(r2, t)) } @@ -238,16 +209,14 @@ func TestRolloutUseDesiredWeight100(t *testing.T) { f.expectPatchRolloutAction(r2) - f.fakeTrafficRouting = *newUnmockedFakeTrafficRoutingReconciler() - for _, fakeTrafficRouting := range f.fakeTrafficRouting { - fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) - fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { - // make sure SetWeight was called with correct value - assert.Equal(t, int32(100), desiredWeight) - return nil - }) - fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(true, nil) - } + f.fakeTrafficRouting = newUnmockedFakeTrafficRoutingReconciler() + f.fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { + // make sure SetWeight was called with correct value + assert.Equal(t, int32(100), desiredWeight) + return nil + }) + f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(true, nil) f.run(getKey(r2, t)) } @@ -304,45 +273,41 @@ func TestRolloutWithExperimentStep(t *testing.T) { t.Run("Experiment Running - WeightDestination created", func(t *testing.T) { ex.Status.Phase = v1alpha1.AnalysisPhaseRunning - f.fakeTrafficRouting = *newUnmockedFakeTrafficRoutingReconciler() - for _, fakeTrafficRouting := range f.fakeTrafficRouting { - fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) - fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, weightDestinations ...v1alpha1.WeightDestination) error { - // make sure SetWeight was called with correct value - assert.Equal(t, int32(10), desiredWeight) - assert.Equal(t, int32(5), weightDestinations[0].Weight) - assert.Equal(t, ex.Status.TemplateStatuses[0].ServiceName, weightDestinations[0].ServiceName) - assert.Equal(t, ex.Status.TemplateStatuses[0].PodTemplateHash, weightDestinations[0].PodTemplateHash) - return nil - }) - fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(func(desiredWeight int32, weightDestinations ...v1alpha1.WeightDestination) error { - assert.Equal(t, int32(10), desiredWeight) - assert.Equal(t, int32(5), weightDestinations[0].Weight) - assert.Equal(t, ex.Status.TemplateStatuses[0].ServiceName, weightDestinations[0].ServiceName) - assert.Equal(t, ex.Status.TemplateStatuses[0].PodTemplateHash, weightDestinations[0].PodTemplateHash) - return nil - }) - } + f.fakeTrafficRouting = newUnmockedFakeTrafficRoutingReconciler() + f.fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, weightDestinations ...v1alpha1.WeightDestination) error { + // make sure SetWeight was called with correct value + assert.Equal(t, int32(10), desiredWeight) + assert.Equal(t, int32(5), weightDestinations[0].Weight) + assert.Equal(t, ex.Status.TemplateStatuses[0].ServiceName, weightDestinations[0].ServiceName) + assert.Equal(t, ex.Status.TemplateStatuses[0].PodTemplateHash, weightDestinations[0].PodTemplateHash) + return nil + }) + f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(func(desiredWeight int32, weightDestinations ...v1alpha1.WeightDestination) error { + assert.Equal(t, int32(10), desiredWeight) + assert.Equal(t, int32(5), weightDestinations[0].Weight) + assert.Equal(t, ex.Status.TemplateStatuses[0].ServiceName, weightDestinations[0].ServiceName) + assert.Equal(t, ex.Status.TemplateStatuses[0].PodTemplateHash, weightDestinations[0].PodTemplateHash) + return nil + }) f.run(getKey(r2, t)) }) t.Run("Experiment Pending - no WeightDestination created", func(t *testing.T) { ex.Status.Phase = v1alpha1.AnalysisPhasePending - f.fakeTrafficRouting = *newUnmockedFakeTrafficRoutingReconciler() - for _, fakeTrafficRouting := range f.fakeTrafficRouting { - fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) - fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, weightDestinations ...v1alpha1.WeightDestination) error { - // make sure SetWeight was called with correct value - assert.Equal(t, int32(10), desiredWeight) - assert.Len(t, weightDestinations, 0) - return nil - }) - fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(func(desiredWeight int32, weightDestinations ...v1alpha1.WeightDestination) error { - assert.Equal(t, int32(10), desiredWeight) - assert.Len(t, weightDestinations, 0) - return nil - }) - } + f.fakeTrafficRouting = newUnmockedFakeTrafficRoutingReconciler() + f.fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, weightDestinations ...v1alpha1.WeightDestination) error { + // make sure SetWeight was called with correct value + assert.Equal(t, int32(10), desiredWeight) + assert.Len(t, weightDestinations, 0) + return nil + }) + f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(func(desiredWeight int32, weightDestinations ...v1alpha1.WeightDestination) error { + assert.Equal(t, int32(10), desiredWeight) + assert.Len(t, weightDestinations, 0) + return nil + }) f.run(getKey(r2, t)) }) } @@ -385,17 +350,15 @@ func TestRolloutUsePreviousSetWeight(t *testing.T) { f.expectUpdateReplicaSetAction(rs2) f.expectPatchRolloutAction(r2) - f.fakeTrafficRouting = *newUnmockedFakeTrafficRoutingReconciler() - for _, fakeTrafficRouting := range f.fakeTrafficRouting { - fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) - fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { - // make sure SetWeight was called with correct value - assert.Equal(t, int32(10), desiredWeight) - return nil - }) - fakeTrafficRouting.On("VerifyWeight", mock.Anything, mock.Anything).Return(pointer.BoolPtr(true), nil) - fakeTrafficRouting.On("error patching alb ingress", mock.Anything, mock.Anything).Return(true, nil) - } + f.fakeTrafficRouting = newUnmockedFakeTrafficRoutingReconciler() + f.fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { + // make sure SetWeight was called with correct value + assert.Equal(t, int32(10), desiredWeight) + return nil + }) + f.fakeTrafficRouting.On("VerifyWeight", mock.Anything, mock.Anything).Return(pointer.BoolPtr(true), nil) + f.fakeTrafficRouting.On("error patching alb ingress", mock.Anything, mock.Anything).Return(true, nil) f.run(getKey(r2, t)) } @@ -453,25 +416,25 @@ func TestRolloutUseDynamicWeightOnPromoteFull(t *testing.T) { t.Run("DynamicStableScale true", func(t *testing.T) { r2.Spec.Strategy.Canary.DynamicStableScale = true - f.fakeSingleTrafficRouting = newUnmockedSingalFakeTrafficRoutingReconciler() - f.fakeSingleTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) - f.fakeSingleTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { + f.fakeTrafficRouting = newUnmockedFakeTrafficRoutingReconciler() + f.fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { assert.Equal(t, int32(50), desiredWeight) return nil }) - f.fakeSingleTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) + f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) f.run(getKey(r2, t)) }) t.Run("DynamicStableScale false", func(t *testing.T) { r2.Spec.Strategy.Canary.DynamicStableScale = false - f.fakeSingleTrafficRouting = newUnmockedSingalFakeTrafficRoutingReconciler() - f.fakeSingleTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) - f.fakeSingleTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { + f.fakeTrafficRouting = newUnmockedFakeTrafficRoutingReconciler() + f.fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { assert.Equal(t, int32(5), desiredWeight) return nil }) - f.fakeSingleTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) + f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) f.run(getKey(r2, t)) }) } @@ -507,16 +470,14 @@ func TestRolloutSetWeightToZeroWhenFullyRolledOut(t *testing.T) { f.expectPatchRolloutAction(r1) - f.fakeTrafficRouting = *newUnmockedFakeTrafficRoutingReconciler() - for _, fakeTrafficRouting := range f.fakeTrafficRouting { - fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) - fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { - // make sure SetWeight was called with correct value - assert.Equal(t, int32(0), desiredWeight) - return nil - }) - fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) - } + f.fakeTrafficRouting = newUnmockedFakeTrafficRoutingReconciler() + f.fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { + // make sure SetWeight was called with correct value + assert.Equal(t, int32(0), desiredWeight) + return nil + }) + f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) f.run(getKey(r1, t)) } @@ -782,3 +743,141 @@ func TestCanaryWithTrafficRoutingScaleDownLimit(t *testing.T) { _, ok := rs1Updated.Annotations[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey] assert.False(t, ok, "annotation not removed") } + +// TestDynamicScalingDontIncreaseWeightWhenAborted verifies we don't increase the traffic weight if +// we are aborted, using dynamic scaling, and available stable replicas is less than desired +func TestDynamicScalingDontIncreaseWeightWhenAborted(t *testing.T) { + f := newFixture(t) + defer f.Close() + + steps := []v1alpha1.CanaryStep{ + { + SetWeight: pointer.Int32Ptr(50), + }, + { + Pause: &v1alpha1.RolloutPause{}, + }, + } + r1 := newCanaryRollout("foo", 5, nil, steps, pointer.Int32Ptr(1), intstr.FromInt(1), intstr.FromInt(1)) + r1.Spec.Strategy.Canary.DynamicStableScale = true + r1.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{ + SMI: &v1alpha1.SMITrafficRouting{}, + } + r1.Spec.Strategy.Canary.CanaryService = "canary" + r1.Spec.Strategy.Canary.StableService = "stable" + r1.Status.ReadyReplicas = 4 + r1.Status.AvailableReplicas = 4 + r1.Status.Abort = true + r1.Status.AbortedAt = &metav1.Time{Time: time.Now().Add(-1 * time.Minute)} + r2 := bumpVersion(r1) + + rs1 := newReplicaSetWithStatus(r1, 5, 4) // have less available than desired to test calculation + rs2 := newReplicaSetWithStatus(r2, 0, 0) + + rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] + rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] + canarySelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash} + stableSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs1PodHash} + canarySvc := newService("canary", 80, canarySelector, r1) + stableSvc := newService("stable", 80, stableSelector, r1) + r2.Status.StableRS = rs1PodHash + r2.Status.Canary.Weights = &v1alpha1.TrafficWeights{ + Canary: v1alpha1.WeightDestination{ + Weight: 0, + ServiceName: "canary", + PodTemplateHash: rs2PodHash, + }, + Stable: v1alpha1.WeightDestination{ + Weight: 100, + ServiceName: "stable", + PodTemplateHash: rs1PodHash, + }, + } + + f.kubeobjects = append(f.kubeobjects, rs1, rs2, canarySvc, stableSvc) + f.replicaSetLister = append(f.replicaSetLister, rs1, rs2) + + f.rolloutLister = append(f.rolloutLister, r2) + f.objects = append(f.objects, r2) + + f.expectPatchRolloutAction(r2) + + f.fakeTrafficRouting = newUnmockedFakeTrafficRoutingReconciler() + f.fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { + // make sure SetWeight was called with correct value + assert.Equal(t, int32(0), desiredWeight) + return nil + }) + f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) + f.run(getKey(r1, t)) +} + +// TestDynamicScalingDecreaseWeightAccordingToStableAvailabilityWhenAborted verifies we decrease the weight +// to the canary depending on the availability of the stable ReplicaSet when aborting +func TestDynamicScalingDecreaseWeightAccordingToStableAvailabilityWhenAborted(t *testing.T) { + f := newFixture(t) + defer f.Close() + + steps := []v1alpha1.CanaryStep{ + { + SetWeight: pointer.Int32Ptr(50), + }, + { + Pause: &v1alpha1.RolloutPause{}, + }, + } + r1 := newCanaryRollout("foo", 5, nil, steps, pointer.Int32Ptr(1), intstr.FromInt(1), intstr.FromInt(1)) + r1.Spec.Strategy.Canary.DynamicStableScale = true + r1.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{ + SMI: &v1alpha1.SMITrafficRouting{}, + } + r1.Spec.Strategy.Canary.CanaryService = "canary" + r1.Spec.Strategy.Canary.StableService = "stable" + r1.Status.ReadyReplicas = 5 + r1.Status.AvailableReplicas = 5 + r1.Status.Abort = true + r1.Status.AbortedAt = &metav1.Time{Time: time.Now().Add(-1 * time.Minute)} + r2 := bumpVersion(r1) + + rs1 := newReplicaSetWithStatus(r1, 5, 1) + rs2 := newReplicaSetWithStatus(r2, 4, 4) + + rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] + rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] + canarySelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash} + stableSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs1PodHash} + canarySvc := newService("canary", 80, canarySelector, r1) + stableSvc := newService("stable", 80, stableSelector, r1) + r2.Status.StableRS = rs1PodHash + r2.Status.Canary.Weights = &v1alpha1.TrafficWeights{ + Canary: v1alpha1.WeightDestination{ + Weight: 100, + ServiceName: "canary", + PodTemplateHash: rs2PodHash, + }, + Stable: v1alpha1.WeightDestination{ + Weight: 0, + ServiceName: "stable", + PodTemplateHash: rs1PodHash, + }, + } + + f.kubeobjects = append(f.kubeobjects, rs1, rs2, canarySvc, stableSvc) + f.replicaSetLister = append(f.replicaSetLister, rs1, rs2) + + f.rolloutLister = append(f.rolloutLister, r2) + f.objects = append(f.objects, r2) + + f.expectPatchRolloutAction(r2) + + f.fakeTrafficRouting = newUnmockedFakeTrafficRoutingReconciler() + f.fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(func(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { + // make sure SetWeight was called with correct value + assert.Equal(t, int32(80), desiredWeight) + return nil + }) + f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) + f.run(getKey(r1, t)) +} diff --git a/utils/conditions/conditions.go b/utils/conditions/conditions.go index d84bc9cb8e..cddbf68db4 100644 --- a/utils/conditions/conditions.go +++ b/utils/conditions/conditions.go @@ -99,13 +99,14 @@ const ( // rollout that paused amidst a rollout and are bounded by a deadline. RolloutResumedMessage = "Rollout is resumed" - // ResumedRolloutReason is added in a rollout when it is resumed. Useful for not failing accidentally - // rollout that paused amidst a rollout and are bounded by a deadline. - RolloutStepCompletedReason = "RolloutStepCompleted" - // ResumeRolloutMessage is added in a rollout when it is resumed. Useful for not failing accidentally - // rollout that paused amidst a rollout and are bounded by a deadline. + // RolloutStepCompleted indicates when a canary step has completed + RolloutStepCompletedReason = "RolloutStepCompleted" RolloutStepCompletedMessage = "Rollout step %d/%d completed (%s)" + // TrafficWeightUpdated is emitted any time traffic weight is modified + TrafficWeightUpdatedReason = "TrafficWeightUpdated" + TrafficWeightUpdatedMessage = "Traffic weight updated %s" + // NewRSAvailableReason is added in a rollout when its newest replica set is made available // ie. the number of new pods that have passed readiness checks and run for at least minReadySeconds // is at least the minimum available pods that need to run for the rollout. From b06e83dfbceb3edb32f6cf3b7a6e665124dc9221 Mon Sep 17 00:00:00 2001 From: William Van Hevelingen Date: Tue, 25 Jan 2022 12:08:11 -0800 Subject: [PATCH 065/175] chore: Configure dependabot to ignore k8s dependencies (#1802) Dependabot does not currently support a depedency grouping feature so in the meantime we will have dependabot ignore them. Signed-off-by: William Van Hevelingen --- .github/dependabot.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d30f881efd..a159b99307 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,6 +4,9 @@ updates: directory: "/" schedule: interval: "daily" + ignore: + - dependency-name: k8s.io/* + - package-ecosystem: "github-actions" directory: "/" schedule: From 0309eb6b4a2176995be1842a0f8d6bfb7f6d9943 Mon Sep 17 00:00:00 2001 From: John Allberg Date: Tue, 25 Jan 2022 23:59:07 +0100 Subject: [PATCH 066/175] chore(deps: bump k8s.io/kubernetes with dependencies to v1.23.1. (#1785) Signed-off-by: John Allberg --- .github/workflows/e2e.yaml | 2 +- .github/workflows/gh-pages.yaml | 2 +- .github/workflows/go.yml | 4 +- Dockerfile | 4 +- Dockerfile.dev | 2 +- Makefile | 7 +- .../features/kustomize/rollout_cr_schema.json | 142 ++++- go.mod | 223 ++++++-- go.sum | 345 ++++++++---- hack/update-k8s-dependencies.sh | 3 + manifests/crds/analysis-run-crd.yaml | 101 ++++ manifests/crds/analysis-template-crd.yaml | 101 ++++ .../crds/cluster-analysis-template-crd.yaml | 101 ++++ manifests/crds/experiment-crd.yaml | 101 ++++ manifests/crds/rollout-crd.yaml | 101 ++++ manifests/install.yaml | 505 ++++++++++++++++++ manifests/namespace-install.yaml | 505 ++++++++++++++++++ pkg/apiclient/rollout/rollout.swagger.json | 148 +++-- .../rollouts/v1alpha1/openapi_generated.go | 1 + .../v1alpha1/zz_generated.deepcopy.go | 1 + pkg/client/clientset/versioned/clientset.go | 34 +- .../v1alpha1/fake/fake_analysisrun.go | 2 +- .../v1alpha1/fake/fake_analysistemplate.go | 2 +- .../fake/fake_clusteranalysistemplate.go | 2 +- .../rollouts/v1alpha1/fake/fake_experiment.go | 2 +- .../rollouts/v1alpha1/fake/fake_rollout.go | 2 +- .../rollouts/v1alpha1/rollouts_client.go | 20 +- rollout/controller_test.go | 2 +- rollout/replicaset.go | 4 +- rollout/temlateref_test.go | 2 +- test/fixtures/when.go | 2 +- utils/conditions/rollouts_test.go | 4 +- utils/experiment/experiment_test.go | 4 +- 33 files changed, 2237 insertions(+), 244 deletions(-) diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index bec5015c09..06e20a4749 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -24,7 +24,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.16 + go-version: 1.17 - uses: actions/checkout@v2 - name: Setup k3s run: | diff --git a/.github/workflows/gh-pages.yaml b/.github/workflows/gh-pages.yaml index 6b706407f7..e3e6183d8b 100644 --- a/.github/workflows/gh-pages.yaml +++ b/.github/workflows/gh-pages.yaml @@ -16,7 +16,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.16 + go-version: 1.17 - name: build run: | pip install mkdocs mkdocs_material diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index be83bb25c6..bb382359d2 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -26,7 +26,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.16 + go-version: 1.17 id: go - name: Check out code into the Go module directory @@ -70,7 +70,7 @@ jobs: - name: Setup Golang uses: actions/setup-go@v1 with: - go-version: 1.16.2 + go-version: 1.17.6 # k8s codegen generates files into GOPATH location instead of the GitHub git checkout location # This symlink is necessary to ensure that `git diff` detects changes - name: Create symlink in GOPATH diff --git a/Dockerfile b/Dockerfile index fd78e01c1a..88e0768b16 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ # Initial stage which pulls prepares build dependencies and CLI tooling we need for our final image # Also used as the image in CI jobs so needs all dependencies #################################################################################################### -FROM golang:1.16.3 as builder +FROM golang:1.17.6 as builder RUN apt-get update && apt-get install -y \ wget \ @@ -42,7 +42,7 @@ RUN NODE_ENV='production' yarn build #################################################################################################### # Rollout Controller Build stage which performs the actual build of argo-rollouts binaries #################################################################################################### -FROM golang:1.16.3 as argo-rollouts-build +FROM golang:1.17.6 as argo-rollouts-build WORKDIR /go/src/github.com/argoproj/argo-rollouts diff --git a/Dockerfile.dev b/Dockerfile.dev index 4794d2b4df..c09858ed36 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,7 +1,7 @@ #################################################################################################### # argo-rollouts-dev #################################################################################################### -FROM golang:1.16.3 as builder +FROM golang:1.17.6 as builder RUN apt-get update && apt-get install -y \ ca-certificates && \ diff --git a/Makefile b/Makefile index 686a0a136b..6330ee9f4b 100644 --- a/Makefile +++ b/Makefile @@ -53,7 +53,7 @@ define protoc -I . \ -I ./vendor \ -I ${GOPATH}/src \ - -I ${GOPATH}/pkg/mod/github.com/gogo/protobuf@v1.3.1/gogoproto \ + -I ${GOPATH}/pkg/mod/github.com/gogo/protobuf@v1.3.2/gogoproto \ -I ${GOPATH}/pkg/mod/github.com/grpc-ecosystem/grpc-gateway@v1.16.0/third_party/googleapis \ --gogofast_out=plugins=grpc:${GOPATH}/src \ --grpc-gateway_out=logtostderr=true:${GOPATH}/src \ @@ -255,3 +255,8 @@ release-plugins: .PHONY: release release: release-precheck precheckin image plugin-image release-plugins + +.PHONY: trivy +trivy: + @trivy fs --clear-cache + @trivy fs . diff --git a/docs/features/kustomize/rollout_cr_schema.json b/docs/features/kustomize/rollout_cr_schema.json index 8b397aa5f0..7b57b232e1 100644 --- a/docs/features/kustomize/rollout_cr_schema.json +++ b/docs/features/kustomize/rollout_cr_schema.json @@ -606,6 +606,21 @@ "format": "int32", "type": "integer" }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, "httpGet": { "properties": { "host": { @@ -751,6 +766,21 @@ "format": "int32", "type": "integer" }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, "httpGet": { "properties": { "host": { @@ -963,6 +993,21 @@ "format": "int32", "type": "integer" }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, "httpGet": { "properties": { "host": { @@ -1470,6 +1515,21 @@ "format": "int32", "type": "integer" }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, "httpGet": { "properties": { "host": { @@ -1591,7 +1651,12 @@ ], "type": "object" }, - "type": "array" + "type": "array", + "x-kubernetes-list-map-keys": [ + "containerPort", + "protocol" + ], + "x-kubernetes-list-type": "map" }, "readinessProbe": { "properties": { @@ -1610,6 +1675,21 @@ "format": "int32", "type": "integer" }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, "httpGet": { "properties": { "host": { @@ -1822,6 +1902,21 @@ "format": "int32", "type": "integer" }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, "httpGet": { "properties": { "host": { @@ -2364,6 +2459,21 @@ "format": "int32", "type": "integer" }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, "httpGet": { "properties": { "host": { @@ -2509,6 +2619,21 @@ "format": "int32", "type": "integer" }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, "httpGet": { "properties": { "host": { @@ -2721,6 +2846,21 @@ "format": "int32", "type": "integer" }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, "httpGet": { "properties": { "host": { diff --git a/go.mod b/go.mod index 20437cfbb8..ebbcee1fb1 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/argoproj/argo-rollouts -go 1.16 +go 1.17 require ( github.com/antonmedv/expr v1.9.0 @@ -13,74 +13,195 @@ require ( github.com/evanphx/json-patch/v5 v5.6.0 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 github.com/gogo/protobuf v1.3.2 - github.com/golang/mock v1.4.4 + github.com/golang/mock v1.5.0 github.com/golang/protobuf v1.5.2 - github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a - github.com/lunixbochs/vtclean v1.0.0 // indirect - github.com/mitchellh/mapstructure v1.3.3 + github.com/mitchellh/mapstructure v1.4.1 github.com/newrelic/newrelic-client-go v0.49.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.11.0 github.com/prometheus/client_model v0.2.0 - github.com/prometheus/common v0.26.0 + github.com/prometheus/common v0.28.0 github.com/servicemeshinterface/smi-sdk-go v0.4.1 github.com/sirupsen/logrus v1.8.1 github.com/soheilhy/cmux v0.1.5 github.com/spaceapegames/go-wavefront v1.8.1 - github.com/spf13/cobra v1.1.3 + github.com/spf13/cobra v1.2.1 github.com/stretchr/testify v1.7.0 github.com/tj/assert v0.0.3 github.com/valyala/fasttemplate v1.2.1 - golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect - google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c - google.golang.org/grpc v1.38.0 - google.golang.org/protobuf v1.26.0 + google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2 + google.golang.org/grpc v1.40.0 + google.golang.org/protobuf v1.27.1 gopkg.in/yaml.v2 v2.4.0 - k8s.io/api v0.22.5 - k8s.io/apiextensions-apiserver v0.21.0 - k8s.io/apimachinery v0.22.5 - k8s.io/apiserver v0.22.5 - k8s.io/cli-runtime v0.22.5 - k8s.io/client-go v0.22.5 - k8s.io/code-generator v0.22.5 - k8s.io/component-base v0.22.5 - k8s.io/klog/v2 v2.9.0 - k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c - k8s.io/kubectl v0.21.0 - k8s.io/kubernetes v1.22.5 - k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a + k8s.io/api v0.23.1 + k8s.io/apiextensions-apiserver v0.23.1 + k8s.io/apimachinery v0.23.2-rc.0 + k8s.io/apiserver v0.23.1 + k8s.io/cli-runtime v0.23.1 + k8s.io/client-go v0.23.1 + k8s.io/code-generator v0.23.2-rc.0 + k8s.io/component-base v0.23.1 + k8s.io/klog/v2 v2.30.0 + k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 + k8s.io/kubectl v0.23.1 + k8s.io/kubernetes v1.23.1 + k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b +) + +require ( + cloud.google.com/go v0.81.0 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Azure/go-autorest v14.2.0+incompatible // indirect + github.com/Azure/go-autorest/autorest v0.11.18 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect + github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect + github.com/Azure/go-autorest/logger v0.2.1 // indirect + github.com/Azure/go-autorest/tracing v0.6.0 // indirect + github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd // indirect + github.com/Masterminds/goutils v1.1.0 // indirect + github.com/Masterminds/semver v1.5.0 // indirect + github.com/Masterminds/sprig v2.22.0+incompatible // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60 // indirect + github.com/aws/aws-sdk-go-v2 v1.13.0 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.8.0 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.10.0 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.4 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.2.0 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.9.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.14.0 // indirect + github.com/aws/smithy-go v1.10.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bradleyfalzon/ghinstallation v1.1.1 // indirect + github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect + github.com/cyphar/filepath-securejoin v0.2.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect + github.com/docker/distribution v2.7.1+incompatible // indirect + github.com/emicklei/go-restful v2.9.5+incompatible // indirect + github.com/evanphx/json-patch v4.12.0+incompatible // indirect + github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect + github.com/felixge/httpsnoop v1.0.1 // indirect + github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect + github.com/go-errors/errors v1.0.1 // indirect + github.com/go-logr/logr v1.2.0 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.19.5 // indirect + github.com/go-openapi/swag v0.19.14 // indirect + github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect + github.com/golang/glog v1.0.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/google/btree v1.0.1 // indirect + github.com/google/go-cmp v0.5.6 // indirect + github.com/google/go-github/v29 v29.0.2 // indirect + github.com/google/go-github/v33 v33.0.0 // indirect + github.com/google/go-querystring v1.0.0 // indirect + github.com/google/gofuzz v1.1.0 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/googleapis/gnostic v0.5.5 // indirect + github.com/gorilla/websocket v1.4.2 // indirect + github.com/gregdel/pushover v1.1.0 // indirect + github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect + github.com/hashicorp/go-cleanhttp v0.5.1 // indirect + github.com/hashicorp/go-retryablehttp v0.6.8 // indirect + github.com/huandu/xstrings v1.3.2 // indirect + github.com/imdario/mergo v0.3.11 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect + github.com/lunixbochs/vtclean v1.0.0 // indirect + github.com/mailru/easyjson v0.7.6 // indirect + github.com/mattn/go-colorable v0.1.8 // indirect + github.com/mattn/go-isatty v0.0.12 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + github.com/mitchellh/copystructure v1.0.0 // indirect + github.com/mitchellh/go-wordwrap v1.0.0 // indirect + github.com/mitchellh/reflectwalk v1.0.1 // indirect + github.com/moby/spdystream v0.2.0 // indirect + github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/runc v1.0.2 // indirect + github.com/opsgenie/opsgenie-go-sdk-v2 v1.0.5 // indirect + github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/procfs v0.6.0 // indirect + github.com/russross/blackfriday v1.5.2 // indirect + github.com/slack-go/slack v0.6.6 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/objx v0.2.0 // indirect + github.com/technoweenie/multipartstreamer v1.0.1 // indirect + github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/whilp/git-urls v0.0.0-20191001220047-6db9661140c0 // indirect + github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect + go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect + golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect + golang.org/x/mod v0.4.2 // indirect + golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect + golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect + golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect + golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect + golang.org/x/text v0.3.7 // indirect + golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect + golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + gomodules.xyz/envconfig v1.3.1-0.20190308184047-426f31af0d45 // indirect + gomodules.xyz/notify v0.1.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect + gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + k8s.io/cluster-bootstrap v0.0.0 // indirect + k8s.io/component-helpers v0.23.1 // indirect + k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c // indirect + sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect + sigs.k8s.io/kustomize/api v0.10.1 // indirect + sigs.k8s.io/kustomize/kyaml v0.13.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect + sigs.k8s.io/yaml v1.2.0 // indirect ) replace ( github.com/go-check/check => github.com/go-check/check v0.0.0-20180628173108-788fd7840127 github.com/grpc-ecosystem/grpc-gateway => github.com/grpc-ecosystem/grpc-gateway v1.16.0 - k8s.io/api => k8s.io/api v0.22.5 - k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.22.5 - k8s.io/apimachinery => k8s.io/apimachinery v0.22.6-rc.0 - k8s.io/apiserver => k8s.io/apiserver v0.22.5 - k8s.io/cli-runtime => k8s.io/cli-runtime v0.22.5 - k8s.io/client-go => k8s.io/client-go v0.22.5 - k8s.io/cloud-provider => k8s.io/cloud-provider v0.22.5 - k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.22.5 - k8s.io/code-generator => k8s.io/code-generator v0.22.6-rc.0 - k8s.io/component-base => k8s.io/component-base v0.22.5 - k8s.io/component-helpers => k8s.io/component-helpers v0.22.5 - k8s.io/controller-manager => k8s.io/controller-manager v0.22.5 - k8s.io/cri-api => k8s.io/cri-api v0.22.6-rc.0 - k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.22.5 - k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.22.5 - k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.22.5 - k8s.io/kube-proxy => k8s.io/kube-proxy v0.22.5 - k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.22.5 - k8s.io/kubectl => k8s.io/kubectl v0.22.5 - k8s.io/kubelet => k8s.io/kubelet v0.22.5 - k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.22.5 - k8s.io/metrics => k8s.io/metrics v0.22.5 - k8s.io/mount-utils => k8s.io/mount-utils v0.22.6-rc.0 - k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.22.5 - k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.22.5 - k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.22.5 - k8s.io/sample-controller => k8s.io/sample-controller v0.22.5 + k8s.io/api => k8s.io/api v0.23.1 + k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.23.1 + k8s.io/apimachinery => k8s.io/apimachinery v0.23.2-rc.0 + k8s.io/apiserver => k8s.io/apiserver v0.23.1 + k8s.io/cli-runtime => k8s.io/cli-runtime v0.23.1 + k8s.io/client-go => k8s.io/client-go v0.23.1 + k8s.io/cloud-provider => k8s.io/cloud-provider v0.23.1 + k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.23.1 + k8s.io/code-generator => k8s.io/code-generator v0.23.2-rc.0 + k8s.io/component-base => k8s.io/component-base v0.23.1 + k8s.io/component-helpers => k8s.io/component-helpers v0.23.1 + k8s.io/controller-manager => k8s.io/controller-manager v0.23.1 + k8s.io/cri-api => k8s.io/cri-api v0.23.2-rc.0 + k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.23.1 + k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.23.1 + k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.23.1 + k8s.io/kube-proxy => k8s.io/kube-proxy v0.23.1 + k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.23.1 + k8s.io/kubectl => k8s.io/kubectl v0.23.1 + k8s.io/kubelet => k8s.io/kubelet v0.23.1 + k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.23.1 + k8s.io/metrics => k8s.io/metrics v0.23.1 + k8s.io/mount-utils => k8s.io/mount-utils v0.23.2-rc.0 + k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.23.1 + k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.23.1 + k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.23.1 + k8s.io/sample-controller => k8s.io/sample-controller v0.23.1 ) diff --git a/go.sum b/go.sum index f781c3ab8b..7f91b9e152 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,5 @@ 4d63.com/gochecknoglobals v0.0.0-20201008074935-acfc0b28355a/go.mod h1:wfdC5ZjKSPr7CybKEcgJhUOgeAQW1+7WcyK8OvUilfo= +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= bitbucket.org/bertimus9/systemstat v0.0.0-20180207000608-0eeff89b0690/go.mod h1:Ulb78X89vxKYgdL24HMTiXYHlyHEvruOj1ZPlqeNEZM= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= @@ -11,15 +12,21 @@ cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxK cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.55.0/go.mod h1:ZHmoY+/lIMNkN2+fBmuTiqZ4inFhvQad8ft7MT8IV5Y= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.58.0 h1:vtAfVc723K3xKq1BQydk/FyCldnaNFhGhpJxaJzgRMQ= cloud.google.com/go v0.58.0/go.mod h1:W+9FnSUw6nhVwXlFcp1eL+krq5+HQUJeUogSeJZZiWg= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0 h1:at8Tk2zUz63cLPR0JPWm5vp77pEZmzxEQBEfRKn1VV8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -39,6 +46,7 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.9.0/go.mod h1:m+/etGaqZbylxaNT876QGXqEHp4PR2Rq5GMqICWb9bU= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= code.gitea.io/sdk/gitea v0.12.1/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY= code.gitea.io/sdk/gitea v0.13.1/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY= contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= @@ -98,7 +106,7 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/Djarvur/go-err113 v0.0.0-20200511133814-5174e21577d5/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20191009163259-e802c2cb94ae/go.mod h1:mjwGPas4yKduTyubHvD1Atl9r1rUq8DfVy+gkVvZ+oo= -github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20200415212048-7901bc822317/go.mod h1:DF8FZRxMHMGv/vP2lQP6h+dYzzjpuRn24VeRiYn3qjQ= +github.com/GoogleCloudPlatform/k8s-cloud-provider v1.16.1-0.20210702024009-ea6160c1d0e3/go.mod h1:8XasY4ymP2V/tn2OOV9ZadmiTE1FIB/h3W+yNlPttKw= github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5hodBMJ5+l/7J4xAyMeuM2PNuepvHlGs8yilUCA= github.com/Jeffail/gabs v1.4.0 h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo= github.com/Jeffail/gabs v1.4.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= @@ -113,9 +121,9 @@ github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZC github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/Masterminds/sprig/v3 v3.1.0/go.mod h1:ONGMf7UfYGAbMXCZmQLy8x3lCDIPrEZE/rU8pmrbihA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= -github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= -github.com/Microsoft/hcsshim v0.8.10-0.20200715222032-5eafd1556990/go.mod h1:ay/0dTb7NsG8QMDfsRfLHgZo/6xAJShLe1+ePPflihk= +github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/hcsshim v0.8.22/go.mod h1:91uVCVzvX2QD16sMCenoxxXo6L1wJnLMX2PSufFMtF0= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= @@ -139,6 +147,7 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5 github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= github.com/antonmedv/expr v1.8.9/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmHhwGEk8= github.com/antonmedv/expr v1.9.0 h1:j4HI3NHEdgDnN9p6oI6Ndr0G5QryMY0FNxT4ONrFDGU= github.com/antonmedv/expr v1.9.0/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmHhwGEk8= @@ -198,6 +207,7 @@ github.com/aws/smithy-go v1.10.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiA github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -205,6 +215,7 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= @@ -226,39 +237,39 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 h1:7aWHqerlJ41y6FOsEUvknqgXnGmJyJSbjhAWq5pO4F8= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= -github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313/go.mod h1:P1wt9Z3DP8O6W3rvwCt0REIlshg1InHImaLW0t3ObY0= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27/go.mod h1:VQx0hjo2oUeQkQUET7wRwradO6f+fN5jzXgB/zROxxE= github.com/container-storage-interface/spec v1.5.0/go.mod h1:8K96oQNkJ7pFcC2R9Z1ynGGBB1I93kcS6PGg3SsOk8s= -github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= -github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= +github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= -github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.4.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= -github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= -github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= -github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/containerd v1.4.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.11/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= +github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= -github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= -github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= +github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= github.com/coredns/caddy v1.1.0/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4= -github.com/coredns/corefile-migration v1.0.12/go.mod h1:NJOI8ceUF/NTgEwtjD+TUq3/BnH/GF7WAM3RzCa3hBo= +github.com/coredns/corefile-migration v1.0.14/go.mod h1:XnhgULOEouimnzgn0t4WPuFDN2/PJQcTxdWKC5eXNGE= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -266,8 +277,7 @@ github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHo github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.3.1/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -292,10 +302,9 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v20.10.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= @@ -310,12 +319,15 @@ github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdRwPr2TU5ThnS43puaKEMpja1uw= -github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= @@ -343,6 +355,7 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM= +github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew= @@ -375,8 +388,10 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v0.3.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= @@ -423,8 +438,9 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -437,8 +453,9 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -479,7 +496,9 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/cadvisor v0.39.2/go.mod h1:kN93gpdevu+bpS227TyHVZyCU5bbqCzTj5T9drl34MI= +github.com/google/cadvisor v0.43.0/go.mod h1:+RdMSbc3FVr5NYCD2dOEJy/LI0jYJ/0xJXkzWXEyiFQ= +github.com/google/cel-go v0.9.0/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w= +github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -488,6 +507,7 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= @@ -506,6 +526,8 @@ github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -513,6 +535,11 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/rpmpack v0.0.0-20200731134257-3685799e8fdf/go.mod h1:+y9lKiqDhR4zkLl+V9h4q0rdyrYVsWWm6LLCQP33DIk= github.com/google/rpmpack v0.0.0-20200919095143-1c1eea455332/go.mod h1:+y9lKiqDhR4zkLl+V9h4q0rdyrYVsWWm6LLCQP33DIk= @@ -606,6 +633,7 @@ github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= @@ -639,8 +667,9 @@ github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2E github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -699,6 +728,7 @@ github.com/lusis/slack-test v0.0.0-20190426140909-c40012f20018/go.mod h1:sFlOUpQ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailgun/mailgun-go v2.0.0+incompatible/go.mod h1:NWTyU+O4aczg/nsGhQnvHL6v2n5Gy6Sv5tNDVvC6FbU= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -758,8 +788,9 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= @@ -774,8 +805,9 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= @@ -823,17 +855,14 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v1.0.0-rc95/go.mod h1:z+bZxa/+Tz/FmYVWkhUajJdzFeOqjc5vrqskhVyHGUM= github.com/opencontainers/runc v1.0.2 h1:opHZMaswlyxz1OuGpBE53Dwe4/xF7EZTY0A2L/FpCOg= github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opsgenie/opsgenie-go-sdk-v2 v1.0.5 h1:AnS8ZCC5dle8P4X4FZ+IOlX9v0jAkCMiZDIzRnYwBbs= @@ -844,6 +873,7 @@ github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtb github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= @@ -873,15 +903,14 @@ github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7q github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/common v0.28.0 h1:vGVfV9KrDTvWt5boZO0I19g2E3CsWfpPPKZM9dt3mEw= +github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= @@ -959,15 +988,17 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.3.2/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.4.1 h1:asw9sl74539yqavKaglDM5hFpdJVK0Y5Dr/JOgQ89nQ= github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= -github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw= +github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -977,6 +1008,7 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= github.com/ssgreg/nlreturn/v2 v2.0.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= github.com/ssgreg/nlreturn/v2 v2.1.0/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= @@ -1045,7 +1077,6 @@ github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1 github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/whilp/git-urls v0.0.0-20191001220047-6db9661140c0 h1:qqllXPzXh+So+mmANlX/gCJrgo+1kQyshMoQ+NASzm0= github.com/whilp/git-urls v0.0.0-20191001220047-6db9661140c0/go.mod h1:2rx5KE5FLD0HRfkkpyn8JwbVLBdhgeiOb2D2D9LLKM4= -github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= github.com/xanzy/go-gitlab v0.37.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= github.com/xanzy/go-gitlab v0.39.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8= @@ -1061,6 +1092,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= @@ -1075,6 +1107,9 @@ go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= @@ -1096,6 +1131,7 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/ go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= gocloud.dev v0.20.0/go.mod h1:+Y/RpSXrJthIOM8uFNzWp6MRu9pFPNFEEZrQMxpkfIc= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1118,8 +1154,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1149,6 +1185,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -1161,6 +1198,8 @@ golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hM golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1182,10 +1221,10 @@ golang.org/x/net v0.0.0-20190607181551-461777fb6f67/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1208,8 +1247,16 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1218,8 +1265,18 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1288,27 +1345,41 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201109165425-215b40eba54c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1316,12 +1387,12 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1396,23 +1467,35 @@ golang.org/x/tools v0.0.0-20200519015757-0d0afa43d58a/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200601175630-2caf76543d99/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200606014950-c42cb6316fb6/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200608174601-1b747fd94509/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200624225443-88f3c62a19ff/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200625211823-6506e20df31f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200701041122-1837592efa10/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200731060945-b5fad4ed8dd6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200812195022-5ae4c3c160a0/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200831203904-5a2aa26beb65/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201001104356-43ebab892c4c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201007032633-0806396f153e/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201011145850-ed2f50202694/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201013201025-64a9e34f3752/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff h1:VX/uD7MK0AHXGiScH3fsieUQUcpmRERPDYtqZdJnA+Q= +golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1436,7 +1519,6 @@ google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.1-0.20200106000736-b8fc810ca6b5/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= @@ -1444,14 +1526,25 @@ google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/ google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.26.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= +google.golang.org/api v0.46.0/go.mod h1:ceL4oozhkAiTID8XMmJBsIxID/9wMXJVVFXPg4ylg3I= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1486,27 +1579,50 @@ google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1m google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200603110839-e855014d5736/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= +google.golang.org/genproto v0.0.0-20201102152239-715cce707fb0/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2 h1:NHN4wOCScVzKhPenJ2dt+BTs3X/XkBVI/Rh4iDt55T8= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1518,8 +1634,9 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/AlecAivazis/survey.v1 v1.8.7/go.mod h1:iBNOmqKz/NUbZx3bA+4hAGLRC7fSK7tgtVDT4tB22XA= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= @@ -1564,8 +1681,6 @@ gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/gotestsum v0.6.0/go.mod h1:LEX+ioCVdeWhZc8GYfiBRag360eBhwixWJ62R9eDQtI= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= @@ -1579,59 +1694,61 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.6/go.mod h1:pyyisuGw24ruLjrr1ddx39WE0y9OooInRzEYLhQB2YY= -k8s.io/api v0.22.5 h1:xk7C+rMjF/EGELiD560jdmwzrB788mfcHiNbMQLIVI8= -k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs= -k8s.io/apiextensions-apiserver v0.22.5 h1:ML0QqT7FIlmZHN+9+2EtARJ3cJVHeoizt6GCteFRE0o= -k8s.io/apiextensions-apiserver v0.22.5/go.mod h1:tIXeZ0BrDxUb1PoAz+tgOz43Zi1Bp4BEEqVtUccMJbE= -k8s.io/apimachinery v0.22.6-rc.0 h1:7fsM4YnKNmb3qLznaIPFJ6Rk7hjo8TxbHv2FS3I7804= -k8s.io/apimachinery v0.22.6-rc.0/go.mod h1:xziclGKwuuJ2RM5/rSFQSYAj0zdbci3DH8kj+WvyN0U= -k8s.io/apiserver v0.22.5 h1:71krQxCUz218ecb+nPhfDsNB6QgP1/4EMvi1a2uYBlg= -k8s.io/apiserver v0.22.5/go.mod h1:s2WbtgZAkTKt679sYtSudEQrTGWUSQAPe6MupLnlmaQ= -k8s.io/cli-runtime v0.22.5 h1:bZqLgx1INiPgXyMk/Hu3o5NFmdfvlvtsoE+wHJuKA2U= -k8s.io/cli-runtime v0.22.5/go.mod h1:12ah4O0kaevIYHsRcFGt8RKER0wlTN2yCgHp1c4Uxp4= -k8s.io/client-go v0.22.5 h1:I8Zn/UqIdi2r02aZmhaJ1hqMxcpfJ3t5VqvHtctHYFo= -k8s.io/client-go v0.22.5/go.mod h1:cs6yf/61q2T1SdQL5Rdcjg9J1ElXSwbjSrW2vFImM4Y= -k8s.io/cloud-provider v0.22.5/go.mod h1:nBjHLzOB4VNvGTskv4N6SHKmd+jUJYtOg1PxUi+eoL4= -k8s.io/cluster-bootstrap v0.22.5 h1:vCALIBnbpL9DRPpqSffqQfTftQxK4raMn+DbNJzcZ/M= -k8s.io/cluster-bootstrap v0.22.5/go.mod h1:apRzF71o+erN4FmzaHVuaFj2RtTI44nqZFBTrB7zJNg= -k8s.io/code-generator v0.22.6-rc.0 h1:yy0LyeCSlUNF011N8a9Uy62F1CcKBb/umYGaBCPSPhc= -k8s.io/code-generator v0.22.6-rc.0/go.mod h1:sbdWCOVob+KaQ5O7xs8PNNaCTpbWVqNgA6EPwLOmRNk= -k8s.io/component-base v0.22.5 h1:U0eHqZm7mAFE42hFwYhY6ze/MmVaW00JpMrzVsQmzYE= -k8s.io/component-base v0.22.5/go.mod h1:VK3I+TjuF9eaa+Ln67dKxhGar5ynVbwnGrUiNF4MqCI= -k8s.io/component-helpers v0.22.5 h1:DbON3tctKjVJyV1XALj85ZKU1NRpWKc3CrpAJ4Nb07k= -k8s.io/component-helpers v0.22.5/go.mod h1:UK4H16PcV6pTInkhAOfkPbN/aXHPXPX2/ZI4lfCXH4I= -k8s.io/controller-manager v0.22.5/go.mod h1:Ad1qlS+ygzKgxImZ6ccExOMutfmGprodopbIzrHKgJw= -k8s.io/cri-api v0.22.6-rc.0/go.mod h1:uAw9CICQq20/1yB4ZnWT2TjJyMMROl4typFfWaURLwQ= -k8s.io/csi-translation-lib v0.22.5/go.mod h1:vqSdiDUFMdo0WT5TuO4j3ZVrODoYkzGjTLluKEqs2eQ= +k8s.io/api v0.23.1 h1:ncu/qfBfUoClqwkTGbeRqqOqBCRoUAflMuOaOD7J0c8= +k8s.io/api v0.23.1/go.mod h1:WfXnOnwSqNtG62Y1CdjoMxh7r7u9QXGCkA1u0na2jgo= +k8s.io/apiextensions-apiserver v0.23.1 h1:xxE0q1vLOVZiWORu1KwNRQFsGWtImueOrqSl13sS5EU= +k8s.io/apiextensions-apiserver v0.23.1/go.mod h1:0qz4fPaHHsVhRApbtk3MGXNn2Q9M/cVWWhfHdY2SxiM= +k8s.io/apimachinery v0.23.2-rc.0 h1:MnclcThycinuHAhHBk1dAqEOYi85WlXeAbz2tfGjvWM= +k8s.io/apimachinery v0.23.2-rc.0/go.mod h1:SADt2Kl8/sttJ62RRsi9MIV4o8f5S3coArm0Iu3fBno= +k8s.io/apiserver v0.23.1 h1:vWGf8LcV9Pk/z5rdLmCiBDqE21ccbe930dzrtVMhw9g= +k8s.io/apiserver v0.23.1/go.mod h1:Bqt0gWbeM2NefS8CjWswwd2VNAKN6lUKR85Ft4gippY= +k8s.io/cli-runtime v0.23.1 h1:vHUZrq1Oejs0WaJnxs09mLHKScvIIl2hMSthhS8o8Yo= +k8s.io/cli-runtime v0.23.1/go.mod h1:r9r8H/qfXo9w+69vwUL7LokKlLRKW5D6A8vUKCx+YL0= +k8s.io/client-go v0.23.1 h1:Ma4Fhf/p07Nmj9yAB1H7UwbFHEBrSPg8lviR24U2GiQ= +k8s.io/client-go v0.23.1/go.mod h1:6QSI8fEuqD4zgFK0xbdwfB/PthBsIxCJMa3s17WlcO0= +k8s.io/cloud-provider v0.23.1/go.mod h1:kI8AnYwOSru5Bci8pPUWwV5kJMVkY1ICOp1p8KKZWpc= +k8s.io/cluster-bootstrap v0.23.1 h1:zHRsIwMSLWujGHlaXLglbwyiDOKFLXSGz7LTbAez3MM= +k8s.io/cluster-bootstrap v0.23.1/go.mod h1:p2732QxwSa13WPemmyIeykk16qVw15W7lgNRB6x7NpY= +k8s.io/code-generator v0.23.2-rc.0 h1:sG0zykJJ8CvByPs/chc8DThmILi607fnNfW+0YTaOZs= +k8s.io/code-generator v0.23.2-rc.0/go.mod h1:V7yn6VNTCWW8GqodYCESVo95fuiEg713S8B7WacWZDA= +k8s.io/component-base v0.23.1 h1:j/BqdZUWeWKCy2v/jcgnOJAzpRYWSbGcjGVYICko8Uc= +k8s.io/component-base v0.23.1/go.mod h1:6llmap8QtJIXGDd4uIWJhAq0Op8AtQo6bDW2RrNMTeo= +k8s.io/component-helpers v0.23.1 h1:Xrtj0LwXUqYyTPvN2bOE2UcqURX+uSBmKX1koNGhVxI= +k8s.io/component-helpers v0.23.1/go.mod h1:ZK24U+2oXnBPcas2KolLigVVN9g5zOzaHLkHiQMFGr0= +k8s.io/controller-manager v0.23.1/go.mod h1:AFE4qIllvTh+nRwGr3SRSUt7F+xVSzXCeb0hhzYlU4k= +k8s.io/cri-api v0.23.2-rc.0/go.mod h1:REJE3PSU0h/LOV1APBrupxrEJqnoxZC8KWzkBUHwrK4= +k8s.io/csi-translation-lib v0.23.1/go.mod h1:0ZyB0cZBV4ZkqibwilEhKnxOne28rq5FDSjO+0MUVio= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027 h1:Uusb3oh8XcdzDF/ndlI4ToKTYVlkCSJP39SRY2mfRAw= -k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c h1:GohjlNKauSai7gN4wsJkeZ3WAJx4Sh+oT/b5IYn5suA= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.5.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM= -k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/kube-aggregator v0.22.5/go.mod h1:UhgfJb/mvIvfjc+d0pY2GP8S9+zHquxDzQAuWRxqzq8= -k8s.io/kube-controller-manager v0.22.5/go.mod h1:/ND3VocEUJifrOUSreSZksNx0GL+Bcd1ht2MF/GMenQ= +k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw= +k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-aggregator v0.23.1/go.mod h1:1SPZXYD/je2gKxxLBkYyG3yFxSCUWI5QTyjqP2ZxRDI= +k8s.io/kube-controller-manager v0.23.1/go.mod h1:KbZeNSFsBM5j2ddB5yXJ1nTQx2j/1/Cf7cXzG27aKZ0= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= -k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c h1:jvamsI1tn9V0S8jicyX82qaFC0H/NKxv2e5mbqsgR80= -k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= -k8s.io/kube-proxy v0.22.5/go.mod h1:0XigADqqbYWE23zIs8JpBZGJcGCKYFIJ5uqh1CBZRxU= -k8s.io/kube-scheduler v0.22.5/go.mod h1:JEeZKTpcr07eIxrcW9DptOtgylMu6KnQPAQ+Ew45Ask= -k8s.io/kubectl v0.22.5 h1:diivOcs6dyDjpBqOpy9iiI3srZnW1khJDWwsFSapFt8= -k8s.io/kubectl v0.22.5/go.mod h1:uwKSKhaC6HOwnbk1cVLxVPYwfvazj9x06oZAOsL43N8= -k8s.io/kubelet v0.22.5/go.mod h1:f/f0+phP4j+JZirY3twlszp3Re3q/NRPIhdU4bashIk= -k8s.io/kubernetes v1.22.5 h1:DfYHZkWXDra2xKEKb7C96cq4vQuxjn4j0YthK2naLRo= -k8s.io/kubernetes v1.22.5/go.mod h1:ejAVRNlNOIWvq0c5m3qAnzEdizuFlWBKXRf/HV6Z2zA= -k8s.io/legacy-cloud-providers v0.22.5/go.mod h1:a+nO87Q1eJjGpBcfmv1llCMufHF6sRpKSoXFMp1tj+s= -k8s.io/metrics v0.22.5/go.mod h1:dCqOkoZQWLSfBhUtPFMiDrzJaPtXJlVePVuJbEx0hW8= -k8s.io/mount-utils v0.22.6-rc.0/go.mod h1:dHl6c2P60T5LHUnZxVslyly9EDCMzvhtISO5aY+Z4sk= -k8s.io/pod-security-admission v0.22.5/go.mod h1:2a1JSU7b+CHFoSGIr8FwZBBeAJFau41srx08/qEy+NI= -k8s.io/sample-apiserver v0.22.5/go.mod h1:0/GPEcsJQg4ljzx+mTv3yhj6c+aZ7KPo4BkQ++KlT4Q= -k8s.io/system-validators v1.5.0/go.mod h1:bPldcLgkIUK22ALflnsXk8pvkTEndYdNuaHH6gRrl0Q= +k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4= +k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= +k8s.io/kube-proxy v0.23.1/go.mod h1:65QJpMrjUMHfgX1q5Pl/KqVRZBMM4qLHNMo5MhKsnp0= +k8s.io/kube-scheduler v0.23.1/go.mod h1:SFPvXnt7KlxTZILrtjH8VNwGDzXcdKKHrv4TkeZdYro= +k8s.io/kubectl v0.23.1 h1:gmscOiV4Y4XIRIn14gQBBADoyyVrDZPbxRCTDga4RSA= +k8s.io/kubectl v0.23.1/go.mod h1:Ui7dJKdUludF8yWAOSN7JZEkOuYixX5yF6E6NjoukKE= +k8s.io/kubelet v0.23.1/go.mod h1:WdvMiehtNPhtiW8sSVVvr8YYU00L0u+0HkfMDEB0LKM= +k8s.io/kubernetes v1.23.1 h1:iJfubd03CDap4m69Ue+u2I6quNUYiYlC8+TakEHATjc= +k8s.io/kubernetes v1.23.1/go.mod h1:baMGbPpwwP0kT/+eAPtdqoWNRoXyyTJ2Zf+fw/Y8t04= +k8s.io/legacy-cloud-providers v0.23.1/go.mod h1:HIt+r/ReEfjS6IGaGfpZ7tCna7hbMBXMOaIp/SWABVE= +k8s.io/metrics v0.23.1/go.mod h1:qXvsM1KANrc+ZZeFwj6Phvf0NLiC+d3RwcsLcdGc+xs= +k8s.io/mount-utils v0.23.2-rc.0/go.mod h1:9pFhzVjxle1osJUo++9MFDat9HPkQUOoHCn+eExZ3Ew= +k8s.io/pod-security-admission v0.23.1/go.mod h1:WDb/vFWf7jKSGe2e07LTEjDZ0MHMDhUIzXNvQ45HytU= +k8s.io/sample-apiserver v0.23.1/go.mod h1:5ZQrkouVpN6GeNMZEJFkIpFwaxgDPJin/cIBXyDboC4= +k8s.io/system-validators v1.6.0/go.mod h1:bPldcLgkIUK22ALflnsXk8pvkTEndYdNuaHH6gRrl0Q= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g= -k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b h1:wxEMGetGMur3J1xuGLQY7GEQYg9bZxKn3tKo5k/eYcs= +k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= @@ -1647,13 +1764,15 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= -sigs.k8s.io/kustomize/api v0.8.11 h1:LzQzlq6Z023b+mBtc6v72N2mSHYmN8x7ssgbf/hv0H8= -sigs.k8s.io/kustomize/api v0.8.11/go.mod h1:a77Ls36JdfCWojpUqR6m60pdGY1AYFix4AH83nJtY1g= -sigs.k8s.io/kustomize/cmd/config v0.9.13/go.mod h1:7547FLF8W/lTaDf0BDqFTbZxM9zqwEJqCKN9sSR0xSs= -sigs.k8s.io/kustomize/kustomize/v4 v4.2.0/go.mod h1:MOkR6fmhwG7hEDRXBYELTi5GSFcLwfqwzTRHW3kv5go= -sigs.k8s.io/kustomize/kyaml v0.11.0 h1:9KhiCPKaVyuPcgOLJXkvytOvjMJLoxpjodiycb4gHsA= -sigs.k8s.io/kustomize/kyaml v0.11.0/go.mod h1:GNMwjim4Ypgp/MueD3zXHLRJEjz7RvtPae0AwlvEMFM= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.25/go.mod h1:Mlj9PNLmG9bZ6BHFwFKDo5afkpWyUISkb9Me0GnK66I= +sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s= +sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= +sigs.k8s.io/kustomize/api v0.10.1 h1:KgU7hfYoscuqag84kxtzKdEC3mKMb99DPI3a0eaV1d0= +sigs.k8s.io/kustomize/api v0.10.1/go.mod h1:2FigT1QN6xKdcnGS2Ppp1uIWrtWN28Ms8A3OZUZhwr8= +sigs.k8s.io/kustomize/cmd/config v0.10.2/go.mod h1:K2aW7nXJ0AaT+VA/eO0/dzFLxmpFcTzudmAgDwPY1HQ= +sigs.k8s.io/kustomize/kustomize/v4 v4.4.1/go.mod h1:qOKJMMz2mBP+vcS7vK+mNz4HBLjaQSWRY22EF6Tb7Io= +sigs.k8s.io/kustomize/kyaml v0.13.0 h1:9c+ETyNfSrVhxvphs+K2dzT3dh5oVPPEqPOE/cUpScY= +sigs.k8s.io/kustomize/kyaml v0.13.0/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= diff --git a/hack/update-k8s-dependencies.sh b/hack/update-k8s-dependencies.sh index c8f0ba2bf1..fab66785f6 100755 --- a/hack/update-k8s-dependencies.sh +++ b/hack/update-k8s-dependencies.sh @@ -19,3 +19,6 @@ for MOD in "${MODS[@]}"; do go mod edit "-replace=${MOD}=${MOD}@${V}" done go get "k8s.io/kubernetes@v${VERSION}" + +go mod vendor +go mod tidy diff --git a/manifests/crds/analysis-run-crd.yaml b/manifests/crds/analysis-run-crd.yaml index eae64e49ed..416627dbab 100644 --- a/manifests/crds/analysis-run-crd.yaml +++ b/manifests/crds/analysis-run-crd.yaml @@ -833,6 +833,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -927,6 +937,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1063,6 +1083,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1402,6 +1432,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1480,6 +1520,10 @@ spec: - containerPort type: object type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map readinessProbe: properties: exec: @@ -1492,6 +1536,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1628,6 +1682,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1971,6 +2035,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2065,6 +2139,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2201,6 +2285,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2312,6 +2406,13 @@ spec: type: string type: object x-kubernetes-map-type: atomic + os: + properties: + name: + type: string + required: + - name + type: object overhead: additionalProperties: anyOf: diff --git a/manifests/crds/analysis-template-crd.yaml b/manifests/crds/analysis-template-crd.yaml index 0210a582a8..f1a2574030 100644 --- a/manifests/crds/analysis-template-crd.yaml +++ b/manifests/crds/analysis-template-crd.yaml @@ -829,6 +829,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -923,6 +933,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1059,6 +1079,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1398,6 +1428,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1476,6 +1516,10 @@ spec: - containerPort type: object type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map readinessProbe: properties: exec: @@ -1488,6 +1532,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1624,6 +1678,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1967,6 +2031,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2061,6 +2135,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2197,6 +2281,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2308,6 +2402,13 @@ spec: type: string type: object x-kubernetes-map-type: atomic + os: + properties: + name: + type: string + required: + - name + type: object overhead: additionalProperties: anyOf: diff --git a/manifests/crds/cluster-analysis-template-crd.yaml b/manifests/crds/cluster-analysis-template-crd.yaml index e7d358b497..8afa62eebc 100644 --- a/manifests/crds/cluster-analysis-template-crd.yaml +++ b/manifests/crds/cluster-analysis-template-crd.yaml @@ -829,6 +829,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -923,6 +933,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1059,6 +1079,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1398,6 +1428,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1476,6 +1516,10 @@ spec: - containerPort type: object type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map readinessProbe: properties: exec: @@ -1488,6 +1532,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1624,6 +1678,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1967,6 +2031,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2061,6 +2135,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2197,6 +2281,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2308,6 +2402,13 @@ spec: type: string type: object x-kubernetes-map-type: atomic + os: + properties: + name: + type: string + required: + - name + type: object overhead: additionalProperties: anyOf: diff --git a/manifests/crds/experiment-crd.yaml b/manifests/crds/experiment-crd.yaml index e2301e1dcd..af9b47f896 100644 --- a/manifests/crds/experiment-crd.yaml +++ b/manifests/crds/experiment-crd.yaml @@ -722,6 +722,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -816,6 +826,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -952,6 +972,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1291,6 +1321,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1369,6 +1409,10 @@ spec: - containerPort type: object type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map readinessProbe: properties: exec: @@ -1381,6 +1425,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1517,6 +1571,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1860,6 +1924,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1954,6 +2028,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2090,6 +2174,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2201,6 +2295,13 @@ spec: type: string type: object x-kubernetes-map-type: atomic + os: + properties: + name: + type: string + required: + - name + type: object overhead: additionalProperties: anyOf: diff --git a/manifests/crds/rollout-crd.yaml b/manifests/crds/rollout-crd.yaml index 27ed952f64..5665fa4f47 100644 --- a/manifests/crds/rollout-crd.yaml +++ b/manifests/crds/rollout-crd.yaml @@ -1297,6 +1297,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1391,6 +1401,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1527,6 +1547,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1866,6 +1896,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1944,6 +1984,10 @@ spec: - containerPort type: object type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map readinessProbe: properties: exec: @@ -1956,6 +2000,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2092,6 +2146,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2435,6 +2499,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2529,6 +2603,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2665,6 +2749,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2776,6 +2870,13 @@ spec: type: string type: object x-kubernetes-map-type: atomic + os: + properties: + name: + type: string + required: + - name + type: object overhead: additionalProperties: anyOf: diff --git a/manifests/install.yaml b/manifests/install.yaml index 51ef4c808a..0ebe8c0b0d 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -834,6 +834,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -928,6 +938,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1064,6 +1084,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1403,6 +1433,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1481,6 +1521,10 @@ spec: - containerPort type: object type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map readinessProbe: properties: exec: @@ -1493,6 +1537,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1629,6 +1683,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1972,6 +2036,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2066,6 +2140,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2202,6 +2286,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2313,6 +2407,13 @@ spec: type: string type: object x-kubernetes-map-type: atomic + os: + properties: + name: + type: string + required: + - name + type: object overhead: additionalProperties: anyOf: @@ -3593,6 +3694,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -3687,6 +3798,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -3823,6 +3944,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -4162,6 +4293,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -4240,6 +4381,10 @@ spec: - containerPort type: object type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map readinessProbe: properties: exec: @@ -4252,6 +4397,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -4388,6 +4543,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -4731,6 +4896,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -4825,6 +5000,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -4961,6 +5146,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -5072,6 +5267,13 @@ spec: type: string type: object x-kubernetes-map-type: atomic + os: + properties: + name: + type: string + required: + - name + type: object overhead: additionalProperties: anyOf: @@ -6242,6 +6444,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -6336,6 +6548,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -6472,6 +6694,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -6811,6 +7043,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -6889,6 +7131,10 @@ spec: - containerPort type: object type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map readinessProbe: properties: exec: @@ -6901,6 +7147,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -7037,6 +7293,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -7380,6 +7646,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -7474,6 +7750,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -7610,6 +7896,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -7721,6 +8017,13 @@ spec: type: string type: object x-kubernetes-map-type: atomic + os: + properties: + name: + type: string + required: + - name + type: object overhead: additionalProperties: anyOf: @@ -8784,6 +9087,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -8878,6 +9191,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -9014,6 +9337,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -9353,6 +9686,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -9431,6 +9774,10 @@ spec: - containerPort type: object type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map readinessProbe: properties: exec: @@ -9443,6 +9790,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -9579,6 +9936,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -9922,6 +10289,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -10016,6 +10393,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -10152,6 +10539,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -10263,6 +10660,13 @@ spec: type: string type: object x-kubernetes-map-type: atomic + os: + properties: + name: + type: string + required: + - name + type: object overhead: additionalProperties: anyOf: @@ -11844,6 +12248,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -11938,6 +12352,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -12074,6 +12498,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -12413,6 +12847,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -12491,6 +12935,10 @@ spec: - containerPort type: object type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map readinessProbe: properties: exec: @@ -12503,6 +12951,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -12639,6 +13097,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -12982,6 +13450,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -13076,6 +13554,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -13212,6 +13700,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -13323,6 +13821,13 @@ spec: type: string type: object x-kubernetes-map-type: atomic + os: + properties: + name: + type: string + required: + - name + type: object overhead: additionalProperties: anyOf: diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index d5714a1aef..d968473b8b 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -834,6 +834,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -928,6 +938,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1064,6 +1084,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1403,6 +1433,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1481,6 +1521,10 @@ spec: - containerPort type: object type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map readinessProbe: properties: exec: @@ -1493,6 +1537,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1629,6 +1683,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -1972,6 +2036,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2066,6 +2140,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2202,6 +2286,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -2313,6 +2407,13 @@ spec: type: string type: object x-kubernetes-map-type: atomic + os: + properties: + name: + type: string + required: + - name + type: object overhead: additionalProperties: anyOf: @@ -3593,6 +3694,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -3687,6 +3798,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -3823,6 +3944,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -4162,6 +4293,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -4240,6 +4381,10 @@ spec: - containerPort type: object type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map readinessProbe: properties: exec: @@ -4252,6 +4397,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -4388,6 +4543,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -4731,6 +4896,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -4825,6 +5000,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -4961,6 +5146,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -5072,6 +5267,13 @@ spec: type: string type: object x-kubernetes-map-type: atomic + os: + properties: + name: + type: string + required: + - name + type: object overhead: additionalProperties: anyOf: @@ -6242,6 +6444,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -6336,6 +6548,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -6472,6 +6694,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -6811,6 +7043,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -6889,6 +7131,10 @@ spec: - containerPort type: object type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map readinessProbe: properties: exec: @@ -6901,6 +7147,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -7037,6 +7293,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -7380,6 +7646,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -7474,6 +7750,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -7610,6 +7896,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -7721,6 +8017,13 @@ spec: type: string type: object x-kubernetes-map-type: atomic + os: + properties: + name: + type: string + required: + - name + type: object overhead: additionalProperties: anyOf: @@ -8784,6 +9087,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -8878,6 +9191,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -9014,6 +9337,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -9353,6 +9686,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -9431,6 +9774,10 @@ spec: - containerPort type: object type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map readinessProbe: properties: exec: @@ -9443,6 +9790,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -9579,6 +9936,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -9922,6 +10289,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -10016,6 +10393,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -10152,6 +10539,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -10263,6 +10660,13 @@ spec: type: string type: object x-kubernetes-map-type: atomic + os: + properties: + name: + type: string + required: + - name + type: object overhead: additionalProperties: anyOf: @@ -11844,6 +12248,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -11938,6 +12352,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -12074,6 +12498,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -12413,6 +12847,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -12491,6 +12935,10 @@ spec: - containerPort type: object type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map readinessProbe: properties: exec: @@ -12503,6 +12951,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -12639,6 +13097,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -12982,6 +13450,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -13076,6 +13554,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -13212,6 +13700,16 @@ spec: failureThreshold: format: int32 type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object httpGet: properties: host: @@ -13323,6 +13821,13 @@ spec: type: string type: object x-kubernetes-map-type: atomic + os: + properties: + name: + type: string + required: + - name + type: object overhead: additionalProperties: anyOf: diff --git a/pkg/apiclient/rollout/rollout.swagger.json b/pkg/apiclient/rollout/rollout.swagger.json index 3008334089..671eb495ab 100644 --- a/pkg/apiclient/rollout/rollout.swagger.json +++ b/pkg/apiclient/rollout/rollout.swagger.json @@ -2160,10 +2160,10 @@ }, "targetContainerName": { "type": "string", - "title": "If set, the name of the container from PodSpec that this ephemeral container targets.\nThe ephemeral container will be run in the namespaces (IPC, PID, etc) of this container.\nIf not set then the ephemeral container is run in whatever namespaces are shared\nfor the pod. Note that the container runtime must support this feature.\n+optional" + "description": "If set, the name of the container from PodSpec that this ephemeral container targets.\nThe ephemeral container will be run in the namespaces (IPC, PID, etc) of this container.\nIf not set then the ephemeral container uses the namespaces configured in the Pod spec.\n\nThe container runtime must implement support for this feature. If the runtime does not\nsupport namespace targeting then the result of setting this field is undefined.\n+optional" } }, - "description": "An EphemeralContainer is a container that may be added temporarily to an existing pod for\nuser-initiated activities such as debugging. Ephemeral containers have no resource or\nscheduling guarantees, and they will not be restarted when they exit or when a pod is\nremoved or restarted. If an ephemeral container causes a pod to exceed its resource\nallocation, the pod may be evicted.\nEphemeral containers may not be added by directly updating the pod spec. They must be added\nvia the pod's ephemeralcontainers subresource, and they will appear in the pod spec\nonce added.\nThis is an alpha feature enabled by the EphemeralContainers feature flag." + "description": "An EphemeralContainer is a temporary container that you may add to an existing Pod for\nuser-initiated activities such as debugging. Ephemeral containers have no resource or\nscheduling guarantees, and they will not be restarted when they exit or when a Pod is\nremoved or restarted. The kubelet may evict a Pod if an ephemeral container causes the\nPod to exceed its resource allocation.\n\nTo add an ephemeral container, use the ephemeralcontainers subresource of an existing\nPod. Ephemeral containers may not be removed or restarted.\n\nThis is a beta feature available on clusters that haven't disabled the EphemeralContainers feature gate." }, "k8s.io.api.core.v1.EphemeralContainerCommon": { "type": "object", @@ -2199,7 +2199,7 @@ "items": { "$ref": "#/definitions/k8s.io.api.core.v1.ContainerPort" }, - "description": "Ports are not allowed for ephemeral containers." + "title": "Ports are not allowed for ephemeral containers.\n+optional\n+patchMergeKey=containerPort\n+patchStrategy=merge\n+listType=map\n+listMapKey=containerPort\n+listMapKey=protocol" }, "envFrom": { "type": "array", @@ -2224,7 +2224,7 @@ "items": { "$ref": "#/definitions/k8s.io.api.core.v1.VolumeMount" }, - "title": "Pod volumes to mount into the container's filesystem.\nCannot be updated.\n+optional\n+patchMergeKey=mountPath\n+patchStrategy=merge" + "title": "Pod volumes to mount into the container's filesystem. Subpath mounts are not allowed for ephemeral containers.\nCannot be updated.\n+optional\n+patchMergeKey=mountPath\n+patchStrategy=merge" }, "volumeDevices": { "type": "array", @@ -2402,6 +2402,20 @@ }, "description": "Represents a Persistent Disk resource in Google Compute Engine.\n\nA GCE PD must exist before mounting to a container. The disk must\nalso be in the same GCE project and zone as the kubelet. A GCE PD\ncan only be mounted as read/write once or read-only many times. GCE\nPDs support ownership management and SELinux relabeling." }, + "k8s.io.api.core.v1.GRPCAction": { + "type": "object", + "properties": { + "port": { + "type": "integer", + "format": "int32", + "description": "Port number of the gRPC service. Number must be in the range 1 to 65535." + }, + "service": { + "type": "string", + "description": "Service is the name of the service to place in the gRPC HealthCheckRequest\n(see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).\n\nIf this is not specified, the default behavior is defined by gRPC.\n+optional\n+default=\"\"" + } + } + }, "k8s.io.api.core.v1.GitRepoVolumeSource": { "type": "object", "properties": { @@ -2481,24 +2495,6 @@ }, "title": "HTTPHeader describes a custom header to be used in HTTP probes" }, - "k8s.io.api.core.v1.Handler": { - "type": "object", - "properties": { - "exec": { - "$ref": "#/definitions/k8s.io.api.core.v1.ExecAction", - "title": "One and only one of the following should be specified.\nExec specifies the action to take.\n+optional" - }, - "httpGet": { - "$ref": "#/definitions/k8s.io.api.core.v1.HTTPGetAction", - "title": "HTTPGet specifies the http request to perform.\n+optional" - }, - "tcpSocket": { - "$ref": "#/definitions/k8s.io.api.core.v1.TCPSocketAction", - "title": "TCPSocket specifies an action involving a TCP port.\nTCP hooks not yet supported\nTODO: implement a realistic TCP lifecycle hook\n+optional" - } - }, - "description": "Handler defines a specific action that should be taken\nTODO: pass structured data to these actions, and document that data here." - }, "k8s.io.api.core.v1.HostAlias": { "type": "object", "properties": { @@ -2607,16 +2603,34 @@ "type": "object", "properties": { "postStart": { - "$ref": "#/definitions/k8s.io.api.core.v1.Handler", + "$ref": "#/definitions/k8s.io.api.core.v1.LifecycleHandler", "title": "PostStart is called immediately after a container is created. If the handler fails,\nthe container is terminated and restarted according to its restart policy.\nOther management of the container blocks until the hook completes.\nMore info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks\n+optional" }, "preStop": { - "$ref": "#/definitions/k8s.io.api.core.v1.Handler", - "title": "PreStop is called immediately before a container is terminated due to an\nAPI request or management event such as liveness/startup probe failure,\npreemption, resource contention, etc. The handler is not called if the\ncontainer crashes or exits. The reason for termination is passed to the\nhandler. The Pod's termination grace period countdown begins before the\nPreStop hooked is executed. Regardless of the outcome of the handler, the\ncontainer will eventually terminate within the Pod's termination grace\nperiod. Other management of the container blocks until the hook completes\nor until the termination grace period is reached.\nMore info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks\n+optional" + "$ref": "#/definitions/k8s.io.api.core.v1.LifecycleHandler", + "title": "PreStop is called immediately before a container is terminated due to an\nAPI request or management event such as liveness/startup probe failure,\npreemption, resource contention, etc. The handler is not called if the\ncontainer crashes or exits. The Pod's termination grace period countdown begins before the\nPreStop hook is executed. Regardless of the outcome of the handler, the\ncontainer will eventually terminate within the Pod's termination grace\nperiod (unless delayed by finalizers). Other management of the container blocks until the hook completes\nor until the termination grace period is reached.\nMore info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks\n+optional" } }, "description": "Lifecycle describes actions that the management system should take in response to container lifecycle\nevents. For the PostStart and PreStop lifecycle handlers, management of the container blocks\nuntil the action is complete, unless the container process fails, in which case the handler is aborted." }, + "k8s.io.api.core.v1.LifecycleHandler": { + "type": "object", + "properties": { + "exec": { + "$ref": "#/definitions/k8s.io.api.core.v1.ExecAction", + "title": "Exec specifies the action to take.\n+optional" + }, + "httpGet": { + "$ref": "#/definitions/k8s.io.api.core.v1.HTTPGetAction", + "title": "HTTPGet specifies the http request to perform.\n+optional" + }, + "tcpSocket": { + "$ref": "#/definitions/k8s.io.api.core.v1.TCPSocketAction", + "title": "Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept\nfor the backward compatibility. There are no validation of this field and\nlifecycle hooks will fail in runtime when tcp handler is specified.\n+optional" + } + }, + "description": "LifecycleHandler defines a specific action that should be taken in a lifecycle\nhook. One and only one of the fields, except TCPSocket must be specified." + }, "k8s.io.api.core.v1.LocalObjectReference": { "type": "object", "properties": { @@ -2746,7 +2760,7 @@ }, "resources": { "$ref": "#/definitions/k8s.io.api.core.v1.ResourceRequirements", - "title": "Resources represents the minimum resources the volume should have.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources\n+optional" + "title": "Resources represents the minimum resources the volume should have.\nIf RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements\nthat are lower than previous value but must still be higher than capacity recorded in the\nstatus field of the claim.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources\n+optional" }, "volumeName": { "type": "string", @@ -2919,6 +2933,16 @@ }, "description": "PodDNSConfigOption defines DNS resolver options of a pod." }, + "k8s.io.api.core.v1.PodOS": { + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "Name is the name of the operating system. The currently supported values are linux and windows.\nAdditional value may be defined in future and can be one of:\nhttps://github.com/opencontainers/runtime-spec/blob/master/config.md#platform-specific-configuration\nClients should expect to handle additional values and treat unrecognized values in this field as os: null" + } + }, + "description": "PodOS defines the OS parameters of a pod." + }, "k8s.io.api.core.v1.PodReadinessGate": { "type": "object", "properties": { @@ -2934,21 +2958,21 @@ "properties": { "seLinuxOptions": { "$ref": "#/definitions/k8s.io.api.core.v1.SELinuxOptions", - "title": "The SELinux context to be applied to all containers.\nIf unspecified, the container runtime will allocate a random SELinux context for each\ncontainer. May also be set in SecurityContext. If set in\nboth SecurityContext and PodSecurityContext, the value specified in SecurityContext\ntakes precedence for that container.\n+optional" + "title": "The SELinux context to be applied to all containers.\nIf unspecified, the container runtime will allocate a random SELinux context for each\ncontainer. May also be set in SecurityContext. If set in\nboth SecurityContext and PodSecurityContext, the value specified in SecurityContext\ntakes precedence for that container.\nNote that this field cannot be set when spec.os.name is windows.\n+optional" }, "windowsOptions": { "$ref": "#/definitions/k8s.io.api.core.v1.WindowsSecurityContextOptions", - "title": "The Windows specific settings applied to all containers.\nIf unspecified, the options within a container's SecurityContext will be used.\nIf set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.\n+optional" + "title": "The Windows specific settings applied to all containers.\nIf unspecified, the options within a container's SecurityContext will be used.\nIf set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.\nNote that this field cannot be set when spec.os.name is linux.\n+optional" }, "runAsUser": { "type": "string", "format": "int64", - "title": "The UID to run the entrypoint of the container process.\nDefaults to user specified in image metadata if unspecified.\nMay also be set in SecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence\nfor that container.\n+optional" + "title": "The UID to run the entrypoint of the container process.\nDefaults to user specified in image metadata if unspecified.\nMay also be set in SecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence\nfor that container.\nNote that this field cannot be set when spec.os.name is windows.\n+optional" }, "runAsGroup": { "type": "string", "format": "int64", - "title": "The GID to run the entrypoint of the container process.\nUses runtime default if unset.\nMay also be set in SecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence\nfor that container.\n+optional" + "title": "The GID to run the entrypoint of the container process.\nUses runtime default if unset.\nMay also be set in SecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence\nfor that container.\nNote that this field cannot be set when spec.os.name is windows.\n+optional" }, "runAsNonRoot": { "type": "boolean", @@ -2960,12 +2984,12 @@ "type": "string", "format": "int64" }, - "title": "A list of groups applied to the first process run in each container, in addition\nto the container's primary GID. If unspecified, no groups will be added to\nany container.\n+optional" + "title": "A list of groups applied to the first process run in each container, in addition\nto the container's primary GID. If unspecified, no groups will be added to\nany container.\nNote that this field cannot be set when spec.os.name is windows.\n+optional" }, "fsGroup": { "type": "string", "format": "int64", - "description": "1. The owning GID will be the FSGroup\n2. The setgid bit is set (new files created in the volume will be owned by FSGroup)\n3. The permission bits are OR'd with rw-rw----\n\nIf unset, the Kubelet will not modify the ownership and permissions of any volume.\n+optional", + "description": "1. The owning GID will be the FSGroup\n2. The setgid bit is set (new files created in the volume will be owned by FSGroup)\n3. The permission bits are OR'd with rw-rw----\n\nIf unset, the Kubelet will not modify the ownership and permissions of any volume.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", "title": "A special supplemental group that applies to all containers in a pod.\nSome volume types allow the Kubelet to change the ownership of that volume\nto be owned by the pod:" }, "sysctls": { @@ -2973,15 +2997,15 @@ "items": { "$ref": "#/definitions/k8s.io.api.core.v1.Sysctl" }, - "title": "Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported\nsysctls (by the container runtime) might fail to launch.\n+optional" + "title": "Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported\nsysctls (by the container runtime) might fail to launch.\nNote that this field cannot be set when spec.os.name is windows.\n+optional" }, "fsGroupChangePolicy": { "type": "string", - "title": "fsGroupChangePolicy defines behavior of changing ownership and permission of the volume\nbefore being exposed inside Pod. This field will only apply to\nvolume types which support fsGroup based ownership(and permissions).\nIt will have no effect on ephemeral volume types such as: secret, configmaps\nand emptydir.\nValid values are \"OnRootMismatch\" and \"Always\". If not specified, \"Always\" is used.\n+optional" + "title": "fsGroupChangePolicy defines behavior of changing ownership and permission of the volume\nbefore being exposed inside Pod. This field will only apply to\nvolume types which support fsGroup based ownership(and permissions).\nIt will have no effect on ephemeral volume types such as: secret, configmaps\nand emptydir.\nValid values are \"OnRootMismatch\" and \"Always\". If not specified, \"Always\" is used.\nNote that this field cannot be set when spec.os.name is windows.\n+optional" }, "seccompProfile": { "$ref": "#/definitions/k8s.io.api.core.v1.SeccompProfile", - "title": "The seccomp options to use by the containers in this pod.\n+optional" + "title": "The seccomp options to use by the containers in this pod.\nNote that this field cannot be set when spec.os.name is windows.\n+optional" } }, "description": "PodSecurityContext holds pod-level security attributes and common container settings.\nSome fields are also present in container.securityContext. Field values of\ncontainer.securityContext take precedence over field values of PodSecurityContext." @@ -3015,7 +3039,7 @@ "items": { "$ref": "#/definitions/k8s.io.api.core.v1.EphemeralContainer" }, - "title": "List of ephemeral containers run in this pod. Ephemeral containers may be run in an existing\npod to perform user-initiated actions such as debugging. This list cannot be specified when\ncreating a pod, and it cannot be modified by updating the pod spec. In order to add an\nephemeral container to an existing pod, use the pod's ephemeralcontainers subresource.\nThis field is alpha-level and is only honored by servers that enable the EphemeralContainers feature.\n+optional\n+patchMergeKey=name\n+patchStrategy=merge" + "title": "List of ephemeral containers run in this pod. Ephemeral containers may be run in an existing\npod to perform user-initiated actions such as debugging. This list cannot be specified when\ncreating a pod, and it cannot be modified by updating the pod spec. In order to add an\nephemeral container to an existing pod, use the pod's ephemeralcontainers subresource.\nThis field is beta-level and available on clusters that haven't disabled the EphemeralContainers feature gate.\n+optional\n+patchMergeKey=name\n+patchStrategy=merge" }, "restartPolicy": { "type": "string", @@ -3164,6 +3188,10 @@ "setHostnameAsFQDN": { "type": "boolean", "title": "If true the pod's hostname will be configured as the pod's FQDN, rather than the leaf name (the default).\nIn Linux containers, this means setting the FQDN in the hostname field of the kernel (the nodename field of struct utsname).\nIn Windows containers, this means setting the registry value of hostname for the registry key HKEY_LOCAL_MACHINE\\\\SYSTEM\\\\CurrentControlSet\\\\Services\\\\Tcpip\\\\Parameters to FQDN.\nIf a pod does not have FQDN, this has no effect.\nDefault to false.\n+optional" + }, + "os": { + "$ref": "#/definitions/k8s.io.api.core.v1.PodOS", + "description": "Specifies the OS of the containers in the pod.\nSome pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset:\n-securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset:\n- spec.hostPID\n- spec.hostIPC\n- spec.securityContext.seLinuxOptions\n- spec.securityContext.seccompProfile\n- spec.securityContext.fsGroup\n- spec.securityContext.fsGroupChangePolicy\n- spec.securityContext.sysctls\n- spec.shareProcessNamespace\n- spec.securityContext.runAsUser\n- spec.securityContext.runAsGroup\n- spec.securityContext.supplementalGroups\n- spec.containers[*].securityContext.seLinuxOptions\n- spec.containers[*].securityContext.seccompProfile\n- spec.containers[*].securityContext.capabilities\n- spec.containers[*].securityContext.readOnlyRootFilesystem\n- spec.containers[*].securityContext.privileged\n- spec.containers[*].securityContext.allowPrivilegeEscalation\n- spec.containers[*].securityContext.procMount\n- spec.containers[*].securityContext.runAsUser\n- spec.containers[*].securityContext.runAsGroup\n+optional\nThis is an alpha field and requires the IdentifyPodOS feature" } }, "description": "PodSpec is a description of a pod." @@ -3219,7 +3247,7 @@ "type": "object", "properties": { "handler": { - "$ref": "#/definitions/k8s.io.api.core.v1.Handler", + "$ref": "#/definitions/k8s.io.api.core.v1.ProbeHandler", "title": "The action taken to determine the health of a container" }, "initialDelaySeconds": { @@ -3255,6 +3283,28 @@ }, "description": "Probe describes a health check to be performed against a container to determine whether it is\nalive or ready to receive traffic." }, + "k8s.io.api.core.v1.ProbeHandler": { + "type": "object", + "properties": { + "exec": { + "$ref": "#/definitions/k8s.io.api.core.v1.ExecAction", + "title": "Exec specifies the action to take.\n+optional" + }, + "httpGet": { + "$ref": "#/definitions/k8s.io.api.core.v1.HTTPGetAction", + "title": "HTTPGet specifies the http request to perform.\n+optional" + }, + "tcpSocket": { + "$ref": "#/definitions/k8s.io.api.core.v1.TCPSocketAction", + "title": "TCPSocket specifies an action involving a TCP port.\n+optional" + }, + "grpc": { + "$ref": "#/definitions/k8s.io.api.core.v1.GRPCAction", + "title": "GRPC specifies an action involving a GRPC port.\nThis is an alpha field and requires enabling GRPCContainerProbe feature gate.\n+featureGate=GRPCContainerProbe\n+optional" + } + }, + "description": "ProbeHandler defines a specific action that should be taken in a probe.\nOne and only one of the fields must be specified." + }, "k8s.io.api.core.v1.ProjectedVolumeSource": { "type": "object", "properties": { @@ -3548,29 +3598,29 @@ "properties": { "capabilities": { "$ref": "#/definitions/k8s.io.api.core.v1.Capabilities", - "title": "The capabilities to add/drop when running containers.\nDefaults to the default set of capabilities granted by the container runtime.\n+optional" + "title": "The capabilities to add/drop when running containers.\nDefaults to the default set of capabilities granted by the container runtime.\nNote that this field cannot be set when spec.os.name is windows.\n+optional" }, "privileged": { "type": "boolean", - "title": "Run container in privileged mode.\nProcesses in privileged containers are essentially equivalent to root on the host.\nDefaults to false.\n+optional" + "title": "Run container in privileged mode.\nProcesses in privileged containers are essentially equivalent to root on the host.\nDefaults to false.\nNote that this field cannot be set when spec.os.name is windows.\n+optional" }, "seLinuxOptions": { "$ref": "#/definitions/k8s.io.api.core.v1.SELinuxOptions", - "title": "The SELinux context to be applied to the container.\nIf unspecified, the container runtime will allocate a random SELinux context for each\ncontainer. May also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\n+optional" + "title": "The SELinux context to be applied to the container.\nIf unspecified, the container runtime will allocate a random SELinux context for each\ncontainer. May also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\nNote that this field cannot be set when spec.os.name is windows.\n+optional" }, "windowsOptions": { "$ref": "#/definitions/k8s.io.api.core.v1.WindowsSecurityContextOptions", - "title": "The Windows specific settings applied to all containers.\nIf unspecified, the options from the PodSecurityContext will be used.\nIf set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.\n+optional" + "title": "The Windows specific settings applied to all containers.\nIf unspecified, the options from the PodSecurityContext will be used.\nIf set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.\nNote that this field cannot be set when spec.os.name is linux.\n+optional" }, "runAsUser": { "type": "string", "format": "int64", - "title": "The UID to run the entrypoint of the container process.\nDefaults to user specified in image metadata if unspecified.\nMay also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\n+optional" + "title": "The UID to run the entrypoint of the container process.\nDefaults to user specified in image metadata if unspecified.\nMay also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\nNote that this field cannot be set when spec.os.name is windows.\n+optional" }, "runAsGroup": { "type": "string", "format": "int64", - "title": "The GID to run the entrypoint of the container process.\nUses runtime default if unset.\nMay also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\n+optional" + "title": "The GID to run the entrypoint of the container process.\nUses runtime default if unset.\nMay also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\nNote that this field cannot be set when spec.os.name is windows.\n+optional" }, "runAsNonRoot": { "type": "boolean", @@ -3578,19 +3628,19 @@ }, "readOnlyRootFilesystem": { "type": "boolean", - "title": "Whether this container has a read-only root filesystem.\nDefault is false.\n+optional" + "title": "Whether this container has a read-only root filesystem.\nDefault is false.\nNote that this field cannot be set when spec.os.name is windows.\n+optional" }, "allowPrivilegeEscalation": { "type": "boolean", - "title": "AllowPrivilegeEscalation controls whether a process can gain more\nprivileges than its parent process. This bool directly controls if\nthe no_new_privs flag will be set on the container process.\nAllowPrivilegeEscalation is true always when the container is:\n1) run as Privileged\n2) has CAP_SYS_ADMIN\n+optional" + "title": "AllowPrivilegeEscalation controls whether a process can gain more\nprivileges than its parent process. This bool directly controls if\nthe no_new_privs flag will be set on the container process.\nAllowPrivilegeEscalation is true always when the container is:\n1) run as Privileged\n2) has CAP_SYS_ADMIN\nNote that this field cannot be set when spec.os.name is windows.\n+optional" }, "procMount": { "type": "string", - "title": "procMount denotes the type of proc mount to use for the containers.\nThe default is DefaultProcMount which uses the container runtime defaults for\nreadonly paths and masked paths.\nThis requires the ProcMountType feature flag to be enabled.\n+optional" + "title": "procMount denotes the type of proc mount to use for the containers.\nThe default is DefaultProcMount which uses the container runtime defaults for\nreadonly paths and masked paths.\nThis requires the ProcMountType feature flag to be enabled.\nNote that this field cannot be set when spec.os.name is windows.\n+optional" }, "seccompProfile": { "$ref": "#/definitions/k8s.io.api.core.v1.SeccompProfile", - "title": "The seccomp options to use by this container. If seccomp options are\nprovided at both the pod \u0026 container level, the container options\noverride the pod options.\n+optional" + "title": "The seccomp options to use by this container. If seccomp options are\nprovided at both the pod \u0026 container level, the container options\noverride the pod options.\nNote that this field cannot be set when spec.os.name is windows.\n+optional" } }, "description": "SecurityContext holds security configuration that will be applied to a container.\nSome fields are present in both SecurityContext and PodSecurityContext. When both\nare set, the values in SecurityContext take precedence." @@ -3709,7 +3759,7 @@ }, "whenUnsatisfiable": { "type": "string", - "description": "WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy\nthe spread constraint.\n- DoNotSchedule (default) tells the scheduler not to schedule it.\n- ScheduleAnyway tells the scheduler to schedule the pod in any location,\n but giving higher precedence to topologies that would help reduce the\n skew.\nA constraint is considered \"Unsatisfiable\" for an incoming pod\nif and only if every possible node assigment for that pod would violate\n\"MaxSkew\" on some topology.\nFor example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same\nlabelSelector spread as 3/1/1:\n+-------+-------+-------+\n| zone1 | zone2 | zone3 |\n+-------+-------+-------+\n| P P P | P | P |\n+-------+-------+-------+\nIf WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled\nto zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies\nMaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler\nwon't make it *more* imbalanced.\nIt's a required field." + "description": "WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy\nthe spread constraint.\n- DoNotSchedule (default) tells the scheduler not to schedule it.\n- ScheduleAnyway tells the scheduler to schedule the pod in any location,\n but giving higher precedence to topologies that would help reduce the\n skew.\nA constraint is considered \"Unsatisfiable\" for an incoming pod\nif and only if every possible node assignment for that pod would violate\n\"MaxSkew\" on some topology.\nFor example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same\nlabelSelector spread as 3/1/1:\n+-------+-------+-------+\n| zone1 | zone2 | zone3 |\n+-------+-------+-------+\n| P P P | P | P |\n+-------+-------+-------+\nIf WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled\nto zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies\nMaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler\nwon't make it *more* imbalanced.\nIt's a required field." }, "labelSelector": { "$ref": "#/definitions/k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector", @@ -3933,7 +3983,7 @@ }, "ephemeral": { "$ref": "#/definitions/k8s.io.api.core.v1.EphemeralVolumeSource", - "description": "Ephemeral represents a volume that is handled by a cluster storage driver.\nThe volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts,\nand deleted when the pod is removed.\n\nUse this if:\na) the volume is only needed while the pod runs,\nb) features of normal volumes like restoring from snapshot or capacity\n tracking are needed,\nc) the storage driver is specified through a storage class, and\nd) the storage driver supports dynamic volume provisioning through\n a PersistentVolumeClaim (see EphemeralVolumeSource for more\n information on the connection between this volume type\n and PersistentVolumeClaim).\n\nUse PersistentVolumeClaim or one of the vendor-specific\nAPIs for volumes that persist for longer than the lifecycle\nof an individual pod.\n\nUse CSI for light-weight local ephemeral volumes if the CSI driver is meant to\nbe used that way - see the documentation of the driver for\nmore information.\n\nA pod can use both types of ephemeral volumes and\npersistent volumes at the same time.\n\nThis is a beta feature and only available when the GenericEphemeralVolume\nfeature gate is enabled.\n\n+optional" + "description": "Ephemeral represents a volume that is handled by a cluster storage driver.\nThe volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts,\nand deleted when the pod is removed.\n\nUse this if:\na) the volume is only needed while the pod runs,\nb) features of normal volumes like restoring from snapshot or capacity\n tracking are needed,\nc) the storage driver is specified through a storage class, and\nd) the storage driver supports dynamic volume provisioning through\n a PersistentVolumeClaim (see EphemeralVolumeSource for more\n information on the connection between this volume type\n and PersistentVolumeClaim).\n\nUse PersistentVolumeClaim or one of the vendor-specific\nAPIs for volumes that persist for longer than the lifecycle\nof an individual pod.\n\nUse CSI for light-weight local ephemeral volumes if the CSI driver is meant to\nbe used that way - see the documentation of the driver for\nmore information.\n\nA pod can use both types of ephemeral volumes and\npersistent volumes at the same time.\n\n+optional" } }, "description": "Represents the source of a volume to mount.\nOnly one of its members may be specified." diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index 210ea00906..72d10f584d 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* diff --git a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go index 79e420ea85..f184a9b9b4 100644 --- a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index 7b022d43a0..b4c63e2ced 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -20,6 +20,7 @@ package versioned import ( "fmt" + "net/http" argoprojv1alpha1 "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned/typed/rollouts/v1alpha1" discovery "k8s.io/client-go/discovery" @@ -55,22 +56,41 @@ func (c *Clientset) Discovery() discovery.DiscoveryInterface { // NewForConfig creates a new Clientset for the given config. // If config's RateLimiter is not set and QPS and Burst are acceptable, // NewForConfig will generate a rate-limiter in configShallowCopy. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*Clientset, error) { configShallowCopy := *c + + // share the transport between all clients + httpClient, err := rest.HTTPClientFor(&configShallowCopy) + if err != nil { + return nil, err + } + + return NewForConfigAndClient(&configShallowCopy, httpClient) +} + +// NewForConfigAndClient creates a new Clientset for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfigAndClient will generate a rate-limiter in configShallowCopy. +func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) { + configShallowCopy := *c if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { if configShallowCopy.Burst <= 0 { return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") } configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) } + var cs Clientset var err error - cs.argoprojV1alpha1, err = argoprojv1alpha1.NewForConfig(&configShallowCopy) + cs.argoprojV1alpha1, err = argoprojv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient) if err != nil { return nil, err } - cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient) if err != nil { return nil, err } @@ -80,11 +100,11 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { // NewForConfigOrDie creates a new Clientset for the given config and // panics if there is an error in the config. func NewForConfigOrDie(c *rest.Config) *Clientset { - var cs Clientset - cs.argoprojV1alpha1 = argoprojv1alpha1.NewForConfigOrDie(c) - - cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) - return &cs + cs, err := NewForConfig(c) + if err != nil { + panic(err) + } + return cs } // New creates a new Clientset for the given RESTClient. diff --git a/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/fake/fake_analysisrun.go b/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/fake/fake_analysisrun.go index d425d94dcd..89de9c005c 100644 --- a/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/fake/fake_analysisrun.go +++ b/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/fake/fake_analysisrun.go @@ -117,7 +117,7 @@ func (c *FakeAnalysisRuns) UpdateStatus(ctx context.Context, analysisRun *v1alph // Delete takes name of the analysisRun and deletes it. Returns an error if one occurs. func (c *FakeAnalysisRuns) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewDeleteAction(analysisrunsResource, c.ns, name), &v1alpha1.AnalysisRun{}) + Invokes(testing.NewDeleteActionWithOptions(analysisrunsResource, c.ns, name, opts), &v1alpha1.AnalysisRun{}) return err } diff --git a/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/fake/fake_analysistemplate.go b/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/fake/fake_analysistemplate.go index ffd134dde4..2cbb02d515 100644 --- a/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/fake/fake_analysistemplate.go +++ b/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/fake/fake_analysistemplate.go @@ -105,7 +105,7 @@ func (c *FakeAnalysisTemplates) Update(ctx context.Context, analysisTemplate *v1 // Delete takes name of the analysisTemplate and deletes it. Returns an error if one occurs. func (c *FakeAnalysisTemplates) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewDeleteAction(analysistemplatesResource, c.ns, name), &v1alpha1.AnalysisTemplate{}) + Invokes(testing.NewDeleteActionWithOptions(analysistemplatesResource, c.ns, name, opts), &v1alpha1.AnalysisTemplate{}) return err } diff --git a/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/fake/fake_clusteranalysistemplate.go b/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/fake/fake_clusteranalysistemplate.go index 36823a912f..36389661de 100644 --- a/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/fake/fake_clusteranalysistemplate.go +++ b/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/fake/fake_clusteranalysistemplate.go @@ -99,7 +99,7 @@ func (c *FakeClusterAnalysisTemplates) Update(ctx context.Context, clusterAnalys // Delete takes name of the clusterAnalysisTemplate and deletes it. Returns an error if one occurs. func (c *FakeClusterAnalysisTemplates) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewRootDeleteAction(clusteranalysistemplatesResource, name), &v1alpha1.ClusterAnalysisTemplate{}) + Invokes(testing.NewRootDeleteActionWithOptions(clusteranalysistemplatesResource, name, opts), &v1alpha1.ClusterAnalysisTemplate{}) return err } diff --git a/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/fake/fake_experiment.go b/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/fake/fake_experiment.go index eb2b7fb5d9..f237ce32d1 100644 --- a/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/fake/fake_experiment.go +++ b/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/fake/fake_experiment.go @@ -117,7 +117,7 @@ func (c *FakeExperiments) UpdateStatus(ctx context.Context, experiment *v1alpha1 // Delete takes name of the experiment and deletes it. Returns an error if one occurs. func (c *FakeExperiments) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewDeleteAction(experimentsResource, c.ns, name), &v1alpha1.Experiment{}) + Invokes(testing.NewDeleteActionWithOptions(experimentsResource, c.ns, name, opts), &v1alpha1.Experiment{}) return err } diff --git a/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/fake/fake_rollout.go b/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/fake/fake_rollout.go index fca9011ae1..fce5e8d66e 100644 --- a/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/fake/fake_rollout.go +++ b/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/fake/fake_rollout.go @@ -117,7 +117,7 @@ func (c *FakeRollouts) UpdateStatus(ctx context.Context, rollout *v1alpha1.Rollo // Delete takes name of the rollout and deletes it. Returns an error if one occurs. func (c *FakeRollouts) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewDeleteAction(rolloutsResource, c.ns, name), &v1alpha1.Rollout{}) + Invokes(testing.NewDeleteActionWithOptions(rolloutsResource, c.ns, name, opts), &v1alpha1.Rollout{}) return err } diff --git a/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/rollouts_client.go b/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/rollouts_client.go index 91c3ecbd8d..61e7ef4170 100644 --- a/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/rollouts_client.go +++ b/pkg/client/clientset/versioned/typed/rollouts/v1alpha1/rollouts_client.go @@ -19,6 +19,8 @@ limitations under the License. package v1alpha1 import ( + "net/http" + v1alpha1 "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned/scheme" rest "k8s.io/client-go/rest" @@ -59,12 +61,28 @@ func (c *ArgoprojV1alpha1Client) Rollouts(namespace string) RolloutInterface { } // NewForConfig creates a new ArgoprojV1alpha1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*ArgoprojV1alpha1Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err } - client, err := rest.RESTClientFor(&config) + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new ArgoprojV1alpha1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*ArgoprojV1alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) if err != nil { return nil, err } diff --git a/rollout/controller_test.go b/rollout/controller_test.go index 8a71878027..acb3c6b395 100644 --- a/rollout/controller_test.go +++ b/rollout/controller_test.go @@ -1300,7 +1300,7 @@ func TestPodTemplateHashEquivalence(t *testing.T) { var err error // NOTE: This test will fail on every k8s library upgrade. // To fix it, update expectedReplicaSetName to match the new hash. - expectedReplicaSetName := "guestbook-586d86c77b" + expectedReplicaSetName := "guestbook-859fc5d686" r1 := newBlueGreenRollout("guestbook", 1, nil, "active", "") r1Resources := ` diff --git a/rollout/replicaset.go b/rollout/replicaset.go index 8a39e657ef..dceff65aa0 100644 --- a/rollout/replicaset.go +++ b/rollout/replicaset.go @@ -77,7 +77,7 @@ func (c *Controller) getReplicaSetsForRollouts(r *v1alpha1.Rollout) ([]*appsv1.R } // If any adoptions are attempted, we should first recheck for deletion with // an uncached quorum read sometime after listing ReplicaSets (see #42639). - canAdoptFunc := controller.RecheckDeletionTimestamp(func() (metav1.Object, error) { + canAdoptFunc := controller.RecheckDeletionTimestamp(func(ctx context.Context) (metav1.Object, error) { fresh, err := c.argoprojclientset.ArgoprojV1alpha1().Rollouts(r.Namespace).Get(ctx, r.Name, metav1.GetOptions{}) if err != nil { return nil, err @@ -88,7 +88,7 @@ func (c *Controller) getReplicaSetsForRollouts(r *v1alpha1.Rollout) ([]*appsv1.R return fresh, nil }) cm := controller.NewReplicaSetControllerRefManager(c.replicaSetControl, r, replicaSetSelector, controllerKind, canAdoptFunc) - return cm.ClaimReplicaSets(rsList) + return cm.ClaimReplicaSets(ctx, rsList) } // removeScaleDownDeadlines removes the scale-down-deadline annotation from the new/stable ReplicaSets, diff --git a/rollout/temlateref_test.go b/rollout/temlateref_test.go index d859996aba..cd81b2d1a6 100644 --- a/rollout/temlateref_test.go +++ b/rollout/temlateref_test.go @@ -159,7 +159,7 @@ func TestResolve_UnknownAPIResource(t *testing.T) { err := resolver.Resolve(&rollout) assert.Error(t, err) - assert.Equal(t, `GroupVersion "apps/v1" not found`, err.Error()) + assert.Equal(t, `the server could not find the requested resource, GroupVersion "apps/v1" not found`, err.Error()) } func TestResolve_RefDoesNotExists(t *testing.T) { diff --git a/test/fixtures/when.go b/test/fixtures/when.go index 7df2beb810..ea6d855e43 100644 --- a/test/fixtures/when.go +++ b/test/fixtures/when.go @@ -75,7 +75,7 @@ func (w *When) injectDelays(un *unstructured.Unstructured) { if E2EPodDelay == 0 { return } - sleepHandler := corev1.Handler{ + sleepHandler := corev1.LifecycleHandler{ Exec: &corev1.ExecAction{ Command: []string{"sleep", strconv.Itoa(E2EPodDelay)}, }, diff --git a/utils/conditions/rollouts_test.go b/utils/conditions/rollouts_test.go index c633a4e40c..b8376a027f 100644 --- a/utils/conditions/rollouts_test.go +++ b/utils/conditions/rollouts_test.go @@ -411,13 +411,13 @@ func TestRolloutComplete(t *testing.T) { { name: "BlueGreen complete", // update hash to status.CurrentPodHash after k8s library update - r: blueGreenRollout(5, 5, 5, 5, true, "85f7cf5fc7", "85f7cf5fc7"), + r: blueGreenRollout(5, 5, 5, 5, true, "78957574d7", "78957574d7"), expected: true, }, { name: "BlueGreen complete with extra old replicas", // update hash to status.CurrentPodHash after k8s library update - r: blueGreenRollout(5, 6, 5, 5, true, "85f7cf5fc7", "85f7cf5fc7"), + r: blueGreenRollout(5, 6, 5, 5, true, "78957574d7", "78957574d7"), expected: true, }, { diff --git a/utils/experiment/experiment_test.go b/utils/experiment/experiment_test.go index 194065cbf7..1b9ed861da 100644 --- a/utils/experiment/experiment_test.go +++ b/utils/experiment/experiment_test.go @@ -100,14 +100,14 @@ func TestReplicaSetNameFromExperiment(t *testing.T) { Name: "foo", }, } - assert.Equal(t, "foo-template-85f7cf5fc7", ReplicasetNameFromExperiment(e, template)) + assert.Equal(t, "foo-template-78957574d7", ReplicasetNameFromExperiment(e, template)) newTemplateStatus := v1alpha1.TemplateStatus{ Name: templateName, CollisionCount: pointer.Int32Ptr(1), } e.Status.TemplateStatuses = append(e.Status.TemplateStatuses, newTemplateStatus) - assert.Equal(t, "foo-template-56ccbc9b64", ReplicasetNameFromExperiment(e, template)) + assert.Equal(t, "foo-template-db98f55f8", ReplicasetNameFromExperiment(e, template)) } func TestExperimentByCreationTimestamp(t *testing.T) { From fbf680c80e2caab77fc726ce21cd14d4756568a3 Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Thu, 27 Jan 2022 14:49:12 -0800 Subject: [PATCH 067/175] docs: update membership information (#1814) Signed-off-by: Jesse Suen --- OWNERS | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/OWNERS b/OWNERS index ef7133eca0..4552f99648 100644 --- a/OWNERS +++ b/OWNERS @@ -4,9 +4,13 @@ owners: approvers: - alexmt +- huikang - jessesuen - khhirani reviewers: +- agrawroh - dthomson25 -- huikang \ No newline at end of file +- harikrongali +- kostis-codefresh +- perenesenko From 91c1eab8ee9d497e5e928919a3c8dfecf2f0ddad Mon Sep 17 00:00:00 2001 From: cskh Date: Thu, 27 Jan 2022 17:51:20 -0500 Subject: [PATCH 068/175] fix: remove non-existent target in makefile (#1813) Signed-off-by: Hui Kang --- Makefile | 4 ++-- docs/CONTRIBUTING.md | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 6330ee9f4b..eecbc4eb00 100644 --- a/Makefile +++ b/Makefile @@ -123,12 +123,12 @@ gen-k8scodegen: go-mod-vendor # generates ./manifests/crds/ .PHONY: gen-crd -gen-crd: $(DIST_DIR)/controller-gen +gen-crd: install-go-tools-local go run ./hack/gen-crd-spec/main.go # generates mock files from interfaces .PHONY: gen-mocks -gen-mocks: $(DIST_DIR)/mockery +gen-mocks: install-go-tools-local ./hack/update-mocks.sh # generates openapi_generated.go diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 029f8a8a5e..f8edb986d4 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -56,6 +56,8 @@ cd ~/go/src/github.com/argoproj/argo-rollouts The `make controller` command will build the controller. +* `make install-tools-local` - Runs scripts to install codegen utility CLIs necessary for codegen. + * `make codegen` - Runs the code generator that creates the informers, client, lister, and deepcopies from the types.go and modifies the open-api spec. From 9f3f4c8f486d1ae3746960cb8b150f40ea1c7447 Mon Sep 17 00:00:00 2001 From: "Kostis (Codefresh)" <39800303+kostis-codefresh@users.noreply.github.com> Date: Fri, 28 Jan 2022 00:51:39 +0200 Subject: [PATCH 069/175] docs: Added ArgoCon 21 presentation (#1811) Signed-off-by: Kostis Kapelonis --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index cccd5c3f8c..10da141d86 100644 --- a/README.md +++ b/README.md @@ -62,5 +62,6 @@ To learn more about Argo Rollouts go to the [complete documentation](https://arg * [GitOps with Argo CD and an Argo Rollouts canary release](https://www.youtube.com/watch?v=35Qimb_AZ8U) * [Multi-Stage Delivery with Keptn and Argo Rollouts](https://www.youtube.com/watch?v=w-E8FzTbN3g&t=1s) * [Gradual Code Releases Using an In-House Kubernetes Canary Controller on top of Argo Rollouts](https://doordash.engineering/2021/04/14/gradual-code-releases-using-an-in-house-kubernetes-canary-controller/) +* [How Scalable is Argo-Rollouts: A Cloud Operator’s Perspective](https://www.youtube.com/watch?v=rCEhxJ2NSTI) From edfe42e57a9e91c225623de66a0a5d27e7403a93 Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Thu, 27 Jan 2022 16:40:15 -0800 Subject: [PATCH 070/175] chore(deps): update github.com/miekg/dns for CVE-2019-19794 (#1810) Signed-off-by: Jesse Suen --- go.mod | 11 ++++++----- go.sum | 25 ++++++++++++++++++------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index ebbcee1fb1..59d3bb6008 100644 --- a/go.mod +++ b/go.mod @@ -148,14 +148,14 @@ require ( github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect - golang.org/x/mod v0.4.2 // indirect - golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect + golang.org/x/mod v0.5.1 // indirect + golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba // indirect golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect - golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect - golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect + golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect - golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff // indirect + golang.org/x/tools v0.1.9 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect gomodules.xyz/envconfig v1.3.1-0.20190308184047-426f31af0d45 // indirect gomodules.xyz/notify v0.1.0 // indirect @@ -177,6 +177,7 @@ require ( replace ( github.com/go-check/check => github.com/go-check/check v0.0.0-20180628173108-788fd7840127 github.com/grpc-ecosystem/grpc-gateway => github.com/grpc-ecosystem/grpc-gateway v1.16.0 + github.com/miekg/dns => github.com/miekg/dns v1.1.45 k8s.io/api => k8s.io/api v0.23.1 k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.23.1 k8s.io/apimachinery => k8s.io/apimachinery v0.23.2-rc.0 diff --git a/go.sum b/go.sum index 7f91b9e152..a88def4a92 100644 --- a/go.sum +++ b/go.sum @@ -768,7 +768,7 @@ github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182aff github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mbilski/exhaustivestruct v1.1.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.45/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/mindprince/gonvml v0.0.0-20190828220739-9ebdce4bb989/go.mod h1:2eu9pRWp8mo84xCg6KswZ+USQHjwgRhNp06sozOdsTY= github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= github.com/minio/minio-go/v7 v7.0.2/go.mod h1:dJ80Mv2HeGkYLH1sqS/ksz07ON6csH3S6JUMSQ2zAns= @@ -1093,6 +1093,7 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= @@ -1200,8 +1201,9 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1255,10 +1257,13 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba h1:6u6sik+bn/y7vILcYkK3iwTBWN7WtBvB0+SZswQnbf8= +golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1373,13 +1378,17 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E= -golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1494,8 +1503,10 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff h1:VX/uD7MK0AHXGiScH3fsieUQUcpmRERPDYtqZdJnA+Q= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM= +golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 85cdf40cbd1e4e4b11d1515e6991f5a664b41669 Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Thu, 27 Jan 2022 16:41:34 -0800 Subject: [PATCH 071/175] fix: client can detect if rollout is in the process of unpausing (#1798) Signed-off-by: Jesse Suen --- pkg/apiclient/rollout/rollout.swagger.json | 2 +- pkg/apis/rollouts/v1alpha1/generated.proto | 6 +++++- .../rollouts/v1alpha1/openapi_generated.go | 2 +- pkg/apis/rollouts/v1alpha1/types.go | 6 +++++- test/e2e/istio_test.go | 5 +---- utils/replicaset/canary.go | 2 +- utils/rollout/rolloututil.go | 15 +++++++++++++- utils/rollout/rolloututil_test.go | 20 +++++++++++++++++++ 8 files changed, 48 insertions(+), 10 deletions(-) diff --git a/pkg/apiclient/rollout/rollout.swagger.json b/pkg/apiclient/rollout/rollout.swagger.json index 671eb495ab..28b07ad208 100644 --- a/pkg/apiclient/rollout/rollout.swagger.json +++ b/pkg/apiclient/rollout/rollout.swagger.json @@ -1300,7 +1300,7 @@ "items": { "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.PauseCondition" }, - "title": "PauseConditions indicates why the rollout is currently paused" + "title": "PauseConditions is a list of reasons why rollout became automatically paused (e.g.\nCanaryPauseStep, BlueGreenPause, InconclusiveAnalysis). The items in this list are populated\nby the controller but are cleared by the user (e.g. plugin, argo-cd resume action) when they\nwish to unpause. If pause conditions is empty, but controllerPause is true, it indicates\nthe user manually unpaused the Rollout" }, "controllerPause": { "type": "boolean", diff --git a/pkg/apis/rollouts/v1alpha1/generated.proto b/pkg/apis/rollouts/v1alpha1/generated.proto index ad006306fb..e4063d3721 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.proto +++ b/pkg/apis/rollouts/v1alpha1/generated.proto @@ -1207,7 +1207,11 @@ message RolloutStatus { // Abort cancel the current rollout progression optional bool abort = 1; - // PauseConditions indicates why the rollout is currently paused + // PauseConditions is a list of reasons why rollout became automatically paused (e.g. + // CanaryPauseStep, BlueGreenPause, InconclusiveAnalysis). The items in this list are populated + // by the controller but are cleared by the user (e.g. plugin, argo-cd resume action) when they + // wish to unpause. If pause conditions is empty, but controllerPause is true, it indicates + // the user manually unpaused the Rollout repeated PauseCondition pauseConditions = 2; // ControllerPause indicates the controller has paused the rollout. It is set to true when diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index 72d10f584d..43ca298d45 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -3662,7 +3662,7 @@ func schema_pkg_apis_rollouts_v1alpha1_RolloutStatus(ref common.ReferenceCallbac }, "pauseConditions": { SchemaProps: spec.SchemaProps{ - Description: "PauseConditions indicates why the rollout is currently paused", + Description: "PauseConditions is a list of reasons why rollout became automatically paused (e.g. CanaryPauseStep, BlueGreenPause, InconclusiveAnalysis). The items in this list are populated by the controller but are cleared by the user (e.g. plugin, argo-cd resume action) when they wish to unpause. If pause conditions is empty, but controllerPause is true, it indicates the user manually unpaused the Rollout", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ diff --git a/pkg/apis/rollouts/v1alpha1/types.go b/pkg/apis/rollouts/v1alpha1/types.go index cfa95043a9..bc43fd5fb2 100644 --- a/pkg/apis/rollouts/v1alpha1/types.go +++ b/pkg/apis/rollouts/v1alpha1/types.go @@ -684,7 +684,11 @@ const ( type RolloutStatus struct { // Abort cancel the current rollout progression Abort bool `json:"abort,omitempty" protobuf:"varint,1,opt,name=abort"` - // PauseConditions indicates why the rollout is currently paused + // PauseConditions is a list of reasons why rollout became automatically paused (e.g. + // CanaryPauseStep, BlueGreenPause, InconclusiveAnalysis). The items in this list are populated + // by the controller but are cleared by the user (e.g. plugin, argo-cd resume action) when they + // wish to unpause. If pause conditions is empty, but controllerPause is true, it indicates + // the user manually unpaused the Rollout PauseConditions []PauseCondition `json:"pauseConditions,omitempty" protobuf:"bytes,2,rep,name=pauseConditions"` // ControllerPause indicates the controller has paused the rollout. It is set to true when // the controller adds a pause condition. This field helps to discern the scenario where a diff --git a/test/e2e/istio_test.go b/test/e2e/istio_test.go index 478d7eca05..2a0b2fe7c2 100644 --- a/test/e2e/istio_test.go +++ b/test/e2e/istio_test.go @@ -1,3 +1,4 @@ +//go:build e2e // +build e2e package e2e @@ -292,10 +293,6 @@ func (s *IstioSuite) TestIstioAbortUpdateDeleteAllCanaryPods() { PromoteRollout(). WaitForRolloutStatus("Paused"). Then(). - When(). - PromoteRollout(). - WaitForRolloutStatus("Paused"). - Then(). ExpectRevisionPodCount("2", 4). When(). AbortRollout(). diff --git a/utils/replicaset/canary.go b/utils/replicaset/canary.go index 8a3835eb31..157d90f916 100644 --- a/utils/replicaset/canary.go +++ b/utils/replicaset/canary.go @@ -436,7 +436,7 @@ func GetCurrentCanaryStep(rollout *v1alpha1.Rollout) (*v1alpha1.CanaryStep, *int // GetCanaryReplicasOrWeight either returns a static set of replicas or a weight percentage func GetCanaryReplicasOrWeight(rollout *v1alpha1.Rollout) (*int32, int32) { - if rollout.Status.PromoteFull || rollout.Status.CurrentPodHash == rollout.Status.StableRS { + if rollout.Status.PromoteFull || rollout.Status.StableRS == "" || rollout.Status.CurrentPodHash == rollout.Status.StableRS { return nil, 100 } if scs := UseSetCanaryScale(rollout); scs != nil { diff --git a/utils/rollout/rolloututil.go b/utils/rollout/rolloututil.go index c2e997aa00..c9243c3215 100644 --- a/utils/rollout/rolloututil.go +++ b/utils/rollout/rolloututil.go @@ -23,7 +23,9 @@ func GetRolloutPhase(ro *v1alpha1.Rollout) (v1alpha1.RolloutPhase, string) { if !isGenerationObserved(ro) { return v1alpha1.RolloutPhaseProgressing, "waiting for rollout spec update to be observed" } - + if IsUnpausing(ro) { + return v1alpha1.RolloutPhaseProgressing, "waiting for rollout to unpause" + } if ro.Spec.TemplateResolvedFromRef && !isWorkloadGenerationObserved(ro) { return v1alpha1.RolloutPhaseProgressing, "waiting for rollout spec update to be observed for the reference workload" } @@ -51,6 +53,17 @@ func isGenerationObserved(ro *v1alpha1.Rollout) bool { return int64(observedGen) == ro.Generation } +// IsUnpausing detects if we are in the process of unpausing a rollout. This is determined by seeing +// if status.controllerPause is true, but the list of pause conditions (status.pauseConditions) +// is empty. This implies that a user cleared the pause conditions but controller has not yet +// observed or reacted to it. +// NOTE: this function is necessary because unlike metadata.generation & status.observedGeneration +// status.controllerPause & status.pauseConditions are both status fields and does not benefit from +// the auto-incrementing behavior of metadata.generation. +func IsUnpausing(ro *v1alpha1.Rollout) bool { + return ro.Status.ControllerPause && len(ro.Status.PauseConditions) == 0 +} + func isWorkloadGenerationObserved(ro *v1alpha1.Rollout) bool { if _, ok := annotations.GetWorkloadGenerationAnnotation(ro); !ok { return true diff --git a/utils/rollout/rolloututil_test.go b/utils/rollout/rolloututil_test.go index 4fc15a4c63..efb76af9a3 100644 --- a/utils/rollout/rolloututil_test.go +++ b/utils/rollout/rolloututil_test.go @@ -394,3 +394,23 @@ func TestCanaryStepString(t *testing.T) { assert.Equal(t, test.expectedString, CanaryStepString(test.step)) } } + +func TestIsUnpausing(t *testing.T) { + ro := newCanaryRollout() + ro.Status.Phase = v1alpha1.RolloutPhasePaused + ro.Status.Message = "canary pause" + ro.Status.PauseConditions = []v1alpha1.PauseCondition{ + { + Reason: v1alpha1.PauseReasonCanaryPauseStep, + }, + } + ro.Status.ControllerPause = true + status, message := GetRolloutPhase(ro) + assert.Equal(t, v1alpha1.RolloutPhasePaused, status) + assert.Equal(t, "canary pause", message) + + ro.Status.PauseConditions = nil + status, message = GetRolloutPhase(ro) + assert.Equal(t, v1alpha1.RolloutPhaseProgressing, status) + assert.Equal(t, "waiting for rollout to unpause", message) +} From 11cfc3b538db8cef47351f9a65f200870692369f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Jan 2022 18:08:15 -0800 Subject: [PATCH 072/175] chore(deps): bump github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 (#1797) Bumps [github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2](https://github.com/aws/aws-sdk-go-v2) from 1.6.1 to 1.16.0. - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.6.1...service/s3/v1.16.0) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 59d3bb6008..5e266e3321 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/argoproj/pkg v0.9.0 github.com/aws/aws-sdk-go-v2/config v1.13.0 github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.5.0 - github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.6.1 + github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.16.0 github.com/blang/semver v3.5.1+incompatible github.com/evanphx/json-patch/v5 v5.6.0 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 diff --git a/go.sum b/go.sum index a88def4a92..ec613f738e 100644 --- a/go.sum +++ b/go.sum @@ -175,7 +175,6 @@ github.com/aws/aws-sdk-go v1.33.16/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZve github.com/aws/aws-sdk-go v1.35.24/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k= github.com/aws/aws-sdk-go v1.38.49/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go-v2 v1.7.0/go.mod h1:tb9wi5s61kTDA5qCkcDbt3KRVV74GGslQkl/DRdX/P4= -github.com/aws/aws-sdk-go-v2 v1.8.1/go.mod h1:xEFuWz+3TYdlPRuo+CqATbeDWIWyaT5uAPwPaWtgse0= github.com/aws/aws-sdk-go-v2 v1.13.0 h1:1XIXAfxsEmbhbj5ry3D3vX+6ZcUYvIqSm4CWWEuGZCA= github.com/aws/aws-sdk-go-v2 v1.13.0/go.mod h1:L6+ZpqHaLbAaxsqV0L4cvxZY7QupWJB4fhkf8LXvC7w= github.com/aws/aws-sdk-go-v2/config v1.13.0 h1:1ij3YPk13RrIn1h+pH+dArh3lNPD5JSAP+ifOkNhnB0= @@ -192,8 +191,8 @@ github.com/aws/aws-sdk-go-v2/internal/ini v1.3.4 h1:0NrDHIwS1LIR750ltj6ciiu4NZLp github.com/aws/aws-sdk-go-v2/internal/ini v1.3.4/go.mod h1:R3sWUqPcfXSiF/LSFJhjyJmpg9uV6yP2yv3YZZjldVI= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.5.0 h1:XO1uX7dQKWfD0WzycEfz+bL/7rl0SsQ05VJwLPWGzGM= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.5.0/go.mod h1:acH3+MQoiMzozT/ivU+DbRg7Ooo2298RdRaWcOv+4vM= -github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.6.1 h1:mGc8UvJS4XJv8Tp7Doxlx2p3vfwPx46K9zg+9s9szPE= -github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.6.1/go.mod h1:lGKz4aJbqGX+pgyXG47ZBAJPjwrlA5+TJsAuJ2+aE2g= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.16.0 h1:4NawSD1qP7RPEqtCoahFNwkTa4MHtoKF08mhy+Y2Kok= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.16.0/go.mod h1:5rsn/Fxs9Rnq28KLB8n1pJcRR3UtrHY787uapxrvDRA= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0 h1:4QAOB3KrvI1ApJK14sliGr3Ie2pjyvNypn/lfzDHfUw= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0/go.mod h1:K/qPe6AP2TGYv4l6n7c88zh9jWBDf6nHhvg1fx/EWfU= github.com/aws/aws-sdk-go-v2/service/sso v1.9.0 h1:1qLJeQGBmNQW3mBNzK2CFmrQNmoXWrscPqsrAaU1aTA= @@ -201,7 +200,6 @@ github.com/aws/aws-sdk-go-v2/service/sso v1.9.0/go.mod h1:vCV4glupK3tR7pw7ks7Y4j github.com/aws/aws-sdk-go-v2/service/sts v1.14.0 h1:ksiDXhvNYg0D2/UFkLejsaz3LqpW5yjNQ8Nx9Sn2c0E= github.com/aws/aws-sdk-go-v2/service/sts v1.14.0/go.mod h1:u0xMJKDvvfocRjiozsoZglVNXRG19043xzp3r2ivLIk= github.com/aws/smithy-go v1.5.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= -github.com/aws/smithy-go v1.7.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.10.0 h1:gsoZQMNHnX+PaghNw4ynPsyGP7aUCqx5sY2dlPQsZ0w= github.com/aws/smithy-go v1.10.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= From 4bb17d7b0f489a1e6c26aa7bf311095bfd15e87a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Jan 2022 21:01:28 -0800 Subject: [PATCH 073/175] chore(deps): bump github.com/prometheus/common from 0.21.0 to 0.32.1 (#1604) Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.21.0 to 0.32.1. - [Release notes](https://github.com/prometheus/common/releases) - [Commits](https://github.com/prometheus/common/compare/v0.21.0...v0.32.1) --- updated-dependencies: - dependency-name: github.com/prometheus/common dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 5e266e3321..744f63c188 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.11.0 github.com/prometheus/client_model v0.2.0 - github.com/prometheus/common v0.28.0 + github.com/prometheus/common v0.32.1 github.com/servicemeshinterface/smi-sdk-go v0.4.1 github.com/sirupsen/logrus v1.8.1 github.com/soheilhy/cmux v0.1.5 diff --git a/go.sum b/go.sum index ec613f738e..f4e5ea4857 100644 --- a/go.sum +++ b/go.sum @@ -902,8 +902,9 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.28.0 h1:vGVfV9KrDTvWt5boZO0I19g2E3CsWfpPPKZM9dt3mEw= github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= From 74e95f8bd386a68131b43c9513f9468fde2a73d2 Mon Sep 17 00:00:00 2001 From: Kostis Kapelonis Date: Fri, 28 Jan 2022 13:41:23 +0200 Subject: [PATCH 074/175] docs: mention internal architecture Signed-off-by: Kostis Kapelonis --- docs/CONTRIBUTING.md | 15 +++++++++++++++ .../internal-architecture.png | Bin 0 -> 622877 bytes 2 files changed, 15 insertions(+) create mode 100644 docs/architecture-assets/internal-architecture.png diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index f8edb986d4..b3c1f1be87 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -93,6 +93,21 @@ Then run the e2e tests: make test-e2e ``` +## Controller architecture + +Argo Rollouts is actually a collection of individual controllers +that handle a specific aspect of Progressive Delivery. + +[![Internal Architecture](architecture-assets/internal-architecture.png)](architecture-assets/internal-architecture.png) + +The controllers are: + +* [Rollout Controller](https://github.com/argoproj/argo-rollouts/blob/master/controller/controller.go) +* [Service Controller](https://github.com/argoproj/argo-rollouts/blob/master/service/service.go) +* [Ingress Controller](https://github.com/argoproj/argo-rollouts/blob/master/ingress/ingress.go) +* [Experiment Controller](https://github.com/argoproj/argo-rollouts/blob/master/experiments/controller.go) +* [AnalysisRun Controller](https://github.com/argoproj/argo-rollouts/blob/master/analysis/controller.go) + ### Tips 1. You can run the tests using a different kubeconfig by setting the `KUBECONFIG` environment variable: diff --git a/docs/architecture-assets/internal-architecture.png b/docs/architecture-assets/internal-architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..56502807b53a9da3f2a44a85d681bf5df346bd44 GIT binary patch literal 622877 zcmb@tW00l65-r-c?P=S#ZM%EgHg?;#Z5z|JZA{z7w5^%GJ#*fRI49oy`7&b1j<0@v zwRcrzR<5-&BNXK&;9+oJfPjGDr6fg_fq)>PfPg?%pg_Jx*q*nazP^B+l_i9MYG?4y zz8=8Lh2(^QfPTcmei(v(JwrQ4YB>V|VUYa&0FNsfSOWolmPm;Tsk-Z5{D#aoSyRJ@ zTj^F~aLNA3!pCLFN-|A(;!lbsj3NnT7%-M@0ynaH+Ksp^wezLmv=v7zwr+azbJkQx)ts7yH<@}86*A};1So1R%$0e?Q zh}q4|S$^UF*Y+!dmrv0DFQ$O~6SC<4HqQ0`@3;aUj(pG=nu^%}*f5@~<25g(eKwh! zeaWw!M`LjxMr|dfTP&nFPV>nhx?9kU8iOzl$-&^1tN;5W6?|!Xz%d-2ZIbVNxx!px z*7O~JmLrPOP*W3tW|9jWW!DTlkqMI+>c0Xs@@3{0e@6a~C4m7jv#&fZYtuk<@+|1D zlkaUE6Az5>+At|JZ5z)y$h{f{h&n4?LaP3c@p>S;^^g~P znNBlLEj3~o3iEVQi%S@ z@R&K`q@w)4%{>w5nrr}6u4T>=eyW=xRw@7qMOy17c>Idv7?}-MQR!Q>x~eK326b+Q zn5k`b?z41_M=AU_lXIV<25oCVyi^cjN~COj(r#^VqGf{<4s*?9-G9HooO91#M`Np- zy-T6=l+N7OKFiK4h@r6`?Cqw9=)NNdk&ll(AxT|20~C!&!Q(%NAWT9jvxbVsb&nY` z0nYB$%}1VmKRKy9GtGlFV>l+lxLp{a{lEJf0o`l4#7Ar1mW02{p5fMdg>t$NUw6-9 z0+%Mpf42(O&Jz&N8CVrkQpk^0Q(n#q_hQ15HoZSzEJNKUWvYT^bWZQ?B3|?vN<|F~ ze0;?le2M&#P}P5-r}4k@U}6InBRAAm@Ek#{V|2UU*XD+b)1GJ2J>53FK`TU^KzuoJ zGVs$GD75-Ktn&ZOr3r^2!O%&0R((cW(7sD+K zbixn)He{KAJhq!y11Ufd#ICITdHMgi^L~Wz2?EY;P32CmQ7w=9*oOi6CD6s<85l9D zV3L)hH0)tCm0qcVEhC+@J~AbRQiO=BNprX-b-}+sPuX`KmHIuJsZ{XoTN>B|I3x&Nx<}A*-mJFHA9mIMUGrOrYXQ^+y-Kte@F}F$ zaz~CBTz%A6?1}7{*6!}S)AScTM$q3W-HB@wo~u>>oI#lYw?$Q<{3!Kp(ZS^i&x!wR z!zrj*{BVM6l9<*Ai057T8?=y+kvMW#A*Z!vKkvBVsILARQxb18s$i*5%hf)7r8uQ2 zyi@>w!T&Bsn{aCm3rB8gXg-y|JerE{%Y*#vUF=3@~Szai``%0xR z*)Fivt&w+^{B6U_HC5#E1{Xc9s!caAZTOI<`<-c|@Aw_PKqzmNcI|vAzd~yPiU0h; zoq9kf&q}xJERm6n9KHX{Byk%o@^1Q*pa4AsP^2Z3!NTy6IaUnIl8y55O*ggC-M%7e ztq?gZgwruS0t`XKL0EZCQhv^POHx_szs)iFbW^+ZT{$Sa%Wy=GD)SB@SsY?0I7`dg zadbMnBd#UOh=qj-XEg(|W*du?SylFSn*_$216j>cn*6$G-hM*do|Kk*m=?{H({dhe z+k=@wUrcNmue_Ws$9|tS(s(2~A+SRKR|u(#k&0S#OI9Of^nlp}mFVvf5^VS;$UKl- z4`QDo9BHnCm8kCg|8*-ogjWowsErK=sktqyhTEBx*6~2+WDcFi^aR<)+U;rkPkpS) z9asvw2&9|%CGW_F+jJzniiN@*-#emT(d;g{{%-(u-u+1)VRLK%2<4y_FZ8XtLjaLM{=*6(nu!Kv` zKF^P-xnZttz9)z}&C-B{ff>91dHpzqDHhb2T(yAzty=7%;WABTzVxc=Z3J+Jl@A?i z>9cVfCxTLzIe=T#Z?_(VD-g|-?XxhE+!BN#SlH?ol4M2Hkc_Y+$n0S3Bq|Xm$PAzp z9^#lHgA)2xk`pynN=bC6pGcUNo<AZmSz49CZyR$Rg&(u9Ic>1876r2nLE!%+V>7#h(lQq;KC1m#Yu zN|=?sFWg|@p_<1`aNh3QpnJ30rH#aFsRZe`n1|jv?6xkHKkR}kE$K;C7PyVZ5W*mX z2+o`!I1f9eG}XHqrz|K@5m~K4uGC_gc%7PS687R=Pm@+ zX==kXbF5!6ViZJEi$o$nu{;}yip(M!b2Pg5(Ed;)D>FWHBJ1go4p>79kI0MeF)E?f zwN#OWj1UYVRC|(_Wbg~Tb-(&Wj;su2#yz&zgKkJB8aS*r2MK-B-`| zXyK+BeCi)E09q!BN66*)!a<3nZOFU@9(0J+?OL{0-?+$(&5Lk&qL_YEz3)D2% zPTr4kFDgzT%1ye^LyBp}Fs-VWU^Uc`y^9Ac%;I7x&5?c@2u57olz^DAgICO38F((-6}s4tmM#&Iw+GK4$IWT%D4K?ct|Zcs(IC;u0grEC#(H zdGCpABrKl{M?uC1@}Z&9!f^?=utmJ)B|qrfug|f&6IV%c)hse>H~906a0SnOFEBoo-YhLx7)bf%{3 zT#6KBQR*FaYGT1mmtJ)xLMSVI^;3JwjAw1=J%(JBPqe_q(oUHAPx~L0RAlW{_>gEM zS9K@WV33>}3iy8@Aqk;6y<5fs?MHl#wv-fxdJ{$|h#BqP8M9hdRxhC5VR_rYU18mGdq=#~ikiQ9~%ls*Z^+I`IBVRbH)dbpC}z1d$0s=!a?O z_CDl78#g5=xcDR%&!Cd+)oUjbkp}rgDp`R@y_ww#vW)x;OIA`*-lB10cc(`{hC$=u zw0DvvRd-aM(hw&MDNhQviv$~wY6)HAj8iaw5?H)k={zW`&}jw!)Pu5cfKCW1JFVMj zyxHr#(mY8z`>%xQbv+_MhKa)gkSP@52%AJXNh^v$xI3p5!Pw*i!7CR4De?lYKVc82 zu)-J2D0jaT2B(Y6#q1aUim1sdO0GPo`~C_^&<&CRQu!7vhf9;^VVQ$HhXwXq@q+Ru zQVMXJZNWk1O~->y36Aw2%@v}HWt`B<7;e*oGQh7kX12Y%9CB5Q!5Q8|iCxoE(d{Fs zSpU3D3S6~JKE(CmQc8R)tGMG#9L=;T5Zlsx>qKIIkQl{eswOawd~kksqD@JN6=agN z>AnR~-%bAhF%2%yPrQ>0TlaV0;ffv3=QR(7+cy( z?dD-J0z%SZv$3xYJ3%`FU`0@DkqwvmN0}QDa*7Ud#M2aws^sEBIWUab#$T zUozcnC-><5g(vo~d562m0&Dd#80<}Sf)g42rgUpb0nis{*k*;yNqdTNSM!lm(#_xq zorHgB0Sc54eY9qp^E5TyI@c@L@c15ogj8L+VcONbK*4t7e%S$sb+}Og%~s2qqj^&( ziw0yJpW90_W^)}UY-|4tFYjv}hy1qN=ppPo<96Et`&uQJfL}!3Emo_s4g`5VB5hi| zg*JCE8LYV$K!&iwtd(i@1jteTwlRWX0y^f+ps8?wJdUzX3>zfTK-{YOzS4+VO}#jJ z_8LoW?vdM_vMwL}aZB}CxpZ9rvRI2CE>wkov8m|}Ywp(N#NwtDcKzD(?FPFuQ{e3| zpttQdUhBK-(s?6;PB-9lcf~&Q;}~-!&W@3ThI_%dOOj1U?xa(~uwW^W%quD+o&t3f zHYA2dlxUHFhJx0)eoSBKb_jHo&`t8HiTm(Az@8o@dJhAHS|=#j;)Jl{bV5g>Ki4z* zwk=;NWYSE}7&^oOI-XG(x)HinSW1WWN=)!`xp+H{l$R5wknO=pMz}nnok*BL5vaGb z7-G&MSsNu5Y+j5Ci&$b6ROmEh6>d49b*Eha|;2h`~p$ zAt1WT7(I8EJo4wI5Eh|3DL5Y+a4qajy$rEqIVB(??nN4YXqpI8-+9Q@pD?VbnM`EC zR}U%J9iPdxagE0)?SY`659DggGE3+xV*&plkq&bI#^hi#(%6y@0@b?K)pKmV>@{jW) zU4>RskSW5VffoQty68&H14eZpL5ee%v0YRu zR2LO%A!Fvq@**?p)mo5I&i0+V^JF#+jw8YF^}5w6;^?s${q?=x*2nY(b|vm}WjbjCF`dFxN^IqUsfQ6f52`QyLEhIv zbCE}E`6rTWVPI%oTXkdO({UUb7XPyp*!bCgoi%F`3Ua*38<5_Z8POK>T-Y(uy<#}_bPciB7@vh-uF zp>yIxxeTvRAFw!~U2cmde23muHMqjek*1cg5dQHi5|yigiIcrZLk}_!LNhrYVj>hz zCW}sEXe4(>hM2(>)x^;W=Il0Lh?Qpjr`On1WHt&nUi}?2PPPcoFm0z*gZBA0Ft&$5 ziFATTNr@rUR1se6Ldu~X|F?QQg_!$j?;lzBPM-cF0Z^ntuZv315;Vi+-d9n|?^(puVVRs}&O8MH+MZi6+7 z0k+&N#(ct-G)v#zxyY?*W_MK($M;p=L9$Eqszt<)qxH{^0}1;!V-eQDS1<88pY0Zo zUX#%ly`sEcyN|3^*;+ra3|GWiye`+{ng?;7T-GFLKl?9sIZ*y+KvuUj4PPp;b4h^| zmbo-QwAqbl4II^jU4(PlYLB~L@h{!To6)x(*sxH+(0+^}bs29s#o9I%c*E#S&b-Y7 zgq=hPOc$+A``Z6Hj}$uM64ZOSBkj$z+FA3uJQ@1kRo_{i<#&++{!5SoUfbSG3_L#? z9g|HK>?~gQYY9)!2l$tpbM!ujj5GN8e%y@o?L5@YTLw=XY|4&a9+Q8I1EH+0JpL(% z&QgVv$V6+1ih55<`f^TZh*uMg?IbqrD6uYvx-ZF#=TdL|ZJG&A!PS7=W5tNo`kiC8 z^y%4~qz_C#{(zB-dMb)KOlTfK>I3+K4TFM~9*{JBd+07MY)ix8+AWCQzp%0x$0!RJG}jL_~X( zLF(GA3`83>cYsvJ^s!631( zK`Pb!u-G5ptGX$#jb`2Gso=0t^N_pLzd=vX^EmJ{P;w?A(E7CTZOv^EAJ_Vqr0t=< zn7+gDLK>g>hR*jN_x+`>IXV=*-h+p^&1dP?8pCr&y72tr5p|WnwxmUNVJm6q)97{s z^L+5&rue9azFU|?`Db4Si~QyCZ;J!dv{Q>o({3gXY9H|Wfx*E%<~w+BO~=7n(9*G) zdn8?$@#Lrcl}``yH>BT7Ix~CU9-e+N5b%3`j^ufpUApl%T<3<3j4g(QXa*bHah1XM zUdaHuuUTC#-2`PPyg4DfwPfgki3weLPTH6f&dJdvXYt_r%xtUBEX8+Ar!T z!_B5bN(QivfNOtkQV|eH+@2sQhP9^f3#CgjQ|9_?D=qsSsF_5AZFv4 z!(`1deL5Ginxjs~*O1krutd+Z$iu3{X%@u|2)m5L|NNCz80ZVVA1hOlMo8<8ARDhs z1ltcEx-1%2==(3oJuR87?mIb1uKQ#$FYvqvO9t(I)*U+R?-c|(pL+ke>|8$EPS9k& zRF+9jRkgDK5O?kt@V`IqUj|(keL60_VefMG<4#bnx)l0?m!Pm5j_ECE^9ox@f#L)071X zy9njUKRQg1BCHu&@35Q*4d|_ZFn2yhMjk}CNTzm{(5~JJliNrnuRL$masc6c5@JF( z%8FZg%z0=Sx+kPY=`n{e685IusLJ8PL}tG-Mi)1PzVohJDx zeV4q>Z&l(xPcS9SUXM7X&H0zkm-0#U!>U9BAsC|1-)kD zoN=xgC?<3c(0fu&3{sikGg&DlWA1D|9;l9w(WVC}kD50nBuixUjxsorGU%O1ehV?; zA18z9ArTgaFm_x4;Z9<#!z^&{m}oyV5tW`W`{khgU3x(*I%w>*-IseSBSc)oD?Wn+#A@J)d*#H6++wS4-e+2_uAackj=EjCuNFfT35Bw z&g1Z=k{Cx5fnXtFG8n#V9RK*?$YfTO>+p~8rC?X3QhtRh@8dMAMK)bi5Ig$=KT)c^F0`|eWv~t!02;Kb-BS{+k3UYR}jXreLoM{`#cZ&%*TC| z!VyJD$H!)XpX+*l1JAJfr{lz4;MYaTPMhVO3`exUGvSCKMPaHCAcXGDgmF1;<>0%% zLrJnY5=A6!@B+${!(Ky<^?2}AH?R&kDGgk_S5su3%Oreb0AiAtq`(d08q;fF5>|@z1#Ida< z&*4h7R}#sXgl%R*TncZljf=L%I5ie$}mJ$bs zJho~CYJd6)eb=szYcSz^k1Q`I3T`|9*nD~k^nAv?^L%S#HB*&6ih(o4oN_vUdU|Bo z{9`)1_Vf^?;rqNiKKq^HH43uSIG9QG77mYNQSM{nmRtY|M=gg=b-VX=zyS(#tH}3WOP{6a#`EJlVd6IjpB`}LeB=%ItMez?W ziTg-%8?TKjz||VdTh2ylFJN)i>aCQHQX`n(%ODW0{Om>AGWQ;+rKVYF5nTPlMhbux z1j-uo*q3Xv@|K{>ELS?&64FenrizE^B5JL`VzFYh@nf_$9l+}*Im{aiLJR_&v^5M? zLKCoM%F*btPVcRHm$^+g_A48tUNSK)5bjt6)h9z|kP>s9EKnl#VV+@e{N7NX`vId z4h_pGLej!Nejj`deoOGdw2_foY7B%93!umf2wT@A8A=?X-=Kk6#Uah;ppS{Plk@HvE*KZ}LnBU> z7*$V_KH)-E)RPHfoIf-}u*s6NyVe=yxD{i^jNVz*rJbjY-!G}<>cgLTbm1L1&% zNm5O<4HXZ+PO@5wipZRtB-c>-7 zhmD9EoRMP-1jXge=GomfrlWoakhvPrX|>Z;wnhsI4Jwc4c4ef_HQ#&`)(CnXej5Fg zfjMuHOiR!l+N86&%#w!Njvs$1VJ~SHJ0~JLryfofU!V~9$BqonyR2&SXB)L*Ace-QG1Nhy_;^3&DRW(Z|> zZV{w#vi8FL@_y^&Z99zJ?Ndx9Q}Di-wJIq5X%j>v9>o6Zt0}#5qxiw74$&s9LxsI# zh<^G;3qz>iA?HfusbHwDmiT&E19rsDAXF0~K;kHj5MtXyVUqUBR1K1;*@Hm8>lccL z8A65p>&4ie!xKP^QyP|NkCJ(oA)=QvbLnbiKXeAS` z|IHys5i5l&T`D=KWh%H`g^IiwMY7Xp-15>GtcmK^pDm>7mBaJ0RyswuhPdiZE+01+ zH?F-s-;eJ%B)+YG#0acC2lVo~Ul01y)Sw-eli|w3dnrIAr{+{mSLHV2$4SiU_@2}x zeR>?ckUYyCwA0{bx!`2l?UrSHC40rPV4{Ce_6;T0z?JF{saA|vNcz*d&dGml z{iy(J&}1%}ZjFOr;Hi48N`wFIIeYa zP~F1dcYMy#Wp=X7C-be#?@cBz&-PIqI`V#Mw+I5hpTHT!|PuX}Mq0&jPLh}2QWwi){6Sf?4k(=PiWPcTl zN;e`+kY^I5_Yl^a#)4hox*t%;flt`X6noPun&5~mLf4~PCVmVwM84(RbHL{w#pU!4pGMy9F{$jZ=kvs6}k8b5&Uy(T>lX(Ar=H2L= zOW53=H~6}3kLB$n1zyJAYu2NFp3lj7Y*@QYl*G|t8+4OgcB8m2qCnL^R<$ZOcc~bt zHwMYISW)dZxQe@;@_>FmT_Nb&5$eaoDe8*C!e9XUhJsO^)G6K{sdQtL>L(S@9ba%T zl}<}&&@r zL$Rn1J1)E2&Ag9$5?ntiv<6Jn8-}*qK6nI{OK0$)g~_#n8t_l(7!s)^46abeOhk4q zB1|9D*0yj_AWq*Jzaz(fB87u^A)X(%V8s{DK8jgz9kIHf=)T->7k{6^4^r51Ib9K` zzcyZ}DcKpjcZy@J(4GOxV4Z27+izchl&48oGRzHFda(C?ti=>Ceq4-0@I7x#66p5& zI1OEL`6;jOqT>O%Wp-fJHE$=cx_I^s1Dg;?fzYWcf-)7zY!|VGl>Y1i>|l6@U|#7r ztb*H8^g?gw6%N3KUN;<&Su^0ldhY(?3ud;XS#El#HN`YjG;EPfw~lfuNu3Bt7ui ze8}XlPp%NqfThe&oGw1;tqrp_=h%)w1_jY5W@E`vz#HhuE5k8Fm7N03l0oNubVMD$ zLV(7aol(hahjKV(GK0TukAut8#GIqSmaUqi0w`>p0Zp({Z_zEKiW91p#08*43HC?_ zQj!T-4kz$ML$sm=F-=ttU}U#bf)e5O@}LB%n0*xvqYbZIQ0F)+a^}(95iTP`CM1mq zD#lVg<~otx!IcSaZ|W?-dGuMfAK%DH_F+i}7U;qxaf7Ku@(N?YC-jP(mU{$~Nt}YG zD*l0cTo0;E_ZIYEguY^wsaBA9!fFWHG5*zHfQF!~o<#J(32`|7`)|UDhhJS;|5Nbk zZAd-6hO6Gh&C2C946_jZ=m!x+tTr>QcfzSdxLZV~5o!0C_)LF=%pzv)+MgP8gzqle z_Ze9TzpwHxKZ|-f^L5ThfFK8Wb$Mw?4}Im>tDK8xg!@BfX7t};S1x_WS=8;he|}uB zW%;>}J`{*>VZJp&{~X5>&=<&ULd`y$BjE<1fK6D!V#loR^fQ22YDp2kBNXvC+ z;k0dkU2x9q^&P$`Tln64!tw^k9!9eqOaz8}Wys#mYnA1t$ z)ZHk5LY2zS9u)ZzLQ5U%Y`e+PukX$G4N>ZU?&kXyyv;r;ASvE&_ui5zYsgt*HpWLB zoC6s$QLDcnOB6A!(qI>m5p}H@Ibi=TSCfc1c*1g9(NRL~1Op^C&5FR1O~21|b39)~ zhoeYOA9j(zNEy1(L-v(z(Vyfmpu}S?|LoQQxsrwy>qmR@*7h_28IiuXGLcolHTI{? z^H?y{Bt``bIXt{5_wULOsjCu|JHqAmu59$*(RcC~6*PD5By+=RLLqi1_d{2L zkn-qv#-&uvN|0ts#MCXUa%-60*aV(8p@LLQWXh8%q9z_5Ub6@$gD{52kZ_FME$7jK z<4Wm7%j>~yf>lVIyX@Zs`xZ@wkHWl4%O06@Y&KC~;t^ghjdEiX&kZ2du}S4{qcWS* z&rDxiy9qZSq!@v(seds5Ba@xVf8lv{nubot1}M?51uk@7(tLXncjXgx`O(euGr7o;QIY zGteR__g_Ylq0YM7q(B=cMh&~gk9h>Xw$gE=<@J8R*R4HXl-1~V`rYK!;`{Aho%Kxj zyC>RTE>bX;ebw_I8tvaw^10;8wAdBHX(*$|aD`}f5{)|fXQ&v!t~iSQ5?% z9A_B7Uzj1zYw#;eGR;>H$F?~$QMF-E3@c`u9OamDCKc3fuIS|VtT0l2c=#cP0(viM zkRimE98f5JM~lT1r3t`;?aa3_(wZqg7SARFf9t98tS&w-_y7FuPlM zAV@6GMA9=Q2WGmIS|}byZlmOWD%fmlbmPD>rR5K_0pw8JW9BV3`^NzTpZ4GplV)ea z9bGhuFvMJwSu=fWY#nlq21Q_SJcI<3y_R1`RADQ>=Ih1ELSzC=+jx}+dxo!mM!{nz zvU7mXs-VE2v)YVt$=mL5JBUkxz-;wl4yvd4r*Mu75kgBp4Yv$ix(=FdWla%zRn9fFuNbgtjl zRT*$$g;k1$2K!}@Pd3)yyWMVlG~j0SGJRhbA-8{@K-Tse8~dnupv-{}a5{xIhDb-~ z1@vYW#32MwIa@P~lTpy|Vo`u)YhAU8uD|Wz1LBU#_B3havJ4p_!5NwJZ3%>8^+8YiT zT6s!MI&sTy&M6(61Hj6{4Fq!F;=px^_rAP`0tY<-k}GI?V$%p{6uBK!+L>FAalIYL zv7g>iQ}ZW=X&DP6{23JFas)31-u?0NsgW~@9Fti&JxDEJR#<_zWgCVs+?Ozml4eXvD08;kJ+%@3fdP3MX7zmU0I@v+`YY55yk{D5$*TC%Pcw=hv> zx6C9R7>(v-@$jtEZfi=He2IU5J$7~rv-_~t<+Cn-m(9k*;!54`<*=vkUK?)#u3K!Q zBEyvF^)lK(v{K_Mw5b`*%@xJ$*Y3iJor;x%s!Vp!I!v8{7YWuB9m@k_V8Vxw z$OJ%-O@qa@n{LgB{0+GsC$?VqGJwsFwU0Pl3U*v7OHR5p2ute2YZad93gDV10C zC~<^F2b2eqKKxj@+znL?o7#CA#tL0T7MlEhDhONOOV*yep`QLN7G2A*go@eZ%)QiD z{DK6?zJzW3fH|e`0cHVGB5^!nXmFUQ0q{p=jv(F8#76LTG?0XTLVHW52jP|(r1X*$ z#c%`Ggp*^YsZ#Bs3nGg~Yy{X4${?ikO;w#XxIMLXt>istF6LC${_#DU0rTbiyD4VO`6;a0_UxL1Sg?{rM$D)?2^7=SK#~<&iY~I6uyAT{ z5h;2)A(p8T`aou^;{~%p(+G7W^HiI3`wQJ8Af2HZSKAmUCZZrruHULAW7`phdf~q? zkd9X`X^XIZe=&SNoH8UoPlZip`P=+LJ5or!-e}GS-Jls|M3O;$aWQF!AKcqb%(>+FzV7|_dU-l``1vs$ zu=9TUr;`Bdd7ErvAvmo%(o~8i$Wk&)U^bQuHqAnQ3xtYJeAeQ`c)WPF&t`l=Wz>KX zhy5g*-}~33Th}?)#&cX~ulwN3R;&CKH)pe0|BIk#{D?V4GyKOSjZa1-0}MJZcc~z{ zwG5z-)om>r`HVN23+RF#buz-9EvwbS;2~>utJU)5~(Hx&(Lvba)m5Li@YzE#Z;{cW&4^4r4j;(BD2hZ?j3Dx zJV4ih)MuK0#zu9Ppt8UuHK3#wvke@L%%=b1XdYoLKx@ITJ{sHmhqO!tftKL$9jA2q z^c-R~5gyU;aYoi9mM1NjGs`TwRx*G+1?jG^&mTFk3H-j^15QVycn!{sDg72oQ#U~mQyOlM1{Q=lm}srY8alE7&x0kK z1yQH%Z~sj2+CCy0gU&)v;ySD` zLNsA(cIPrp;DoprDaLf>=5ct>Ig9?bQn?Q#P$w+;bH#}%VrfRPz{GB>Nw;8_5|5)< zFaqCML^B9t%dM9aI|&V&D^IJcprd_%(e#I~si<|8Yasjuk z!)>;*vug9To0Nsc{cDzhLyy}Q)+7qtkz?gxT5OY6(e>N2nW9JN>RFQcuSUfEFB$bP(!cI)^VO?ln+9U7f9#FG>jz6E-Vwt?JD9ho=O5hsUjr-v|05mT@g z436(Q-Que`qhv`L9%bv)lFpi3)zXktnF?9!(8XJzoQQZIL&=YIul_{5Z?zy%OdOIDXbYi!2? zXJVG7VzB~Y0M{^b3?P&`P2Y&pIxdse=Xrfw2|&k7YmQ9JA?Cf>*IEE2!3Bpy>}Bi&+zL4Z9X4g=whego3R)KxKTho80x0a2%+@S zgfV+R=w5x=V^pN7TT?~+a(6**nnR%GcW6`?;!f{vj{<@BiNw<-59e)bM(Mx-S$3oh zbontW&hVS6CBk={&_G2iCKfgVml>yai(*Oe>tkq% zIV>XZ$$C>EWjsv&DMf4!SS}dWc0UWjIgG=ixRIxzw9$O9T*Mb<=NB72gLCkSE}8a& zai+XAN0)ym6wKxbTp8J>1=X)`X+VfJ}8 z`F``G#SxI^ghn8GcPhCRX4~ zyRh1JGJMZb_-4o3@k*ib&3hD*z{laU_&$G0Q+-x(TXpxRxZ0vC08$oC-XDBXL{<=L z5nNN=R5D;}j~OG}X(q}ggQomD${xmwS=pt{_xH_9d++(D#b?^zw|tAA-dl%_h;okw z%HLoYb$T3Gj%MAXDYSV2?4$XdjF_x;)|P05D$^sR!6k>Vj8jEQA*^P;Q6y@ut$6-^Hd@u#2pj9-pUS~^FQcK*!uJo|co z>LJD!ed~ika#ii5H$m3mKQS`P96_uR9fxeK51&%hA4b(=5gOQ}N(P3Q$d(Ld&D`R* zfjr4&@_c2{=>4PCnTbER^Jm~tK#!&85vT`Y zqDxWpI*}J%7L}gcH6QKJgW?Qv?V|mPSKG&gn`S;JzRLuAl6q*DCn$L1wdoE&P;`a? z#%hNp9G9*xDkdZTyem^EKSsM#HMh|Qs3(UPtw^9zcL;)U1|4JT^R7vOOqLqF>7Rx) z`t}DK;A$%=jI6MPpzb_64!3X7_lnz00JyI>2YaKnA|`ac)ugjyxS zhS#gG&=aZJkJ6J$#z=s%!`n?tAA;v6Y0bJ$d+>rhGvt6`*O=gFTjRn42tbj~^q3x; zv~-PNZq+DqL-kn=&CNBZq0jqXsi@1~1IC^}qN26w*6EwnzO?C*JvPHq;$$+_lz5Dp zn)rz7L>Gj9WpJ(5XKFq7_ z8v?K;N#cR-f&emGn(%mIIGQVmZIl1i@6+ky)yL8?fdk#Dn%Eo3xhO~W)&s??S^OJ)KrG*BHKUYSqC`d~3(fdk$x1C$oxx-`6&Pt&u*ip0jDiG=GVqP03GmcZTSXzM z&B6bwjc+s+6L>EH{a>yzl@mkFjM&Eg8$g_BDYEqB1{HT|{LG!v(1+ zGQ{9r8Tpf>GJM5lEqL%vrfJfHrabHNrb;(W;h%PtY!5H8wZB#0sul8Q1xaBL#6!@t z4<2TpiHX1&R|1aE>CRLswcgIoa-6M=XVCeIl7({HIV+G-E+mX(W6`|Yy0CLyFs)r_ z#hNsgP2pZ++HlSU!2Uq6cHqSXkeh`OcrP*(q`V{cI8&hNSOV3_)1n+HWDS@~o3%?v zm+Any6HLE+JVZb}Z9$3j7&}AM&+J2ujTl4roI{rd6OC~0>gZ72OK1L^xNY!(hTXyK z&~d%%Lu%jK9oYlF%iDS1^@FE#*nqDSSdwiX7)p^gge?&2r$(iT3&`H{VV{bKSH%a1 zimi4b%TnJBzbFa`6>a@}K=5y{Lfq5m9&9tx>McbXR-nxa!;* zEJMAguI(2+Y?y_ayPqBQj$L(G%pxb_^&?*;*Ma}oEte(N%WmJ@!1vBSsf9vre@3cK z#z+4kfq#F{l47`ofIU~WR-!YpPtchu7m3vpm78Ed<+`86Il#ERvm5eeuOggZ4DSh2 zEj|cuQ6ldDH*J6LSl&}nb4|L-=RYxbq9h2|%gSPG;Ec2W)|T_#frlqT>q{$f+L$Fi z%YH;I&@B|ryLgkajne}Gu?&a6CLifQq;e)hVl(nvv|IdUae({SeXk%ZkoqB$C-6) z37V5KV^MtlX{lJOTo_^ft=&~@#1p1Qy&pQ*icT{21sgI{i?T&Lbu6BZ`H?B%TV+Fm z*tieKOM4JNEMJQ({HP|KNzRf;D=lry>mug_67YlZ}p7Z z8-;sBK5h@1Ul&UQoz5T6?>sW%1Z(s)J9+%-U*<>&!kR3O<#x(Olk0!IM=^5{IO6DM ziSCG>E$$D)91I03eT~BzrBW|gwPg7H&u`5a^!(pzJa2g2A17Yq13xP6r2Y`r#xvJw zd0p1EsqM-p@=24WQ zCFi)yrrtQ#_hj=%SKaq% zM$Lg|Y<`w+j&J^+3W4t#Q(yhAK315?1fe)XqIa&oBX^zohZ8kGPTal%F7*e|#(n8A z$t1pH%!~WGwC9*qg#LrKBRaxo#w!i$--z1GSH`=;y4~_;`%-o1TvXoUQDhzIEJMrP zX{nCLr^5!!?H-P)O@|J2f(hCIIq%>pOtD}V7-1t&6?bqHFR-N2)n*wM04_7>DdOz+ z>Wi4*^rIx)x)NwV|8=f$qNeYRl7z#eSdgwmCRk+TPX_HS2&#Kh;NEmFTPl(;LP#z9 zc!cI%vI9x5tR|O~(`eo!%diR=vKMFq-^)2hb8uO&B3yt|Y7qp}WR}Z7zNZ-JZ9dcz zOmVg-gYLgY3$QpLCgK&!1V})O0WqXst}rx@we+Qx4DmFnKTu?><%FOlvU9%8^@qVN z&1U5-2v^)7aAqM48Kh9?UvV2>k#EID#i_O-^_N+cVVmff_1{C}7>ef11$&=)FpSFn zE&_-$t>GE4Gl*qRn0LHqvtXtyqH>b6Dz(obk?X5jx8aG4C{z4*khxScprfh~mCcn5 z7_sT3lr>uASg%ts!8?{e^-KIR=~PP~zbB2HLmGNXKFnpJ3_K4%XYl_I?;(Ai9fFKZ ztAnb)OD!X*(v=yhg_1Wm+oR&YA+nwcYi@Rck7X%E2xWv>X-S%WPSLkzA>$8QmSsvL z=t&O%&F})ht!qd-9q;RPX$D+>yV=K`x13?`{BW3oEqf(9LlZgy?_rLknUp-f6!Ta) zN)ankEiiN;I}2i(fc(GZ7F;?uf6&veDyqVL2j>c70*6WiA|h=sF48kOX>>h{^jyiDC;WL|tb zAx<+-bEC4Ct?L|8c_v*CSeDv}bJn20D$aF*ONL7jVv>Kpx)eAO!2=|vH!k9A&}ozL zV^HvxU3;uFFg@WO-PFNwxEEcAPZ(G5UBH5L3?#;(FsYSBympFi$72pwlhJ{vKNldX zCoLg5L^oZ6OI!}v+>0j64HUHNvsxk^?rGA6&A4F4t+hO3?Ph0_*0s+m1^)q&0biY< zIbRy;zNw9E4b@cOt7T-^*kukLc=WkQEKC|3!G?;cY19!rQg3;}V8W=%Ls@OkQ=Vr8 zb0t&ny_#1pm*HfdP$xmyD<1J)86UHb({SXwA4|vWq>L@UPPUe!T%t~m%V&Q!@;@zk ziQ2512r?xC)ah=wFzTO>5w0=V^SfZV&)$@5trBpCxrC*|X|-I(fm;8yg0sVs+<{Np z#LqYP$eTbjJ0i-oLv0w1pHA6x)S~ph&fuFP)#|RsB(|5U(x{LuHIf{k&Az_AYZ5d6VLmggI$h63Aj~I0$m!*A3Hc0|tvO>1gdZrLzp0>Qc3f=>>tbd` zyT_M`Wo%HMjwtwx_kSv|U?UOZC!n)tI}>kSsjA#Cu*9rz+q#9*Au<)`D-vCVD{Q*{ z^bGmD!?CBze=U1XO33rJk5uT^a-*L3>dRJ6qRgF!dwbO3#)R@WHIzil-BBN^D1o&VgBVLNJR%Q_g?M2XijhNKb^-lX!;8({a-Wg zC#d^^e4`DqY=5ET7QXN)X!`-?uDtlU4i@qzT%Z1>sv%GC(GT4!T9r+|09 zp6B*LcS+pkM*eKUP*Z~eiDvnE$uQ|-yQ9e^U*|YdaHjPA6Z$NhLj>K$ja_K0X1P0I zd;={(Z{ZJw@r79^jtrt=o_1CDuAL>j?Xe5j@`Y!*v~k5s?H?idvuJ5*G0V^2kdycV zU0D$>hu-h!@t}z%gABYZ)XX#eR_(bv3~%+YRvV0$$mYJ^p&nX3rY!ua3F1=|(lsS< zwwQ%M_N`Hwi=DpkQV{*NKu_Bze_=4Is$N-I8tDnd&)URLeVnBl1$>)id8;Bt8P~ua zvLG+SM68JYP9?_VNP^nE;bK;b$V7m#h*cLfS+Hk5GMf}59C~LSg#<$-?`#Y*J@8_n zsMm~k*i&<#$tHMcd#W5Dir%{RBUQP=lJ z4fYebV*9@S$faRW1;Ma+){H;aUw9o-S;Fx{&7TfTYGjwF=*5wZ&7i$t42M)57&ML( zG>T1zlfyDw7N!#)l5!-GoIlK%9P+|Rz^!S}`1l`ce$S{W^f-7p08$DT?9fDVH_iT9 zU&%4SCH7#9Zy?S8+rVLbA#Vy{2B&BDojDnrL6;M77t9Dlg}8n4f9xgrU=)3lc?L!Y zXMP=`^XP~J?dfLtJerlGR($*8tG34awF{gkV(+^^Fh~O*DA`72g}wBvFg^h%^=R9N-Tc zR8F5UJI|IJ2ere_5QytHji}jw$;HpwZ*d zT3`puz}A`pnN_Fy`LsiEk+DXe*==84Pb_AISTgm}=3oh>6nnIM$=+I+9j=#MmWm7_ zE7Ec0=LG_a$}REH6P>6ea}@ci!A~-v6*Dn(hlCuwN;Hb=w6(2>M04)C1`j*x4`K!^ zjTL$+b$UDjjbAm8St(X3+>C1lvvvtU_Ow}cazN={ycEF+oEiui7j{016k-awq`N(8 zET~Xg*26dC9Pj!PL(!k?rRBtu=(|`SXeM$1VVX*#=wopQ2Yo_x`1|!Wit;)icF7D*-FMM z?wK$XDiXzP<5f8_rtJK6wunh8G=HRJAG*!{6tiR_I|5Oen7M{M-nL zHM0&H+Vj(-87N>`#xoWTrQEj-80>ktRR5*vO%TXhiKGrLTh!kaAbmD#UNuGd6ArVl z2d=Pd^eJ_=7J%_m%gwsI^6#2461Psiq3?3>&*#=>jib)Nf>eo$KLY*}U{M9>LKu~^ z)NO0_iKPwl@2=yKYqjwoq_`i|SDF6QkJ)T^qHYWH;YD#>3kaI1H8UW`Ay)q#TTlIf zyJ_a%a}B$I&(fX>PvTZMA^f8k{#wW#GB1Icg$><{zuevj=0%Z(`S2CnNx|6ilCMPt0lH zZFuWvjL^I$=><{$|C1pV_P;H5zI44Itx<=UTAg4s+?RA4h56kGLx0C6UWT|0$A|pE zzEAK z&g^!nU#QKA%|`3G2c$MlC$CeFYg^>4S0-3?3F6do7?oQ}8hJDfW+G26fch;@uSgz3A(!)!aAQ)DS2J_F-2mz zh(UZk#2NwP*^ZozC{J2A(+wp+kwF^JbFi3?t^A4ayHu#FcXOA@hAEdR@)OSNTZqNv z(1qrt8N7LIu{t(m0$MYyi?!8~i+hHmcL-~X`e78eXNCj^UD?0`-Xq(QnIdOoB(4a> zW0-I=nXtkoYqsc?W-#1~!3;?#D?W=U!SZW3T=9-RCk2ZY%moXuNZf3kShy@)%ZV77O=IDSl1~W#LfM8}!+PUjfp_ZQ3t?jy24YwY_Qo_a%llyz8 z+ilmJKV2q|_kwe<4c~9~6G29Yw%0$tY2jNmqdiIl5Be#Zi-Nm{c{E zE^7jhW%*Z`ZclR4g^^S9S!6DCQw09`OZt`TtvGpp{`z zj9wF*J9RM;*hr+z@#nXv4o#0cMICsB@}c;f>UEZSzwMvF7O)A}@_yV}qI{l3KJWQ$ zoQ-dWTE>ROkfl%+>W0X3@deYZfNR^u<;MUYP~xWglfHK=gC~$z1*+XmzpRW^Kn|kdeTH=P(-nsadEZvh3xN2wL4s&_-;mcppSkk&!fr>q7VD? zV_cUbDlAPy0H))rHRq#H3<26B^zrm*_GhlR9+p$Mgk?rot;pt?|v_pt#hlmtV%!k&zjQZxaWO7rQ8^H$BC67ylGUDl`BQR`rT2KUJ zp4Qqpi`Ft1G)i@}m4Y+MZza=n`DsAIC>N@7f!N!O5FCX;yiLlvYGhkgL7YH`(^+!S zMF_r~jGg&I`3c~?V_TzErC2`h+FqA+I5asGlJ%srECye=)TQ+lj8;qL3v>SHa6it?G zjP9jJ9M)@*q00WkKDXDK_O+)Wi1+9Icj`B4-w9-*f$z?^&s}OSM^Kk;m=}R`(N(vi zB36Ftvd)PKj|Ldj*efy53YlavS|i$c6Ta>nyxZ^QVa!2^6r*JzhOyuBR7sHoMR74M zMv}Ytre3e-<2bH;;F!ivhG)X($@%y|-~{j?(aYeh>CR*`)uX$gljP*bHqkf3vX+Q^ zx77wcW87T>B#yZR{QnJwCvob$ZvW)kAaOZ7o6_Slcoya#ZTbZqGPxsufEQI4p~6(w zA^o?~;4#=XXg9r$B;~&a!F8{z@sW>#?6Gm%%F`k7qts$jm)8Cohapd9hsvn*9pGo_PlRCM-cB zhUs(K0iP2u|6OeyN_(V?fC7V}w89QrO zZl3tf7KQn*IYpcYAFKqYT`wI*#O+q!NQn?gn_m=Lp_fU6t)j9eqh9I!Mkq{Xl@@$| z`oO7%w8~Cz%osWFr(#;O3?--NigS8OVQLLC>c8V+D#3b?cq72xX-(26K+cr7@ zs>38MZrhqd#2hU(a9L9PNkfwn=lR0m*r?dU*~K(*ELkXwG5lh+jKp6tR5~io88|}W zIvk;&be)>3(u8@$qA#kjkfP_EvH2|{Ele9ZT$;?0X(%fI!zOhw+61vG5=^uIic$9X zzZKrNptoXDSURO~R7VudoH>(ak-UWMwaSZ{vZjmJB%bs`A+H^&SBBSALZn$Ak?DI_ z96beQy${SGCV1PMIC?LAleSq%7&KYxmIal4nMAkQ$`bty@kyEVD}xWMCTI>Dc5Q-= znOw2dWM=F{`;oKj%y!3tPXBrOxrqk8S6$Nmuj&QTZ>>l0mOs-NtIW2-A=0(DC$x9C zEHfhF)TJr8iwQA_t>vk+mxw1*>MN)yi1VQvWi8_7$N8kcyW4U@QBlzjx)w!t(v!0b zT<4WtQT1ly6dq?_IYttOmCwWDeq$+jzVJ)Y@DgmO z1HnACG75!E9|~S*QY=}6**63NbcnqhY~a0c=v=EV3?+GrRoJGlT4gJZDTKO=83Fqi za*$;xl^8g5qlSxZxS2(bc8D&W%nkCaN^R5RRjstNpl41*4iXr9i)!;xJIo+MsAQ@%<>9+Zr0)IYxVE0*05W;i8x zEL0vN26mqm7r{x@61iu#$0R+L3h+^BfxK!mnysGDG-%R@swwSu;o}huAXe-TGfRGv zjN5rpzxb_1CF=JOBoQz^(K14+-0{s(rv`C&>Tk0Ux=3VkB*}5#@j}%jEKNf)h%LI$ znEH#I;P3G&F$=y;|ARx5#(}j*S8YdtH4(A1ND{=K`R9!ncF}?sI6sJ_FP9iSZqOYe z_mi;hs9cW3w3GL@0kBbqnFim!x&JjnEk^q+7H(*i$`ei>suJWbP!>V_i!Qc`u$o57 z78)*PD%FkHzAjnpEWAm-Pzkn%ur#Bvcl5xmTY$)K$9!bKf6b{e@L{1|`d{Zlx?El+gCvr@uut~AZcw*Q!m+o)FZ!eW;?-Sj9!1I23CRBXg@|8Mv zH@?-Oe*X*V$2vbg??y?>9Kx&GBsC~{doQt;_%yOl&JFd(T$9Y$*nTKs?+2+q z;YO1CmyWC}XEuBpc9rl7c>Hq1(%2s~_L_j<6UCMsIa_YY-2WRx+~7O(T=@R)k@nN2 zHxSZvEBYWq6ofM9VEhlHg06lTM-D;Xhno zx1s2~BcG-8R3%qzzxc*1M@Egv?v_sTGd2h_aWA<{+IR%+o ztWItDvy?+LIFIjHIIdWpky;(@IfPOSF`akpo04}J+%No88`G9{t)@rluGtFp@zE^( zxewJTAPG=3mjZlxd0IH-LH2ibBNidc5PY)k)Rvcvg!?v-DV1C-St!!edQuaKUfCfQ zLdTL%jMaY2LJIt9#^KVAJ&Z0TC}&%^*kqP_Mo!8wX+}5|d3<%T`fo|}j}+g@Ff8q| z3voV|nai2=?J8WU6!Zsf?XT5lP(0VP_gP-r{X-!A&otVVR1xFSIl5eSm& zZptfPmgOYNTvB%e!`lz0>?$JwE(y{|{5v1BHrsg;M~&A%{xTK}eApUvJ?MKXe%;ZI zCvMiYh9Ap++rzVWX!VndqJi49Z^IZ0nGKf>hQogt4)}jXUFne__NT<>9=4AHoq20@ z^TQC`{y!m-sYUL&7rmv=TkN@kk0;nKAjfNY2eZ+970w>PGCh%g+n-iW-P<*Z4xAM- z@W4nZHpM!ywEnKxjJT~#q^+Yp+&lFT38TFo)v7dI+Z=eEu$yKw1*UrVhJf|mq)b^Hb3}jW#TH&A?Y)ofLM!RtnMK+w47FQqH*b!&f)0QS z(I+}YHgirR?b;3tZ5)PKFayES^YQSQ^>;G3b?58TY4Aa}p8~6OIVO)s*UN z*0cqXe#NeqH<>mIrUQ?n*Nnz%I1Qg&7qCSjkkm|$&QCX$lMYWw^$nsfZRU1y2AT=3 zoXjD|9SxEWT|DvHgS>|vcvS*#7Cw5IDoEDM3j>$Mktp-fu9D3FSJB-U#ns6)m7A@e zw!&1LtNj*o%+lVt!hFJng-C85Es;bPM&KvrW*n5~id~9P?UcbOl4k@FzI*49O(P6E zjR!r@v2go1@;NEWE`ZWWsaZ4~LWT_f$%w;=zw~|oIXwz#sa$tx*v5Cs` zU_Mxen&|1Iyp*+^OeKjrBczFuC9E%Lp7loJf4_0#zdJt#8-5M;^RnWRRg~B@-#0y} zLS&cHNtUQ!!-%aPmM?QTj~9^7ls=-Vf{8TYDd9TAs;6L|a`0GY1*b|UpxtZ3W028W zh(G{kgNA9POfn&V!Q`B0`0^Bbe=f_hYJZ**-n!)~a^{{6baAqwLP6rrUJCN^CH5Ty zg#%sxI`6^0An2zh8?{z}sp=~dY5RC+eqf5F#R~9=<4oVA$7TESn@tOAYIJ6Sg_muk zT(f5|@rGF&BYoEdqwU}gS;x$xB!t(Y3#JjND@kEP)O#oh>lO)Vi$Pd3U@uV?$Kng0 zxxR5>b2Rjc4KIi0?qwGTR8jG!;uy-)p;4(((vf~j>QU~#|{)RIMZ3y37bm;_i1JVUTZ|Il6)PW8V zRRr-x6?fh#yGT|>j1~i|`d$PNA+y4^2cRrL{p-qmYggA*b))Dy3-2bT+8Usa)bIN2X+lpgm4yl|MJnq!zg}D; z2VVQ79J(x5KnXRX;>1w~WIp8>;K*Eq>W{)9-pcw&H(1&bIaHxidwc5)@_tkBQ^5ER zEKXRuloYd6vNGYhBXGT-mz@9n|qK_Ere}OUC7lVDUJJD(Y1!dk*%- z>al$K+~t9BYSaQ~st(3wXJiu*=909LXnwDL4Cc9w0>-Tob%+;}8?oLGh4YO zh%@FeQ!acdWA6yQqEm&8Qbw2Q#5gSBzOS95w80^;E|9r#9e_ydJ7lN z}pP za&KY+66oC4dZZZa*65>n-Z>2V$?@6d0jsohe5&av&SwPCV?+$MdL&b$bqc0t5b&PI zDIJc0Atx>Bl2u;&4})`vLqF$Lb9u{lY|gy%L`NK2UM;Zjo=~MdQ>$=Kdr^#`tdPP$ z?S^uMWNf6Ghiq+9uLWFc`3*nd?OF5sUm=eIi2xL4eEgp5duU2FoAL;S6&79!)4nnp z@3yJb{}_MbBCsvMeWA8mh0|Q4y$RcG#hlYA3~@v&myr1i0*k}e_DI47SZg$BD{GlL}P1_C0CQ!vTqO|5ixf}&Kd0SXl=L}n<9r#QBh zbu`v80L0PZ1ZWjeg~o_NmrM3Z3TY!o0`Y2@Tkb_Qco5Op5r7yk$(SGWt2TR8u~V72 zy)MH9NS>Bw$LV(ZhI-J3D$O0O&pWzGCDsY2iCBsuJLxfi1rQqbuasV}b?CFxTEhwL>UHP?z}UJ*lBaBecf zMF3r}MCVQEKwpA5XR$?jjy+cetijeJ@M-ryy?fLgRl;2z4(DIyo*k!ASkL@oKc%X{N-?S{&?{CWYKR(KiDo|;n(B)|w7PF#jz$!khY&DuU(K92&Z(xDOO-6%lVZ$L;ap>rL zr&O@%uXs&E8+rYq{$? zHKfCTOz?GjC#=}nB-px6kF5|uGz#C1r~il57Z~ZgNlV(QIUi;axn?88Ookqn5i2a` ze!+%1_Sv~jZ=dyi`hAgq0(?*{L~N#i=xkqvg~X81%Ho$>IGDpJX68N)6JVT2al{gm z%NW_xLA2;)tuC|uRzR7uV^fQCNWW2(x^Q#hl37#J!N;S=CfL#5%1}FUzma~m_6hBd^C#7Q44UiI@Qi)7>$+x7fu<~; zF$B>Lk)6kriMKCF4nl0t_K?Qy&(+y{BLM4eRg*7El&bDG0ajWu0Vr3o_{Q6nB z(F9AS3{D#c=XXP2dhxoLAB$KN3FPXHDKTJ*(8YR94y-#}A!cHhq|&BYZHPA}l$kUv z($C#X;h&pSgSN&$CR)8p(woa}P>fO&vXtd;D=9MSK)=69L6jQT$6W`#QA?>!cZkiI z0M75+jJHV1Lj~Q5RdXVqjjVj#0GB3LXTp)K+L?FRQr7IA&PuDCgx*BcBi!REyr?w{ z$^~-9D0MBv4WB%0V-z8XOOm|&p>yZhU*tc24_i9rqTo;x{lAdyC z+)n$`X-&Cx*ln9)6sm0IluO327Zr|_Bp#$mG~XLB@@wPJ?9)}7qOt9_~7TzqKaoBaw@EE%{k)=eBz#$oQHQe z)PM_7=Cox7HwchzbM)`v2c)`qEn3)(%7uQf(<{)X!}Z-QbwSkGHmU*tRER`y*`ikaNA=>ch{ovmxvezZ)>r??oMpTs*y?k&PLftIz4xs1x#J-tISTknVXYovC>hJ6~v3h)o>S7dh%!iI#dhl4I z_>tWbBSJ3*E67DT4o@cARQ;0@V2S85p^Jv(ldN0FOSx~QZ!lh54=YIV&Hn$&mvLH-Dm4p>}m<33~8YzH}VjSZ*F zLPsXgl{mFHDg-gQ8)u(8-a!3>G(``7Zq7t;HAoxJh}a-4-YWynp@$i;TDy(}P~{RH z(Q91(DxaIotM4%Fpw7qr9rdS#nGf;Jn`)P3_b{4?uliPYnr<>SD6&q=Hm*SI3=GQ7 z0oPJ_F~x*W&Nh%r-5g2j%uQ;)$(1Bq{}ibeDD3RnW!)uW$7f81WsZhy(VdrMmdj+h zK(`eCUk(MR9hQl|zhJRV`vu7$r_w{Eg($+ly5wfnv5c_EZPWj8Y5#CL4uakT-i%pq zHlVHO)ISr+)HLQWRB~Xk(-SI0kt;pZ{;{VE6l2O_;iRe(fQ5U=1;FE7QyZEUYfzlU zl`B}R?ETK+O9_{D!9zSCnzX$>^YXddFRx+I_CBvWasLOzILU?SSiXQJHgE4UOAhkB zH|J`|o`*}sc$LTm5d}_A8K*tWnk6T|a~vKPD{AZ&{|=fuD@g}MELhTRYwy6EJJ{BD z*^i{{ix_?)7IF>!YZfV5N{*Wk0b+;wc>|$}5XfScI)(64_s&~am{RPrO!Hsy4l^}5 z2`rQ7;G<1bPNTv24n6DaCe__U0b9>O;4Vp8FXK@Ojp;CyW zvj<}oBo&yU2f$gbpaEqjVc1G2WePv`g-j*!8zgpCXT3=Q zu9|LqTMD^l3u-IBSs1x~f-L!xpRp258Mm5DeS?q9*wwX{{e8XY&yOp(Bb6%9vnu7E zg_jxyn4&qS%~_S?2(~ZAcG4Pqux7P?N|l0TI!*0s5EcU%>F@O1R%3}?}}4WV~aFHP5nPnxnwj-9pl z+hwr7rgda?5T(GkcNw#>4cnjOASkvvuzfeRJ}(RVKIA~hbQ*Sp(2#73U`iWE5t<4) zLqfe%qpsh6qk1+^=8A>eeaMTvH)RszI|DyHdNjIUKCP&otrno}*n%5LwH;6iE%J;P zbfrg8!C-3dz-p^j>)Z&kmW1ZqYX1&n4e05?Dp%LP*k*YJ*S5GoaZ_ssxkM>aY#trd zU~6k^(Z_`Lq_Cu)Cwpv9+ez4LEFW6)=h`~%B^jQIX_Q5sBjY#7p(U`ZVW{C5k$6(u z9)m$AvP&mZ@+DIQ|D46YIRU8F_-)y`dh%PzD5r_rq%~(9Np9OmaDi#e`~8ZTjq8=m zkgfPpO(0YnmH^L=I}aa zlLQGJiC_en+*h|%Y(fkve+{yj>v_f$>SfVfw{CG8j0pkozH<7m0|TEfc0Nz_J--JT z8r;uf#TD2l$#I8r<=(k4n~fV&QOv8et1XEojAUxQ@CuTNgMV*d4Oe&FT9z(=CW87! z1zOK0wz3nK%Pwhbsu9FkrNpe~y;8K@_TV>=%$BhkI-Ok%d>UE~e0&g+cEifa{&K6+ zCp_u6)CGbmL1c8I%{rhXBqwKKGZcs)lBBBq)aD-Iu21m%c{Gi)4&IeANId*3v%>Eo zPfWhG6#v?KiyJSPcYxRFzna%)-)XsX8<*~})2M$Rn3yx;<)OJC;($CeUbd^h)fPg* zsoqaCADPx0?HH9bS%hCgMJq~==hF;sgKyPBQGFF9YlEu830Ja|Wr3&`j%2CB$G#jk zzCu#~!6%n2=mj9pnakGxNt?F*-~$OXKr+7G&Qo=v%Eg&ceWVjF8Zw1XvZsmlm=EEL z6?YR^RhAn9<3lG~J{KgokdJe`*Cfu7m2)%IdC# zLV6i-scdN)PAjrniW;3MoH=&|P0UmWm9O_dj3!j0C1^@J+)hg9liHFC<}0hz=u_s+ zP;ghaAwg5Q0MBQvdhXAF@#UY-NZ;=d;qGV7SuIS|wckS4s`T8H7ghb;iJS1G@lENt zrqJo!E@9Nz5VC!NBcdmX<#f0cs!NB5#Na+l`5{@qSoZkA%8}fj7I{&(T9hSIVNL7wa%^4K<&&_H1%!48}InwPwJ9eXNb*wQ3Z%~wLK8%{cuLwB{tfn z+}8+J1D`SSn^8GR_=g-kazqJBvAZ>aD?4?)_pr*ShY^*oJU{{(@4}}2c`$ti{IR|X zm{kVu7DrE`r=M*)5>#Xqk~fU8!bZ%*%Jt{(SHVMIpvApmgA_HbtrOguABP~`npv}V zw~{onjeW(j;*xHh#C{AdYAY;MW8phVI1YP)R&|LHPs$Ze_3neb6Q8pz>-PPdwaIXj z`jl}KV%(5hIk8^5?fOygT^xvDoCCGs3N zbx+oIXMhaG%0H-Do*7zF2Q{kqBCx!uZdQ3m%^5gV-8bb#KS|>5KetysmTMC8{6?Ef)doZ=FbO$zly zLldN#8{Hxpe;ULOa5h~|M*gKjPGdS74M@B!x=2n#$gW#|sv`b3javAT@V-sjX;E5pgIJx?wiuJXbvMP58(PnAWf66Kfya90HV<(r!uzF}8Z~8$jZoqsR7<2|NufN- zz#5^vfHTBR3a6vZ8F+)o(34k@2z!R;%G342Fn^Z-Gii(#tx)60*06(Q`&Nu^7gt%> z?ffBO$xytWfvuLl(&}8t22Q~Yut9KA0*rRbU&l2aPsJSLRWgZih#gU<*eFb}l;y)l z(z3n^6z4ihg3nx2N_m*&ga`!j&T znN{wvCZ-$t?9ILI>X#5-K#G9n{I9n)OaJF<+<#}9c^?^w9oPD8uHtz=yq=p7g|utK zg((%~xz8B|(~Ef8&>+g?Cug_|1r?UL&=u7z!s?*pImST;Cl&VF;0J&;(PN!j%;ioe zqg-rlglo{D{G{(6Q>trOEKbA z#uDkcF1_N=UCEaU^F$ChynY2nef&Ij7_t~g4AtvaA#l}XY6xr4b`(+Vz3g~oUDMh} z81jzwUG5*{zIH1%AExHWYJ3uv86Bh&ukDga8QlvdHOEu14hoqoKP0EBJoFQ!oJiq7lc-%kM8L!ZdS{4GC zcFt1B3=Sc!*=kx4ecVzuUse_C635u3f;#^bfhDr4YdD*U9g4`w;TlVk8%2wd4<03O z47KK?6!iCOaTD));RbkD%O64ynZ$fU3*f-j6H8)(AY})XxhlYSY$C38$y=p@iO|e} zWsMMK%p(P59VVcW8B3;*fdscH2uXh|Vp@I9h4C?(=cs){@u`?Aq#b0dW7eX6`F{`- z^5+gg^WTyCZQTmVV0NJ|*_6bhD$)}Q6lU+ig=T>$QDyN~J(xW8M!C4neR>ck_4#28 zXU#n^Vu}1xX7iK5d5;D8!@PF?1(`kZ44C{$9010h=k+(MAK?FYM^&6TdCj{%nq50S z#(&R$W^3Mb{YyhP zWZ49Fi0mLf#Q=DEIUn|63oKf-&RE<%aN;RO`jiGAh2+l_ln)_$+QrcZIL^>_f$w2- zo3R3En6l40Co`?2f&Ijj3?O!8x!yBe>I}_xNwr!fjuYfQ&6>bN$dYEi)9ElrBq#V( zbeB6rb2UU7gvB9Lq*9TQ-?53JaPf4xtCEPA?L$&sF~pW7Cp{StQJDhIUfYtLJnN1< zlFpr;OP093l}Z=Af@-dCG*R2Cztcp_(P3`D=osiUpMVo3t9(&qE*@Pg5>HS?!OX>9 z7wPA)=n}lQggj!Ox3O+=zk!U2e7#5qinWN*fASU6gi^-R&;t;yo)Xqm)FrEu!R=r1 z=z_^%rk5Huin*pN!_3+}el~KzezcCvOj%=f+U(ARvEWX^_{g|I`c)(5xk!g|OjY$| zBb!lQ5esF0$kprgT`E6pMdH~-SA;tA7jR>`$Y=s|@!ojS=n$x7^0~b*nZ3(}>*H%)HHj-@;)&>2}}&~#6;l8oeVR`g!Zx z4#p9!IE<_&t{1u6uKTj+s{IpBq98SLIazx~z#Zz?@8-5We&+ab8LaS;E9Xvk$OVQx zjbSz@K6AnHuPfOV3<`LEP76&cYXc^Z9SqX~hc41c$wTQ#OEWT;yauu8UadBHQYnq^ zL?aWe{JOGhg5*UdD?%0vV^8)%&C#An`^!!HaIp9?^Skf+-}~FI-EbZuys>YCQu%jA z>N1@`t2Xf*r|)5H|L%Uwc9E_B^-AeG7LPy?wQt6^!nBcl=BfOom7mJZEA!fw0T=g1 zELE=vLYG3J>7CcH|GGp}e1~1&zfL>-w*dTKnT|0H&5wAlMHx8$XAe8EqO|L2Wmid% zKlBf&@;8w*+Lb&o1L#gQbatz%`dc(e)=3ok)}+h=Zi4u>r2%7$C3`%l7kAX_b= z>+NnwNL2?)wNO@lka$zT$!8wG=`?rT{k;jrPQYWNYR~*mr6WvQtGThc^OaMOp^~Z` z`cL{CeXpJbtw#1pEwG0RTlvG28&0HT5YnA8NQdXdEB`BbQMXbf;?wKbU(;L8gZYju zg1#j$2h1C9uXimA20#93m;dJJ)+A8&KTk&a*k3@oASpvgxAbL8ZE}-@;RNo(T_6eN zhIAYfS~|B&%q(?;=1`TxHcB|bwT{Rwtrm;?`@U6vkxqV$^&U&+OdGmVka9vSKtM~Y zFIbhOIUf4+!>owtsR}q!Bk;wKL|v6b93oOAComR*Ms5bYjYGVS1+NbcTU-{^P*mf2 z@ORGIYFW-)_ioeyv;XF8Ise-1F2TXW0nFDt z!$MX$@=;hht`>s60Z-Tol~qCQbs@k&i_c26MyJzLi?89{6cA!vXl+B8UEdnT_@$1{ zqqGN|BUs&ldR43^>hJVofAPWyYscVP(SLJ2$4;YRR%G*!A_{mgZR|5Orcj#W+HK$P zin)vDa%bZ8>19EWVe7Py{+f+X|7xKKM7`Q$I8yB9YBuHOwudb8l62?3r;3$v2Ck+4 zR0Sf$T(_y?(6m@4K4+IZ!7Lc$HdaIVySB9Q+s{#Gs)^4y-z6pxnVwEH0x6Tr{BF~8F0HnsRYzy z1wFewdpi%KTfl2yfWt;n>uVo`ihlKTXe<@G>j!`oz?sKFboqr<*upcJs`3$|QsFj1Etjv*$JrC?cicM@AT-nb{>X%v|82B)L<+mjc zc%*)_r0LBRBbHbEYOUveOmtVMDPEpFBJI}}m9c~^hN%NeaXzEJe$g}I=GL3s zK+NI^fR?7~&bUAKnU{o}E{0x9&A?eqZd>!3I8FaNNI@9fU!Ooh_F`G%W;vOL?K@DA zKW87zo2B&f2KPqib-%`UJ5RTKj1Ey>W!*-D+pfi;G{ZQG%~;SolH_b^m@>w2xhSDS zmZRImz2knPBEL_DdxbdK;ue=W1(b&!Jl#|d}N?I^(#C`i8@ zG~$?>x!oWHqZ00%&q)D3l&3yUKf7*@o=TCS=b9e3TQdxITp{w|F9&m^8r3UHz?)~+ zD;ASvt9g27H%R#COn-M%TeC&G$(A=CI6e%~5V|iaoyXIiePQ2@=AbEjMZXaK=*5b%56={dZgyz1KfTyGothR5d$1A#x~ zBYU8wBBOvK-t>)B!X1Q&vpKHib-xOF?v*ef4nEW>?p>C!t+~xqD>dH;O7;9ItJ~v!AAHPC=n9A8L6CzutLvJQ86K2{FWA&U|yfw zbh{c7_4AI{7QpE&m7?!OJy3^Eya6AUML#z)al=3r^f+e-v%Tvpi?wTY#xUT4%CsgeA(w_|qEv*l>DQ^M$eT5E6sd`ix`mR%_C_-l`uiqR03jmITkE(Yj%tCufdatj=E^K`- zG)-O3sW}LD<&p0Rwn=^1LODwbsPMeV0EPzWLxl=ZmRJc8@92#Eix&Skknf8mWiZEU zXOavw{<~A%MoLC6n<9)Gz->!B3x#L|Mdw>O7K`bi0otW=Pp6tZ`GhQueue^E0BWix z-PBB-UK?{PG;_Dji9NvVP55&$XX~Zi)*{#GTv-wc+q*Y+=cyZP#qYR^zq;L_kt3#e z-%KHRET0nTM+4KuF+F3tBw~_$twyEH@|*P!32S6q1%SiSVf5p*fw3cVm5vqU!(~Bj z6_Aj$^*k}2=s#S46Nc>gg^lb=&hnE7H}dxP3B8gA>1)1jT04F@%D6G_2f8l3Z)c0}zuJ^iycH(1tSB;G?(r zay3d3Mz$ti4~pUXepLRuRC>oP5WrnUIa�GbF5tZ>C0ZQ}jxv%VF|sQ|2cyO~(AI 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%0Aw* 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 D#D6HV literal 0 HcmV?d00001 From 56a94f4c5502b5ca3867ea95fecef78fea921737 Mon Sep 17 00:00:00 2001 From: Kostis Kapelonis Date: Mon, 31 Jan 2022 10:28:19 +0200 Subject: [PATCH 075/175] docs: fixed rollout controller link Signed-off-by: Kostis Kapelonis --- docs/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index b3c1f1be87..d4e4d89b6d 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -102,7 +102,7 @@ that handle a specific aspect of Progressive Delivery. The controllers are: -* [Rollout Controller](https://github.com/argoproj/argo-rollouts/blob/master/controller/controller.go) +* [Rollout Controller](https://github.com/argoproj/argo-rollouts/blob/master/rollout/controller.go) * [Service Controller](https://github.com/argoproj/argo-rollouts/blob/master/service/service.go) * [Ingress Controller](https://github.com/argoproj/argo-rollouts/blob/master/ingress/ingress.go) * [Experiment Controller](https://github.com/argoproj/argo-rollouts/blob/master/experiments/controller.go) From d3275e09d782d916160047892c3d9d77966fadb2 Mon Sep 17 00:00:00 2001 From: cskh Date: Mon, 31 Jan 2022 13:27:20 -0500 Subject: [PATCH 076/175] fix(canary): scale up and down old replicas (#1824) Signed-off-by: Hui Kang --- rollout/canary.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/rollout/canary.go b/rollout/canary.go index b666d503e8..c5f3014107 100644 --- a/rollout/canary.go +++ b/rollout/canary.go @@ -174,7 +174,6 @@ func (c *rolloutContext) scaleDownOldReplicaSetsForCanary(oldRSs []*appsv1.Repli } annotationedRSs := int32(0) - rolloutReplicas := defaults.GetReplicasOrDefault(c.rollout.Spec.Replicas) for _, targetRS := range oldRSs { if replicasetutil.IsStillReferenced(c.rollout.Status, targetRS) { // We should technically never get here because we shouldn't be passing a replicaset list @@ -204,8 +203,8 @@ func (c *rolloutContext) scaleDownOldReplicaSetsForCanary(oldRSs []*appsv1.Repli // 1. if we are using dynamic scaling, then this should be scaled down to 0 now desiredReplicaCount = 0 } else { - // 2. otherwise, honor scaledown delay second - annotationedRSs, desiredReplicaCount, err = c.scaleDownDelayHelper(targetRS, annotationedRSs, rolloutReplicas) + // 2. otherwise, honor scaledown delay second and keep replicas of the current step + annotationedRSs, desiredReplicaCount, err = c.scaleDownDelayHelper(targetRS, annotationedRSs, *targetRS.Spec.Replicas) if err != nil { return totalScaledDown, err } From e7f7e85a66f56487b30377c3a21730dce495f494 Mon Sep 17 00:00:00 2001 From: Leonardo Luz Almeida Date: Tue, 1 Feb 2022 13:42:27 -0500 Subject: [PATCH 077/175] chore: generate and upload sbom during release (#1834) Signed-off-by: Leonardo Luz Almeida --- .github/workflows/release.yaml | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 0dfc96f945..9db56c214a 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,11 +1,11 @@ name: Release on: - workflow_dispatch: - inputs: - tag: - description: Git tag to build release from - required: true + workflow_dispatch: + inputs: + tag: + description: Git tag to build release from + required: true jobs: release-images: runs-on: ubuntu-latest @@ -120,6 +120,25 @@ jobs: make release-plugins make manifests IMAGE_TAG=${{ github.event.inputs.tag }} + - name: Generate SBOM (spdx) + id: spdx-builder + env: + # defines the https://github.com/opensbom-generator/spdx-sbom-generator + # to use. + SPDX_GEN_VERSION: v0.0.13 + # comma delimited list of project relative folders to inspect for package + # managers (gomod, yarn, npm). + PROJECT_FOLDERS: ".,./ui" + run: | + yarn install --cwd ./ui + wget -q https://github.com/opensbom-generator/spdx-sbom-generator/releases/download/$SPDX_GEN_VERSION/spdx-sbom-generator-$SPDX_GEN_VERSION-linux-386.tar.gz -O generator.tar.gz + tar -zxf generator.tar.gz + for folder in $(echo $PROJECT_FOLDERS | sed "s/,/ /g") + do + ./spdx-sbom-generator -p $folder -o /tmp + done + tar -zcf /tmp/sbom.tar.gz /tmp/*.spdx + - name: Draft release uses: softprops/action-gh-release@v1 with: @@ -135,5 +154,6 @@ jobs: manifests/namespace-install.yaml manifests/notifications-install.yaml docs/features/kustomize/rollout_cr_schema.json + /tmp/sbom.tar.gz env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 86dc378cf0daa51ff612a7731270cc52297eed9d Mon Sep 17 00:00:00 2001 From: harikrongali <81331774+harikrongali@users.noreply.github.com> Date: Tue, 1 Feb 2022 10:43:02 -0800 Subject: [PATCH 078/175] fix: flaky unit test (#1831) Signed-off-by: hari rongali --- rollout/experiment_test.go | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/rollout/experiment_test.go b/rollout/experiment_test.go index b002913d0f..c8b610a303 100644 --- a/rollout/experiment_test.go +++ b/rollout/experiment_test.go @@ -1,6 +1,7 @@ package rollout import ( + "encoding/json" "fmt" "testing" "time" @@ -343,25 +344,13 @@ func TestPauseRolloutAfterInconclusiveExperiment(t *testing.T) { patchIndex := f.expectPatchRolloutAction(r1) f.run(getKey(r2, t)) patch := f.getPatchedRollout(patchIndex) - expectedPatchFmt := `{ - "status": { - "canary": { - "currentExperiment": null - }, - "pauseConditions": [{ - "reason": "%s", - "startTime": "%s" - }], - "conditions": %s, - "controllerPause": true, - "phase": "Paused", - "message": "%s" - } - }` - now := metav1.Now().UTC().Format(time.RFC3339) - conditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "") - expectedPatch := calculatePatch(r2, fmt.Sprintf(expectedPatchFmt, v1alpha1.PauseReasonInconclusiveExperiment, now, conditions, v1alpha1.PauseReasonInconclusiveExperiment)) - assert.Equal(t, expectedPatch, patch) + ro := v1alpha1.Rollout{} + err := json.Unmarshal([]byte(patch), &ro) + if err != nil { + panic(err) + } + assert.Equal(t, ro.Status.PauseConditions[0].Reason, v1alpha1.PauseReason("InconclusiveExperiment")) + assert.Equal(t, ro.Status.Message, "InconclusiveExperiment") } func TestRolloutExperimentScaleDownExperimentFromPreviousStep(t *testing.T) { From 808fd794f4e7d3a31d25ec4fdee91d8653d790e1 Mon Sep 17 00:00:00 2001 From: Rohit Agrawal Date: Thu, 20 Jan 2022 00:05:58 +0530 Subject: [PATCH 079/175] feat(experiment): Add Measurements Retention Limit Option for Metrics Signed-off-by: Rohit Agrawal --- docs/features/analysis.md | 32 +- experiments/experiment.go | 16 +- manifests/crds/experiment-crd.yaml | 13 + manifests/install.yaml | 13 + manifests/namespace-install.yaml | 13 + pkg/apis/api-rules/violation_exceptions.list | 1 + .../rollouts/v1alpha1/experiment_types.go | 5 + pkg/apis/rollouts/v1alpha1/generated.pb.go | 921 ++++++++++-------- pkg/apis/rollouts/v1alpha1/generated.proto | 6 + .../rollouts/v1alpha1/openapi_generated.go | 22 +- .../v1alpha1/zz_generated.deepcopy.go | 5 + test/e2e/experiment_test.go | 11 + ...riment-measurement-retention-analysis.yaml | 55 ++ test/fixtures/then.go | 20 + 14 files changed, 693 insertions(+), 440 deletions(-) create mode 100644 test/e2e/functional/experiment-measurement-retention-analysis.yaml diff --git a/docs/features/analysis.md b/docs/features/analysis.md index f1db6579ff..478a7280f3 100644 --- a/docs/features/analysis.md +++ b/docs/features/analysis.md @@ -714,7 +714,7 @@ spec: ## Measurements Retention !!! important -Available since v1.2 + Available since v1.2 `measurementRetention` can be used to retain other than the latest ten results for the metrics running in any mode (dry/non-dry). Setting this option to `0` would disable it and, the controller will revert to the existing behavior of @@ -804,6 +804,36 @@ spec: limit: 20 ``` +### Measurements Retention for Experiments + +If an experiment wants to retain more results of its analysis metrics, it simply needs to specify the +`measurementRetention` field under its specs. In the following example, all the metrics from `analyze-job` matching the +RegEx rule `test.*` will have their latest twenty measurements get retained instead of the default ten. + +```yaml hl_lines="20 21 22" +kind: Experiment +spec: + templates: + - name: baseline + selector: + matchLabels: + app: rollouts-demo + template: + metadata: + labels: + app: rollouts-demo + spec: + containers: + - name: rollouts-demo + image: argoproj/rollouts-demo:blue + analyses: + - name: analyze-job + templateName: analyze-job + measurementRetention: + - metricName: test.* + limit: 20 +``` + ## Inconclusive Runs Analysis runs can also be considered `Inconclusive`, which indicates the run was neither successful, diff --git a/experiments/experiment.go b/experiments/experiment.go index ee0cf51964..aa154d03d9 100644 --- a/experiments/experiment.go +++ b/experiments/experiment.go @@ -100,7 +100,7 @@ func (ec *experimentContext) reconcile() *v1alpha1.ExperimentStatus { } for _, analysis := range ec.ex.Spec.Analyses { - ec.reconcileAnalysisRun(analysis, ec.ex.Spec.DryRun) + ec.reconcileAnalysisRun(analysis, ec.ex.Spec.DryRun, ec.ex.Spec.MeasurementRetention) } newStatus := ec.calculateStatus() @@ -371,7 +371,7 @@ func calculateEnqueueDuration(ex *v1alpha1.Experiment, newStatus *v1alpha1.Exper // reconcileAnalysisRun reconciles a single analysis run, creating or terminating it as necessary. // Updates the analysis run statuses, which may subsequently fail the experiment. -func (ec *experimentContext) reconcileAnalysisRun(analysis v1alpha1.ExperimentAnalysisTemplateRef, dryRunMetrics []v1alpha1.DryRun) { +func (ec *experimentContext) reconcileAnalysisRun(analysis v1alpha1.ExperimentAnalysisTemplateRef, dryRunMetrics []v1alpha1.DryRun, measurementRetentionMetrics []v1alpha1.MeasurementRetention) { logCtx := ec.log.WithField("analysis", analysis.Name) logCtx.Infof("Reconciling analysis") prevStatus := experimentutil.GetAnalysisRunStatus(ec.ex.Status, analysis.Name) @@ -427,7 +427,7 @@ func (ec *experimentContext) reconcileAnalysisRun(analysis v1alpha1.ExperimentAn logCtx.Warnf("Skipping AnalysisRun creation for analysis %s: experiment is terminating", analysis.Name) return } - run, err := ec.createAnalysisRun(analysis, dryRunMetrics) + run, err := ec.createAnalysisRun(analysis, dryRunMetrics, measurementRetentionMetrics) if err != nil { msg := fmt.Sprintf("Failed to create AnalysisRun for analysis '%s': %v", analysis.Name, err.Error()) newStatus.Phase = v1alpha1.AnalysisPhaseError @@ -474,13 +474,13 @@ func (ec *experimentContext) reconcileAnalysisRun(analysis v1alpha1.ExperimentAn // createAnalysisRun creates the analysis run. If an existing runs exists with same name, is // semantically equal, and is not complete, returns the existing one, otherwise creates a new // run with a collision counter increase. -func (ec *experimentContext) createAnalysisRun(analysis v1alpha1.ExperimentAnalysisTemplateRef, dryRunMetrics []v1alpha1.DryRun) (*v1alpha1.AnalysisRun, error) { +func (ec *experimentContext) createAnalysisRun(analysis v1alpha1.ExperimentAnalysisTemplateRef, dryRunMetrics []v1alpha1.DryRun, measurementRetentionMetrics []v1alpha1.MeasurementRetention) (*v1alpha1.AnalysisRun, error) { analysisRunIf := ec.argoProjClientset.ArgoprojV1alpha1().AnalysisRuns(ec.ex.Namespace) args, err := ec.ResolveAnalysisRunArgs(analysis.Args) if err != nil { return nil, err } - run, err := ec.newAnalysisRun(analysis, args, dryRunMetrics) + run, err := ec.newAnalysisRun(analysis, args, dryRunMetrics, measurementRetentionMetrics) if err != nil { return nil, err } @@ -616,7 +616,7 @@ func (ec *experimentContext) assessAnalysisRuns() (v1alpha1.AnalysisPhase, strin } // newAnalysisRun generates an AnalysisRun from the experiment and template -func (ec *experimentContext) newAnalysisRun(analysis v1alpha1.ExperimentAnalysisTemplateRef, args []v1alpha1.Argument, dryRunMetrics []v1alpha1.DryRun) (*v1alpha1.AnalysisRun, error) { +func (ec *experimentContext) newAnalysisRun(analysis v1alpha1.ExperimentAnalysisTemplateRef, args []v1alpha1.Argument, dryRunMetrics []v1alpha1.DryRun, measurementRetentionMetrics []v1alpha1.MeasurementRetention) (*v1alpha1.AnalysisRun, error) { if analysis.ClusterScope { clusterTemplate, err := ec.clusterAnalysisTemplateLister.Get(analysis.TemplateName) @@ -626,7 +626,7 @@ func (ec *experimentContext) newAnalysisRun(analysis v1alpha1.ExperimentAnalysis name := fmt.Sprintf("%s-%s", ec.ex.Name, analysis.Name) clusterAnalysisTemplates := []*v1alpha1.ClusterAnalysisTemplate{clusterTemplate} - run, err := analysisutil.NewAnalysisRunFromTemplates(nil, clusterAnalysisTemplates, args, dryRunMetrics, []v1alpha1.MeasurementRetention{}, name, "", ec.ex.Namespace) + run, err := analysisutil.NewAnalysisRunFromTemplates(nil, clusterAnalysisTemplates, args, dryRunMetrics, measurementRetentionMetrics, name, "", ec.ex.Namespace) if err != nil { return nil, err } @@ -644,7 +644,7 @@ func (ec *experimentContext) newAnalysisRun(analysis v1alpha1.ExperimentAnalysis name := fmt.Sprintf("%s-%s", ec.ex.Name, analysis.Name) analysisTemplates := []*v1alpha1.AnalysisTemplate{template} - run, err := analysisutil.NewAnalysisRunFromTemplates(analysisTemplates, nil, args, dryRunMetrics, []v1alpha1.MeasurementRetention{}, name, "", ec.ex.Namespace) + run, err := analysisutil.NewAnalysisRunFromTemplates(analysisTemplates, nil, args, dryRunMetrics, measurementRetentionMetrics, name, "", ec.ex.Namespace) if err != nil { return nil, err } diff --git a/manifests/crds/experiment-crd.yaml b/manifests/crds/experiment-crd.yaml index af9b47f896..0e163e4991 100644 --- a/manifests/crds/experiment-crd.yaml +++ b/manifests/crds/experiment-crd.yaml @@ -95,6 +95,19 @@ spec: type: array duration: type: string + measurementRetention: + items: + properties: + limit: + format: int32 + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array progressDeadlineSeconds: format: int32 type: integer diff --git a/manifests/install.yaml b/manifests/install.yaml index 0ebe8c0b0d..d4547cbe5a 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -8460,6 +8460,19 @@ spec: type: array duration: type: string + measurementRetention: + items: + properties: + limit: + format: int32 + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array progressDeadlineSeconds: format: int32 type: integer diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index d968473b8b..71f6d0fa15 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -8460,6 +8460,19 @@ spec: type: array duration: type: string + measurementRetention: + items: + properties: + limit: + format: int32 + type: integer + metricName: + type: string + required: + - limit + - metricName + type: object + type: array progressDeadlineSeconds: format: int32 type: integer diff --git a/pkg/apis/api-rules/violation_exceptions.list b/pkg/apis/api-rules/violation_exceptions.list index 6b08b1daf0..b69a0e1854 100644 --- a/pkg/apis/api-rules/violation_exceptions.list +++ b/pkg/apis/api-rules/violation_exceptions.list @@ -14,6 +14,7 @@ API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,ExperimentAnalysisTemplateRef,Args API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,ExperimentSpec,Analyses API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,ExperimentSpec,DryRun +API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,ExperimentSpec,MeasurementRetention API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,ExperimentSpec,Templates API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,ExperimentStatus,AnalysisRuns API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,ExperimentStatus,Conditions diff --git a/pkg/apis/rollouts/v1alpha1/experiment_types.go b/pkg/apis/rollouts/v1alpha1/experiment_types.go index c197a23c06..5fcc27cb7c 100644 --- a/pkg/apis/rollouts/v1alpha1/experiment_types.go +++ b/pkg/apis/rollouts/v1alpha1/experiment_types.go @@ -60,6 +60,11 @@ type ExperimentSpec struct { // +patchStrategy=merge // +optional DryRun []DryRun `json:"dryRun,omitempty" patchStrategy:"merge" patchMergeKey:"metricName" protobuf:"bytes,7,rep,name=dryRun"` + // MeasurementRetention object contains the settings for retaining the number of measurements during the analysis + // +patchMergeKey=metricName + // +patchStrategy=merge + // +optional + MeasurementRetention []MeasurementRetention `json:"measurementRetention,omitempty" patchStrategy:"merge" patchMergeKey:"metricName" protobuf:"bytes,8,rep,name=measurementRetention"` } type TemplateSpec struct { diff --git a/pkg/apis/rollouts/v1alpha1/generated.pb.go b/pkg/apis/rollouts/v1alpha1/generated.pb.go index 86c45cf571..0810ed7716 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.pb.go +++ b/pkg/apis/rollouts/v1alpha1/generated.pb.go @@ -2676,436 +2676,437 @@ func init() { } var fileDescriptor_e0e705f843545fab = []byte{ - // 6861 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x5d, 0x8c, 0x24, 0x57, - 0x75, 0xb0, 0xab, 0x7f, 0x66, 0x7a, 0xce, 0xfc, 0xdf, 0x9d, 0x65, 0xc7, 0x6b, 0xef, 0xb6, 0x29, - 0x23, 0x7f, 0xe6, 0x0b, 0xcc, 0xc2, 0xda, 0x4e, 0x0c, 0x46, 0x56, 0xba, 0x67, 0x76, 0xbd, 0xb3, - 0x9e, 0xd9, 0x9d, 0xbd, 0x3d, 0xeb, 0x05, 0x83, 0x09, 0x35, 0xdd, 0x77, 0x7a, 0x6a, 0xb7, 0xba, - 0xaa, 0xa9, 0xaa, 0x9e, 0xdd, 0x31, 0x08, 0xec, 0x20, 0x3b, 0x24, 0x02, 0xe1, 0x04, 0x78, 0x88, - 0x22, 0x22, 0x14, 0xf1, 0x10, 0x85, 0x3c, 0x44, 0x28, 0x51, 0x5e, 0x90, 0x12, 0x25, 0x20, 0x91, - 0x87, 0x44, 0x44, 0x4a, 0x02, 0x44, 0xd0, 0xc1, 0x4d, 0xf2, 0x90, 0x28, 0x52, 0x14, 0x89, 0x28, - 0x62, 0x9f, 0xa2, 0xfb, 0x5b, 0xb7, 0xaa, 0xab, 0x67, 0xbb, 0xa7, 0x6b, 0x16, 0x94, 0xf0, 0xd6, - 0x7d, 0xcf, 0xb9, 0xe7, 0xdc, 0xdf, 0x73, 0xcf, 0xb9, 0xe7, 0xdc, 0x53, 0xb0, 0xd1, 0xb4, 0xc3, - 0xbd, 0xce, 0xce, 0x4a, 0xdd, 0x6b, 0x9d, 0xb3, 0xfc, 0xa6, 0xd7, 0xf6, 0xbd, 0x9b, 0xec, 0xc7, - 0x3b, 0x7d, 0xcf, 0x71, 0xbc, 0x4e, 0x18, 0x9c, 0x6b, 0xdf, 0x6a, 0x9e, 0xb3, 0xda, 0x76, 0x70, - 0x4e, 0x95, 0xec, 0xbf, 0xdb, 0x72, 0xda, 0x7b, 0xd6, 0xbb, 0xcf, 0x35, 0x89, 0x4b, 0x7c, 0x2b, - 0x24, 0x8d, 0x95, 0xb6, 0xef, 0x85, 0x1e, 0x7a, 0x5f, 0x44, 0x6d, 0x45, 0x52, 0x63, 0x3f, 0x7e, - 0x45, 0xd6, 0x5d, 0x69, 0xdf, 0x6a, 0xae, 0x50, 0x6a, 0x2b, 0xaa, 0x44, 0x52, 0x3b, 0xfd, 0x4e, - 0xad, 0x2d, 0x4d, 0xaf, 0xe9, 0x9d, 0x63, 0x44, 0x77, 0x3a, 0xbb, 0xec, 0x1f, 0xfb, 0xc3, 0x7e, - 0x71, 0x66, 0xa7, 0x1f, 0xbd, 0xf5, 0x74, 0xb0, 0x62, 0x7b, 0xb4, 0x6d, 0xe7, 0x76, 0xac, 0xb0, - 0xbe, 0x77, 0x6e, 0xbf, 0xaf, 0x45, 0xa7, 0x4d, 0x0d, 0xa9, 0xee, 0xf9, 0x24, 0x0d, 0xe7, 0xc9, - 0x08, 0xa7, 0x65, 0xd5, 0xf7, 0x6c, 0x97, 0xf8, 0x07, 0x51, 0xaf, 0x5b, 0x24, 0xb4, 0xd2, 0x6a, - 0x9d, 0x1b, 0x54, 0xcb, 0xef, 0xb8, 0xa1, 0xdd, 0x22, 0x7d, 0x15, 0x7e, 0xf1, 0x5e, 0x15, 0x82, - 0xfa, 0x1e, 0x69, 0x59, 0x7d, 0xf5, 0x9e, 0x18, 0x54, 0xaf, 0x13, 0xda, 0xce, 0x39, 0xdb, 0x0d, - 0x83, 0xd0, 0x4f, 0x56, 0x32, 0xbf, 0x91, 0x87, 0xa9, 0xca, 0x46, 0xb5, 0x16, 0x5a, 0x61, 0x27, - 0x40, 0xaf, 0x1b, 0x30, 0xe3, 0x78, 0x56, 0xa3, 0x6a, 0x39, 0x96, 0x5b, 0x27, 0xfe, 0xb2, 0xf1, - 0x88, 0xf1, 0xf8, 0xf4, 0xf9, 0x8d, 0x95, 0x71, 0xe6, 0x6b, 0xa5, 0x72, 0x3b, 0xc0, 0x24, 0xf0, - 0x3a, 0x7e, 0x9d, 0x60, 0xb2, 0x5b, 0x5d, 0xfa, 0x56, 0xb7, 0xfc, 0x40, 0xaf, 0x5b, 0x9e, 0xd9, - 0xd0, 0x38, 0xe1, 0x18, 0x5f, 0xf4, 0x45, 0x03, 0x16, 0xeb, 0x96, 0x6b, 0xf9, 0x07, 0xdb, 0x96, - 0xdf, 0x24, 0xe1, 0x73, 0xbe, 0xd7, 0x69, 0x2f, 0xe7, 0x8e, 0xa1, 0x35, 0x0f, 0x8a, 0xd6, 0x2c, - 0xae, 0x26, 0xd9, 0xe1, 0xfe, 0x16, 0xb0, 0x76, 0x05, 0xa1, 0xb5, 0xe3, 0x10, 0xbd, 0x5d, 0xf9, - 0xe3, 0x6c, 0x57, 0x2d, 0xc9, 0x0e, 0xf7, 0xb7, 0xc0, 0x7c, 0x2d, 0x0f, 0x8b, 0x95, 0x8d, 0xea, - 0xb6, 0x6f, 0xed, 0xee, 0xda, 0x75, 0xec, 0x75, 0x42, 0xdb, 0x6d, 0xa2, 0xb7, 0xc3, 0xa4, 0xed, - 0x36, 0x7d, 0x12, 0x04, 0x6c, 0x22, 0xa7, 0xaa, 0xf3, 0x82, 0xe8, 0xe4, 0x3a, 0x2f, 0xc6, 0x12, - 0x8e, 0x9e, 0x82, 0xe9, 0x80, 0xf8, 0xfb, 0x76, 0x9d, 0x6c, 0x79, 0x7e, 0xc8, 0x46, 0xba, 0x58, - 0x3d, 0x21, 0xd0, 0xa7, 0x6b, 0x11, 0x08, 0xeb, 0x78, 0xb4, 0x9a, 0xef, 0x79, 0xa1, 0x80, 0xb3, - 0x81, 0x98, 0x8a, 0xaa, 0xe1, 0x08, 0x84, 0x75, 0x3c, 0xf4, 0x86, 0x01, 0x0b, 0x41, 0x68, 0xd7, - 0x6f, 0xd9, 0x2e, 0x09, 0x82, 0x55, 0xcf, 0xdd, 0xb5, 0x9b, 0xcb, 0x45, 0x36, 0x8a, 0x57, 0xc6, - 0x1b, 0xc5, 0x5a, 0x82, 0x6a, 0x75, 0xa9, 0xd7, 0x2d, 0x2f, 0x24, 0x4b, 0x71, 0x1f, 0x77, 0xb4, - 0x06, 0x0b, 0x96, 0xeb, 0x7a, 0xa1, 0x15, 0xda, 0x9e, 0xbb, 0xe5, 0x93, 0x5d, 0xfb, 0xce, 0x72, - 0x81, 0x75, 0x67, 0x59, 0x74, 0x67, 0xa1, 0x92, 0x80, 0xe3, 0xbe, 0x1a, 0xe6, 0x1a, 0x2c, 0x57, - 0x5a, 0x3b, 0x56, 0x10, 0x58, 0x0d, 0xcf, 0x4f, 0xcc, 0xc6, 0xe3, 0x50, 0x6a, 0x59, 0xed, 0xb6, - 0xed, 0x36, 0xe9, 0x74, 0xe4, 0x1f, 0x9f, 0xaa, 0xce, 0xf4, 0xba, 0xe5, 0xd2, 0xa6, 0x28, 0xc3, - 0x0a, 0x6a, 0x7e, 0x2f, 0x07, 0xd3, 0x15, 0xd7, 0x72, 0x0e, 0x02, 0x3b, 0xc0, 0x1d, 0x17, 0x7d, - 0x04, 0x4a, 0x54, 0xba, 0x34, 0xac, 0xd0, 0x12, 0x3b, 0xf2, 0x5d, 0x2b, 0x7c, 0xb3, 0xaf, 0xe8, - 0x9b, 0x3d, 0x1a, 0x17, 0x8a, 0xbd, 0xb2, 0xff, 0xee, 0x95, 0xab, 0x3b, 0x37, 0x49, 0x3d, 0xdc, - 0x24, 0xa1, 0x55, 0x45, 0xa2, 0x17, 0x10, 0x95, 0x61, 0x45, 0x15, 0x79, 0x50, 0x08, 0xda, 0xa4, - 0x2e, 0x76, 0xd8, 0xe6, 0x98, 0x2b, 0x39, 0x6a, 0x7a, 0xad, 0x4d, 0xea, 0xd5, 0x19, 0xc1, 0xba, - 0x40, 0xff, 0x61, 0xc6, 0x08, 0xdd, 0x86, 0x89, 0x80, 0xc9, 0x1c, 0xb1, 0x79, 0xae, 0x66, 0xc7, - 0x92, 0x91, 0xad, 0xce, 0x09, 0xa6, 0x13, 0xfc, 0x3f, 0x16, 0xec, 0xcc, 0x7f, 0x34, 0xe0, 0x84, - 0x86, 0x5d, 0xf1, 0x9b, 0x9d, 0x16, 0x71, 0x43, 0xf4, 0x08, 0x14, 0x5c, 0xab, 0x45, 0xc4, 0x46, - 0x51, 0x4d, 0xbe, 0x62, 0xb5, 0x08, 0x66, 0x10, 0xf4, 0x28, 0x14, 0xf7, 0x2d, 0xa7, 0x43, 0xd8, - 0x20, 0x4d, 0x55, 0x67, 0x05, 0x4a, 0xf1, 0x05, 0x5a, 0x88, 0x39, 0x0c, 0x7d, 0x1c, 0xa6, 0xd8, - 0x8f, 0x8b, 0xbe, 0xd7, 0xca, 0xa8, 0x6b, 0xa2, 0x85, 0x2f, 0x48, 0xb2, 0xd5, 0xd9, 0x5e, 0xb7, - 0x3c, 0xa5, 0xfe, 0xe2, 0x88, 0xa1, 0xf9, 0x4f, 0x06, 0xcc, 0x6b, 0x9d, 0xdb, 0xb0, 0x83, 0x10, - 0x7d, 0xa8, 0x6f, 0xf1, 0xac, 0x0c, 0xb7, 0x78, 0x68, 0x6d, 0xb6, 0x74, 0x16, 0x44, 0x4f, 0x4b, - 0xb2, 0x44, 0x5b, 0x38, 0x2e, 0x14, 0xed, 0x90, 0xb4, 0x82, 0xe5, 0xdc, 0x23, 0xf9, 0xc7, 0xa7, - 0xcf, 0xaf, 0x67, 0x36, 0x8d, 0xd1, 0xf8, 0xae, 0x53, 0xfa, 0x98, 0xb3, 0x31, 0xbf, 0x56, 0x88, - 0xf5, 0x90, 0xae, 0x28, 0xe4, 0xc1, 0x64, 0x8b, 0x84, 0xbe, 0x5d, 0xe7, 0xfb, 0x6a, 0xfa, 0xfc, - 0xda, 0x78, 0xad, 0xd8, 0x64, 0xc4, 0x22, 0x61, 0xc9, 0xff, 0x07, 0x58, 0x72, 0x41, 0x7b, 0x50, - 0xb0, 0xfc, 0xa6, 0xec, 0xf3, 0xc5, 0x6c, 0xe6, 0x37, 0x5a, 0x73, 0x15, 0xbf, 0x19, 0x60, 0xc6, - 0x01, 0x9d, 0x83, 0xa9, 0x90, 0xf8, 0x2d, 0xdb, 0xb5, 0x42, 0x2e, 0x5d, 0x4b, 0xd5, 0x45, 0x81, - 0x36, 0xb5, 0x2d, 0x01, 0x38, 0xc2, 0x41, 0x0e, 0x4c, 0x34, 0xfc, 0x03, 0xdc, 0x71, 0x97, 0x0b, - 0x59, 0x0c, 0xc5, 0x1a, 0xa3, 0x15, 0x6d, 0x26, 0xfe, 0x1f, 0x0b, 0x1e, 0xe8, 0x2b, 0x06, 0x2c, - 0xb5, 0x88, 0x15, 0x74, 0x7c, 0x42, 0xbb, 0x80, 0x49, 0x48, 0x5c, 0x2a, 0x0d, 0x97, 0x8b, 0x8c, - 0x39, 0x1e, 0x77, 0x1e, 0xfa, 0x29, 0x57, 0x1f, 0x16, 0x4d, 0x59, 0x4a, 0x83, 0xe2, 0xd4, 0xd6, - 0x98, 0xdf, 0x2b, 0xc0, 0x62, 0x9f, 0x84, 0x40, 0x4f, 0x42, 0xb1, 0xbd, 0x67, 0x05, 0x72, 0xcb, - 0x9f, 0x95, 0xeb, 0x6d, 0x8b, 0x16, 0xde, 0xed, 0x96, 0x67, 0x65, 0x15, 0x56, 0x80, 0x39, 0x32, - 0x3d, 0x53, 0x5b, 0x24, 0x08, 0xac, 0xa6, 0x94, 0x03, 0xda, 0x32, 0x61, 0xc5, 0x58, 0xc2, 0xd1, - 0xaf, 0x19, 0x30, 0xcb, 0x97, 0x0c, 0x26, 0x41, 0xc7, 0x09, 0xa9, 0xac, 0xa3, 0xc3, 0x72, 0x39, - 0x8b, 0xe5, 0xc9, 0x49, 0x56, 0x4f, 0x0a, 0xee, 0xb3, 0x7a, 0x69, 0x80, 0xe3, 0x7c, 0xd1, 0x0d, - 0x98, 0x0a, 0x42, 0xcb, 0x0f, 0x49, 0xa3, 0x12, 0xb2, 0x53, 0x6d, 0xfa, 0xfc, 0xff, 0x1f, 0x4e, - 0x08, 0x6c, 0xdb, 0x2d, 0xc2, 0x05, 0x4e, 0x4d, 0x12, 0xc0, 0x11, 0x2d, 0xf4, 0x71, 0x00, 0xbf, - 0xe3, 0xd6, 0x3a, 0xad, 0x96, 0xe5, 0x1f, 0x88, 0x13, 0xfc, 0xd2, 0x78, 0xdd, 0xc3, 0x8a, 0x5e, - 0x74, 0x66, 0x45, 0x65, 0x58, 0xe3, 0x87, 0x5e, 0x35, 0x60, 0x96, 0xaf, 0x44, 0xd9, 0x82, 0x89, - 0x8c, 0x5b, 0xb0, 0x48, 0x87, 0x76, 0x4d, 0x67, 0x81, 0xe3, 0x1c, 0xcd, 0xbf, 0x8f, 0x9f, 0x27, - 0xb5, 0x90, 0x6a, 0xd7, 0xcd, 0x03, 0xf4, 0x41, 0x78, 0x30, 0xe8, 0xd4, 0xeb, 0x24, 0x08, 0x76, - 0x3b, 0x0e, 0xee, 0xb8, 0x97, 0xec, 0x20, 0xf4, 0xfc, 0x83, 0x0d, 0xbb, 0x65, 0x87, 0x6c, 0xc5, - 0x15, 0xab, 0x67, 0x7a, 0xdd, 0xf2, 0x83, 0xb5, 0x41, 0x48, 0x78, 0x70, 0x7d, 0x64, 0xc1, 0x43, - 0x1d, 0x77, 0x30, 0x79, 0xae, 0xbd, 0x95, 0x7b, 0xdd, 0xf2, 0x43, 0xd7, 0x07, 0xa3, 0xe1, 0xc3, - 0x68, 0x98, 0xff, 0x66, 0xc0, 0x82, 0xec, 0xd7, 0x36, 0x69, 0xb5, 0x1d, 0x2a, 0x5d, 0x8e, 0x5f, - 0x11, 0x09, 0x63, 0x8a, 0x08, 0xce, 0xe6, 0x38, 0x91, 0xed, 0x1f, 0xa4, 0x8d, 0x98, 0xff, 0x6a, - 0xc0, 0x52, 0x12, 0xf9, 0x3e, 0x1c, 0x9e, 0x41, 0xfc, 0xf0, 0xbc, 0x92, 0x6d, 0x6f, 0x07, 0x9c, - 0xa0, 0xaf, 0x17, 0xfa, 0xfb, 0xfa, 0xbf, 0xfd, 0x18, 0x8d, 0x4e, 0xc5, 0xfc, 0x4f, 0xf3, 0x54, - 0x2c, 0xfc, 0x4c, 0x9d, 0x8a, 0xbf, 0x5f, 0x80, 0x99, 0x8a, 0x1b, 0xda, 0x95, 0xdd, 0x5d, 0xdb, - 0xb5, 0xc3, 0x03, 0xf4, 0x99, 0x1c, 0x9c, 0x6b, 0xfb, 0x64, 0x97, 0xf8, 0x3e, 0x69, 0xac, 0x75, - 0x7c, 0xdb, 0x6d, 0xd6, 0xea, 0x7b, 0xa4, 0xd1, 0x71, 0x6c, 0xb7, 0xb9, 0xde, 0x74, 0x3d, 0x55, - 0x7c, 0xe1, 0x0e, 0xa9, 0x77, 0x58, 0x97, 0xf8, 0xa6, 0x68, 0x8d, 0xd7, 0xa5, 0xad, 0xd1, 0x98, - 0x56, 0x9f, 0xe8, 0x75, 0xcb, 0xe7, 0x46, 0xac, 0x84, 0x47, 0xed, 0x1a, 0xfa, 0x74, 0x0e, 0x56, - 0x7c, 0xf2, 0xd1, 0x8e, 0x3d, 0xfc, 0x68, 0x70, 0xa9, 0xe5, 0x8c, 0x79, 0xfc, 0x8c, 0xc4, 0xb3, - 0x7a, 0xbe, 0xd7, 0x2d, 0x8f, 0x58, 0x07, 0x8f, 0xd8, 0x2f, 0xf3, 0x2f, 0x0d, 0x28, 0x8d, 0x60, - 0x29, 0x95, 0xe3, 0x96, 0xd2, 0x54, 0x9f, 0x95, 0x14, 0xf6, 0x5b, 0x49, 0xcf, 0x8d, 0x37, 0x68, - 0xc3, 0x58, 0x47, 0xff, 0x61, 0xc0, 0x62, 0x9f, 0x35, 0x85, 0xf6, 0x60, 0xa9, 0xed, 0x35, 0xa4, - 0x24, 0xbc, 0x64, 0x05, 0x7b, 0x0c, 0x26, 0xba, 0xf7, 0x24, 0xdd, 0x54, 0x5b, 0x29, 0xf0, 0xbb, - 0xdd, 0xf2, 0xb2, 0x22, 0x92, 0x40, 0xc0, 0xa9, 0x14, 0x51, 0x1b, 0x4a, 0xbb, 0x36, 0x71, 0x1a, - 0x98, 0xec, 0x8a, 0x95, 0x32, 0xa6, 0xcc, 0xbb, 0x28, 0xa8, 0xf1, 0x8b, 0x04, 0xf9, 0x0f, 0x2b, - 0x2e, 0xe6, 0x35, 0x98, 0x8b, 0x5f, 0x2b, 0x0d, 0x31, 0x79, 0x67, 0x20, 0x6f, 0xf9, 0xae, 0x98, - 0xba, 0x69, 0x81, 0x90, 0xaf, 0xe0, 0x2b, 0x98, 0x96, 0x9b, 0x3f, 0x29, 0xc0, 0x7c, 0xd5, 0xe9, - 0x90, 0xe7, 0x7c, 0x42, 0xa4, 0x26, 0x5d, 0x81, 0xf9, 0xb6, 0x4f, 0xf6, 0x6d, 0x72, 0xbb, 0x46, - 0x1c, 0x52, 0x0f, 0x3d, 0x5f, 0xd0, 0x3f, 0x25, 0xaa, 0xcf, 0x6f, 0xc5, 0xc1, 0x38, 0x89, 0x8f, - 0x9e, 0x85, 0x39, 0xab, 0x1e, 0xda, 0xfb, 0x44, 0x51, 0xe0, 0x0d, 0x78, 0x8b, 0xa0, 0x30, 0x57, - 0x89, 0x41, 0x71, 0x02, 0x1b, 0x7d, 0x08, 0x96, 0x83, 0xba, 0xe5, 0x90, 0xeb, 0x6d, 0xc1, 0x6a, - 0x75, 0x8f, 0xd4, 0x6f, 0x6d, 0x79, 0xb6, 0x1b, 0x0a, 0xbb, 0xe9, 0x11, 0x41, 0x69, 0xb9, 0x36, - 0x00, 0x0f, 0x0f, 0xa4, 0x80, 0xfe, 0xcc, 0x80, 0x33, 0x6d, 0x9f, 0x6c, 0xf9, 0x5e, 0xcb, 0xa3, - 0x1b, 0xa2, 0xcf, 0x98, 0x10, 0x4a, 0xf5, 0x0b, 0x63, 0xee, 0x7c, 0x5e, 0xd2, 0x7f, 0x99, 0xf1, - 0xd6, 0x5e, 0xb7, 0x7c, 0x66, 0xeb, 0xb0, 0x06, 0xe0, 0xc3, 0xdb, 0x87, 0xfe, 0xc2, 0x80, 0xb3, - 0x6d, 0x2f, 0x08, 0x0f, 0xe9, 0x42, 0xf1, 0x58, 0xbb, 0x60, 0xf6, 0xba, 0xe5, 0xb3, 0x5b, 0x87, - 0xb6, 0x00, 0xdf, 0xa3, 0x85, 0x66, 0x6f, 0x1a, 0x16, 0xb5, 0xb5, 0x27, 0x34, 0xed, 0x67, 0x60, - 0x56, 0x2e, 0x06, 0x7e, 0x0b, 0xc9, 0xd7, 0x9e, 0xb2, 0x8c, 0x2a, 0x3a, 0x10, 0xc7, 0x71, 0xe9, - 0xba, 0x53, 0x4b, 0x91, 0xd7, 0x4e, 0xac, 0xbb, 0xad, 0x18, 0x14, 0x27, 0xb0, 0xd1, 0x3a, 0x9c, - 0x10, 0x25, 0x98, 0xb4, 0x1d, 0xbb, 0x6e, 0xad, 0x7a, 0x1d, 0xb1, 0xe4, 0x8a, 0xd5, 0x53, 0xbd, - 0x6e, 0xf9, 0xc4, 0x56, 0x3f, 0x18, 0xa7, 0xd5, 0x41, 0x1b, 0xb0, 0x64, 0x75, 0x42, 0x4f, 0xf5, - 0xff, 0x82, 0x6b, 0xed, 0x38, 0xa4, 0xc1, 0x96, 0x56, 0xa9, 0xba, 0x4c, 0x05, 0x51, 0x25, 0x05, - 0x8e, 0x53, 0x6b, 0xa1, 0xad, 0x04, 0xb5, 0x1a, 0xa9, 0x7b, 0x6e, 0x83, 0xcf, 0x72, 0x31, 0xd2, - 0x17, 0x2a, 0x29, 0x38, 0x38, 0xb5, 0x26, 0x72, 0x60, 0xae, 0x65, 0xdd, 0xb9, 0xee, 0x5a, 0xfb, - 0x96, 0xed, 0x50, 0x26, 0xc2, 0xda, 0x1a, 0x6c, 0x02, 0x74, 0x42, 0xdb, 0x59, 0xe1, 0x8e, 0x87, - 0x95, 0x75, 0x37, 0xbc, 0xea, 0xd7, 0x42, 0x7a, 0xae, 0x54, 0x11, 0x1d, 0xd8, 0xcd, 0x18, 0x2d, - 0x9c, 0xa0, 0x8d, 0xae, 0xc2, 0x49, 0xb6, 0x1d, 0xd7, 0xbc, 0xdb, 0xee, 0x1a, 0x71, 0xac, 0x03, - 0xd9, 0x81, 0x49, 0xd6, 0x81, 0x07, 0x7b, 0xdd, 0xf2, 0xc9, 0x5a, 0x1a, 0x02, 0x4e, 0xaf, 0x47, - 0x6d, 0xa6, 0x38, 0x00, 0x93, 0x7d, 0x3b, 0xb0, 0x3d, 0x97, 0xdb, 0x4c, 0xa5, 0xc8, 0x66, 0xaa, - 0x0d, 0x46, 0xc3, 0x87, 0xd1, 0x40, 0xbf, 0x63, 0xc0, 0x52, 0xda, 0x36, 0x5c, 0x9e, 0xca, 0xe2, - 0x5a, 0x35, 0xb1, 0xb5, 0xf8, 0x8a, 0x48, 0x15, 0x0a, 0xa9, 0x8d, 0x40, 0xaf, 0x18, 0x30, 0x63, - 0x69, 0xfa, 0xde, 0x32, 0xb0, 0x56, 0x5d, 0x1e, 0xd7, 0xea, 0x88, 0x28, 0x56, 0x17, 0x7a, 0xdd, - 0x72, 0x4c, 0xa7, 0xc4, 0x31, 0x8e, 0xe8, 0x77, 0x0d, 0x38, 0x99, 0xba, 0xc7, 0x97, 0xa7, 0x8f, - 0x63, 0x84, 0xd8, 0x22, 0x49, 0x97, 0x39, 0xe9, 0xcd, 0x40, 0x6f, 0x18, 0xea, 0x28, 0xdb, 0x94, - 0x76, 0xdf, 0x0c, 0x6b, 0xda, 0xb5, 0x31, 0x55, 0xdc, 0x48, 0x21, 0x90, 0x84, 0xab, 0x27, 0xb4, - 0x93, 0x51, 0x16, 0xe2, 0x24, 0x7b, 0xf4, 0x59, 0x43, 0x1e, 0x8d, 0xaa, 0x45, 0xb3, 0xc7, 0xd5, - 0x22, 0x14, 0x9d, 0xb4, 0xaa, 0x41, 0x09, 0xe6, 0xe8, 0xc3, 0x70, 0xda, 0xda, 0xf1, 0xfc, 0x30, - 0x75, 0xf3, 0x2d, 0xcf, 0xb1, 0x6d, 0x74, 0xb6, 0xd7, 0x2d, 0x9f, 0xae, 0x0c, 0xc4, 0xc2, 0x87, - 0x50, 0x30, 0xbf, 0x5f, 0x80, 0x19, 0xee, 0x8b, 0x13, 0x47, 0xd7, 0xd7, 0x0d, 0x78, 0xb8, 0xde, - 0xf1, 0x7d, 0xe2, 0x86, 0xb5, 0x90, 0xb4, 0xfb, 0x0f, 0x2e, 0xe3, 0x58, 0x0f, 0xae, 0x47, 0x7a, - 0xdd, 0xf2, 0xc3, 0xab, 0x87, 0xf0, 0xc7, 0x87, 0xb6, 0x0e, 0xfd, 0x8d, 0x01, 0xa6, 0x40, 0xa8, - 0x5a, 0xf5, 0x5b, 0x4d, 0xdf, 0xeb, 0xb8, 0x8d, 0xfe, 0x4e, 0xe4, 0x8e, 0xb5, 0x13, 0x8f, 0xf5, - 0xba, 0x65, 0x73, 0xf5, 0x9e, 0xad, 0xc0, 0x43, 0xb4, 0x14, 0x3d, 0x07, 0x8b, 0x02, 0xeb, 0xc2, - 0x9d, 0x36, 0xf1, 0x6d, 0xaa, 0x4e, 0x0b, 0xcf, 0x5f, 0xe4, 0x4c, 0x4d, 0x22, 0xe0, 0xfe, 0x3a, - 0x28, 0x80, 0xc9, 0xdb, 0xc4, 0x6e, 0xee, 0x85, 0x52, 0x7d, 0x1a, 0xd3, 0x83, 0x2a, 0xfc, 0x6d, - 0x37, 0x38, 0xcd, 0xea, 0x74, 0xaf, 0x5b, 0x9e, 0x14, 0x7f, 0xb0, 0xe4, 0x64, 0xfe, 0x51, 0x01, - 0x40, 0x2e, 0x2f, 0xd2, 0x46, 0xbf, 0x00, 0x53, 0x01, 0x09, 0x39, 0x96, 0xb8, 0x96, 0xe3, 0xb7, - 0x9d, 0xb2, 0x10, 0x47, 0x70, 0x74, 0x0b, 0x8a, 0x6d, 0xab, 0x13, 0x10, 0x31, 0x59, 0x97, 0x33, - 0x99, 0xac, 0x2d, 0x4a, 0x91, 0xdb, 0x48, 0xec, 0x27, 0xe6, 0x3c, 0xd0, 0xa7, 0x0c, 0x00, 0x12, - 0x1f, 0xe0, 0xe9, 0xf3, 0xb5, 0x4c, 0x58, 0x46, 0x73, 0x40, 0xc7, 0xa0, 0x3a, 0xd7, 0xeb, 0x96, - 0x41, 0x9b, 0x2a, 0x8d, 0x2d, 0xba, 0x0d, 0x25, 0x4b, 0xca, 0xe8, 0xc2, 0x71, 0xc8, 0x68, 0x66, - 0xba, 0xa8, 0x45, 0xa6, 0x98, 0xa1, 0x4f, 0x1b, 0x30, 0x17, 0x90, 0x50, 0x4c, 0x15, 0x95, 0x14, - 0x42, 0x41, 0x1d, 0x73, 0x91, 0xd4, 0x62, 0x34, 0xb9, 0xc4, 0x8b, 0x97, 0xe1, 0x04, 0x5f, 0xf3, - 0xfb, 0xd3, 0x30, 0x27, 0x97, 0x4c, 0xa4, 0x73, 0xf2, 0xe0, 0x80, 0x01, 0x3a, 0xe7, 0xaa, 0x0e, - 0xc4, 0x71, 0x5c, 0x5a, 0x99, 0x7b, 0xf0, 0xe3, 0x2a, 0xa7, 0xaa, 0x5c, 0xd3, 0x81, 0x38, 0x8e, - 0x8b, 0x5a, 0x50, 0x0c, 0x42, 0xd2, 0x96, 0xbe, 0x84, 0x31, 0xaf, 0xba, 0xa3, 0x9d, 0x10, 0xdd, - 0x16, 0xd2, 0x7f, 0x01, 0xe6, 0x5c, 0xd0, 0xe7, 0x0c, 0x98, 0x0b, 0x63, 0x7e, 0x6c, 0xb1, 0x0c, - 0xb2, 0x59, 0x89, 0x71, 0x17, 0x39, 0x9f, 0x8d, 0x78, 0x19, 0x4e, 0xb0, 0x4f, 0x51, 0x43, 0x8b, - 0xc7, 0xa8, 0x86, 0xbe, 0x08, 0xa5, 0x96, 0x75, 0xa7, 0xd6, 0xf1, 0x9b, 0x47, 0x57, 0x77, 0x85, - 0x9b, 0x9f, 0x53, 0xc1, 0x8a, 0x1e, 0x7a, 0xd5, 0xd0, 0x36, 0xd7, 0x24, 0x23, 0x7e, 0x23, 0xdb, - 0xcd, 0xa5, 0xa4, 0xf8, 0xc0, 0x6d, 0xd6, 0xa7, 0x14, 0x96, 0xee, 0xbb, 0x52, 0x48, 0x15, 0x1c, - 0xbe, 0x41, 0x94, 0x82, 0x33, 0x75, 0xac, 0x0a, 0xce, 0x6a, 0x8c, 0x19, 0x4e, 0x30, 0x67, 0xed, - 0xe1, 0x7b, 0x4e, 0xb5, 0x07, 0x8e, 0xb5, 0x3d, 0xb5, 0x18, 0x33, 0x9c, 0x60, 0x3e, 0xd8, 0x12, - 0x9a, 0x3e, 0x1e, 0x4b, 0x68, 0x26, 0x03, 0x4b, 0xe8, 0x70, 0x25, 0x71, 0x76, 0x5c, 0x25, 0x11, - 0x5d, 0x06, 0xd4, 0x38, 0x70, 0xad, 0x96, 0x5d, 0x17, 0xc2, 0x92, 0x1d, 0x10, 0x73, 0xcc, 0x52, - 0x3e, 0x2d, 0x04, 0x19, 0x5a, 0xeb, 0xc3, 0xc0, 0x29, 0xb5, 0xcc, 0xff, 0x32, 0x60, 0x61, 0xd5, - 0xf1, 0x3a, 0x8d, 0x1b, 0x56, 0x58, 0xdf, 0xe3, 0x5e, 0x0a, 0xf4, 0x2c, 0x94, 0x6c, 0x37, 0x24, - 0xfe, 0xbe, 0xe5, 0x08, 0xd9, 0x6e, 0x4a, 0x47, 0xce, 0xba, 0x28, 0xbf, 0xdb, 0x2d, 0xcf, 0xad, - 0x75, 0x7c, 0x16, 0xfe, 0xc3, 0x77, 0x3a, 0x56, 0x75, 0xd0, 0x97, 0x0d, 0x58, 0xe4, 0x7e, 0x8e, - 0x35, 0x2b, 0xb4, 0xae, 0x75, 0x88, 0x6f, 0x13, 0xe9, 0xe9, 0x18, 0x73, 0x93, 0x27, 0xdb, 0x2a, - 0x19, 0x1c, 0x44, 0xea, 0xd7, 0x66, 0x92, 0x33, 0xee, 0x6f, 0x8c, 0xf9, 0xf9, 0x3c, 0x3c, 0x38, - 0x90, 0x16, 0x3a, 0x0d, 0x39, 0xbb, 0x21, 0xba, 0x0e, 0x82, 0x6e, 0x6e, 0xbd, 0x81, 0x73, 0x76, - 0x03, 0xad, 0x30, 0xcd, 0xc4, 0x27, 0x41, 0x20, 0x2f, 0xbd, 0xa7, 0x94, 0x12, 0x21, 0x4a, 0xb1, - 0x86, 0x81, 0xca, 0x50, 0x74, 0xac, 0x1d, 0xe2, 0x08, 0x2d, 0x91, 0xe9, 0x3a, 0x1b, 0xb4, 0x00, - 0xf3, 0x72, 0xf4, 0xab, 0x06, 0x00, 0x6f, 0x20, 0xd5, 0x31, 0xc5, 0x09, 0x83, 0xb3, 0x1d, 0x26, - 0x4a, 0x99, 0xb7, 0x32, 0xfa, 0x8f, 0x35, 0xae, 0x68, 0x1b, 0x26, 0xa8, 0xda, 0xe3, 0x35, 0x8e, - 0x7c, 0xa0, 0x40, 0xaf, 0x5b, 0x9e, 0xd8, 0x62, 0x34, 0xb0, 0xa0, 0x45, 0xc7, 0xca, 0x27, 0x61, - 0xc7, 0x77, 0xe9, 0xd0, 0xb2, 0x23, 0xa4, 0xc4, 0x5b, 0x81, 0x55, 0x29, 0xd6, 0x30, 0xcc, 0x3f, - 0xcd, 0xc1, 0x52, 0x5a, 0xd3, 0xa9, 0xa4, 0x9e, 0xe0, 0xad, 0x15, 0x06, 0xcf, 0xfb, 0xb3, 0x1f, - 0x1f, 0xe1, 0xb2, 0x53, 0x8e, 0x2d, 0x11, 0x54, 0x20, 0xf8, 0xa2, 0xf7, 0xab, 0x11, 0xca, 0x1d, - 0x71, 0x84, 0x14, 0xe5, 0xc4, 0x28, 0x3d, 0x02, 0x85, 0x80, 0xce, 0x7c, 0x3e, 0x7e, 0x2d, 0xcd, - 0xe6, 0x88, 0x41, 0x28, 0x46, 0xc7, 0xb5, 0x43, 0x11, 0x93, 0xa7, 0x30, 0xae, 0xbb, 0x76, 0x88, - 0x19, 0xc4, 0xfc, 0x62, 0x0e, 0x4e, 0x0f, 0xee, 0x14, 0xfa, 0xa2, 0x01, 0xd0, 0xa0, 0x4a, 0x2d, - 0x5d, 0x92, 0xd2, 0xc5, 0x69, 0x1d, 0xd7, 0x18, 0xae, 0x49, 0x4e, 0x91, 0xbf, 0x5b, 0x15, 0x05, - 0x58, 0x6b, 0x08, 0x3a, 0x2f, 0x97, 0xfe, 0x15, 0xab, 0x25, 0x55, 0x41, 0x55, 0x67, 0x53, 0x41, - 0xb0, 0x86, 0x45, 0xad, 0x16, 0xd7, 0x6a, 0x91, 0xa0, 0x6d, 0xa9, 0xa0, 0x4b, 0x66, 0xb5, 0x5c, - 0x91, 0x85, 0x38, 0x82, 0x9b, 0x0e, 0x3c, 0x3a, 0x44, 0x3b, 0x33, 0x0a, 0x80, 0x33, 0xff, 0xd3, - 0x80, 0x53, 0xab, 0x4e, 0x27, 0x08, 0x89, 0xff, 0x7f, 0x26, 0x7c, 0xe0, 0xbf, 0x0d, 0x78, 0x68, - 0x40, 0x9f, 0xef, 0x43, 0x14, 0xc1, 0xcb, 0xf1, 0x28, 0x82, 0xeb, 0xe3, 0x2e, 0xe9, 0xd4, 0x7e, - 0x0c, 0x08, 0x26, 0x08, 0x61, 0x96, 0x4a, 0xad, 0x86, 0xd7, 0xcc, 0xe8, 0xdc, 0x7c, 0x14, 0x8a, - 0x1f, 0xa5, 0xe7, 0x4f, 0x72, 0x8d, 0xb1, 0x43, 0x09, 0x73, 0x98, 0xf9, 0x3e, 0x10, 0x2e, 0xf7, - 0xc4, 0xe6, 0x31, 0x86, 0xd9, 0x3c, 0xe6, 0x3f, 0xe4, 0x40, 0xb3, 0x76, 0xef, 0xc3, 0xa2, 0x74, - 0x63, 0x8b, 0x72, 0x4c, 0xfb, 0x55, 0xb3, 0xdd, 0x07, 0xc5, 0xd6, 0xee, 0x27, 0x62, 0x6b, 0xaf, - 0x64, 0xc6, 0xf1, 0xf0, 0xd0, 0xda, 0xef, 0x18, 0xf0, 0x50, 0x84, 0xdc, 0x7f, 0x71, 0x74, 0x6f, - 0x09, 0xf3, 0x14, 0x4c, 0x5b, 0x51, 0x35, 0xb1, 0x06, 0x54, 0x38, 0xb9, 0x46, 0x11, 0xeb, 0x78, - 0x51, 0x24, 0x5f, 0xfe, 0x88, 0x91, 0x7c, 0x85, 0xc3, 0x23, 0xf9, 0xcc, 0x1f, 0xe7, 0xe0, 0x4c, - 0x7f, 0xcf, 0xe4, 0xde, 0x18, 0xce, 0xaf, 0xfa, 0x34, 0xcc, 0x84, 0xa2, 0x82, 0x26, 0xe9, 0xd5, - 0x63, 0x88, 0x6d, 0x0d, 0x86, 0x63, 0x98, 0xb4, 0x66, 0x9d, 0xef, 0xca, 0x5a, 0xdd, 0x6b, 0xcb, - 0x38, 0x50, 0x55, 0x73, 0x55, 0x83, 0xe1, 0x18, 0xa6, 0x8a, 0xb0, 0x29, 0x1c, 0x7b, 0x84, 0x4d, - 0x0d, 0x4e, 0xca, 0x98, 0x82, 0x8b, 0x9e, 0xbf, 0xea, 0xb5, 0xda, 0x0e, 0x11, 0x91, 0xa0, 0xb4, - 0xb1, 0x67, 0x44, 0x95, 0x93, 0x38, 0x0d, 0x09, 0xa7, 0xd7, 0x35, 0xbf, 0x93, 0x87, 0x13, 0xd1, - 0xb0, 0xaf, 0x7a, 0x6e, 0xc3, 0x66, 0x91, 0x19, 0xcf, 0x40, 0x21, 0x3c, 0x68, 0xcb, 0xc1, 0xfe, - 0x7f, 0xb2, 0x39, 0xdb, 0x07, 0x6d, 0x3a, 0xdb, 0xa7, 0x52, 0xaa, 0x50, 0x10, 0x66, 0x95, 0xd0, - 0x86, 0xda, 0x1d, 0x7c, 0x06, 0x9e, 0x8c, 0xaf, 0xe6, 0xbb, 0xdd, 0x72, 0xca, 0x5b, 0xa0, 0x15, - 0x45, 0x29, 0xbe, 0xe6, 0xd1, 0x4d, 0x98, 0x73, 0xac, 0x20, 0xbc, 0xde, 0x6e, 0x58, 0x21, 0xd9, - 0xb6, 0x5b, 0x44, 0xec, 0xb9, 0x51, 0xc2, 0x2b, 0x95, 0xaf, 0x71, 0x23, 0x46, 0x09, 0x27, 0x28, - 0xa3, 0x7d, 0x40, 0xb4, 0x64, 0xdb, 0xb7, 0xdc, 0x80, 0xf7, 0x8a, 0xf2, 0x1b, 0x3d, 0x9c, 0x53, - 0x19, 0x48, 0x1b, 0x7d, 0xd4, 0x70, 0x0a, 0x07, 0xf4, 0x18, 0x4c, 0xf8, 0xc4, 0x0a, 0xc4, 0x64, - 0x4e, 0x45, 0xfb, 0x1f, 0xb3, 0x52, 0x2c, 0xa0, 0xfa, 0x86, 0x9a, 0xb8, 0xc7, 0x86, 0xfa, 0x81, - 0x01, 0x73, 0xd1, 0x34, 0xdd, 0x87, 0x43, 0xb2, 0x15, 0x3f, 0x24, 0x2f, 0x65, 0x25, 0x12, 0x07, - 0x9c, 0x8b, 0x5f, 0x2e, 0xea, 0xfd, 0x63, 0xe1, 0x75, 0x1f, 0x83, 0x29, 0xb9, 0xab, 0xa5, 0xf6, - 0x39, 0xe6, 0x2d, 0x4b, 0x4c, 0x2f, 0xd1, 0xc2, 0xc2, 0x05, 0x13, 0x1c, 0xf1, 0xa3, 0xc7, 0x72, - 0x43, 0x1c, 0xb9, 0x62, 0xd9, 0xab, 0x63, 0x59, 0x1e, 0xc5, 0x69, 0xc7, 0xb2, 0xac, 0x83, 0xae, - 0xc3, 0xa9, 0xb6, 0xef, 0xb1, 0xa7, 0x42, 0x6b, 0xc4, 0x6a, 0x38, 0xb6, 0x4b, 0xa4, 0x31, 0xcf, - 0x5d, 0xdd, 0x0f, 0xf5, 0xba, 0xe5, 0x53, 0x5b, 0xe9, 0x28, 0x78, 0x50, 0xdd, 0x78, 0x78, 0x7b, - 0x61, 0x88, 0xf0, 0xf6, 0x5f, 0x57, 0x57, 0x66, 0x24, 0x10, 0x41, 0xe6, 0x1f, 0xcc, 0x6a, 0x2a, - 0x53, 0xc4, 0x7a, 0xb4, 0xa4, 0x2a, 0x82, 0x29, 0x56, 0xec, 0x07, 0xdf, 0xcb, 0x4c, 0x1c, 0xf1, - 0x5e, 0x26, 0x8a, 0x52, 0x9c, 0x3c, 0xfe, 0x28, 0x45, 0xf3, 0xb5, 0x22, 0x2c, 0x24, 0x8f, 0xf6, - 0xe3, 0x8f, 0x89, 0xff, 0x2d, 0x03, 0x16, 0xe4, 0xb2, 0xe4, 0x3c, 0x89, 0xbc, 0xca, 0xde, 0xc8, - 0x68, 0x37, 0x70, 0x25, 0x45, 0xbd, 0xda, 0xda, 0x4e, 0x70, 0xc3, 0x7d, 0xfc, 0xd1, 0x4b, 0x30, - 0xad, 0x6e, 0x7c, 0x8f, 0x14, 0x20, 0x3f, 0xcf, 0xd4, 0x93, 0x88, 0x04, 0xd6, 0xe9, 0xa1, 0xd7, - 0x0c, 0x80, 0xba, 0x3c, 0x3f, 0xe4, 0xb2, 0xbd, 0x96, 0xd5, 0xb2, 0x55, 0x27, 0x53, 0xa4, 0x85, - 0xaa, 0xa2, 0x00, 0x6b, 0x8c, 0xd1, 0xe7, 0xd9, 0x5d, 0xaf, 0x52, 0x9b, 0xe8, 0x42, 0xa5, 0x2d, - 0xf9, 0x40, 0xd6, 0x1b, 0x28, 0x72, 0x3b, 0x2a, 0x1d, 0x45, 0x03, 0x05, 0x38, 0xd6, 0x08, 0xf3, - 0x19, 0x50, 0x91, 0x6b, 0x54, 0x1e, 0xb0, 0xd8, 0xb5, 0x2d, 0x2b, 0xdc, 0x13, 0x4b, 0x50, 0xc9, - 0x83, 0x8b, 0x12, 0x80, 0x23, 0x1c, 0xf3, 0x23, 0x30, 0xf7, 0x9c, 0x6f, 0xb5, 0xf7, 0x6c, 0x76, - 0xa7, 0x4a, 0x0d, 0x90, 0xb7, 0xc3, 0xa4, 0xd5, 0x68, 0xa4, 0xbd, 0x79, 0xac, 0xf0, 0x62, 0x2c, - 0xe1, 0xc3, 0xd9, 0x1a, 0xdf, 0x30, 0x60, 0x69, 0x3d, 0x08, 0x6d, 0x6f, 0x8d, 0x04, 0x21, 0x15, - 0x42, 0x54, 0x5f, 0xe9, 0x38, 0x64, 0x08, 0x8d, 0x6f, 0x0d, 0x16, 0x84, 0xe3, 0xa7, 0xb3, 0x13, - 0x90, 0x50, 0xd3, 0xfa, 0xd4, 0xe2, 0x5c, 0x4d, 0xc0, 0x71, 0x5f, 0x0d, 0x4a, 0x45, 0x78, 0x80, - 0x22, 0x2a, 0xf9, 0x38, 0x95, 0x5a, 0x02, 0x8e, 0xfb, 0x6a, 0x98, 0xdf, 0xce, 0xc3, 0x09, 0xd6, - 0x8d, 0xc4, 0xa3, 0xc4, 0xcf, 0x1a, 0x30, 0xb7, 0x6f, 0xfb, 0x61, 0xc7, 0x72, 0x74, 0x57, 0xd6, - 0xd8, 0xeb, 0x93, 0xf1, 0x7a, 0x21, 0x46, 0x98, 0x5f, 0x76, 0xc7, 0xcb, 0x70, 0x82, 0x39, 0xfa, - 0x4d, 0x03, 0xe6, 0x1b, 0xf1, 0x91, 0xce, 0xc6, 0x98, 0x4f, 0x9b, 0x43, 0x1e, 0x81, 0x91, 0x28, - 0xc4, 0x49, 0xfe, 0xe8, 0x0b, 0x06, 0xcc, 0xc7, 0x9b, 0x29, 0x45, 0xd6, 0x31, 0x0c, 0x92, 0x0a, - 0x99, 0x8c, 0x97, 0x07, 0x38, 0xd9, 0x04, 0xf3, 0xef, 0x0c, 0x31, 0xa5, 0x71, 0xcc, 0x21, 0x16, - 0xa6, 0x09, 0x13, 0xbe, 0xd7, 0x09, 0xc5, 0x85, 0xf4, 0x14, 0xbf, 0xb7, 0xc4, 0xac, 0x04, 0x0b, - 0x08, 0xba, 0x0d, 0x53, 0xa1, 0x13, 0xf0, 0x42, 0xd1, 0xdb, 0x31, 0xed, 0x87, 0xed, 0x8d, 0x1a, - 0x23, 0xa7, 0x1d, 0xf1, 0xa2, 0x84, 0xaa, 0x2a, 0x92, 0x97, 0xf9, 0x55, 0x03, 0xa6, 0x2e, 0x7b, - 0x3b, 0x62, 0x3b, 0x7f, 0x38, 0x03, 0xeb, 0x5c, 0x1d, 0xe2, 0xca, 0xc5, 0x12, 0xe9, 0x85, 0xcf, - 0xc6, 0x6c, 0xf3, 0x87, 0x35, 0xda, 0x2b, 0x2c, 0x57, 0x00, 0x25, 0x75, 0xd9, 0xdb, 0x19, 0x78, - 0xf5, 0xf3, 0x7b, 0x45, 0x98, 0x7d, 0xde, 0x3a, 0x20, 0x6e, 0x68, 0x8d, 0x2e, 0x80, 0xa8, 0xb9, - 0xdb, 0x66, 0x11, 0x80, 0x9a, 0x62, 0x16, 0x99, 0xbb, 0x11, 0x08, 0xeb, 0x78, 0x91, 0x5c, 0xe1, - 0x4f, 0x97, 0xd3, 0x24, 0xc2, 0x6a, 0x02, 0x8e, 0xfb, 0x6a, 0xa0, 0xcb, 0x80, 0xc4, 0x43, 0x8c, - 0x4a, 0xbd, 0xee, 0x75, 0x5c, 0x2e, 0x59, 0xb8, 0x25, 0xac, 0x2c, 0x84, 0xcd, 0x3e, 0x0c, 0x9c, - 0x52, 0x0b, 0x7d, 0x08, 0x96, 0xeb, 0x8c, 0xb2, 0xd0, 0x17, 0x75, 0x8a, 0xdc, 0x66, 0x50, 0xd1, - 0xb7, 0xab, 0x03, 0xf0, 0xf0, 0x40, 0x0a, 0xb4, 0xa5, 0x41, 0xe8, 0xf9, 0x56, 0x93, 0xe8, 0x74, - 0x27, 0xe2, 0x2d, 0xad, 0xf5, 0x61, 0xe0, 0x94, 0x5a, 0xe8, 0x93, 0x30, 0x15, 0xee, 0xf9, 0x24, - 0xd8, 0xf3, 0x9c, 0x86, 0xf0, 0xb9, 0x8e, 0x79, 0x3d, 0x22, 0x66, 0x7f, 0x5b, 0x52, 0xd5, 0x96, - 0xb7, 0x2c, 0xc2, 0x11, 0x4f, 0xe4, 0xc3, 0x44, 0x40, 0x6d, 0xf3, 0x60, 0xb9, 0x94, 0x85, 0x0d, - 0x20, 0xb8, 0x33, 0x73, 0x5f, 0xbb, 0x98, 0x61, 0x1c, 0xb0, 0xe0, 0x64, 0x7e, 0x33, 0x07, 0x33, - 0x3a, 0xe2, 0x10, 0x22, 0xe2, 0x53, 0x06, 0xcc, 0xd4, 0x3d, 0x37, 0xf4, 0x3d, 0x87, 0x5f, 0x3a, - 0xf0, 0x0d, 0x32, 0xe6, 0xfb, 0x5e, 0x46, 0x6a, 0x8d, 0x84, 0x96, 0xed, 0x68, 0xf7, 0x17, 0x1a, - 0x1b, 0x1c, 0x63, 0x8a, 0x3e, 0x63, 0xc0, 0x7c, 0x14, 0x8c, 0x12, 0xdd, 0x7e, 0x64, 0xda, 0x10, - 0x25, 0x71, 0x2f, 0xc4, 0x39, 0xe1, 0x24, 0x6b, 0x73, 0x07, 0x16, 0x92, 0xb3, 0x4d, 0x87, 0xb2, - 0x6d, 0x89, 0xbd, 0x9e, 0x8f, 0x86, 0x72, 0xcb, 0x0a, 0x02, 0xcc, 0x20, 0xe8, 0x1d, 0x50, 0x6a, - 0x59, 0x7e, 0xd3, 0x76, 0x2d, 0x87, 0x8d, 0x62, 0x5e, 0x13, 0x48, 0xa2, 0x1c, 0x2b, 0x0c, 0xf3, - 0x47, 0x05, 0x98, 0xd6, 0x1e, 0xf1, 0x1c, 0xbf, 0x46, 0x1e, 0x7b, 0x1b, 0x9a, 0xcf, 0xf0, 0x6d, - 0xe8, 0x8b, 0x00, 0xbb, 0xb6, 0x6b, 0x07, 0x7b, 0x47, 0x7c, 0x75, 0xca, 0xbc, 0x64, 0x17, 0x15, - 0x05, 0xac, 0x51, 0x8b, 0x5c, 0x11, 0xc5, 0x43, 0xde, 0xe2, 0xbf, 0x66, 0x68, 0x87, 0xc7, 0x44, - 0x16, 0xae, 0x57, 0x6d, 0x62, 0x56, 0xe4, 0x61, 0x72, 0xc1, 0x0d, 0xfd, 0x83, 0x43, 0xcf, 0x98, - 0x6d, 0x28, 0xf9, 0x24, 0xe8, 0xb4, 0xa8, 0x6d, 0x31, 0x39, 0xf2, 0x30, 0xb0, 0xc8, 0x0d, 0x2c, - 0xea, 0x63, 0x45, 0xe9, 0xf4, 0x33, 0x30, 0x1b, 0x6b, 0x02, 0x5a, 0x80, 0xfc, 0x2d, 0x72, 0xc0, - 0xd7, 0x09, 0xa6, 0x3f, 0xd1, 0x52, 0xcc, 0x61, 0x23, 0x86, 0xe5, 0xbd, 0xb9, 0xa7, 0x0d, 0xd3, - 0x83, 0xd4, 0x97, 0x62, 0x47, 0xb9, 0x4f, 0xa7, 0x73, 0xe1, 0x68, 0xcf, 0x4e, 0xd5, 0x5c, 0xf0, - 0x30, 0x01, 0x0e, 0x33, 0x7f, 0x3c, 0x01, 0xc2, 0x9b, 0x38, 0x84, 0xf0, 0xd1, 0x9d, 0x08, 0xb9, - 0x23, 0x38, 0x11, 0x2e, 0xc3, 0x8c, 0xed, 0xda, 0xa1, 0x6d, 0x39, 0xcc, 0xbe, 0x16, 0x87, 0xe3, - 0x63, 0x52, 0xe0, 0xac, 0x6b, 0xb0, 0x14, 0x3a, 0xb1, 0xba, 0xe8, 0x1a, 0x14, 0xd9, 0xe9, 0x21, - 0x16, 0xf0, 0xe8, 0x2e, 0x4f, 0xe6, 0xed, 0xe6, 0x61, 0xff, 0x9c, 0x12, 0xd3, 0xe8, 0xf9, 0xbb, - 0x5b, 0x65, 0xa8, 0x89, 0x75, 0x1c, 0x69, 0xf4, 0x09, 0x38, 0xee, 0xab, 0x41, 0xa9, 0xec, 0x5a, - 0xb6, 0xd3, 0xf1, 0x49, 0x44, 0x65, 0x22, 0x4e, 0xe5, 0x62, 0x02, 0x8e, 0xfb, 0x6a, 0xa0, 0x5d, - 0x98, 0x11, 0x65, 0x3c, 0xf8, 0x63, 0xf2, 0x88, 0xbd, 0x64, 0x41, 0x3e, 0x17, 0x35, 0x4a, 0x38, - 0x46, 0x17, 0x75, 0x60, 0xd1, 0x76, 0xeb, 0x9e, 0x5b, 0x77, 0x3a, 0x81, 0xbd, 0x4f, 0xa2, 0x98, - 0xfb, 0xa3, 0x30, 0x3b, 0xd9, 0xeb, 0x96, 0x17, 0xd7, 0x93, 0xe4, 0x70, 0x3f, 0x07, 0xf4, 0xaa, - 0x01, 0x27, 0xeb, 0x9e, 0x1b, 0xb0, 0x87, 0x6c, 0xfb, 0xe4, 0x82, 0xef, 0x7b, 0x3e, 0xe7, 0x3d, - 0x75, 0x44, 0xde, 0xec, 0x5a, 0x67, 0x35, 0x8d, 0x24, 0x4e, 0xe7, 0x84, 0x5e, 0x86, 0x52, 0xdb, - 0xf7, 0xf6, 0xed, 0x06, 0xf1, 0x45, 0x20, 0xd1, 0x46, 0x16, 0x0f, 0x6b, 0xb7, 0x04, 0xcd, 0x48, - 0xf4, 0xc8, 0x12, 0xac, 0xf8, 0x99, 0x7f, 0x58, 0x82, 0xb9, 0x38, 0x3a, 0xfa, 0x04, 0x40, 0xdb, - 0xf7, 0x5a, 0x24, 0xdc, 0x23, 0x2a, 0x76, 0xfa, 0xca, 0xb8, 0xef, 0x37, 0x25, 0x3d, 0x19, 0x40, - 0x40, 0xc5, 0x45, 0x54, 0x8a, 0x35, 0x8e, 0xc8, 0x87, 0xc9, 0x5b, 0xfc, 0x10, 0x15, 0x3a, 0xc5, - 0xf3, 0x99, 0x68, 0x40, 0x82, 0x33, 0x0b, 0xfa, 0x15, 0x45, 0x58, 0x32, 0x42, 0x3b, 0x90, 0xbf, - 0x4d, 0x76, 0xb2, 0x79, 0x69, 0x78, 0x83, 0x08, 0xdb, 0xa4, 0x3a, 0xd9, 0xeb, 0x96, 0xf3, 0x37, - 0xc8, 0x0e, 0xa6, 0xc4, 0x69, 0xbf, 0x1a, 0xdc, 0x15, 0x2a, 0x44, 0xc5, 0x98, 0xfd, 0x8a, 0xf9, - 0x55, 0x79, 0xbf, 0x44, 0x11, 0x96, 0x8c, 0xd0, 0xcb, 0x30, 0x75, 0xdb, 0xda, 0x27, 0xbb, 0xbe, - 0xe7, 0x86, 0x22, 0x6a, 0x65, 0xcc, 0xf0, 0xdc, 0x1b, 0x92, 0x9c, 0xe0, 0xcb, 0x8e, 0x77, 0x55, - 0x88, 0x23, 0x76, 0x68, 0x1f, 0x4a, 0x2e, 0xb9, 0x8d, 0x89, 0x63, 0xd7, 0x45, 0x64, 0xe4, 0x98, - 0xcb, 0xfa, 0x8a, 0xa0, 0x26, 0x38, 0xb3, 0x73, 0x4f, 0x96, 0x61, 0xc5, 0x8b, 0xce, 0xe5, 0x4d, - 0x6f, 0x47, 0x08, 0xaa, 0x31, 0xe7, 0x52, 0xd9, 0x99, 0x7c, 0x2e, 0x2f, 0x7b, 0x3b, 0x98, 0x12, - 0xa7, 0x7b, 0xa4, 0xae, 0x42, 0x26, 0x84, 0x98, 0xba, 0x92, 0x6d, 0xa8, 0x08, 0xdf, 0x23, 0x51, - 0x29, 0xd6, 0x38, 0xd2, 0xb1, 0x6d, 0x8a, 0x6b, 0x2d, 0x21, 0xa8, 0xc6, 0x1c, 0xdb, 0xf8, 0x25, - 0x19, 0x1f, 0x5b, 0x59, 0x86, 0x15, 0x2f, 0xf3, 0x5f, 0x0a, 0x30, 0xa3, 0x27, 0x12, 0x19, 0xe2, - 0xac, 0x56, 0xfa, 0x69, 0x6e, 0x14, 0xfd, 0x94, 0x9a, 0x17, 0xda, 0xa3, 0x74, 0x79, 0xc3, 0xb0, - 0x9e, 0x99, 0x7a, 0x16, 0x99, 0x17, 0x5a, 0x61, 0x80, 0x63, 0x4c, 0x47, 0xf0, 0x00, 0x53, 0x25, - 0x87, 0xab, 0x01, 0xc5, 0xb8, 0x92, 0x13, 0x3b, 0xd8, 0xcf, 0x03, 0x44, 0x09, 0x35, 0x84, 0x1b, - 0x40, 0x69, 0x4f, 0x5a, 0xa2, 0x0f, 0x0d, 0x0b, 0x3d, 0x06, 0x13, 0xf4, 0xa0, 0x24, 0x0d, 0xf1, - 0xb0, 0x4d, 0xd9, 0x70, 0x17, 0x59, 0x29, 0x16, 0x50, 0xf4, 0x34, 0xd5, 0x69, 0xa2, 0xe3, 0x4d, - 0xbc, 0x57, 0x5b, 0x8a, 0x74, 0x9a, 0x08, 0x86, 0x63, 0x98, 0xb4, 0xe9, 0x84, 0x9e, 0x46, 0x6c, - 0x25, 0x69, 0x4d, 0x67, 0x47, 0x14, 0xe6, 0x30, 0x76, 0xa7, 0x90, 0x38, 0xbd, 0xd8, 0x61, 0x55, - 0xd4, 0xee, 0x14, 0x12, 0x70, 0xdc, 0x57, 0x83, 0x76, 0x46, 0x78, 0x30, 0xa6, 0x79, 0xa0, 0xdb, - 0x00, 0xdf, 0xc3, 0x47, 0x60, 0x2e, 0xbe, 0xdb, 0xe9, 0x54, 0xb4, 0x7d, 0x6f, 0xd7, 0x76, 0x48, - 0xf2, 0xd6, 0x64, 0x8b, 0x17, 0x63, 0x09, 0x1f, 0xee, 0xda, 0xf6, 0xaf, 0xf2, 0x70, 0xe2, 0x4a, - 0xd3, 0x76, 0xef, 0x24, 0xee, 0x3b, 0xd3, 0xd2, 0xbc, 0x19, 0xa3, 0xa6, 0x79, 0x8b, 0x22, 0xf8, - 0x45, 0x1e, 0xbd, 0xf4, 0x08, 0x7e, 0x99, 0x64, 0x2f, 0x8e, 0x8b, 0x7e, 0x60, 0xc0, 0xc3, 0x56, - 0x83, 0xeb, 0x5f, 0x96, 0x23, 0x4a, 0x23, 0xa6, 0x72, 0x2f, 0x04, 0x63, 0x4a, 0xd3, 0xfe, 0xce, - 0xaf, 0x54, 0x0e, 0xe1, 0xca, 0xcd, 0x98, 0xb7, 0x89, 0x1e, 0x3c, 0x7c, 0x18, 0x2a, 0x3e, 0xb4, - 0xf9, 0xa7, 0xaf, 0xc2, 0x5b, 0xef, 0xc9, 0x68, 0x24, 0x63, 0xe5, 0x53, 0x06, 0x4c, 0xf1, 0xeb, - 0x3c, 0x4c, 0x76, 0xe9, 0x26, 0xb3, 0xda, 0xf6, 0x0b, 0xc4, 0x0f, 0x64, 0xfe, 0x09, 0xcd, 0x44, - 0xa9, 0x6c, 0xad, 0x0b, 0x08, 0xd6, 0xb0, 0xa8, 0x18, 0xbb, 0x65, 0xbb, 0x0d, 0x31, 0x4d, 0x4a, - 0x8c, 0x3d, 0x6f, 0xbb, 0x0d, 0xcc, 0x20, 0x4a, 0xd0, 0xe5, 0x07, 0x09, 0x3a, 0xf3, 0x2b, 0x06, - 0xcc, 0xb1, 0x07, 0x3a, 0x91, 0xf2, 0xfc, 0x94, 0x72, 0x8c, 0xf3, 0x66, 0x9c, 0x89, 0x3b, 0xc6, - 0xef, 0x76, 0xcb, 0xd3, 0xfc, 0x49, 0x4f, 0xdc, 0x4f, 0xfe, 0x41, 0x61, 0x71, 0x33, 0xf7, 0x7d, - 0x6e, 0x64, 0x83, 0x50, 0xdd, 0x2f, 0xd5, 0x24, 0x11, 0x1c, 0xd1, 0x33, 0xff, 0x38, 0x0f, 0x27, - 0x52, 0x22, 0xcd, 0xa9, 0x31, 0x3c, 0xc1, 0x82, 0x6d, 0xa5, 0xf3, 0xf9, 0xa5, 0xcc, 0xa3, 0xd9, - 0x57, 0x58, 0x4c, 0xaf, 0x58, 0x49, 0x6a, 0xeb, 0xf3, 0x42, 0x2c, 0x98, 0xa3, 0xdf, 0x36, 0x60, - 0xda, 0xd2, 0x16, 0x3b, 0xf7, 0xc7, 0xef, 0x64, 0xdf, 0x98, 0xbe, 0xb5, 0xad, 0xc5, 0x11, 0x45, - 0x4b, 0x59, 0x6f, 0xcb, 0xe9, 0xf7, 0xc0, 0xb4, 0xd6, 0x85, 0x51, 0xd6, 0xe8, 0xe9, 0x67, 0x61, - 0x61, 0xac, 0x35, 0xfe, 0x01, 0x18, 0x35, 0xa1, 0x09, 0x15, 0xb6, 0xb7, 0xf5, 0x77, 0x6b, 0x6a, - 0xc4, 0xc5, 0xc3, 0x35, 0x01, 0x35, 0x77, 0x60, 0x21, 0xa9, 0xa0, 0x67, 0xee, 0x25, 0x7b, 0x17, - 0x8c, 0x98, 0x82, 0xc4, 0xfc, 0xeb, 0x1c, 0x4c, 0x8a, 0xe7, 0x2a, 0xf7, 0x21, 0x04, 0xef, 0x56, - 0xec, 0x9a, 0x7f, 0x3d, 0x93, 0x57, 0x36, 0x03, 0xe3, 0xef, 0x82, 0x44, 0xfc, 0xdd, 0xf3, 0xd9, - 0xb0, 0x3b, 0x3c, 0xf8, 0xee, 0x2b, 0x05, 0x98, 0x4f, 0x3c, 0xff, 0x41, 0xaf, 0x1b, 0xfd, 0x31, - 0x27, 0xd7, 0x33, 0x7d, 0x61, 0xa4, 0xc2, 0x43, 0x0f, 0x0f, 0x3f, 0x09, 0x62, 0x99, 0x9e, 0xae, - 0x65, 0x96, 0x24, 0xf2, 0xe7, 0x49, 0x9f, 0x46, 0x4d, 0xfa, 0xf4, 0xcf, 0x06, 0x3c, 0x38, 0xf0, - 0x95, 0x18, 0x7b, 0xfe, 0xee, 0xc7, 0xa1, 0x62, 0x43, 0x66, 0xfc, 0xea, 0x53, 0xdd, 0xb9, 0x27, - 0x5f, 0x2c, 0x27, 0xd9, 0xa3, 0x27, 0x61, 0x86, 0x1d, 0x6e, 0x54, 0xa6, 0x84, 0xa4, 0x2d, 0x2e, - 0x19, 0xd9, 0x75, 0x53, 0x4d, 0x2b, 0xc7, 0x31, 0x2c, 0xf3, 0xcb, 0x06, 0x2c, 0x0f, 0x7a, 0x0c, - 0x3d, 0x84, 0x51, 0xf3, 0x4b, 0x89, 0x18, 0xc1, 0x72, 0x5f, 0x8c, 0x60, 0xc2, 0xac, 0x91, 0xe1, - 0x80, 0x9a, 0x45, 0x91, 0xbf, 0x47, 0x08, 0xdc, 0x67, 0x0d, 0x38, 0x35, 0x60, 0x37, 0xf5, 0xc5, - 0x8a, 0x1a, 0x47, 0x8e, 0x15, 0xcd, 0x0d, 0x1b, 0x2b, 0x6a, 0xfe, 0x6d, 0x1e, 0x16, 0x44, 0x7b, - 0x22, 0x0d, 0xe7, 0xe9, 0x58, 0xa4, 0xe5, 0xdb, 0x12, 0x91, 0x96, 0x4b, 0x49, 0xfc, 0x9f, 0x87, - 0x59, 0xfe, 0x6c, 0x85, 0x59, 0xfe, 0x24, 0x07, 0x27, 0x53, 0xdf, 0x7c, 0xa3, 0x4f, 0xa7, 0x1c, - 0x0d, 0x37, 0x32, 0x7e, 0x5c, 0x3e, 0xe4, 0xe1, 0x30, 0x6e, 0x6c, 0xe2, 0x17, 0xf4, 0x98, 0x40, - 0x2e, 0xea, 0x77, 0x8f, 0xe1, 0x99, 0xfc, 0x88, 0xe1, 0x81, 0xe6, 0x6f, 0xe4, 0xe1, 0xf1, 0x61, - 0x09, 0xfd, 0x8c, 0x86, 0x8f, 0x07, 0xb1, 0xf0, 0xf1, 0xfb, 0x74, 0x6c, 0x1f, 0x4b, 0x24, 0xf9, - 0x57, 0xf3, 0xea, 0xd8, 0xeb, 0x5f, 0x9f, 0x43, 0x79, 0xa4, 0x26, 0xa9, 0x6a, 0x27, 0x33, 0xb7, - 0x45, 0xa2, 0x70, 0xb2, 0xc6, 0x8b, 0xef, 0x76, 0xcb, 0x8b, 0x22, 0x9b, 0x53, 0x8d, 0x84, 0xa2, - 0x10, 0xcb, 0x4a, 0xe8, 0x71, 0x28, 0xf9, 0x1c, 0x2a, 0x03, 0x66, 0x85, 0x5b, 0x8f, 0x97, 0x61, - 0x05, 0x45, 0x9f, 0xd4, 0x74, 0xe1, 0xc2, 0x71, 0x3d, 0x3b, 0x3e, 0xcc, 0x5b, 0xf9, 0x12, 0x94, - 0x02, 0x99, 0x83, 0x8d, 0x5f, 0x29, 0x3f, 0x31, 0x64, 0x1c, 0x36, 0x35, 0x9d, 0x64, 0x42, 0x36, - 0xde, 0x3f, 0x95, 0xae, 0x4d, 0x91, 0x44, 0xa6, 0xb2, 0x5a, 0xf8, 0xfd, 0x18, 0xa4, 0x58, 0x2c, - 0xdf, 0x31, 0x60, 0x5a, 0xcc, 0xd6, 0x7d, 0x08, 0x0d, 0xbf, 0x19, 0x0f, 0x0d, 0xbf, 0x90, 0x89, - 0xec, 0x18, 0x10, 0x17, 0x7e, 0x13, 0x66, 0xf4, 0xb4, 0x1f, 0xe8, 0x45, 0x4d, 0xf6, 0x19, 0xe3, - 0xa4, 0x17, 0x90, 0xd2, 0x31, 0x92, 0x8b, 0xe6, 0x97, 0x4a, 0x6a, 0x14, 0x59, 0x00, 0xba, 0xbe, - 0x06, 0x8d, 0x43, 0xd7, 0xa0, 0xbe, 0x04, 0x72, 0xd9, 0x2f, 0x81, 0x6b, 0x50, 0x92, 0x02, 0x4a, - 0x1c, 0xe3, 0x8f, 0xea, 0x71, 0x57, 0x54, 0x17, 0xa0, 0xc4, 0xb4, 0x85, 0xcb, 0x4c, 0x2d, 0x35, - 0x87, 0x4a, 0x70, 0x2a, 0x32, 0xe8, 0x65, 0x98, 0xbe, 0xed, 0xf9, 0xb7, 0x1c, 0xcf, 0x62, 0xd9, - 0x15, 0x21, 0x0b, 0xe7, 0x80, 0xba, 0x72, 0xe2, 0xe1, 0xbd, 0x37, 0x22, 0xfa, 0x58, 0x67, 0x86, - 0x2a, 0x30, 0xdf, 0xb2, 0x5d, 0x4c, 0xac, 0x86, 0x8a, 0x00, 0x2f, 0xf0, 0xf4, 0x6f, 0x52, 0xc9, - 0xdd, 0x8c, 0x83, 0x71, 0x12, 0x1f, 0x7d, 0x0c, 0x4a, 0x81, 0x48, 0x2d, 0x92, 0x8d, 0x1b, 0x47, - 0xd9, 0x8c, 0x9c, 0x68, 0x34, 0x76, 0xb2, 0x04, 0x2b, 0x86, 0x68, 0x03, 0x96, 0x7c, 0xf1, 0x78, - 0x3f, 0x96, 0x45, 0x9a, 0xef, 0x4f, 0x96, 0x65, 0x0c, 0xa7, 0xc0, 0x71, 0x6a, 0x2d, 0xaa, 0xc5, - 0xb0, 0xfc, 0x35, 0xfc, 0x3e, 0x5b, 0xbb, 0x02, 0x66, 0x0b, 0xbe, 0x81, 0x05, 0xf4, 0xb0, 0x17, - 0x05, 0xa5, 0x31, 0x5e, 0x14, 0xd4, 0xe0, 0x64, 0x12, 0xc4, 0x52, 0x0c, 0xb0, 0xac, 0x06, 0xda, - 0xe9, 0xb1, 0x95, 0x86, 0x84, 0xd3, 0xeb, 0xa2, 0x1b, 0x30, 0xe5, 0x13, 0x66, 0x5f, 0x54, 0xa4, - 0xe3, 0x78, 0xe4, 0x10, 0x19, 0x2c, 0x09, 0xe0, 0x88, 0x16, 0x9d, 0x77, 0x2b, 0x9e, 0x01, 0xed, - 0x5a, 0x86, 0xdf, 0xc1, 0x10, 0x73, 0x3f, 0x20, 0xf5, 0x87, 0xf9, 0xe6, 0x1c, 0xcc, 0xc6, 0xee, - 0x16, 0xd0, 0xa3, 0x50, 0x64, 0x39, 0x17, 0x98, 0x78, 0x28, 0x45, 0x22, 0x8c, 0x0f, 0x0e, 0x87, - 0xa1, 0xcf, 0x19, 0x30, 0xdf, 0x8e, 0xdd, 0x83, 0x4a, 0xc9, 0x39, 0xa6, 0x8f, 0x2a, 0x7e, 0xb9, - 0xaa, 0xe5, 0x0e, 0x8d, 0x33, 0xc3, 0x49, 0xee, 0x74, 0x03, 0x8a, 0xa8, 0x31, 0x87, 0xf8, 0x0c, - 0x5b, 0xe8, 0x38, 0x8a, 0xc4, 0x6a, 0x1c, 0x8c, 0x93, 0xf8, 0x74, 0x86, 0x59, 0xef, 0xc6, 0x49, - 0x90, 0x5f, 0x91, 0x04, 0x70, 0x44, 0x0b, 0x3d, 0x0b, 0x73, 0x22, 0xf1, 0xd5, 0x96, 0xd7, 0xb8, - 0x64, 0x05, 0x7b, 0x42, 0xb9, 0x57, 0xc6, 0xc8, 0x6a, 0x0c, 0x8a, 0x13, 0xd8, 0xac, 0x6f, 0x51, - 0x76, 0x31, 0x46, 0x60, 0x22, 0x9e, 0x5a, 0x75, 0x35, 0x0e, 0xc6, 0x49, 0x7c, 0xf4, 0x0e, 0x4d, - 0xee, 0x73, 0x1f, 0x93, 0x92, 0x06, 0x29, 0xb2, 0xbf, 0x02, 0xf3, 0x1d, 0x66, 0x0b, 0x35, 0x24, - 0x50, 0xec, 0x47, 0xc5, 0xf0, 0x7a, 0x1c, 0x8c, 0x93, 0xf8, 0xe8, 0x19, 0x98, 0xf5, 0xa9, 0x74, - 0x53, 0x04, 0xb8, 0xe3, 0x49, 0x79, 0x47, 0xb0, 0x0e, 0xc4, 0x71, 0x5c, 0xf4, 0x1c, 0x2c, 0x46, - 0xd9, 0x78, 0x24, 0x01, 0xee, 0x89, 0x52, 0xe9, 0x2d, 0x2a, 0x49, 0x04, 0xdc, 0x5f, 0x07, 0xfd, - 0x32, 0x2c, 0x68, 0x23, 0xb1, 0xee, 0x36, 0xc8, 0x1d, 0x91, 0x31, 0x85, 0x7d, 0x12, 0x68, 0x35, - 0x01, 0xc3, 0x7d, 0xd8, 0xe8, 0xbd, 0x30, 0x57, 0xf7, 0x1c, 0x87, 0xc9, 0x38, 0x9e, 0xd6, 0x93, - 0xa7, 0x46, 0xe1, 0x49, 0x64, 0x62, 0x10, 0x9c, 0xc0, 0x44, 0x97, 0x01, 0x79, 0x3b, 0x01, 0xf1, - 0xf7, 0x49, 0xe3, 0x39, 0xfe, 0xc9, 0x2d, 0x7a, 0xc4, 0xcf, 0xc6, 0x63, 0x56, 0xaf, 0xf6, 0x61, - 0xe0, 0x94, 0x5a, 0x2c, 0x3b, 0x86, 0xf6, 0x7e, 0x64, 0x2e, 0x8b, 0x64, 0xf1, 0x49, 0xcb, 0xfd, - 0x9e, 0x8f, 0x47, 0x7c, 0x98, 0xe0, 0x21, 0xc4, 0xcb, 0xf3, 0x59, 0x64, 0x08, 0xd2, 0x33, 0xfc, - 0x45, 0x67, 0x04, 0x2f, 0xc5, 0x82, 0x13, 0xfa, 0x04, 0x4c, 0xed, 0xc8, 0x74, 0xaf, 0xcb, 0x0b, - 0x59, 0x9c, 0x8b, 0x89, 0xcc, 0xc5, 0x91, 0x65, 0xaa, 0x00, 0x38, 0x62, 0x89, 0x1e, 0x83, 0xe9, - 0x4b, 0x5b, 0x15, 0xb5, 0x0a, 0x17, 0xd9, 0xec, 0x17, 0x68, 0x15, 0xac, 0x03, 0xe8, 0x0e, 0x53, - 0xfa, 0x12, 0x62, 0x53, 0x1c, 0x9d, 0xb7, 0xfd, 0xea, 0x0f, 0xc5, 0x66, 0x0e, 0x41, 0x5c, 0x5b, - 0x3e, 0x91, 0xc0, 0x16, 0xe5, 0x58, 0x61, 0xa0, 0x97, 0x60, 0x5a, 0x9c, 0x17, 0x4c, 0x36, 0x2d, - 0x1d, 0xed, 0x6d, 0x12, 0x8e, 0x48, 0x60, 0x9d, 0x1e, 0x7a, 0x0a, 0xa6, 0xdb, 0x2c, 0x0b, 0x26, - 0xb9, 0xd8, 0x71, 0x9c, 0xe5, 0x93, 0x4c, 0x6e, 0x2a, 0x4f, 0xc9, 0x56, 0x04, 0xc2, 0x3a, 0x1e, - 0x7a, 0x42, 0x7a, 0xfd, 0xdf, 0x12, 0x73, 0x7c, 0x29, 0xaf, 0xbf, 0xd2, 0x72, 0x07, 0x04, 0xa5, - 0x9e, 0xba, 0x87, 0xbb, 0x7d, 0x07, 0x4e, 0x4b, 0x15, 0xab, 0x7f, 0x93, 0x2c, 0x2f, 0xc7, 0x6e, - 0x09, 0x4e, 0xdf, 0x18, 0x88, 0x89, 0x0f, 0xa1, 0x82, 0x76, 0x20, 0x6f, 0x39, 0x3b, 0xcb, 0x0f, - 0x66, 0xa1, 0x2b, 0xaa, 0x4f, 0xe8, 0xf1, 0x40, 0x92, 0xca, 0x46, 0x15, 0x53, 0xe2, 0xe6, 0xab, - 0x39, 0x75, 0x2b, 0xaf, 0x72, 0xc7, 0x7d, 0x5c, 0x5f, 0xd5, 0x46, 0x16, 0x9f, 0x88, 0xea, 0xcb, - 0x89, 0xcc, 0x0f, 0xa4, 0xd4, 0x35, 0xdd, 0x56, 0xfb, 0x38, 0x93, 0x74, 0x04, 0xf1, 0xbc, 0x78, - 0xdc, 0x9a, 0x8b, 0xef, 0x62, 0xf3, 0x87, 0x05, 0x75, 0x09, 0x95, 0x70, 0xc6, 0xfb, 0x50, 0xb4, - 0x83, 0xd0, 0xf6, 0x32, 0x7c, 0x72, 0x94, 0x48, 0x28, 0xc7, 0x82, 0x2f, 0x19, 0x00, 0x73, 0x56, - 0x94, 0xa7, 0xdb, 0xb4, 0xdd, 0x3b, 0xa2, 0xfb, 0xd7, 0x32, 0xf7, 0xb2, 0x73, 0x9e, 0x0c, 0x80, - 0x39, 0x2b, 0x74, 0x93, 0xaf, 0xb4, 0x6c, 0x3e, 0x07, 0x96, 0xfc, 0xca, 0x5f, 0x7c, 0xc5, 0x51, - 0x5e, 0x41, 0xcb, 0x16, 0x3a, 0xcc, 0x98, 0xbc, 0x6a, 0x9b, 0xeb, 0x69, 0xbc, 0x6a, 0x9b, 0xeb, - 0x98, 0x32, 0x41, 0xaf, 0x1b, 0x00, 0x96, 0xfa, 0xdc, 0x5d, 0x36, 0x09, 0xc4, 0x07, 0x7d, 0x3e, - 0x8f, 0xc7, 0x4b, 0x45, 0x50, 0xac, 0x71, 0x36, 0xff, 0xdd, 0x00, 0xed, 0x1b, 0x41, 0x51, 0xb0, - 0x8e, 0x31, 0x74, 0xb0, 0x4e, 0x6e, 0xc4, 0x60, 0x9d, 0xfc, 0x48, 0xc1, 0x3a, 0x85, 0xd1, 0x83, - 0x75, 0x8a, 0x83, 0x83, 0x75, 0xcc, 0x37, 0x0c, 0x58, 0xec, 0x9b, 0x9b, 0xe4, 0xb7, 0x18, 0x8d, - 0x21, 0xbf, 0xc5, 0xb8, 0x06, 0x0b, 0x22, 0xc3, 0x62, 0xad, 0xed, 0xd8, 0xa9, 0xaf, 0x14, 0xb7, - 0x13, 0x70, 0xdc, 0x57, 0xc3, 0xfc, 0x73, 0x03, 0xa6, 0xb5, 0x47, 0x15, 0xb4, 0x1f, 0xec, 0xf1, - 0x89, 0x68, 0x46, 0x94, 0x5c, 0x92, 0x5d, 0x33, 0x72, 0x18, 0xbf, 0xf1, 0x6e, 0x6a, 0x39, 0xc4, - 0xa2, 0x1b, 0x6f, 0x5a, 0x8a, 0x05, 0x94, 0x67, 0x87, 0x22, 0xfc, 0x3b, 0x9b, 0x79, 0x3d, 0x3b, - 0x14, 0x69, 0x63, 0x06, 0x61, 0xec, 0xe8, 0x99, 0x26, 0xe2, 0xb8, 0xb4, 0x5c, 0x96, 0x16, 0xb5, - 0x5c, 0x18, 0x0c, 0x9d, 0x81, 0x3c, 0x71, 0x1b, 0x42, 0x01, 0x57, 0x5f, 0x36, 0xb8, 0xe0, 0x36, - 0x30, 0x2d, 0x37, 0xaf, 0xc2, 0x4c, 0x8d, 0xd4, 0x7d, 0x12, 0x3e, 0x4f, 0x0e, 0x86, 0xfe, 0x54, - 0xc2, 0x2d, 0x72, 0x90, 0xfc, 0x54, 0x02, 0xad, 0x4e, 0xcb, 0xcd, 0x3f, 0x30, 0x20, 0x91, 0x5a, - 0x54, 0xbb, 0xfd, 0x32, 0x06, 0xdd, 0x7e, 0xc5, 0xee, 0x69, 0x72, 0x87, 0xde, 0xd3, 0x5c, 0x06, - 0xd4, 0xb2, 0xc2, 0xfa, 0x5e, 0x2c, 0xf1, 0xad, 0xb0, 0x7d, 0xa2, 0x27, 0x5c, 0x7d, 0x18, 0x38, - 0xa5, 0x96, 0xf9, 0x8a, 0x01, 0x7d, 0x9f, 0xc9, 0xa4, 0x27, 0x36, 0x11, 0x59, 0xe8, 0xb9, 0x49, - 0xa8, 0x4e, 0x6c, 0x99, 0x7c, 0x5e, 0xc2, 0xa9, 0xdd, 0x20, 0x6f, 0x9e, 0xa4, 0x1d, 0xcf, 0x1f, - 0xbb, 0x28, 0xbb, 0x61, 0x2d, 0x0e, 0xc6, 0x49, 0x7c, 0xf3, 0x05, 0x28, 0xc9, 0x17, 0x81, 0xec, - 0x59, 0x8d, 0xb4, 0x44, 0xf5, 0x67, 0x35, 0xd4, 0x10, 0x65, 0x10, 0x3a, 0x4c, 0x81, 0x6b, 0x5f, - 0xf2, 0x82, 0x50, 0x3e, 0x63, 0xe4, 0xf7, 0x4d, 0x57, 0xd6, 0x59, 0x19, 0x56, 0x50, 0x73, 0x11, - 0xe6, 0xd5, 0x45, 0x12, 0x5f, 0xf4, 0xe6, 0x37, 0xf3, 0x30, 0x13, 0xfb, 0xf8, 0xd1, 0xbd, 0x27, - 0x7b, 0xf8, 0x69, 0x49, 0xb9, 0x10, 0xca, 0x8f, 0x78, 0x21, 0xa4, 0xdf, 0xc0, 0x15, 0x8e, 0xf7, - 0x06, 0xae, 0x98, 0xcd, 0x0d, 0x5c, 0x08, 0x93, 0xe2, 0xc3, 0xb0, 0x22, 0x1a, 0x78, 0x33, 0xa3, - 0xe7, 0xfc, 0xe2, 0x5d, 0x2c, 0x0b, 0x80, 0x96, 0x02, 0x4c, 0xb2, 0x32, 0xbf, 0x5e, 0x84, 0xb9, - 0xf8, 0x03, 0xff, 0x21, 0x66, 0xf2, 0x1d, 0x7d, 0x33, 0x39, 0xa2, 0x41, 0x9c, 0x1f, 0xd7, 0x20, - 0x2e, 0x8c, 0x6b, 0x10, 0x17, 0x8f, 0x60, 0x10, 0xf7, 0x9b, 0xb3, 0x13, 0x43, 0x9b, 0xb3, 0xef, - 0x53, 0xde, 0xdc, 0xc9, 0x98, 0xfb, 0x23, 0xf2, 0xe6, 0xa2, 0xf8, 0x34, 0xac, 0x7a, 0x8d, 0x54, - 0xaf, 0x78, 0xe9, 0x1e, 0x8a, 0xbf, 0x9f, 0xea, 0x7c, 0x1d, 0xfd, 0xce, 0xed, 0x2d, 0x23, 0x38, - 0x5e, 0xa3, 0x6f, 0x1f, 0xb3, 0xc3, 0x0f, 0xe2, 0x07, 0x67, 0x2d, 0x02, 0x61, 0x1d, 0x8f, 0x7d, - 0xf5, 0x26, 0xfe, 0x99, 0x1f, 0x76, 0xbf, 0xa0, 0x7f, 0xf5, 0x26, 0xf1, 0x59, 0xa0, 0x24, 0xbe, - 0xf9, 0xb5, 0x3c, 0xcc, 0xc5, 0xb3, 0x96, 0xa3, 0xdb, 0x4a, 0x3f, 0xcf, 0xc4, 0x34, 0xe0, 0x64, - 0xb5, 0x27, 0xee, 0x03, 0x8d, 0x6d, 0xfe, 0x45, 0xde, 0x1d, 0xf5, 0xde, 0xfe, 0xf8, 0x18, 0x0b, - 0x2b, 0x57, 0xb0, 0x63, 0x89, 0xce, 0xa3, 0x80, 0x52, 0xe1, 0xc1, 0xcd, 0x9c, 0x7b, 0x14, 0x22, - 0xaa, 0x58, 0x61, 0x8d, 0x2d, 0x15, 0xef, 0xfb, 0xc4, 0xb7, 0x77, 0x6d, 0xf5, 0xc5, 0x15, 0x26, - 0x3c, 0x5f, 0x10, 0x65, 0x58, 0x41, 0xcd, 0x57, 0x72, 0x10, 0x7d, 0x5f, 0x8a, 0x25, 0x50, 0x0e, - 0x34, 0xb5, 0x41, 0x4c, 0xdb, 0xe5, 0x71, 0xb3, 0x94, 0x47, 0x14, 0x45, 0xb0, 0x8b, 0x56, 0x82, - 0x63, 0x1c, 0x7f, 0x0a, 0xdf, 0x95, 0xb2, 0x60, 0x3e, 0xf1, 0x50, 0x24, 0xf3, 0x88, 0xc2, 0x2f, - 0xe5, 0x61, 0x4a, 0x3d, 0xb5, 0x41, 0xef, 0x61, 0xb9, 0x4f, 0xf7, 0x3c, 0x99, 0x91, 0xf6, 0xad, - 0x5a, 0x86, 0xd2, 0x3d, 0xaf, 0x71, 0xb7, 0x5b, 0x9e, 0x57, 0xc8, 0xbc, 0x08, 0x8b, 0x0a, 0x54, - 0x49, 0xeb, 0xf8, 0x4e, 0x52, 0x49, 0xbb, 0x8e, 0x37, 0x30, 0x2d, 0x47, 0x77, 0x60, 0x72, 0x8f, - 0x58, 0x0d, 0xe2, 0xcb, 0xd8, 0x81, 0xcd, 0x8c, 0x9e, 0x07, 0x5d, 0x62, 0x54, 0xa3, 0x61, 0xe0, - 0xff, 0x03, 0x2c, 0xd9, 0xd1, 0x83, 0x6a, 0xc7, 0x6b, 0x1c, 0x24, 0x33, 0x9a, 0x56, 0xbd, 0xc6, - 0x01, 0x66, 0x10, 0xf4, 0x2c, 0xcc, 0x85, 0x76, 0x8b, 0x78, 0x9d, 0x50, 0xff, 0x7a, 0x4f, 0x3e, - 0xba, 0x3c, 0xde, 0x8e, 0x41, 0x71, 0x02, 0x9b, 0x1e, 0x74, 0x37, 0x03, 0xcf, 0x65, 0xd9, 0x54, - 0x26, 0xe2, 0x37, 0x4d, 0x97, 0x6b, 0x57, 0xaf, 0xb0, 0x64, 0x2a, 0x0a, 0x83, 0x62, 0xdb, 0x2c, - 0x9e, 0xdf, 0x27, 0xc2, 0x77, 0xb3, 0x10, 0xbd, 0xba, 0xe4, 0xe5, 0x58, 0x61, 0x98, 0xd7, 0x61, - 0x3e, 0xd1, 0x55, 0xa9, 0x0e, 0x1b, 0xe9, 0xea, 0xf0, 0x70, 0xe9, 0x43, 0xff, 0xc4, 0x80, 0xc5, - 0xbe, 0xcd, 0x3b, 0x6c, 0xa8, 0x6b, 0x52, 0x92, 0xe7, 0x8e, 0x2e, 0xc9, 0xf3, 0xa3, 0x49, 0xf2, - 0xea, 0xca, 0xb7, 0xde, 0x3c, 0xfb, 0xc0, 0xb7, 0xdf, 0x3c, 0xfb, 0xc0, 0x77, 0xdf, 0x3c, 0xfb, - 0xc0, 0x2b, 0xbd, 0xb3, 0xc6, 0xb7, 0x7a, 0x67, 0x8d, 0x6f, 0xf7, 0xce, 0x1a, 0xdf, 0xed, 0x9d, - 0x35, 0x7e, 0xd8, 0x3b, 0x6b, 0xbc, 0xf1, 0xa3, 0xb3, 0x0f, 0xbc, 0x58, 0x92, 0xcb, 0xe4, 0x7f, - 0x02, 0x00, 0x00, 0xff, 0xff, 0x63, 0x35, 0xc7, 0x2a, 0x50, 0x83, 0x00, 0x00, + // 6865 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3d, 0x5b, 0x8c, 0x24, 0x57, + 0x75, 0xae, 0x7e, 0xcc, 0xf4, 0x9c, 0x79, 0xdf, 0x9d, 0x65, 0xc7, 0x6b, 0xef, 0xb6, 0x29, 0x23, + 0xc7, 0x24, 0x30, 0x0b, 0x6b, 0x3b, 0x31, 0x18, 0x59, 0xe9, 0x9e, 0xd9, 0xf5, 0xce, 0x7a, 0x66, + 0x77, 0xf6, 0xf6, 0xac, 0x17, 0x0c, 0x26, 0xd4, 0x74, 0xdf, 0xe9, 0xa9, 0xdd, 0xea, 0xaa, 0xa6, + 0xaa, 0x7a, 0x76, 0xc7, 0x20, 0xb0, 0x83, 0xec, 0x90, 0x08, 0x84, 0x13, 0xe0, 0x23, 0x8a, 0x88, + 0x50, 0xc4, 0x47, 0x14, 0xf2, 0x11, 0xa1, 0x44, 0xf9, 0x41, 0x4a, 0x94, 0x80, 0x42, 0x3e, 0x12, + 0x11, 0x29, 0x09, 0x10, 0x41, 0x07, 0x37, 0xc9, 0x47, 0xa2, 0x48, 0x51, 0x24, 0xa2, 0x08, 0x7f, + 0x45, 0xf7, 0x59, 0xb7, 0xaa, 0xab, 0x67, 0xbb, 0xa7, 0x6b, 0x16, 0x2b, 0xe1, 0xaf, 0xfb, 0x9e, + 0x73, 0xcf, 0xb9, 0xcf, 0x73, 0xcf, 0x39, 0xf7, 0xdc, 0x53, 0xb0, 0xd1, 0xb4, 0xc3, 0xbd, 0xce, + 0xce, 0x4a, 0xdd, 0x6b, 0x9d, 0xb3, 0xfc, 0xa6, 0xd7, 0xf6, 0xbd, 0x9b, 0xec, 0xc7, 0x3b, 0x7d, + 0xcf, 0x71, 0xbc, 0x4e, 0x18, 0x9c, 0x6b, 0xdf, 0x6a, 0x9e, 0xb3, 0xda, 0x76, 0x70, 0x4e, 0x95, + 0xec, 0xbf, 0xdb, 0x72, 0xda, 0x7b, 0xd6, 0xbb, 0xcf, 0x35, 0x89, 0x4b, 0x7c, 0x2b, 0x24, 0x8d, + 0x95, 0xb6, 0xef, 0x85, 0x1e, 0x7a, 0x5f, 0x44, 0x6d, 0x45, 0x52, 0x63, 0x3f, 0x7e, 0x45, 0xd6, + 0x5d, 0x69, 0xdf, 0x6a, 0xae, 0x50, 0x6a, 0x2b, 0xaa, 0x44, 0x52, 0x3b, 0xfd, 0x4e, 0xad, 0x2d, + 0x4d, 0xaf, 0xe9, 0x9d, 0x63, 0x44, 0x77, 0x3a, 0xbb, 0xec, 0x1f, 0xfb, 0xc3, 0x7e, 0x71, 0x66, + 0xa7, 0x1f, 0xbe, 0xf5, 0x64, 0xb0, 0x62, 0x7b, 0xb4, 0x6d, 0xe7, 0x76, 0xac, 0xb0, 0xbe, 0x77, + 0x6e, 0xbf, 0xaf, 0x45, 0xa7, 0x4d, 0x0d, 0xa9, 0xee, 0xf9, 0x24, 0x0d, 0xe7, 0xf1, 0x08, 0xa7, + 0x65, 0xd5, 0xf7, 0x6c, 0x97, 0xf8, 0x07, 0x51, 0xaf, 0x5b, 0x24, 0xb4, 0xd2, 0x6a, 0x9d, 0x1b, + 0x54, 0xcb, 0xef, 0xb8, 0xa1, 0xdd, 0x22, 0x7d, 0x15, 0x7e, 0xf1, 0x6e, 0x15, 0x82, 0xfa, 0x1e, + 0x69, 0x59, 0x7d, 0xf5, 0x1e, 0x1b, 0x54, 0xaf, 0x13, 0xda, 0xce, 0x39, 0xdb, 0x0d, 0x83, 0xd0, + 0x4f, 0x56, 0x32, 0xbf, 0x91, 0x87, 0xa9, 0xca, 0x46, 0xb5, 0x16, 0x5a, 0x61, 0x27, 0x40, 0xaf, + 0x1a, 0x30, 0xe3, 0x78, 0x56, 0xa3, 0x6a, 0x39, 0x96, 0x5b, 0x27, 0xfe, 0xb2, 0xf1, 0x90, 0xf1, + 0xe8, 0xf4, 0xf9, 0x8d, 0x95, 0x71, 0xe6, 0x6b, 0xa5, 0x72, 0x3b, 0xc0, 0x24, 0xf0, 0x3a, 0x7e, + 0x9d, 0x60, 0xb2, 0x5b, 0x5d, 0xfa, 0x56, 0xb7, 0x7c, 0x5f, 0xaf, 0x5b, 0x9e, 0xd9, 0xd0, 0x38, + 0xe1, 0x18, 0x5f, 0xf4, 0x45, 0x03, 0x16, 0xeb, 0x96, 0x6b, 0xf9, 0x07, 0xdb, 0x96, 0xdf, 0x24, + 0xe1, 0x33, 0xbe, 0xd7, 0x69, 0x2f, 0xe7, 0x8e, 0xa1, 0x35, 0xf7, 0x8b, 0xd6, 0x2c, 0xae, 0x26, + 0xd9, 0xe1, 0xfe, 0x16, 0xb0, 0x76, 0x05, 0xa1, 0xb5, 0xe3, 0x10, 0xbd, 0x5d, 0xf9, 0xe3, 0x6c, + 0x57, 0x2d, 0xc9, 0x0e, 0xf7, 0xb7, 0xc0, 0x7c, 0x25, 0x0f, 0x8b, 0x95, 0x8d, 0xea, 0xb6, 0x6f, + 0xed, 0xee, 0xda, 0x75, 0xec, 0x75, 0x42, 0xdb, 0x6d, 0xa2, 0xb7, 0xc3, 0xa4, 0xed, 0x36, 0x7d, + 0x12, 0x04, 0x6c, 0x22, 0xa7, 0xaa, 0xf3, 0x82, 0xe8, 0xe4, 0x3a, 0x2f, 0xc6, 0x12, 0x8e, 0x9e, + 0x80, 0xe9, 0x80, 0xf8, 0xfb, 0x76, 0x9d, 0x6c, 0x79, 0x7e, 0xc8, 0x46, 0xba, 0x58, 0x3d, 0x21, + 0xd0, 0xa7, 0x6b, 0x11, 0x08, 0xeb, 0x78, 0xb4, 0x9a, 0xef, 0x79, 0xa1, 0x80, 0xb3, 0x81, 0x98, + 0x8a, 0xaa, 0xe1, 0x08, 0x84, 0x75, 0x3c, 0xf4, 0x9a, 0x01, 0x0b, 0x41, 0x68, 0xd7, 0x6f, 0xd9, + 0x2e, 0x09, 0x82, 0x55, 0xcf, 0xdd, 0xb5, 0x9b, 0xcb, 0x45, 0x36, 0x8a, 0x57, 0xc6, 0x1b, 0xc5, + 0x5a, 0x82, 0x6a, 0x75, 0xa9, 0xd7, 0x2d, 0x2f, 0x24, 0x4b, 0x71, 0x1f, 0x77, 0xb4, 0x06, 0x0b, + 0x96, 0xeb, 0x7a, 0xa1, 0x15, 0xda, 0x9e, 0xbb, 0xe5, 0x93, 0x5d, 0xfb, 0xce, 0x72, 0x81, 0x75, + 0x67, 0x59, 0x74, 0x67, 0xa1, 0x92, 0x80, 0xe3, 0xbe, 0x1a, 0xe6, 0x1a, 0x2c, 0x57, 0x5a, 0x3b, + 0x56, 0x10, 0x58, 0x0d, 0xcf, 0x4f, 0xcc, 0xc6, 0xa3, 0x50, 0x6a, 0x59, 0xed, 0xb6, 0xed, 0x36, + 0xe9, 0x74, 0xe4, 0x1f, 0x9d, 0xaa, 0xce, 0xf4, 0xba, 0xe5, 0xd2, 0xa6, 0x28, 0xc3, 0x0a, 0x6a, + 0x7e, 0x2f, 0x07, 0xd3, 0x15, 0xd7, 0x72, 0x0e, 0x02, 0x3b, 0xc0, 0x1d, 0x17, 0x7d, 0x04, 0x4a, + 0x54, 0xba, 0x34, 0xac, 0xd0, 0x12, 0x3b, 0xf2, 0x5d, 0x2b, 0x7c, 0xb3, 0xaf, 0xe8, 0x9b, 0x3d, + 0x1a, 0x17, 0x8a, 0xbd, 0xb2, 0xff, 0xee, 0x95, 0xab, 0x3b, 0x37, 0x49, 0x3d, 0xdc, 0x24, 0xa1, + 0x55, 0x45, 0xa2, 0x17, 0x10, 0x95, 0x61, 0x45, 0x15, 0x79, 0x50, 0x08, 0xda, 0xa4, 0x2e, 0x76, + 0xd8, 0xe6, 0x98, 0x2b, 0x39, 0x6a, 0x7a, 0xad, 0x4d, 0xea, 0xd5, 0x19, 0xc1, 0xba, 0x40, 0xff, + 0x61, 0xc6, 0x08, 0xdd, 0x86, 0x89, 0x80, 0xc9, 0x1c, 0xb1, 0x79, 0xae, 0x66, 0xc7, 0x92, 0x91, + 0xad, 0xce, 0x09, 0xa6, 0x13, 0xfc, 0x3f, 0x16, 0xec, 0xcc, 0x7f, 0x32, 0xe0, 0x84, 0x86, 0x5d, + 0xf1, 0x9b, 0x9d, 0x16, 0x71, 0x43, 0xf4, 0x10, 0x14, 0x5c, 0xab, 0x45, 0xc4, 0x46, 0x51, 0x4d, + 0xbe, 0x62, 0xb5, 0x08, 0x66, 0x10, 0xf4, 0x30, 0x14, 0xf7, 0x2d, 0xa7, 0x43, 0xd8, 0x20, 0x4d, + 0x55, 0x67, 0x05, 0x4a, 0xf1, 0x39, 0x5a, 0x88, 0x39, 0x0c, 0x7d, 0x1c, 0xa6, 0xd8, 0x8f, 0x8b, + 0xbe, 0xd7, 0xca, 0xa8, 0x6b, 0xa2, 0x85, 0xcf, 0x49, 0xb2, 0xd5, 0xd9, 0x5e, 0xb7, 0x3c, 0xa5, + 0xfe, 0xe2, 0x88, 0xa1, 0xf9, 0xcf, 0x06, 0xcc, 0x6b, 0x9d, 0xdb, 0xb0, 0x83, 0x10, 0x7d, 0xa8, + 0x6f, 0xf1, 0xac, 0x0c, 0xb7, 0x78, 0x68, 0x6d, 0xb6, 0x74, 0x16, 0x44, 0x4f, 0x4b, 0xb2, 0x44, + 0x5b, 0x38, 0x2e, 0x14, 0xed, 0x90, 0xb4, 0x82, 0xe5, 0xdc, 0x43, 0xf9, 0x47, 0xa7, 0xcf, 0xaf, + 0x67, 0x36, 0x8d, 0xd1, 0xf8, 0xae, 0x53, 0xfa, 0x98, 0xb3, 0x31, 0xbf, 0x56, 0x88, 0xf5, 0x90, + 0xae, 0x28, 0xe4, 0xc1, 0x64, 0x8b, 0x84, 0xbe, 0x5d, 0xe7, 0xfb, 0x6a, 0xfa, 0xfc, 0xda, 0x78, + 0xad, 0xd8, 0x64, 0xc4, 0x22, 0x61, 0xc9, 0xff, 0x07, 0x58, 0x72, 0x41, 0x7b, 0x50, 0xb0, 0xfc, + 0xa6, 0xec, 0xf3, 0xc5, 0x6c, 0xe6, 0x37, 0x5a, 0x73, 0x15, 0xbf, 0x19, 0x60, 0xc6, 0x01, 0x9d, + 0x83, 0xa9, 0x90, 0xf8, 0x2d, 0xdb, 0xb5, 0x42, 0x2e, 0x5d, 0x4b, 0xd5, 0x45, 0x81, 0x36, 0xb5, + 0x2d, 0x01, 0x38, 0xc2, 0x41, 0x0e, 0x4c, 0x34, 0xfc, 0x03, 0xdc, 0x71, 0x97, 0x0b, 0x59, 0x0c, + 0xc5, 0x1a, 0xa3, 0x15, 0x6d, 0x26, 0xfe, 0x1f, 0x0b, 0x1e, 0xe8, 0x2b, 0x06, 0x2c, 0xb5, 0x88, + 0x15, 0x74, 0x7c, 0x42, 0xbb, 0x80, 0x49, 0x48, 0x5c, 0x2a, 0x0d, 0x97, 0x8b, 0x8c, 0x39, 0x1e, + 0x77, 0x1e, 0xfa, 0x29, 0x57, 0x1f, 0x14, 0x4d, 0x59, 0x4a, 0x83, 0xe2, 0xd4, 0xd6, 0x98, 0xdf, + 0x2b, 0xc0, 0x62, 0x9f, 0x84, 0x40, 0x8f, 0x43, 0xb1, 0xbd, 0x67, 0x05, 0x72, 0xcb, 0x9f, 0x95, + 0xeb, 0x6d, 0x8b, 0x16, 0xbe, 0xd1, 0x2d, 0xcf, 0xca, 0x2a, 0xac, 0x00, 0x73, 0x64, 0x7a, 0xa6, + 0xb6, 0x48, 0x10, 0x58, 0x4d, 0x29, 0x07, 0xb4, 0x65, 0xc2, 0x8a, 0xb1, 0x84, 0xa3, 0x5f, 0x33, + 0x60, 0x96, 0x2f, 0x19, 0x4c, 0x82, 0x8e, 0x13, 0x52, 0x59, 0x47, 0x87, 0xe5, 0x72, 0x16, 0xcb, + 0x93, 0x93, 0xac, 0x9e, 0x14, 0xdc, 0x67, 0xf5, 0xd2, 0x00, 0xc7, 0xf9, 0xa2, 0x1b, 0x30, 0x15, + 0x84, 0x96, 0x1f, 0x92, 0x46, 0x25, 0x64, 0xa7, 0xda, 0xf4, 0xf9, 0x9f, 0x1f, 0x4e, 0x08, 0x6c, + 0xdb, 0x2d, 0xc2, 0x05, 0x4e, 0x4d, 0x12, 0xc0, 0x11, 0x2d, 0xf4, 0x71, 0x00, 0xbf, 0xe3, 0xd6, + 0x3a, 0xad, 0x96, 0xe5, 0x1f, 0x88, 0x13, 0xfc, 0xd2, 0x78, 0xdd, 0xc3, 0x8a, 0x5e, 0x74, 0x66, + 0x45, 0x65, 0x58, 0xe3, 0x87, 0x5e, 0x36, 0x60, 0x96, 0xaf, 0x44, 0xd9, 0x82, 0x89, 0x8c, 0x5b, + 0xb0, 0x48, 0x87, 0x76, 0x4d, 0x67, 0x81, 0xe3, 0x1c, 0xcd, 0x7f, 0x88, 0x9f, 0x27, 0xb5, 0x90, + 0x6a, 0xd7, 0xcd, 0x03, 0xf4, 0x41, 0xb8, 0x3f, 0xe8, 0xd4, 0xeb, 0x24, 0x08, 0x76, 0x3b, 0x0e, + 0xee, 0xb8, 0x97, 0xec, 0x20, 0xf4, 0xfc, 0x83, 0x0d, 0xbb, 0x65, 0x87, 0x6c, 0xc5, 0x15, 0xab, + 0x67, 0x7a, 0xdd, 0xf2, 0xfd, 0xb5, 0x41, 0x48, 0x78, 0x70, 0x7d, 0x64, 0xc1, 0x03, 0x1d, 0x77, + 0x30, 0x79, 0xae, 0xbd, 0x95, 0x7b, 0xdd, 0xf2, 0x03, 0xd7, 0x07, 0xa3, 0xe1, 0xc3, 0x68, 0x98, + 0xff, 0x6e, 0xc0, 0x82, 0xec, 0xd7, 0x36, 0x69, 0xb5, 0x1d, 0x2a, 0x5d, 0x8e, 0x5f, 0x11, 0x09, + 0x63, 0x8a, 0x08, 0xce, 0xe6, 0x38, 0x91, 0xed, 0x1f, 0xa4, 0x8d, 0x98, 0xff, 0x66, 0xc0, 0x52, + 0x12, 0xf9, 0x1e, 0x1c, 0x9e, 0x41, 0xfc, 0xf0, 0xbc, 0x92, 0x6d, 0x6f, 0x07, 0x9c, 0xa0, 0xaf, + 0x16, 0xfa, 0xfb, 0xfa, 0x7f, 0xfd, 0x18, 0x8d, 0x4e, 0xc5, 0xfc, 0x4f, 0xf3, 0x54, 0x2c, 0xbc, + 0xa9, 0x4e, 0xc5, 0xdf, 0x2f, 0xc0, 0x4c, 0xc5, 0x0d, 0xed, 0xca, 0xee, 0xae, 0xed, 0xda, 0xe1, + 0x01, 0xfa, 0x4c, 0x0e, 0xce, 0xb5, 0x7d, 0xb2, 0x4b, 0x7c, 0x9f, 0x34, 0xd6, 0x3a, 0xbe, 0xed, + 0x36, 0x6b, 0xf5, 0x3d, 0xd2, 0xe8, 0x38, 0xb6, 0xdb, 0x5c, 0x6f, 0xba, 0x9e, 0x2a, 0xbe, 0x70, + 0x87, 0xd4, 0x3b, 0xac, 0x4b, 0x7c, 0x53, 0xb4, 0xc6, 0xeb, 0xd2, 0xd6, 0x68, 0x4c, 0xab, 0x8f, + 0xf5, 0xba, 0xe5, 0x73, 0x23, 0x56, 0xc2, 0xa3, 0x76, 0x0d, 0x7d, 0x3a, 0x07, 0x2b, 0x3e, 0xf9, + 0x68, 0xc7, 0x1e, 0x7e, 0x34, 0xb8, 0xd4, 0x72, 0xc6, 0x3c, 0x7e, 0x46, 0xe2, 0x59, 0x3d, 0xdf, + 0xeb, 0x96, 0x47, 0xac, 0x83, 0x47, 0xec, 0x97, 0xf9, 0x97, 0x06, 0x94, 0x46, 0xb0, 0x94, 0xca, + 0x71, 0x4b, 0x69, 0xaa, 0xcf, 0x4a, 0x0a, 0xfb, 0xad, 0xa4, 0x67, 0xc6, 0x1b, 0xb4, 0x61, 0xac, + 0xa3, 0xff, 0x34, 0x60, 0xb1, 0xcf, 0x9a, 0x42, 0x7b, 0xb0, 0xd4, 0xf6, 0x1a, 0x52, 0x12, 0x5e, + 0xb2, 0x82, 0x3d, 0x06, 0x13, 0xdd, 0x7b, 0x9c, 0x6e, 0xaa, 0xad, 0x14, 0xf8, 0x1b, 0xdd, 0xf2, + 0xb2, 0x22, 0x92, 0x40, 0xc0, 0xa9, 0x14, 0x51, 0x1b, 0x4a, 0xbb, 0x36, 0x71, 0x1a, 0x98, 0xec, + 0x8a, 0x95, 0x32, 0xa6, 0xcc, 0xbb, 0x28, 0xa8, 0x71, 0x47, 0x82, 0xfc, 0x87, 0x15, 0x17, 0xf3, + 0x1a, 0xcc, 0xc5, 0xdd, 0x4a, 0x43, 0x4c, 0xde, 0x19, 0xc8, 0x5b, 0xbe, 0x2b, 0xa6, 0x6e, 0x5a, + 0x20, 0xe4, 0x2b, 0xf8, 0x0a, 0xa6, 0xe5, 0xe6, 0x4f, 0x0a, 0x30, 0x5f, 0x75, 0x3a, 0xe4, 0x19, + 0x9f, 0x10, 0xa9, 0x49, 0x57, 0x60, 0xbe, 0xed, 0x93, 0x7d, 0x9b, 0xdc, 0xae, 0x11, 0x87, 0xd4, + 0x43, 0xcf, 0x17, 0xf4, 0x4f, 0x89, 0xea, 0xf3, 0x5b, 0x71, 0x30, 0x4e, 0xe2, 0xa3, 0xa7, 0x61, + 0xce, 0xaa, 0x87, 0xf6, 0x3e, 0x51, 0x14, 0x78, 0x03, 0xde, 0x22, 0x28, 0xcc, 0x55, 0x62, 0x50, + 0x9c, 0xc0, 0x46, 0x1f, 0x82, 0xe5, 0xa0, 0x6e, 0x39, 0xe4, 0x7a, 0x5b, 0xb0, 0x5a, 0xdd, 0x23, + 0xf5, 0x5b, 0x5b, 0x9e, 0xed, 0x86, 0xc2, 0x6e, 0x7a, 0x48, 0x50, 0x5a, 0xae, 0x0d, 0xc0, 0xc3, + 0x03, 0x29, 0xa0, 0x3f, 0x33, 0xe0, 0x4c, 0xdb, 0x27, 0x5b, 0xbe, 0xd7, 0xf2, 0xe8, 0x86, 0xe8, + 0x33, 0x26, 0x84, 0x52, 0xfd, 0xdc, 0x98, 0x3b, 0x9f, 0x97, 0xf4, 0x3b, 0x33, 0xde, 0xda, 0xeb, + 0x96, 0xcf, 0x6c, 0x1d, 0xd6, 0x00, 0x7c, 0x78, 0xfb, 0xd0, 0x5f, 0x18, 0x70, 0xb6, 0xed, 0x05, + 0xe1, 0x21, 0x5d, 0x28, 0x1e, 0x6b, 0x17, 0xcc, 0x5e, 0xb7, 0x7c, 0x76, 0xeb, 0xd0, 0x16, 0xe0, + 0xbb, 0xb4, 0xd0, 0xec, 0x4d, 0xc3, 0xa2, 0xb6, 0xf6, 0x84, 0xa6, 0xfd, 0x14, 0xcc, 0xca, 0xc5, + 0xc0, 0xbd, 0x90, 0x7c, 0xed, 0x29, 0xcb, 0xa8, 0xa2, 0x03, 0x71, 0x1c, 0x97, 0xae, 0x3b, 0xb5, + 0x14, 0x79, 0xed, 0xc4, 0xba, 0xdb, 0x8a, 0x41, 0x71, 0x02, 0x1b, 0xad, 0xc3, 0x09, 0x51, 0x82, + 0x49, 0xdb, 0xb1, 0xeb, 0xd6, 0xaa, 0xd7, 0x11, 0x4b, 0xae, 0x58, 0x3d, 0xd5, 0xeb, 0x96, 0x4f, + 0x6c, 0xf5, 0x83, 0x71, 0x5a, 0x1d, 0xb4, 0x01, 0x4b, 0x56, 0x27, 0xf4, 0x54, 0xff, 0x2f, 0xb8, + 0xd6, 0x8e, 0x43, 0x1a, 0x6c, 0x69, 0x95, 0xaa, 0xcb, 0x54, 0x10, 0x55, 0x52, 0xe0, 0x38, 0xb5, + 0x16, 0xda, 0x4a, 0x50, 0xab, 0x91, 0xba, 0xe7, 0x36, 0xf8, 0x2c, 0x17, 0x23, 0x7d, 0xa1, 0x92, + 0x82, 0x83, 0x53, 0x6b, 0x22, 0x07, 0xe6, 0x5a, 0xd6, 0x9d, 0xeb, 0xae, 0xb5, 0x6f, 0xd9, 0x0e, + 0x65, 0x22, 0xac, 0xad, 0xc1, 0x26, 0x40, 0x27, 0xb4, 0x9d, 0x15, 0x7e, 0xf1, 0xb0, 0xb2, 0xee, + 0x86, 0x57, 0xfd, 0x5a, 0x48, 0xcf, 0x95, 0x2a, 0xa2, 0x03, 0xbb, 0x19, 0xa3, 0x85, 0x13, 0xb4, + 0xd1, 0x55, 0x38, 0xc9, 0xb6, 0xe3, 0x9a, 0x77, 0xdb, 0x5d, 0x23, 0x8e, 0x75, 0x20, 0x3b, 0x30, + 0xc9, 0x3a, 0x70, 0x7f, 0xaf, 0x5b, 0x3e, 0x59, 0x4b, 0x43, 0xc0, 0xe9, 0xf5, 0xa8, 0xcd, 0x14, + 0x07, 0x60, 0xb2, 0x6f, 0x07, 0xb6, 0xe7, 0x72, 0x9b, 0xa9, 0x14, 0xd9, 0x4c, 0xb5, 0xc1, 0x68, + 0xf8, 0x30, 0x1a, 0xe8, 0x77, 0x0c, 0x58, 0x4a, 0xdb, 0x86, 0xcb, 0x53, 0x59, 0xb8, 0x55, 0x13, + 0x5b, 0x8b, 0xaf, 0x88, 0x54, 0xa1, 0x90, 0xda, 0x08, 0xf4, 0x92, 0x01, 0x33, 0x96, 0xa6, 0xef, + 0x2d, 0x03, 0x6b, 0xd5, 0xe5, 0x71, 0xad, 0x8e, 0x88, 0x62, 0x75, 0xa1, 0xd7, 0x2d, 0xc7, 0x74, + 0x4a, 0x1c, 0xe3, 0x88, 0x7e, 0xd7, 0x80, 0x93, 0xa9, 0x7b, 0x7c, 0x79, 0xfa, 0x38, 0x46, 0x88, + 0x2d, 0x92, 0x74, 0x99, 0x93, 0xde, 0x0c, 0xf4, 0x9a, 0xa1, 0x8e, 0xb2, 0x4d, 0x69, 0xf7, 0xcd, + 0xb0, 0xa6, 0x5d, 0x1b, 0x53, 0xc5, 0x8d, 0x14, 0x02, 0x49, 0xb8, 0x7a, 0x42, 0x3b, 0x19, 0x65, + 0x21, 0x4e, 0xb2, 0x47, 0x9f, 0x35, 0xe4, 0xd1, 0xa8, 0x5a, 0x34, 0x7b, 0x5c, 0x2d, 0x42, 0xd1, + 0x49, 0xab, 0x1a, 0x94, 0x60, 0x8e, 0x3e, 0x0c, 0xa7, 0xad, 0x1d, 0xcf, 0x0f, 0x53, 0x37, 0xdf, + 0xf2, 0x1c, 0xdb, 0x46, 0x67, 0x7b, 0xdd, 0xf2, 0xe9, 0xca, 0x40, 0x2c, 0x7c, 0x08, 0x05, 0xf3, + 0xfb, 0x05, 0x98, 0xe1, 0x77, 0x71, 0xe2, 0xe8, 0xfa, 0xba, 0x01, 0x0f, 0xd6, 0x3b, 0xbe, 0x4f, + 0xdc, 0xb0, 0x16, 0x92, 0x76, 0xff, 0xc1, 0x65, 0x1c, 0xeb, 0xc1, 0xf5, 0x50, 0xaf, 0x5b, 0x7e, + 0x70, 0xf5, 0x10, 0xfe, 0xf8, 0xd0, 0xd6, 0xa1, 0xbf, 0x35, 0xc0, 0x14, 0x08, 0x55, 0xab, 0x7e, + 0xab, 0xe9, 0x7b, 0x1d, 0xb7, 0xd1, 0xdf, 0x89, 0xdc, 0xb1, 0x76, 0xe2, 0x91, 0x5e, 0xb7, 0x6c, + 0xae, 0xde, 0xb5, 0x15, 0x78, 0x88, 0x96, 0xa2, 0x67, 0x60, 0x51, 0x60, 0x5d, 0xb8, 0xd3, 0x26, + 0xbe, 0x4d, 0xd5, 0x69, 0x71, 0xf3, 0x17, 0x5d, 0xa6, 0x26, 0x11, 0x70, 0x7f, 0x1d, 0x14, 0xc0, + 0xe4, 0x6d, 0x62, 0x37, 0xf7, 0x42, 0xa9, 0x3e, 0x8d, 0x79, 0x83, 0x2a, 0xee, 0xdb, 0x6e, 0x70, + 0x9a, 0xd5, 0xe9, 0x5e, 0xb7, 0x3c, 0x29, 0xfe, 0x60, 0xc9, 0xc9, 0xfc, 0xa3, 0x02, 0x80, 0x5c, + 0x5e, 0xa4, 0x8d, 0x7e, 0x01, 0xa6, 0x02, 0x12, 0x72, 0x2c, 0xe1, 0x96, 0xe3, 0xde, 0x4e, 0x59, + 0x88, 0x23, 0x38, 0xba, 0x05, 0xc5, 0xb6, 0xd5, 0x09, 0x88, 0x98, 0xac, 0xcb, 0x99, 0x4c, 0xd6, + 0x16, 0xa5, 0xc8, 0x6d, 0x24, 0xf6, 0x13, 0x73, 0x1e, 0xe8, 0x53, 0x06, 0x00, 0x89, 0x0f, 0xf0, + 0xf4, 0xf9, 0x5a, 0x26, 0x2c, 0xa3, 0x39, 0xa0, 0x63, 0x50, 0x9d, 0xeb, 0x75, 0xcb, 0xa0, 0x4d, + 0x95, 0xc6, 0x16, 0xdd, 0x86, 0x92, 0x25, 0x65, 0x74, 0xe1, 0x38, 0x64, 0x34, 0x33, 0x5d, 0xd4, + 0x22, 0x53, 0xcc, 0xd0, 0xa7, 0x0d, 0x98, 0x0b, 0x48, 0x28, 0xa6, 0x8a, 0x4a, 0x0a, 0xa1, 0xa0, + 0x8e, 0xb9, 0x48, 0x6a, 0x31, 0x9a, 0x5c, 0xe2, 0xc5, 0xcb, 0x70, 0x82, 0xaf, 0xf9, 0xfd, 0x69, + 0x98, 0x93, 0x4b, 0x26, 0xd2, 0x39, 0x79, 0x70, 0xc0, 0x00, 0x9d, 0x73, 0x55, 0x07, 0xe2, 0x38, + 0x2e, 0xad, 0xcc, 0x6f, 0xf0, 0xe3, 0x2a, 0xa7, 0xaa, 0x5c, 0xd3, 0x81, 0x38, 0x8e, 0x8b, 0x5a, + 0x50, 0x0c, 0x42, 0xd2, 0x96, 0x77, 0x09, 0x63, 0xba, 0xba, 0xa3, 0x9d, 0x10, 0x79, 0x0b, 0xe9, + 0xbf, 0x00, 0x73, 0x2e, 0xe8, 0x73, 0x06, 0xcc, 0x85, 0xb1, 0x7b, 0x6c, 0xb1, 0x0c, 0xb2, 0x59, + 0x89, 0xf1, 0x2b, 0x72, 0x3e, 0x1b, 0xf1, 0x32, 0x9c, 0x60, 0x9f, 0xa2, 0x86, 0x16, 0x8f, 0x51, + 0x0d, 0x7d, 0x1e, 0x4a, 0x2d, 0xeb, 0x4e, 0xad, 0xe3, 0x37, 0x8f, 0xae, 0xee, 0x8a, 0x6b, 0x7e, + 0x4e, 0x05, 0x2b, 0x7a, 0xe8, 0x65, 0x43, 0xdb, 0x5c, 0x93, 0x8c, 0xf8, 0x8d, 0x6c, 0x37, 0x97, + 0x92, 0xe2, 0x03, 0xb7, 0x59, 0x9f, 0x52, 0x58, 0xba, 0xe7, 0x4a, 0x21, 0x55, 0x70, 0xf8, 0x06, + 0x51, 0x0a, 0xce, 0xd4, 0xb1, 0x2a, 0x38, 0xab, 0x31, 0x66, 0x38, 0xc1, 0x9c, 0xb5, 0x87, 0xef, + 0x39, 0xd5, 0x1e, 0x38, 0xd6, 0xf6, 0xd4, 0x62, 0xcc, 0x70, 0x82, 0xf9, 0x60, 0x4b, 0x68, 0xfa, + 0x78, 0x2c, 0xa1, 0x99, 0x0c, 0x2c, 0xa1, 0xc3, 0x95, 0xc4, 0xd9, 0x71, 0x95, 0x44, 0x74, 0x19, + 0x50, 0xe3, 0xc0, 0xb5, 0x5a, 0x76, 0x5d, 0x08, 0x4b, 0x76, 0x40, 0xcc, 0x31, 0x4b, 0xf9, 0xb4, + 0x10, 0x64, 0x68, 0xad, 0x0f, 0x03, 0xa7, 0xd4, 0x32, 0xff, 0xdb, 0x80, 0x85, 0x55, 0xc7, 0xeb, + 0x34, 0x6e, 0x58, 0x61, 0x7d, 0x8f, 0xdf, 0x52, 0xa0, 0xa7, 0xa1, 0x64, 0xbb, 0x21, 0xf1, 0xf7, + 0x2d, 0x47, 0xc8, 0x76, 0x53, 0x5e, 0xe4, 0xac, 0x8b, 0xf2, 0x37, 0xba, 0xe5, 0xb9, 0xb5, 0x8e, + 0xcf, 0xc2, 0x7f, 0xf8, 0x4e, 0xc7, 0xaa, 0x0e, 0xfa, 0xb2, 0x01, 0x8b, 0xfc, 0x9e, 0x63, 0xcd, + 0x0a, 0xad, 0x6b, 0x1d, 0xe2, 0xdb, 0x44, 0xde, 0x74, 0x8c, 0xb9, 0xc9, 0x93, 0x6d, 0x95, 0x0c, + 0x0e, 0x22, 0xf5, 0x6b, 0x33, 0xc9, 0x19, 0xf7, 0x37, 0xc6, 0xfc, 0x7c, 0x1e, 0xee, 0x1f, 0x48, + 0x0b, 0x9d, 0x86, 0x9c, 0xdd, 0x10, 0x5d, 0x07, 0x41, 0x37, 0xb7, 0xde, 0xc0, 0x39, 0xbb, 0x81, + 0x56, 0x98, 0x66, 0xe2, 0x93, 0x20, 0x90, 0x4e, 0xef, 0x29, 0xa5, 0x44, 0x88, 0x52, 0xac, 0x61, + 0xa0, 0x32, 0x14, 0x1d, 0x6b, 0x87, 0x38, 0x42, 0x4b, 0x64, 0xba, 0xce, 0x06, 0x2d, 0xc0, 0xbc, + 0x1c, 0xfd, 0xaa, 0x01, 0xc0, 0x1b, 0x48, 0x75, 0x4c, 0x71, 0xc2, 0xe0, 0x6c, 0x87, 0x89, 0x52, + 0xe6, 0xad, 0x8c, 0xfe, 0x63, 0x8d, 0x2b, 0xda, 0x86, 0x09, 0xaa, 0xf6, 0x78, 0x8d, 0x23, 0x1f, + 0x28, 0xd0, 0xeb, 0x96, 0x27, 0xb6, 0x18, 0x0d, 0x2c, 0x68, 0xd1, 0xb1, 0xf2, 0x49, 0xd8, 0xf1, + 0x5d, 0x3a, 0xb4, 0xec, 0x08, 0x29, 0xf1, 0x56, 0x60, 0x55, 0x8a, 0x35, 0x0c, 0xf3, 0x4f, 0x73, + 0xb0, 0x94, 0xd6, 0x74, 0x2a, 0xa9, 0x27, 0x78, 0x6b, 0x85, 0xc1, 0xf3, 0xfe, 0xec, 0xc7, 0x47, + 0x5c, 0xd9, 0xa9, 0x8b, 0x2d, 0x11, 0x54, 0x20, 0xf8, 0xa2, 0xf7, 0xab, 0x11, 0xca, 0x1d, 0x71, + 0x84, 0x14, 0xe5, 0xc4, 0x28, 0x3d, 0x04, 0x85, 0x80, 0xce, 0x7c, 0x3e, 0xee, 0x96, 0x66, 0x73, + 0xc4, 0x20, 0x14, 0xa3, 0xe3, 0xda, 0xa1, 0x88, 0xc9, 0x53, 0x18, 0xd7, 0x5d, 0x3b, 0xc4, 0x0c, + 0x62, 0x7e, 0x31, 0x07, 0xa7, 0x07, 0x77, 0x0a, 0x7d, 0xd1, 0x00, 0x68, 0x50, 0xa5, 0x96, 0x2e, + 0x49, 0x79, 0xc5, 0x69, 0x1d, 0xd7, 0x18, 0xae, 0x49, 0x4e, 0xd1, 0x7d, 0xb7, 0x2a, 0x0a, 0xb0, + 0xd6, 0x10, 0x74, 0x5e, 0x2e, 0xfd, 0x2b, 0x56, 0x4b, 0xaa, 0x82, 0xaa, 0xce, 0xa6, 0x82, 0x60, + 0x0d, 0x8b, 0x5a, 0x2d, 0xae, 0xd5, 0x22, 0x41, 0xdb, 0x52, 0x41, 0x97, 0xcc, 0x6a, 0xb9, 0x22, + 0x0b, 0x71, 0x04, 0x37, 0x1d, 0x78, 0x78, 0x88, 0x76, 0x66, 0x14, 0x00, 0x67, 0xfe, 0x97, 0x01, + 0xa7, 0x56, 0x9d, 0x4e, 0x10, 0x12, 0xff, 0xff, 0x4d, 0xf8, 0xc0, 0xff, 0x18, 0xf0, 0xc0, 0x80, + 0x3e, 0xdf, 0x83, 0x28, 0x82, 0x17, 0xe3, 0x51, 0x04, 0xd7, 0xc7, 0x5d, 0xd2, 0xa9, 0xfd, 0x18, + 0x10, 0x4c, 0x10, 0xc2, 0x2c, 0x95, 0x5a, 0x0d, 0xaf, 0x99, 0xd1, 0xb9, 0xf9, 0x30, 0x14, 0x3f, + 0x4a, 0xcf, 0x9f, 0xe4, 0x1a, 0x63, 0x87, 0x12, 0xe6, 0x30, 0xf3, 0x7d, 0x20, 0xae, 0xdc, 0x13, + 0x9b, 0xc7, 0x18, 0x66, 0xf3, 0x98, 0xff, 0x98, 0x03, 0xcd, 0xda, 0xbd, 0x07, 0x8b, 0xd2, 0x8d, + 0x2d, 0xca, 0x31, 0xed, 0x57, 0xcd, 0x76, 0x1f, 0x14, 0x5b, 0xbb, 0x9f, 0x88, 0xad, 0xbd, 0x92, + 0x19, 0xc7, 0xc3, 0x43, 0x6b, 0xbf, 0x63, 0xc0, 0x03, 0x11, 0x72, 0xbf, 0xe3, 0xe8, 0xee, 0x12, + 0xe6, 0x09, 0x98, 0xb6, 0xa2, 0x6a, 0x62, 0x0d, 0xa8, 0x70, 0x72, 0x8d, 0x22, 0xd6, 0xf1, 0xa2, + 0x48, 0xbe, 0xfc, 0x11, 0x23, 0xf9, 0x0a, 0x87, 0x47, 0xf2, 0x99, 0x3f, 0xce, 0xc1, 0x99, 0xfe, + 0x9e, 0xc9, 0xbd, 0x31, 0xdc, 0xbd, 0xea, 0x93, 0x30, 0x13, 0x8a, 0x0a, 0x9a, 0xa4, 0x57, 0x8f, + 0x21, 0xb6, 0x35, 0x18, 0x8e, 0x61, 0xd2, 0x9a, 0x75, 0xbe, 0x2b, 0x6b, 0x75, 0xaf, 0x2d, 0xe3, + 0x40, 0x55, 0xcd, 0x55, 0x0d, 0x86, 0x63, 0x98, 0x2a, 0xc2, 0xa6, 0x70, 0xec, 0x11, 0x36, 0x35, + 0x38, 0x29, 0x63, 0x0a, 0x2e, 0x7a, 0xfe, 0xaa, 0xd7, 0x6a, 0x3b, 0x44, 0x44, 0x82, 0xd2, 0xc6, + 0x9e, 0x11, 0x55, 0x4e, 0xe2, 0x34, 0x24, 0x9c, 0x5e, 0xd7, 0xfc, 0x4e, 0x1e, 0x4e, 0x44, 0xc3, + 0xbe, 0xea, 0xb9, 0x0d, 0x9b, 0x45, 0x66, 0x3c, 0x05, 0x85, 0xf0, 0xa0, 0x2d, 0x07, 0xfb, 0xe7, + 0x64, 0x73, 0xb6, 0x0f, 0xda, 0x74, 0xb6, 0x4f, 0xa5, 0x54, 0xa1, 0x20, 0xcc, 0x2a, 0xa1, 0x0d, + 0xb5, 0x3b, 0xf8, 0x0c, 0x3c, 0x1e, 0x5f, 0xcd, 0x6f, 0x74, 0xcb, 0x29, 0x6f, 0x81, 0x56, 0x14, + 0xa5, 0xf8, 0x9a, 0x47, 0x37, 0x61, 0xce, 0xb1, 0x82, 0xf0, 0x7a, 0xbb, 0x61, 0x85, 0x64, 0xdb, + 0x6e, 0x11, 0xb1, 0xe7, 0x46, 0x09, 0xaf, 0x54, 0x77, 0x8d, 0x1b, 0x31, 0x4a, 0x38, 0x41, 0x19, + 0xed, 0x03, 0xa2, 0x25, 0xdb, 0xbe, 0xe5, 0x06, 0xbc, 0x57, 0x94, 0xdf, 0xe8, 0xe1, 0x9c, 0xca, + 0x40, 0xda, 0xe8, 0xa3, 0x86, 0x53, 0x38, 0xa0, 0x47, 0x60, 0xc2, 0x27, 0x56, 0x20, 0x26, 0x73, + 0x2a, 0xda, 0xff, 0x98, 0x95, 0x62, 0x01, 0xd5, 0x37, 0xd4, 0xc4, 0x5d, 0x36, 0xd4, 0x0f, 0x0c, + 0x98, 0x8b, 0xa6, 0xe9, 0x1e, 0x1c, 0x92, 0xad, 0xf8, 0x21, 0x79, 0x29, 0x2b, 0x91, 0x38, 0xe0, + 0x5c, 0xfc, 0xab, 0x09, 0xbd, 0x7f, 0x2c, 0xbc, 0xee, 0x63, 0x30, 0x25, 0x77, 0xb5, 0xd4, 0x3e, + 0xc7, 0xf4, 0xb2, 0xc4, 0xf4, 0x12, 0x2d, 0x2c, 0x5c, 0x30, 0xc1, 0x11, 0x3f, 0x7a, 0x2c, 0x37, + 0xc4, 0x91, 0x2b, 0x96, 0xbd, 0x3a, 0x96, 0xe5, 0x51, 0x9c, 0x76, 0x2c, 0xcb, 0x3a, 0xe8, 0x3a, + 0x9c, 0x6a, 0xfb, 0x1e, 0x7b, 0x2a, 0xb4, 0x46, 0xac, 0x86, 0x63, 0xbb, 0x44, 0x1a, 0xf3, 0xfc, + 0xaa, 0xfb, 0x81, 0x5e, 0xb7, 0x7c, 0x6a, 0x2b, 0x1d, 0x05, 0x0f, 0xaa, 0x1b, 0x0f, 0x6f, 0x2f, + 0x0c, 0x11, 0xde, 0xfe, 0xeb, 0xca, 0x65, 0x46, 0x02, 0x11, 0x64, 0xfe, 0xc1, 0xac, 0xa6, 0x32, + 0x45, 0xac, 0x47, 0x4b, 0xaa, 0x22, 0x98, 0x62, 0xc5, 0x7e, 0xb0, 0x5f, 0x66, 0xe2, 0x88, 0x7e, + 0x99, 0x28, 0x4a, 0x71, 0xf2, 0xa7, 0x19, 0xa5, 0x58, 0x7a, 0x53, 0x45, 0x29, 0xbe, 0x52, 0x84, + 0x85, 0xa4, 0x06, 0x72, 0xfc, 0xa1, 0xfb, 0xbf, 0x65, 0xc0, 0x82, 0xdc, 0x3d, 0x9c, 0x27, 0x91, + 0x1e, 0xf7, 0x8d, 0x8c, 0x36, 0x2d, 0xd7, 0xa5, 0xd4, 0xe3, 0xb2, 0xed, 0x04, 0x37, 0xdc, 0xc7, + 0x1f, 0xbd, 0x00, 0xd3, 0xca, 0x31, 0x7d, 0xa4, 0x38, 0xfe, 0x79, 0xa6, 0x45, 0x45, 0x24, 0xb0, + 0x4e, 0x0f, 0xbd, 0x62, 0x00, 0xd4, 0xe5, 0x31, 0x27, 0x77, 0xd7, 0xb5, 0xac, 0x76, 0x97, 0x3a, + 0x40, 0x23, 0x65, 0x59, 0x15, 0x05, 0x58, 0x63, 0x8c, 0x3e, 0xcf, 0x5c, 0xd2, 0x4a, 0xbb, 0xa3, + 0xfb, 0x89, 0xb6, 0xe4, 0x03, 0x59, 0xef, 0xf3, 0xe8, 0x76, 0x54, 0xa9, 0x52, 0x1a, 0x28, 0xc0, + 0xb1, 0x46, 0x98, 0x4f, 0x81, 0x0a, 0xb0, 0xa3, 0x62, 0x8b, 0x85, 0xd8, 0x6d, 0x59, 0xe1, 0x9e, + 0x58, 0x82, 0x4a, 0x6c, 0x5d, 0x94, 0x00, 0x1c, 0xe1, 0x98, 0x1f, 0x81, 0xb9, 0x67, 0x7c, 0xab, + 0xbd, 0x67, 0x33, 0xd7, 0x2f, 0xb5, 0x93, 0xde, 0x0e, 0x93, 0x56, 0xa3, 0x91, 0xf6, 0x34, 0xb3, + 0xc2, 0x8b, 0xb1, 0x84, 0x0f, 0x67, 0x12, 0x7d, 0xc3, 0x80, 0xa5, 0xf5, 0x20, 0xb4, 0xbd, 0x35, + 0x12, 0x84, 0x54, 0x56, 0xd2, 0x1d, 0xd5, 0x71, 0xc8, 0x10, 0x8a, 0xe9, 0x1a, 0x2c, 0x88, 0xfb, + 0xa9, 0xce, 0x4e, 0x40, 0x42, 0x4d, 0x39, 0x55, 0x8b, 0x73, 0x35, 0x01, 0xc7, 0x7d, 0x35, 0x28, + 0x15, 0x71, 0x51, 0x15, 0x51, 0xc9, 0xc7, 0xa9, 0xd4, 0x12, 0x70, 0xdc, 0x57, 0xc3, 0xfc, 0x76, + 0x1e, 0x4e, 0xb0, 0x6e, 0x24, 0xde, 0x4e, 0x7e, 0xd6, 0x80, 0xb9, 0x7d, 0xdb, 0x0f, 0x3b, 0x96, + 0xa3, 0xdf, 0xb8, 0x8d, 0xbd, 0x3e, 0x19, 0xaf, 0xe7, 0x62, 0x84, 0xb9, 0x4f, 0x3e, 0x5e, 0x86, + 0x13, 0xcc, 0xd1, 0x6f, 0x1a, 0x30, 0xdf, 0x88, 0x8f, 0x74, 0x36, 0x3e, 0x87, 0xb4, 0x39, 0xe4, + 0x81, 0x22, 0x89, 0x42, 0x9c, 0xe4, 0x8f, 0xbe, 0x60, 0xc0, 0x7c, 0xbc, 0x99, 0x52, 0x64, 0x1d, + 0xc3, 0x20, 0xa9, 0xc8, 0xce, 0x78, 0x79, 0x80, 0x93, 0x4d, 0x30, 0xff, 0xde, 0x10, 0x53, 0x1a, + 0xc7, 0x1c, 0x62, 0x61, 0x9a, 0x30, 0xe1, 0x7b, 0x9d, 0x50, 0xf8, 0xcd, 0xa7, 0xb8, 0x7b, 0x15, + 0xb3, 0x12, 0x2c, 0x20, 0xe8, 0x36, 0x4c, 0x85, 0x4e, 0xc0, 0x0b, 0x45, 0x6f, 0xc7, 0x34, 0x73, + 0xb6, 0x37, 0x6a, 0x8c, 0x9c, 0xa6, 0x89, 0x88, 0x12, 0xaa, 0x51, 0x49, 0x5e, 0xe6, 0x57, 0x0d, + 0x98, 0xba, 0xec, 0xed, 0x88, 0xed, 0xfc, 0xe1, 0x0c, 0x9c, 0x08, 0x4a, 0xd7, 0x50, 0x37, 0x41, + 0x91, 0xfa, 0xfa, 0x74, 0xcc, 0x85, 0xf0, 0xa0, 0x46, 0x7b, 0x85, 0xa5, 0x34, 0xa0, 0xa4, 0x2e, + 0x7b, 0x3b, 0x03, 0x3d, 0x54, 0xbf, 0x57, 0x84, 0xd9, 0x67, 0xad, 0x03, 0xe2, 0x86, 0xd6, 0xe8, + 0x02, 0x88, 0x5a, 0xe5, 0x6d, 0x16, 0xa8, 0xa8, 0xe9, 0x8f, 0x91, 0x55, 0x1e, 0x81, 0xb0, 0x8e, + 0x17, 0xc9, 0x15, 0xfe, 0xc2, 0x3a, 0x4d, 0x22, 0xac, 0x26, 0xe0, 0xb8, 0xaf, 0x06, 0xba, 0x0c, + 0x48, 0xbc, 0x17, 0xa9, 0xd4, 0xeb, 0x5e, 0xc7, 0xe5, 0x92, 0x85, 0x1b, 0xec, 0xca, 0x90, 0xd9, + 0xec, 0xc3, 0xc0, 0x29, 0xb5, 0xd0, 0x87, 0x60, 0xb9, 0xce, 0x28, 0x0b, 0xb5, 0x56, 0xa7, 0xc8, + 0x4d, 0x1b, 0x15, 0x24, 0xbc, 0x3a, 0x00, 0x0f, 0x0f, 0xa4, 0x40, 0x5b, 0x1a, 0x84, 0x9e, 0x6f, + 0x35, 0x89, 0x4e, 0x77, 0x22, 0xde, 0xd2, 0x5a, 0x1f, 0x06, 0x4e, 0xa9, 0x85, 0x3e, 0x09, 0x53, + 0xe1, 0x9e, 0x4f, 0x82, 0x3d, 0xcf, 0x69, 0x88, 0xab, 0xe1, 0x31, 0xbd, 0x38, 0x62, 0xf6, 0xb7, + 0x25, 0x55, 0x6d, 0x79, 0xcb, 0x22, 0x1c, 0xf1, 0x44, 0x3e, 0x4c, 0x04, 0x75, 0xaf, 0x4d, 0x02, + 0xa1, 0x0e, 0x5e, 0xce, 0x84, 0x3b, 0xf3, 0x4a, 0x68, 0xfe, 0x23, 0xc6, 0x01, 0x0b, 0x4e, 0xe6, + 0x37, 0x73, 0x30, 0xa3, 0x23, 0x0e, 0x21, 0x22, 0x3e, 0x65, 0xc0, 0x4c, 0xdd, 0x73, 0x43, 0xdf, + 0x73, 0xb8, 0x6f, 0x84, 0x6f, 0x90, 0x31, 0x9f, 0x21, 0x33, 0x52, 0x6b, 0x24, 0xb4, 0x6c, 0x47, + 0x73, 0xb3, 0x68, 0x6c, 0x70, 0x8c, 0x29, 0xfa, 0x8c, 0x01, 0xf3, 0x51, 0xcc, 0x4c, 0xe4, 0xa4, + 0xc9, 0xb4, 0x21, 0x4a, 0xe2, 0x5e, 0x88, 0x73, 0xc2, 0x49, 0xd6, 0xe6, 0x0e, 0x2c, 0x24, 0x67, + 0x9b, 0x0e, 0x65, 0xdb, 0x12, 0x7b, 0x3d, 0x1f, 0x0d, 0xe5, 0x96, 0x15, 0x04, 0x98, 0x41, 0xd0, + 0x3b, 0xa0, 0xd4, 0xb2, 0xfc, 0xa6, 0xed, 0x5a, 0x0e, 0x1b, 0xc5, 0xbc, 0x26, 0x90, 0x44, 0x39, + 0x56, 0x18, 0xe6, 0x8f, 0x0a, 0x30, 0xad, 0x69, 0xf1, 0xc7, 0xaf, 0x91, 0xc7, 0x9e, 0xb0, 0xe6, + 0x33, 0x7c, 0xc2, 0xfa, 0x3c, 0xc0, 0xae, 0xed, 0xda, 0xc1, 0xde, 0x11, 0x1f, 0xc7, 0xb2, 0xcb, + 0xbc, 0x8b, 0x8a, 0x02, 0xd6, 0xa8, 0x45, 0x37, 0x26, 0xc5, 0x43, 0x52, 0x06, 0xbc, 0x62, 0x68, + 0x87, 0xc7, 0x44, 0x16, 0x37, 0xc4, 0xda, 0xc4, 0xac, 0xc8, 0xc3, 0xe4, 0x82, 0x1b, 0xfa, 0x07, + 0x87, 0x9e, 0x31, 0xdb, 0x50, 0xf2, 0x49, 0xd0, 0x69, 0x51, 0xdb, 0x62, 0x72, 0xe4, 0x61, 0x60, + 0x01, 0x26, 0x58, 0xd4, 0xc7, 0x8a, 0xd2, 0xe9, 0xa7, 0x60, 0x36, 0xd6, 0x04, 0xb4, 0x00, 0xf9, + 0x5b, 0xe4, 0x80, 0xaf, 0x13, 0x4c, 0x7f, 0xa2, 0xa5, 0xd8, 0xbd, 0x92, 0x18, 0x96, 0xf7, 0xe6, + 0x9e, 0x34, 0x4c, 0x0f, 0x52, 0x4d, 0xc5, 0xa3, 0xb8, 0xfd, 0xe9, 0x5c, 0x38, 0xda, 0xeb, 0x58, + 0x35, 0x17, 0x3c, 0x9a, 0x81, 0xc3, 0xcc, 0x1f, 0x4f, 0x80, 0xb8, 0xf4, 0x1c, 0x42, 0xf8, 0xe8, + 0x77, 0x1d, 0xb9, 0x23, 0xdc, 0x75, 0x5c, 0x86, 0x19, 0xdb, 0xb5, 0x43, 0xdb, 0x72, 0x98, 0x1b, + 0x40, 0x1c, 0x8e, 0x8f, 0x48, 0x81, 0xb3, 0xae, 0xc1, 0x52, 0xe8, 0xc4, 0xea, 0xa2, 0x6b, 0x50, + 0x64, 0xa7, 0x87, 0x58, 0xc0, 0xa3, 0xdf, 0xcc, 0xb2, 0x4b, 0x79, 0xfe, 0x3a, 0x81, 0x53, 0x62, + 0x1a, 0x3d, 0x7f, 0x1e, 0xac, 0x0c, 0x35, 0xb1, 0x8e, 0x23, 0x8d, 0x3e, 0x01, 0xc7, 0x7d, 0x35, + 0x28, 0x95, 0x5d, 0xcb, 0x76, 0x3a, 0x3e, 0x89, 0xa8, 0x4c, 0xc4, 0xa9, 0x5c, 0x4c, 0xc0, 0x71, + 0x5f, 0x0d, 0xb4, 0x0b, 0x33, 0xa2, 0x8c, 0xc7, 0xa8, 0x4c, 0x1e, 0xb1, 0x97, 0x2c, 0x16, 0xe9, + 0xa2, 0x46, 0x09, 0xc7, 0xe8, 0xa2, 0x0e, 0x2c, 0xda, 0x6e, 0xdd, 0x73, 0xeb, 0x4e, 0x27, 0xb0, + 0xf7, 0x49, 0xf4, 0x34, 0xe0, 0x28, 0xcc, 0x4e, 0xf6, 0xba, 0xe5, 0xc5, 0xf5, 0x24, 0x39, 0xdc, + 0xcf, 0x01, 0xbd, 0x6c, 0xc0, 0xc9, 0xba, 0xe7, 0x06, 0xec, 0xbd, 0xdd, 0x3e, 0xb9, 0xe0, 0xfb, + 0x9e, 0xcf, 0x79, 0x4f, 0x1d, 0x91, 0x37, 0xf3, 0x3e, 0xad, 0xa6, 0x91, 0xc4, 0xe9, 0x9c, 0xd0, + 0x8b, 0x50, 0x6a, 0xfb, 0xde, 0xbe, 0xdd, 0x20, 0xbe, 0x88, 0x77, 0xda, 0xc8, 0xe2, 0xfd, 0xef, + 0x96, 0xa0, 0x19, 0x89, 0x1e, 0x59, 0x82, 0x15, 0x3f, 0xf3, 0x0f, 0x4b, 0x30, 0x17, 0x47, 0x47, + 0x9f, 0x00, 0x68, 0xfb, 0x5e, 0x8b, 0x84, 0x7b, 0x44, 0x85, 0x78, 0x5f, 0x19, 0xf7, 0x99, 0xa9, + 0xa4, 0x27, 0xe3, 0x1c, 0xa8, 0xb8, 0x88, 0x4a, 0xb1, 0xc6, 0x11, 0xf9, 0x30, 0x79, 0x8b, 0x1f, + 0xa2, 0x42, 0xa7, 0x78, 0x36, 0x13, 0x0d, 0x48, 0x70, 0x66, 0xb1, 0xc9, 0xa2, 0x08, 0x4b, 0x46, + 0x68, 0x07, 0xf2, 0xb7, 0xc9, 0x4e, 0x36, 0x0f, 0x22, 0x6f, 0x10, 0x61, 0x9b, 0x54, 0x27, 0x7b, + 0xdd, 0x72, 0xfe, 0x06, 0xd9, 0xc1, 0x94, 0x38, 0xed, 0x57, 0x83, 0xdf, 0xd8, 0x0a, 0x51, 0x31, + 0x66, 0xbf, 0x62, 0xd7, 0xbf, 0xbc, 0x5f, 0xa2, 0x08, 0x4b, 0x46, 0xe8, 0x45, 0x98, 0xba, 0x6d, + 0xed, 0x93, 0x5d, 0xdf, 0x73, 0x43, 0x11, 0x5c, 0x33, 0x66, 0x14, 0xf1, 0x0d, 0x49, 0x4e, 0xf0, + 0x65, 0xc7, 0xbb, 0x2a, 0xc4, 0x11, 0x3b, 0xb4, 0x0f, 0x25, 0x97, 0xdc, 0xc6, 0xc4, 0xb1, 0xeb, + 0x22, 0x80, 0x73, 0xcc, 0x65, 0x7d, 0x45, 0x50, 0x13, 0x9c, 0xd9, 0xb9, 0x27, 0xcb, 0xb0, 0xe2, + 0x45, 0xe7, 0xf2, 0xa6, 0xb7, 0x23, 0x04, 0xd5, 0x98, 0x73, 0xa9, 0xec, 0x4c, 0x3e, 0x97, 0x97, + 0xbd, 0x1d, 0x4c, 0x89, 0xd3, 0x3d, 0x52, 0x57, 0x91, 0x1d, 0x42, 0x4c, 0x5d, 0xc9, 0x36, 0xa2, + 0x85, 0xef, 0x91, 0xa8, 0x14, 0x6b, 0x1c, 0xe9, 0xd8, 0x36, 0x85, 0x5b, 0x4b, 0x08, 0xaa, 0x31, + 0xc7, 0x36, 0xee, 0x24, 0xe3, 0x63, 0x2b, 0xcb, 0xb0, 0xe2, 0x65, 0xfe, 0x6b, 0x01, 0x66, 0xf4, + 0x7c, 0x27, 0x43, 0x9c, 0xd5, 0x4a, 0x3f, 0xcd, 0x8d, 0xa2, 0x9f, 0x52, 0xf3, 0x42, 0xf3, 0x4a, + 0x4b, 0x0f, 0xc3, 0x7a, 0x66, 0xea, 0x59, 0x64, 0x5e, 0x68, 0x85, 0x01, 0x8e, 0x31, 0x1d, 0xe1, + 0xa2, 0x9a, 0x2a, 0x39, 0x5c, 0x0d, 0x28, 0xc6, 0x95, 0x9c, 0xd8, 0xc1, 0x7e, 0x1e, 0x20, 0xca, + 0xfb, 0x21, 0x6e, 0x2b, 0x94, 0xf6, 0xa4, 0xe5, 0x23, 0xd1, 0xb0, 0xd0, 0x23, 0x30, 0x41, 0x0f, + 0x4a, 0xd2, 0x10, 0xef, 0xef, 0x94, 0x0d, 0x77, 0x91, 0x95, 0x62, 0x01, 0x45, 0x4f, 0x52, 0x9d, + 0x26, 0x3a, 0xde, 0xc4, 0xb3, 0xba, 0xa5, 0x48, 0xa7, 0x89, 0x60, 0x38, 0x86, 0x49, 0x9b, 0x4e, + 0xe8, 0x69, 0xc4, 0x56, 0x92, 0xd6, 0x74, 0x76, 0x44, 0x61, 0x0e, 0x63, 0x3e, 0x85, 0xc4, 0xe9, + 0xc5, 0x0e, 0xab, 0xa2, 0xe6, 0x53, 0x48, 0xc0, 0x71, 0x5f, 0x0d, 0xda, 0x19, 0x71, 0xd1, 0x32, + 0xcd, 0xe3, 0xf1, 0xd2, 0xaf, 0x48, 0xcc, 0x8f, 0xc0, 0x5c, 0x7c, 0xb7, 0xd3, 0xa9, 0x68, 0xfb, + 0xde, 0xae, 0xed, 0x90, 0xa4, 0xd7, 0x64, 0x8b, 0x17, 0x63, 0x09, 0x1f, 0xce, 0x6d, 0xfb, 0xd7, + 0x79, 0x38, 0x71, 0xa5, 0x69, 0xbb, 0x77, 0x12, 0xfe, 0xce, 0xb4, 0x6c, 0x74, 0xc6, 0xa8, 0xd9, + 0xe8, 0xa2, 0x87, 0x06, 0x22, 0xdd, 0x5f, 0xfa, 0x43, 0x03, 0x99, 0x0b, 0x30, 0x8e, 0x8b, 0x7e, + 0x60, 0xc0, 0x83, 0x56, 0x83, 0xeb, 0x5f, 0x96, 0x23, 0x4a, 0x23, 0xa6, 0x72, 0x2f, 0x04, 0x63, + 0x4a, 0xd3, 0xfe, 0xce, 0xaf, 0x54, 0x0e, 0xe1, 0xca, 0xcd, 0x98, 0xb7, 0x89, 0x1e, 0x3c, 0x78, + 0x18, 0x2a, 0x3e, 0xb4, 0xf9, 0xa7, 0xaf, 0xc2, 0x5b, 0xef, 0xca, 0x68, 0x24, 0x63, 0xe5, 0x53, + 0x06, 0x4c, 0x71, 0x77, 0x1e, 0x26, 0xbb, 0x74, 0x93, 0x59, 0x6d, 0xfb, 0x39, 0xe2, 0x07, 0x32, + 0x4d, 0x86, 0x66, 0xa2, 0x54, 0xb6, 0xd6, 0x05, 0x04, 0x6b, 0x58, 0x54, 0x8c, 0xdd, 0xb2, 0xdd, + 0x86, 0x98, 0x26, 0x25, 0xc6, 0x9e, 0xb5, 0xdd, 0x06, 0x66, 0x10, 0x25, 0xe8, 0xf2, 0x83, 0x04, + 0x9d, 0xf9, 0x15, 0x03, 0xe6, 0xd8, 0x3b, 0xa2, 0x48, 0x79, 0x7e, 0x42, 0xdd, 0xdf, 0xf3, 0x66, + 0x9c, 0x89, 0xdf, 0xdf, 0xbf, 0xd1, 0x2d, 0x4f, 0xf3, 0x97, 0x47, 0xf1, 0xeb, 0xfc, 0x0f, 0x0a, + 0x8b, 0x9b, 0x45, 0x19, 0xe4, 0x46, 0x36, 0x08, 0x95, 0x7f, 0xa9, 0x26, 0x89, 0xe0, 0x88, 0x9e, + 0xf9, 0xc7, 0x79, 0x38, 0x91, 0x12, 0x10, 0x4f, 0x8d, 0xe1, 0x09, 0x16, 0x13, 0x2c, 0xef, 0xc8, + 0x5f, 0xc8, 0x3c, 0xe8, 0x7e, 0x85, 0x85, 0x1e, 0x8b, 0x95, 0xa4, 0xb6, 0x3e, 0x2f, 0xc4, 0x82, + 0x39, 0xfa, 0x6d, 0x03, 0xa6, 0x2d, 0x6d, 0xb1, 0xf3, 0xb0, 0x81, 0x9d, 0xec, 0x1b, 0xd3, 0xb7, + 0xb6, 0xb5, 0x70, 0xa7, 0x68, 0x29, 0xeb, 0x6d, 0x39, 0xfd, 0x1e, 0x98, 0xd6, 0xba, 0x30, 0xca, + 0x1a, 0x3d, 0xfd, 0x34, 0x2c, 0x8c, 0xb5, 0xc6, 0x3f, 0x00, 0xa3, 0xe6, 0x5d, 0xa1, 0xc2, 0xf6, + 0xb6, 0xfe, 0xbc, 0x4e, 0x8d, 0xb8, 0x78, 0x5f, 0x27, 0xa0, 0xe6, 0x0e, 0x2c, 0x24, 0x15, 0xf4, + 0xcc, 0x6f, 0xc9, 0xde, 0x05, 0x23, 0x66, 0x4a, 0x31, 0xff, 0x26, 0x07, 0x93, 0xe2, 0x55, 0xcd, + 0x3d, 0x88, 0x14, 0xbc, 0x15, 0x73, 0xf3, 0xaf, 0x67, 0xf2, 0x18, 0x68, 0x60, 0x98, 0x60, 0x90, + 0x08, 0x13, 0x7c, 0x36, 0x1b, 0x76, 0x87, 0xc7, 0x08, 0x7e, 0xa5, 0x00, 0xf3, 0x89, 0x57, 0x4a, + 0xe8, 0x55, 0xa3, 0x3f, 0x34, 0xe6, 0x7a, 0xa6, 0x0f, 0xa1, 0x54, 0x14, 0xeb, 0xe1, 0x51, 0x32, + 0x41, 0x2c, 0x21, 0xd5, 0xb5, 0xcc, 0x72, 0x59, 0xfe, 0x2c, 0x37, 0xd5, 0xa8, 0x51, 0x1f, 0xff, + 0x62, 0xc0, 0xfd, 0x03, 0x1f, 0xb3, 0xb1, 0x57, 0xfa, 0x7e, 0x1c, 0x2a, 0x36, 0x64, 0xc6, 0x8f, + 0x53, 0x95, 0xcf, 0x3d, 0xf9, 0xb0, 0x3a, 0xc9, 0x1e, 0x3d, 0x0e, 0x33, 0xec, 0x70, 0xa3, 0x32, + 0x25, 0x24, 0x6d, 0xe1, 0x64, 0x64, 0xee, 0xa6, 0x9a, 0x56, 0x8e, 0x63, 0x58, 0xe6, 0x97, 0x0d, + 0x58, 0x1e, 0xf4, 0x66, 0x7b, 0x08, 0xa3, 0xe6, 0x97, 0x12, 0xa1, 0x8c, 0xe5, 0xbe, 0x50, 0xc6, + 0x84, 0x59, 0x23, 0xa3, 0x16, 0x35, 0x8b, 0x22, 0x7f, 0x97, 0x48, 0xbd, 0xcf, 0x1a, 0x70, 0x6a, + 0xc0, 0x6e, 0xea, 0x0b, 0x69, 0x35, 0x8e, 0x1c, 0xd2, 0x9a, 0x1b, 0x36, 0xa4, 0xd5, 0xfc, 0xbb, + 0x3c, 0x2c, 0x88, 0xf6, 0x44, 0x1a, 0xce, 0x93, 0xb1, 0x80, 0xd0, 0xb7, 0x25, 0x02, 0x42, 0x97, + 0x92, 0xf8, 0x3f, 0x8b, 0x06, 0x7d, 0x73, 0x45, 0x83, 0xfe, 0x24, 0x07, 0x27, 0x53, 0x9f, 0xa6, + 0xa3, 0x4f, 0xa7, 0x1c, 0x0d, 0x37, 0x32, 0x7e, 0x03, 0x3f, 0xe4, 0xe1, 0x30, 0x6e, 0x08, 0xe5, + 0x17, 0xf4, 0xd0, 0x45, 0x2e, 0xea, 0x77, 0x8f, 0xe1, 0x35, 0xff, 0x88, 0x51, 0x8c, 0xe6, 0x6f, + 0xe4, 0xe1, 0xd1, 0x61, 0x09, 0xbd, 0x49, 0xa3, 0xdc, 0x83, 0x58, 0x94, 0xfb, 0x3d, 0x3a, 0xb6, + 0x8f, 0x25, 0xe0, 0xfd, 0xab, 0x79, 0x75, 0xec, 0xf5, 0xaf, 0xcf, 0xa1, 0x6e, 0xa4, 0x26, 0xa9, + 0x6a, 0x27, 0x13, 0xcc, 0x45, 0xa2, 0x70, 0xb2, 0xc6, 0x8b, 0xdf, 0xe8, 0x96, 0x17, 0x45, 0xd2, + 0xa9, 0x1a, 0x09, 0x45, 0x21, 0x96, 0x95, 0xd0, 0xa3, 0x50, 0xf2, 0x39, 0x54, 0xc6, 0xf5, 0x8a, + 0x6b, 0x3d, 0x5e, 0x86, 0x15, 0x14, 0x7d, 0x52, 0xd3, 0x85, 0x0b, 0xc7, 0xf5, 0x3a, 0xfa, 0xb0, + 0xdb, 0xca, 0x17, 0xa0, 0x14, 0xc8, 0x54, 0x71, 0xdc, 0xa5, 0xfc, 0xd8, 0x90, 0xe1, 0xe2, 0xd4, + 0x74, 0x92, 0x79, 0xe3, 0x78, 0xff, 0x54, 0x56, 0x39, 0x45, 0x12, 0x99, 0xca, 0x6a, 0xe1, 0xfe, + 0x31, 0x48, 0xb1, 0x58, 0xbe, 0x63, 0xc0, 0xb4, 0x98, 0xad, 0x7b, 0x10, 0xc1, 0x7e, 0x33, 0x1e, + 0xc1, 0x7e, 0x21, 0x13, 0xd9, 0x31, 0x20, 0x7c, 0xfd, 0x26, 0xcc, 0xe8, 0xd9, 0x49, 0xd0, 0xf3, + 0x9a, 0xec, 0x33, 0xc6, 0xc9, 0x82, 0x20, 0xa5, 0x63, 0x24, 0x17, 0xcd, 0x2f, 0x95, 0xd4, 0x28, + 0xb2, 0x38, 0x79, 0x7d, 0x0d, 0x1a, 0x87, 0xae, 0x41, 0x7d, 0x09, 0xe4, 0xb2, 0x5f, 0x02, 0xd7, + 0xa0, 0x24, 0x05, 0x94, 0x38, 0xc6, 0x1f, 0xd6, 0xe3, 0xae, 0xa8, 0x2e, 0x40, 0x89, 0x69, 0x0b, + 0x97, 0x99, 0x5a, 0x6a, 0x0e, 0x95, 0xe0, 0x54, 0x64, 0xd0, 0x8b, 0x30, 0x7d, 0xdb, 0xf3, 0x6f, + 0x39, 0x9e, 0xc5, 0x92, 0x40, 0x42, 0x16, 0x97, 0x03, 0xca, 0xe5, 0xc4, 0xc3, 0x7b, 0x6f, 0x44, + 0xf4, 0xb1, 0xce, 0x0c, 0x55, 0x60, 0xbe, 0x65, 0xbb, 0x98, 0x58, 0x0d, 0x15, 0xa8, 0x5e, 0xe0, + 0x59, 0xea, 0xa4, 0x92, 0xbb, 0x19, 0x07, 0xe3, 0x24, 0x3e, 0xfa, 0x18, 0x94, 0x02, 0x91, 0x01, + 0x25, 0x9b, 0x6b, 0x1c, 0x65, 0x33, 0x72, 0xa2, 0xd1, 0xd8, 0xc9, 0x12, 0xac, 0x18, 0xa2, 0x0d, + 0x58, 0xf2, 0x45, 0x8e, 0x81, 0x58, 0xb2, 0x6b, 0xbe, 0x3f, 0x59, 0x32, 0x34, 0x9c, 0x02, 0xc7, + 0xa9, 0xb5, 0xa8, 0x16, 0xc3, 0xd2, 0xec, 0x70, 0x7f, 0xb6, 0xe6, 0x02, 0x66, 0x0b, 0xbe, 0x81, + 0x05, 0xf4, 0xb0, 0x87, 0x0f, 0xa5, 0x31, 0x1e, 0x3e, 0xd4, 0xe0, 0x64, 0x12, 0xc4, 0x32, 0x21, + 0xb0, 0xe4, 0x0b, 0xda, 0xe9, 0xb1, 0x95, 0x86, 0x84, 0xd3, 0xeb, 0xa2, 0x1b, 0x30, 0xe5, 0x13, + 0x66, 0x5f, 0x54, 0xe4, 0xc5, 0xf1, 0xc8, 0x21, 0x32, 0x58, 0x12, 0xc0, 0x11, 0x2d, 0x3a, 0xef, + 0x56, 0x3c, 0x51, 0xdb, 0xb5, 0x0c, 0x3f, 0xd7, 0x21, 0xe6, 0x7e, 0x40, 0x86, 0x12, 0xf3, 0xf5, + 0x39, 0x98, 0x8d, 0xf9, 0x16, 0xd0, 0xc3, 0x50, 0x64, 0xa9, 0x21, 0x98, 0x78, 0x28, 0x45, 0x22, + 0x8c, 0x0f, 0x0e, 0x87, 0xa1, 0xcf, 0x19, 0x30, 0xdf, 0x8e, 0xf9, 0x41, 0xa5, 0xe4, 0x1c, 0xf3, + 0x8e, 0x2a, 0xee, 0x5c, 0xd5, 0x52, 0x9c, 0xc6, 0x99, 0xe1, 0x24, 0x77, 0xba, 0x01, 0x45, 0xd4, + 0x98, 0x43, 0x7c, 0x86, 0x2d, 0x74, 0x1c, 0x45, 0x62, 0x35, 0x0e, 0xc6, 0x49, 0x7c, 0x3a, 0xc3, + 0xac, 0x77, 0xe3, 0xe4, 0xf1, 0xaf, 0x48, 0x02, 0x38, 0xa2, 0x85, 0x9e, 0x86, 0x39, 0x91, 0x9f, + 0x6b, 0xcb, 0x6b, 0x5c, 0xb2, 0x82, 0x3d, 0xa1, 0xdc, 0x2b, 0x63, 0x64, 0x35, 0x06, 0xc5, 0x09, + 0x6c, 0xd6, 0xb7, 0x28, 0x09, 0x1a, 0x23, 0x30, 0x11, 0xcf, 0x00, 0xbb, 0x1a, 0x07, 0xe3, 0x24, + 0x3e, 0x7a, 0x87, 0x26, 0xf7, 0xf9, 0x1d, 0x93, 0x92, 0x06, 0x29, 0xb2, 0xbf, 0x02, 0xf3, 0x1d, + 0x66, 0x0b, 0x35, 0x24, 0x50, 0xec, 0x47, 0xc5, 0xf0, 0x7a, 0x1c, 0x8c, 0x93, 0xf8, 0xe8, 0x29, + 0x98, 0xf5, 0xa9, 0x74, 0x53, 0x04, 0xf8, 0xc5, 0x93, 0xba, 0x1d, 0xc1, 0x3a, 0x10, 0xc7, 0x71, + 0xd1, 0x33, 0xb0, 0x18, 0x25, 0x0d, 0x92, 0x04, 0xf8, 0x4d, 0x94, 0xca, 0xc2, 0x51, 0x49, 0x22, + 0xe0, 0xfe, 0x3a, 0xe8, 0x97, 0x61, 0x41, 0x1b, 0x89, 0x75, 0xb7, 0x41, 0xee, 0x88, 0xc4, 0x2e, + 0xec, 0xcb, 0x45, 0xab, 0x09, 0x18, 0xee, 0xc3, 0x46, 0xef, 0x85, 0xb9, 0xba, 0xe7, 0x38, 0x4c, + 0xc6, 0xf1, 0xec, 0xa3, 0x3c, 0x83, 0x0b, 0xcf, 0x75, 0x13, 0x83, 0xe0, 0x04, 0x26, 0xba, 0x0c, + 0xc8, 0xdb, 0x09, 0x88, 0xbf, 0x4f, 0x1a, 0xcf, 0xf0, 0x2f, 0x83, 0xd1, 0x23, 0x7e, 0x36, 0x1e, + 0xb3, 0x7a, 0xb5, 0x0f, 0x03, 0xa7, 0xd4, 0x62, 0x49, 0x3c, 0xb4, 0xf7, 0x23, 0x73, 0x59, 0xe4, + 0xb4, 0x4f, 0x5a, 0xee, 0x77, 0x7d, 0x3c, 0xe2, 0xc3, 0x04, 0x0f, 0x21, 0x5e, 0x9e, 0xcf, 0x22, + 0x91, 0x91, 0x9e, 0x88, 0x30, 0x3a, 0x23, 0x78, 0x29, 0x16, 0x9c, 0xd0, 0x27, 0x60, 0x6a, 0x47, + 0x66, 0xa5, 0x5d, 0x5e, 0xc8, 0xe2, 0x5c, 0x4c, 0x24, 0x58, 0x8e, 0x2c, 0x53, 0x05, 0xc0, 0x11, + 0x4b, 0xf4, 0x08, 0x4c, 0x5f, 0xda, 0xaa, 0xa8, 0x55, 0xb8, 0xc8, 0x66, 0xbf, 0x40, 0xab, 0x60, + 0x1d, 0x40, 0x77, 0x98, 0xd2, 0x97, 0x10, 0x9b, 0xe2, 0xe8, 0xbc, 0xed, 0x57, 0x7f, 0x28, 0x36, + 0xbb, 0x10, 0xc4, 0xb5, 0xe5, 0x13, 0x09, 0x6c, 0x51, 0x8e, 0x15, 0x06, 0x7a, 0x01, 0xa6, 0xc5, + 0x79, 0xc1, 0x64, 0xd3, 0xd2, 0xd1, 0xde, 0x26, 0xe1, 0x88, 0x04, 0xd6, 0xe9, 0xa1, 0x27, 0x60, + 0xba, 0xcd, 0x92, 0x75, 0x92, 0x8b, 0x1d, 0xc7, 0x59, 0x3e, 0xc9, 0xe4, 0xa6, 0xba, 0x29, 0xd9, + 0x8a, 0x40, 0x58, 0xc7, 0x43, 0x8f, 0xc9, 0x5b, 0xff, 0xb7, 0xc4, 0x2e, 0xbe, 0xd4, 0xad, 0xbf, + 0xd2, 0x72, 0x07, 0x04, 0xa5, 0x9e, 0xba, 0xcb, 0x75, 0xfb, 0x0e, 0x9c, 0x96, 0x2a, 0x56, 0xff, + 0x26, 0x59, 0x5e, 0x8e, 0x79, 0x09, 0x4e, 0xdf, 0x18, 0x88, 0x89, 0x0f, 0xa1, 0x82, 0x76, 0x20, + 0x6f, 0x39, 0x3b, 0xcb, 0xf7, 0x67, 0xa1, 0x2b, 0xaa, 0x2f, 0xfd, 0xf1, 0x40, 0x92, 0xca, 0x46, + 0x15, 0x53, 0xe2, 0xe6, 0xcb, 0x39, 0xe5, 0x95, 0x57, 0x29, 0xee, 0x3e, 0xae, 0xaf, 0x6a, 0x23, + 0x8b, 0x2f, 0x59, 0xf5, 0xa5, 0x6e, 0xe6, 0x07, 0x52, 0xea, 0x9a, 0x6e, 0xab, 0x7d, 0x9c, 0x49, + 0xd6, 0x84, 0x78, 0xfa, 0x3e, 0x6e, 0xcd, 0xc5, 0x77, 0xb1, 0xf9, 0xc3, 0x82, 0x72, 0x42, 0x25, + 0x2e, 0xe3, 0x7d, 0x28, 0xda, 0x41, 0x68, 0x7b, 0x19, 0x3e, 0x39, 0x4a, 0xe4, 0xbd, 0x63, 0xc1, + 0x97, 0x0c, 0x80, 0x39, 0x2b, 0xca, 0xd3, 0x6d, 0xda, 0xee, 0x1d, 0xd1, 0xfd, 0x6b, 0x99, 0xdf, + 0xb2, 0x73, 0x9e, 0x0c, 0x80, 0x39, 0x2b, 0x74, 0x93, 0xaf, 0xb4, 0x6c, 0xbe, 0x5a, 0x96, 0xfc, + 0x18, 0x61, 0x7c, 0xc5, 0x51, 0x5e, 0x41, 0xcb, 0x16, 0x3a, 0xcc, 0x98, 0xbc, 0x6a, 0x9b, 0xeb, + 0x69, 0xbc, 0x6a, 0x9b, 0xeb, 0x98, 0x32, 0x41, 0xaf, 0x1a, 0x00, 0x96, 0xfa, 0x2a, 0x5f, 0x36, + 0x79, 0xce, 0x07, 0x7d, 0xe5, 0x8f, 0xc7, 0x4b, 0x45, 0x50, 0xac, 0x71, 0x36, 0xff, 0xc3, 0x00, + 0xed, 0x53, 0x46, 0x51, 0xb0, 0x8e, 0x31, 0x74, 0xb0, 0x4e, 0x6e, 0xc4, 0x60, 0x9d, 0xfc, 0x48, + 0xc1, 0x3a, 0x85, 0xd1, 0x83, 0x75, 0x8a, 0x83, 0x83, 0x75, 0xcc, 0xd7, 0x0c, 0x58, 0xec, 0x9b, + 0x9b, 0xe4, 0x27, 0x23, 0x8d, 0x21, 0x3f, 0x19, 0xb9, 0x06, 0x0b, 0x22, 0x11, 0x64, 0xad, 0xed, + 0xd8, 0xa9, 0xaf, 0x14, 0xb7, 0x13, 0x70, 0xdc, 0x57, 0xc3, 0xfc, 0x73, 0x03, 0xa6, 0xb5, 0x47, + 0x15, 0xb4, 0x1f, 0xec, 0xf1, 0x89, 0x68, 0x46, 0x94, 0x03, 0x93, 0xb9, 0x19, 0x39, 0x8c, 0x7b, + 0xbc, 0x9b, 0x5a, 0xaa, 0xb3, 0xc8, 0xe3, 0x4d, 0x4b, 0xb1, 0x80, 0xf2, 0x24, 0x56, 0x84, 0x7f, + 0x0e, 0x34, 0xaf, 0x27, 0xb1, 0x22, 0x6d, 0xcc, 0x20, 0x8c, 0x1d, 0x3d, 0xd3, 0x44, 0x1c, 0x97, + 0x96, 0x72, 0xd3, 0xa2, 0x96, 0x0b, 0x83, 0xa1, 0x33, 0x90, 0x27, 0x6e, 0x43, 0x28, 0xe0, 0xea, + 0x03, 0x0c, 0x17, 0xdc, 0x06, 0xa6, 0xe5, 0xe6, 0x55, 0x98, 0xa9, 0x91, 0xba, 0x4f, 0xc2, 0x67, + 0xc9, 0xc1, 0xd0, 0x5f, 0x74, 0xb8, 0x45, 0x0e, 0x92, 0x5f, 0x74, 0xa0, 0xd5, 0x69, 0xb9, 0xf9, + 0x07, 0x06, 0x24, 0x32, 0xa0, 0x6a, 0xde, 0x2f, 0x63, 0x90, 0xf7, 0x2b, 0xe6, 0xa7, 0xc9, 0x1d, + 0xea, 0xa7, 0xb9, 0x0c, 0xa8, 0x65, 0x85, 0xf5, 0xbd, 0x58, 0x7e, 0x5e, 0x61, 0xfb, 0x44, 0x4f, + 0xb8, 0xfa, 0x30, 0x70, 0x4a, 0x2d, 0xf3, 0x25, 0x03, 0xfa, 0xbe, 0xe6, 0x49, 0x4f, 0x6c, 0x22, + 0x92, 0xe5, 0x73, 0x93, 0x50, 0x9d, 0xd8, 0x32, 0x47, 0xbe, 0x84, 0x53, 0xbb, 0x41, 0x7a, 0x9e, + 0xa4, 0x1d, 0xcf, 0x1f, 0xbb, 0x28, 0xbb, 0x61, 0x2d, 0x0e, 0xc6, 0x49, 0x7c, 0xf3, 0x39, 0x28, + 0xc9, 0x17, 0x81, 0xec, 0x59, 0x8d, 0xb4, 0x44, 0xf5, 0x67, 0x35, 0xd4, 0x10, 0x65, 0x10, 0x3a, + 0x4c, 0x81, 0x6b, 0x5f, 0xf2, 0x82, 0x50, 0x3e, 0x63, 0xe4, 0xfe, 0xa6, 0x2b, 0xeb, 0xac, 0x0c, + 0x2b, 0xa8, 0xb9, 0x08, 0xf3, 0xca, 0x91, 0xc4, 0x17, 0xbd, 0xf9, 0xcd, 0x3c, 0xcc, 0xc4, 0xbe, + 0xd1, 0x74, 0xf7, 0xc9, 0x1e, 0x7e, 0x5a, 0x52, 0x1c, 0x42, 0xf9, 0x11, 0x1d, 0x42, 0xba, 0x07, + 0xae, 0x70, 0xbc, 0x1e, 0xb8, 0x62, 0x36, 0x1e, 0xb8, 0x10, 0x26, 0xc5, 0xf7, 0x6b, 0x45, 0x34, + 0xf0, 0x66, 0x46, 0xcf, 0xf9, 0xc5, 0xbb, 0x58, 0x16, 0x00, 0x2d, 0x05, 0x98, 0x64, 0x65, 0x7e, + 0xbd, 0x08, 0x73, 0xf1, 0x07, 0xfe, 0x43, 0xcc, 0xe4, 0x3b, 0xfa, 0x66, 0x72, 0x44, 0x83, 0x38, + 0x3f, 0xae, 0x41, 0x5c, 0x18, 0xd7, 0x20, 0x2e, 0x1e, 0xc1, 0x20, 0xee, 0x37, 0x67, 0x27, 0x86, + 0x36, 0x67, 0xdf, 0xa7, 0x6e, 0x73, 0x27, 0x63, 0xd7, 0x1f, 0xd1, 0x6d, 0x2e, 0x8a, 0x4f, 0xc3, + 0xaa, 0xd7, 0x48, 0xbd, 0x15, 0x2f, 0xdd, 0x45, 0xf1, 0xf7, 0x53, 0x2f, 0x5f, 0x47, 0xf7, 0xb9, + 0xbd, 0x65, 0x84, 0x8b, 0xd7, 0xe8, 0x13, 0xcd, 0xec, 0xf0, 0x83, 0xf8, 0xc1, 0x59, 0x8b, 0x40, + 0x58, 0xc7, 0x63, 0x1f, 0xe7, 0x89, 0x7f, 0x8d, 0x88, 0xf9, 0x17, 0xf4, 0x8f, 0xf3, 0x24, 0xbe, + 0x5e, 0x94, 0xc4, 0x37, 0xbf, 0x96, 0x87, 0xb9, 0x78, 0x72, 0x75, 0x74, 0x5b, 0xe9, 0xe7, 0x99, + 0x98, 0x06, 0x9c, 0xac, 0xf6, 0xc4, 0x7d, 0xa0, 0xb1, 0xcd, 0x3f, 0x1c, 0xbc, 0xa3, 0xde, 0xdb, + 0x1f, 0x1f, 0x63, 0x61, 0xe5, 0x0a, 0x76, 0x2c, 0x1f, 0x7b, 0x14, 0x50, 0x2a, 0x6e, 0x70, 0x33, + 0xe7, 0x1e, 0x85, 0x88, 0x2a, 0x56, 0x58, 0x63, 0x4b, 0xc5, 0xfb, 0x3e, 0xf1, 0xed, 0x5d, 0x5b, + 0x7d, 0x18, 0x86, 0x09, 0xcf, 0xe7, 0x44, 0x19, 0x56, 0x50, 0xf3, 0xa5, 0x1c, 0x44, 0x9f, 0xc1, + 0x62, 0x79, 0x9e, 0x03, 0x4d, 0x6d, 0x10, 0xd3, 0x76, 0x79, 0xdc, 0x64, 0xea, 0x11, 0x45, 0x11, + 0xec, 0xa2, 0x95, 0xe0, 0x18, 0xc7, 0x9f, 0xc2, 0xe7, 0xaf, 0x2c, 0x98, 0x4f, 0x3c, 0x14, 0xc9, + 0x3c, 0xa2, 0xf0, 0x4b, 0x79, 0x98, 0x52, 0x4f, 0x6d, 0xd0, 0x7b, 0x58, 0x8a, 0xd6, 0x3d, 0x4f, + 0x26, 0xce, 0x7d, 0xab, 0x96, 0x48, 0x75, 0xcf, 0x6b, 0xbc, 0xd1, 0x2d, 0xcf, 0x2b, 0x64, 0x5e, + 0x84, 0x45, 0x05, 0xaa, 0xa4, 0x75, 0x7c, 0x27, 0xa9, 0xa4, 0x5d, 0xc7, 0x1b, 0x98, 0x96, 0xa3, + 0x3b, 0x30, 0xb9, 0x47, 0xac, 0x06, 0xf1, 0x65, 0xec, 0xc0, 0x66, 0x46, 0xcf, 0x83, 0x2e, 0x31, + 0xaa, 0xd1, 0x30, 0xf0, 0xff, 0x01, 0x96, 0xec, 0xe8, 0x41, 0xb5, 0xe3, 0x35, 0x0e, 0x92, 0x89, + 0x57, 0xab, 0x5e, 0xe3, 0x00, 0x33, 0x08, 0x7a, 0x1a, 0xe6, 0x42, 0xbb, 0x45, 0xbc, 0x4e, 0xa8, + 0x7f, 0x64, 0x28, 0x1f, 0x39, 0x8f, 0xb7, 0x63, 0x50, 0x9c, 0xc0, 0xa6, 0x07, 0xdd, 0xcd, 0xc0, + 0x73, 0x59, 0x36, 0x95, 0x89, 0xb8, 0xa7, 0xe9, 0x72, 0xed, 0xea, 0x15, 0x96, 0x4c, 0x45, 0x61, + 0x50, 0x6c, 0x9b, 0xc5, 0xf3, 0xfb, 0x44, 0xdc, 0xdd, 0x2c, 0x44, 0xaf, 0x2e, 0x79, 0x39, 0x56, + 0x18, 0xe6, 0x75, 0x98, 0x4f, 0x74, 0x55, 0xaa, 0xc3, 0x46, 0xba, 0x3a, 0x3c, 0x5c, 0x96, 0xd3, + 0x3f, 0x31, 0x60, 0xb1, 0x6f, 0xf3, 0x0e, 0x1b, 0xea, 0x9a, 0x94, 0xe4, 0xb9, 0xa3, 0x4b, 0xf2, + 0xfc, 0x68, 0x92, 0xbc, 0xba, 0xf2, 0xad, 0xd7, 0xcf, 0xde, 0xf7, 0xed, 0xd7, 0xcf, 0xde, 0xf7, + 0xdd, 0xd7, 0xcf, 0xde, 0xf7, 0x52, 0xef, 0xac, 0xf1, 0xad, 0xde, 0x59, 0xe3, 0xdb, 0xbd, 0xb3, + 0xc6, 0x77, 0x7b, 0x67, 0x8d, 0x1f, 0xf6, 0xce, 0x1a, 0xaf, 0xfd, 0xe8, 0xec, 0x7d, 0xcf, 0x97, + 0xe4, 0x32, 0xf9, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xde, 0xbc, 0xf3, 0x4f, 0xf7, 0x83, 0x00, + 0x00, } func (m *ALBStatus) Marshal() (dAtA []byte, err error) { @@ -5120,6 +5121,20 @@ func (m *ExperimentSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.MeasurementRetention) > 0 { + for iNdEx := len(m.MeasurementRetention) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.MeasurementRetention[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } + } if len(m.DryRun) > 0 { for iNdEx := len(m.DryRun) - 1; iNdEx >= 0; iNdEx-- { { @@ -8980,6 +8995,12 @@ func (m *ExperimentSpec) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) } } + if len(m.MeasurementRetention) > 0 { + for _, e := range m.MeasurementRetention { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } return n } @@ -10637,6 +10658,11 @@ func (this *ExperimentSpec) String() string { repeatedStringForDryRun += strings.Replace(strings.Replace(f.String(), "DryRun", "DryRun", 1), `&`, ``, 1) + "," } repeatedStringForDryRun += "}" + repeatedStringForMeasurementRetention := "[]MeasurementRetention{" + for _, f := range this.MeasurementRetention { + repeatedStringForMeasurementRetention += strings.Replace(strings.Replace(f.String(), "MeasurementRetention", "MeasurementRetention", 1), `&`, ``, 1) + "," + } + repeatedStringForMeasurementRetention += "}" s := strings.Join([]string{`&ExperimentSpec{`, `Templates:` + repeatedStringForTemplates + `,`, `Duration:` + fmt.Sprintf("%v", this.Duration) + `,`, @@ -10645,6 +10671,7 @@ func (this *ExperimentSpec) String() string { `Analyses:` + repeatedStringForAnalyses + `,`, `ScaleDownDelaySeconds:` + valueToStringGenerated(this.ScaleDownDelaySeconds) + `,`, `DryRun:` + repeatedStringForDryRun + `,`, + `MeasurementRetention:` + repeatedStringForMeasurementRetention + `,`, `}`, }, "") return s @@ -17694,6 +17721,40 @@ func (m *ExperimentSpec) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MeasurementRetention", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MeasurementRetention = append(m.MeasurementRetention, MeasurementRetention{}) + if err := m.MeasurementRetention[len(m.MeasurementRetention)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) diff --git a/pkg/apis/rollouts/v1alpha1/generated.proto b/pkg/apis/rollouts/v1alpha1/generated.proto index e4063d3721..f8277f9f84 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.proto +++ b/pkg/apis/rollouts/v1alpha1/generated.proto @@ -649,6 +649,12 @@ message ExperimentSpec { // +patchStrategy=merge // +optional repeated DryRun dryRun = 7; + + // MeasurementRetention object contains the settings for retaining the number of measurements during the analysis + // +patchMergeKey=metricName + // +patchStrategy=merge + // +optional + repeated MeasurementRetention measurementRetention = 8; } // ExperimentStatus is the status for a Experiment resource diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index 43ca298d45..398d3eee33 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -1911,12 +1911,32 @@ func schema_pkg_apis_rollouts_v1alpha1_ExperimentSpec(ref common.ReferenceCallba }, }, }, + "measurementRetention": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "MeasurementRetention object contains the settings for retaining the number of measurements during the analysis", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.MeasurementRetention"), + }, + }, + }, + }, + }, }, Required: []string{"templates"}, }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DryRun", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ExperimentAnalysisTemplateRef", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TemplateSpec"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DryRun", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ExperimentAnalysisTemplateRef", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.MeasurementRetention", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TemplateSpec"}, } } diff --git a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go index f184a9b9b4..dc0e4b7551 100644 --- a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go @@ -1071,6 +1071,11 @@ func (in *ExperimentSpec) DeepCopyInto(out *ExperimentSpec) { *out = make([]DryRun, len(*in)) copy(*out, *in) } + if in.MeasurementRetention != nil { + in, out := &in.MeasurementRetention, &out.MeasurementRetention + *out = make([]MeasurementRetention, len(*in)) + copy(*out, *in) + } return } diff --git a/test/e2e/experiment_test.go b/test/e2e/experiment_test.go index ac4bf8e29e..4ff844cb50 100644 --- a/test/e2e/experiment_test.go +++ b/test/e2e/experiment_test.go @@ -1,3 +1,4 @@ +//go:build e2e // +build e2e package e2e @@ -108,6 +109,16 @@ func (s *ExperimentSuite) TestExperimentWithDryRunMetrics() { ExpectExperimentDryRunSummary(1, 0, 1, "experiment-with-dry-run") } +func (s *ExperimentSuite) TestExperimentWithMeasurementRetentionMetrics() { + g := s.Given() + g.ApplyManifests("@functional/experiment-measurement-retention-analysis.yaml") + g.When(). + WaitForExperimentPhase("experiment-with-mr", "Successful"). + Sleep(time.Second*3). + Then(). + ExpectExperimentMeasurementsLength(0, 2, "experiment-with-mr") +} + func TestExperimentSuite(t *testing.T) { suite.Run(t, new(ExperimentSuite)) } diff --git a/test/e2e/functional/experiment-measurement-retention-analysis.yaml b/test/e2e/functional/experiment-measurement-retention-analysis.yaml new file mode 100644 index 0000000000..95da9274f7 --- /dev/null +++ b/test/e2e/functional/experiment-measurement-retention-analysis.yaml @@ -0,0 +1,55 @@ +kind: AnalysisTemplate +apiVersion: argoproj.io/v1alpha1 +metadata: + name: measurement-retention-job +spec: + metrics: + - name: test-1 + interval: 3s + failureLimit: 1 + provider: + job: + spec: + template: + spec: + containers: + - name: sleep + image: alpine:3.8 + command: [sh, -c] + args: [exit 0] + restartPolicy: Never + backoffLimit: 0 + +--- +apiVersion: argoproj.io/v1alpha1 +kind: Experiment +metadata: + name: experiment-with-mr +spec: + duration: 30s + progressDeadlineSeconds: 30 + templates: + - name: baseline + replicas: 1 + service: {} + selector: + matchLabels: + app: experiment-with-mr + template: + metadata: + labels: + app: experiment-with-mr + spec: + containers: + - name: experiment-with-mr + image: nginx:1.19-alpine + resources: + requests: + memory: 16Mi + cpu: 1m + analyses: + - name: measurement-retention-job + templateName: measurement-retention-job + measurementRetention: + - metricName: test.* + limit: 2 diff --git a/test/fixtures/then.go b/test/fixtures/then.go index fad9177cba..eac4c9419b 100644 --- a/test/fixtures/then.go +++ b/test/fixtures/then.go @@ -236,6 +236,26 @@ func (t *Then) ExpectExperimentDryRunSummary(expectedCount, expectedErrorCount, return t } +func (t *Then) ExpectExperimentMeasurementsLength(metricResultsIndex, expectedMeasurementsLength int, experiment string) *Then { + t.log.Infof("Expected Measurements Length '%d' for MetricResults index '%d'", expectedMeasurementsLength, metricResultsIndex) + ex, err := t.rolloutClient.ArgoprojV1alpha1().Experiments(t.namespace).Get(t.Context, experiment, metav1.GetOptions{}) + t.CheckError(err) + ar := t.GetExperimentAnalysisRun(ex) + if len(ar.Status.MetricResults) <= metricResultsIndex { + t.log.Errorf("MetricResults Array doesn't have given index '%d' in the AnalysisRun: '%s'", metricResultsIndex, ar.Name) + t.t.FailNow() + } + measurementsLength := len(ar.Status.MetricResults[metricResultsIndex].Measurements) + t.log.Infof("Actual Measurements Length at index '%d': '%d'", metricResultsIndex, measurementsLength) + if measurementsLength == expectedMeasurementsLength { + t.log.Infof("Expectation Matches!") + } else { + t.log.Errorf("Measurements Length at index '%d' of AnalysisRun: '%s' doesn't match the expectations", metricResultsIndex, ar.Name) + t.t.FailNow() + } + return t +} + func (t *Then) ExpectExperimentTemplateReplicaSetNumReplicas(experiment string, template string, expectedReplicas int) *Then { return t.ExpectExperimentTemplateReplicaSet(fmt.Sprintf("experiment template '%s' num replicas == %d", template, expectedReplicas), experiment, template, func(rs *appsv1.ReplicaSet) bool { return int(rs.Status.Replicas) == expectedReplicas From 53643c593f493beb5c4702c4b128c3eec4709c13 Mon Sep 17 00:00:00 2001 From: Kshama Jain Date: Tue, 1 Feb 2022 12:04:41 -0800 Subject: [PATCH 080/175] chore: CVE-2020-26160 (#1829) chore: CVE-2020-26160 (#1829) Signed-off-by: kshamajain99 --- go.mod | 50 +- go.sum | 587 +++++++--------------- metricproviders/newrelic/mock_test.go | 4 +- metricproviders/newrelic/newrelic.go | 8 +- metricproviders/newrelic/newrelic_test.go | 14 +- 5 files changed, 215 insertions(+), 448 deletions(-) diff --git a/go.mod b/go.mod index 744f63c188..995c5a2583 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.17 require ( github.com/antonmedv/expr v1.9.0 - github.com/argoproj/notifications-engine v0.3.0 + github.com/argoproj/notifications-engine v0.3.1-0.20220129012210-32519f8f68ec github.com/argoproj/pkg v0.9.0 github.com/aws/aws-sdk-go-v2/config v1.13.0 github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.5.0 @@ -13,12 +13,12 @@ require ( github.com/evanphx/json-patch/v5 v5.6.0 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 github.com/gogo/protobuf v1.3.2 - github.com/golang/mock v1.5.0 + github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.2 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a - github.com/mitchellh/mapstructure v1.4.1 - github.com/newrelic/newrelic-client-go v0.49.0 + github.com/mitchellh/mapstructure v1.4.3 + github.com/newrelic/newrelic-client-go v0.71.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.11.0 github.com/prometheus/client_model v0.2.0 @@ -27,20 +27,20 @@ require ( github.com/sirupsen/logrus v1.8.1 github.com/soheilhy/cmux v0.1.5 github.com/spaceapegames/go-wavefront v1.8.1 - github.com/spf13/cobra v1.2.1 + github.com/spf13/cobra v1.3.0 github.com/stretchr/testify v1.7.0 github.com/tj/assert v0.0.3 github.com/valyala/fasttemplate v1.2.1 - google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2 - google.golang.org/grpc v1.40.0 + google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa + google.golang.org/grpc v1.42.0 google.golang.org/protobuf v1.27.1 gopkg.in/yaml.v2 v2.4.0 - k8s.io/api v0.23.1 + k8s.io/api v0.23.3 k8s.io/apiextensions-apiserver v0.23.1 - k8s.io/apimachinery v0.23.2-rc.0 + k8s.io/apimachinery v0.23.3 k8s.io/apiserver v0.23.1 k8s.io/cli-runtime v0.23.1 - k8s.io/client-go v0.23.1 + k8s.io/client-go v0.23.3 k8s.io/code-generator v0.23.2-rc.0 k8s.io/component-base v0.23.1 k8s.io/klog/v2 v2.30.0 @@ -51,7 +51,7 @@ require ( ) require ( - cloud.google.com/go v0.81.0 // indirect + cloud.google.com/go v0.99.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest v0.11.18 // indirect @@ -77,12 +77,11 @@ require ( github.com/aws/aws-sdk-go-v2/service/sts v1.14.0 // indirect github.com/aws/smithy-go v1.10.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bradleyfalzon/ghinstallation v1.1.1 // indirect - github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/bradleyfalzon/ghinstallation/v2 v2.0.4 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect github.com/cyphar/filepath-securejoin v0.2.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect github.com/docker/distribution v2.7.1+incompatible // indirect github.com/emicklei/go-restful v2.9.5+incompatible // indirect github.com/evanphx/json-patch v4.12.0+incompatible // indirect @@ -94,14 +93,14 @@ require ( github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.19.5 // indirect github.com/go-openapi/swag v0.19.14 // indirect - github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect + github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.4.0 // indirect + github.com/golang-jwt/jwt/v4 v4.0.0 // indirect github.com/golang/glog v1.0.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/btree v1.0.1 // indirect github.com/google/go-cmp v0.5.6 // indirect - github.com/google/go-github/v29 v29.0.2 // indirect - github.com/google/go-github/v33 v33.0.0 // indirect - github.com/google/go-querystring v1.0.0 // indirect + github.com/google/go-github/v41 v41.0.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.1.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.1.2 // indirect @@ -109,10 +108,10 @@ require ( github.com/gorilla/websocket v1.4.2 // indirect github.com/gregdel/pushover v1.1.0 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect - github.com/hashicorp/go-cleanhttp v0.5.1 // indirect - github.com/hashicorp/go-retryablehttp v0.6.8 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-retryablehttp v0.7.0 // indirect github.com/huandu/xstrings v1.3.2 // indirect - github.com/imdario/mergo v0.3.11 // indirect + github.com/imdario/mergo v0.3.12 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -120,8 +119,8 @@ require ( github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/lunixbochs/vtclean v1.0.0 // indirect github.com/mailru/easyjson v0.7.6 // indirect - github.com/mattn/go-colorable v0.1.8 // indirect - github.com/mattn/go-isatty v0.0.12 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/go-wordwrap v1.0.0 // indirect @@ -138,10 +137,9 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/procfs v0.6.0 // indirect github.com/russross/blackfriday v1.5.2 // indirect - github.com/slack-go/slack v0.6.6 // indirect + github.com/slack-go/slack v0.10.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.2.0 // indirect - github.com/technoweenie/multipartstreamer v1.0.1 // indirect github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/whilp/git-urls v0.0.0-20191001220047-6db9661140c0 // indirect @@ -150,7 +148,7 @@ require ( golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect golang.org/x/mod v0.5.1 // indirect golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba // indirect - golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect + golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect diff --git a/go.sum b/go.sum index f4e5ea4857..f2810b33c3 100644 --- a/go.sum +++ b/go.sum @@ -1,32 +1,35 @@ -4d63.com/gochecknoglobals v0.0.0-20201008074935-acfc0b28355a/go.mod h1:wfdC5ZjKSPr7CybKEcgJhUOgeAQW1+7WcyK8OvUilfo= bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= -bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= bitbucket.org/bertimus9/systemstat v0.0.0-20180207000608-0eeff89b0690/go.mod h1:Ulb78X89vxKYgdL24HMTiXYHlyHEvruOj1ZPlqeNEZM= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.55.0/go.mod h1:ZHmoY+/lIMNkN2+fBmuTiqZ4inFhvQad8ft7MT8IV5Y= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.58.0/go.mod h1:W+9FnSUw6nhVwXlFcp1eL+krq5+HQUJeUogSeJZZiWg= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0 h1:at8Tk2zUz63cLPR0JPWm5vp77pEZmzxEQBEfRKn1VV8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= +cloud.google.com/go v0.99.0 h1:y/cM2iqGgGi5D5DQZl6D9STN/3dR/Vx5Mp8s752oJTY= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -36,7 +39,7 @@ cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM7 cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/firestore v1.2.0/go.mod h1:iISCjWnTpnoJT1R287xRdjvQHJrxQOpeah4phb5D3h0= +cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -45,67 +48,34 @@ cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiy cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.9.0/go.mod h1:m+/etGaqZbylxaNT876QGXqEHp4PR2Rq5GMqICWb9bU= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -code.gitea.io/sdk/gitea v0.12.1/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY= -code.gitea.io/sdk/gitea v0.13.1/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY= -contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= -contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw= -contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= -contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/azure-amqp-common-go/v3 v3.0.0/go.mod h1:SY08giD/XbhTz07tJdpw1SoxQXHPN30+DI3Z04SYqyg= -github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= -github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= -github.com/Azure/azure-sdk-for-go v37.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v55.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-service-bus-go v0.10.1/go.mod h1:E/FOceuKAFUfpbIJDKWz/May6guE+eGibfGT6q+n1to= -github.com/Azure/azure-storage-blob-go v0.9.0/go.mod h1:8UBPbiOhrMQ4pLPi3gA1tXnpjrS76UYE/fo5A40vf4g= -github.com/Azure/go-amqp v0.12.6/go.mod h1:qApuH6OFTSKZFmCOxccvAv5rLizBQf4v8pRmG138DPo= -github.com/Azure/go-amqp v0.12.7/go.mod h1:qApuH6OFTSKZFmCOxccvAv5rLizBQf4v8pRmG138DPo= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= github.com/Azure/go-autorest/autorest v0.11.18 h1:90Y4srNYrwOtAgVo3ndrQkTYn6kf1Eg/AjTFJ8Is2aM= github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= -github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= -github.com/Azure/go-autorest/autorest/adal v0.8.3/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= github.com/Azure/go-autorest/autorest/adal v0.9.13 h1:Mp5hbtOePIzM8pJVRa3YLrWWmZtoxRXqUEzCfJt3+/Q= github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= -github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM= -github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= -github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/Djarvur/go-err113 v0.0.0-20200511133814-5174e21577d5/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= -github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20191009163259-e802c2cb94ae/go.mod h1:mjwGPas4yKduTyubHvD1Atl9r1rUq8DfVy+gkVvZ+oo= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/GoogleCloudPlatform/k8s-cloud-provider v1.16.1-0.20210702024009-ea6160c1d0e3/go.mod h1:8XasY4ymP2V/tn2OOV9ZadmiTE1FIB/h3W+yNlPttKw= github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5hodBMJ5+l/7J4xAyMeuM2PNuepvHlGs8yilUCA= github.com/Jeffail/gabs v1.4.0 h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo= @@ -116,61 +86,44 @@ github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RP github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/Masterminds/sprig/v3 v3.1.0/go.mod h1:ONGMf7UfYGAbMXCZmQLy8x3lCDIPrEZE/rU8pmrbihA= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/hcsshim v0.8.22/go.mod h1:91uVCVzvX2QD16sMCenoxxXo6L1wJnLMX2PSufFMtF0= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= -github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60 h1:prBTRx78AQnXzivNT9Crhu564W/zPPr3ibSlpT9xKcE= github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60/go.mod h1:rjP7sIipbZcagro/6TCk6X0ZeFT2eyudH5+fve/cbBA= -github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= -github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= github.com/antonmedv/expr v1.8.9/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmHhwGEk8= github.com/antonmedv/expr v1.9.0 h1:j4HI3NHEdgDnN9p6oI6Ndr0G5QryMY0FNxT4ONrFDGU= github.com/antonmedv/expr v1.9.0/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmHhwGEk8= -github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA= -github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= -github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= -github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= github.com/appscode/go v0.0.0-20190808133642-1d4ef1f1c1e0/go.mod h1:iy07dV61Z7QQdCKJCIvUoDL21u6AIceRhZzyleh2ymc= -github.com/argoproj/notifications-engine v0.3.0 h1:1KMVYwXlg7SGzX00eg/bU0YupXDVdfpm8FlpNbrkUxM= -github.com/argoproj/notifications-engine v0.3.0/go.mod h1:0TEB4QbOsNN8URcsUJpAFuuG6aw8KS8ZY/YCzsss9JQ= +github.com/argoproj/notifications-engine v0.3.1-0.20220129012210-32519f8f68ec h1:ulv8ieYQZLyQrTVR4za1ucLFnemS0Dksz8y5e91xxak= +github.com/argoproj/notifications-engine v0.3.1-0.20220129012210-32519f8f68ec/go.mod h1:QF4tr3wfWOnhkKSaRpx7k/KEErQAh8iwKQ2pYFu/SfA= github.com/argoproj/pkg v0.9.0 h1:PfWWYykfcEQdN0g41XLbVh/aonTjD+dPkvDp3hwpLYM= github.com/argoproj/pkg v0.9.0/go.mod h1:ra+bQPmbVAoEL+gYSKesuigt4m49i3Qa3mE/xQcjCiA= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/auth0/go-jwt-middleware v1.0.1/go.mod h1:YSeUX3z6+TF2H+7padiEqNJ73Zy9vXW72U//IgN0BIM= -github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= -github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.31.13/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.33.16/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.35.24/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k= github.com/aws/aws-sdk-go v1.38.49/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= @@ -202,7 +155,6 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.14.0/go.mod h1:u0xMJKDvvfocRjiozsoZg github.com/aws/smithy-go v1.5.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.10.0 h1:gsoZQMNHnX+PaghNw4ynPsyGP7aUCqx5sY2dlPQsZ0w= github.com/aws/smithy-go v1.10.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= -github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -214,27 +166,23 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= -github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= -github.com/bombsimon/wsl/v3 v3.1.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= -github.com/bradleyfalzon/ghinstallation v1.1.1 h1:pmBXkxgM1WeF8QYvDLT5kuQiHMcmf+X015GI0KM/E3I= -github.com/bradleyfalzon/ghinstallation v1.1.1/go.mod h1:vyCmHTciHx/uuyN82Zc3rXN3X2KTK8nUTCrTMwAhcug= +github.com/bradleyfalzon/ghinstallation/v2 v2.0.4 h1:tXKVfhE7FcSkhkv0UwkLvPDeZ4kz6OXd0PKPlFqf81M= +github.com/bradleyfalzon/ghinstallation/v2 v2.0.4/go.mod h1:B40qPqJxWE0jDZgOR1JmaMy+4AY1eBP+IByOvqyAKp0= github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q= -github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw= -github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo= -github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 h1:7aWHqerlJ41y6FOsEUvknqgXnGmJyJSbjhAWq5pO4F8= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= @@ -243,12 +191,20 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313/go.mod h1:P1wt9Z3DP8O6W3rvwCt0REIlshg1InHImaLW0t3ObY0= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= @@ -280,25 +236,20 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= -github.com/daixiang0/gci v0.0.0-20200727065011-66f1df783cb2/go.mod h1:+AV8KmHTGxxwp/pY84TLQfFKp2vuKXXJVzF3kD/hfR4= -github.com/daixiang0/gci v0.2.4/go.mod h1:+AV8KmHTGxxwp/pY84TLQfFKp2vuKXXJVzF3kD/hfR4= github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= -github.com/denis-tingajkin/go-header v0.3.1/go.mod h1:sq/2IxMhaZX+RRcgHfCRx/m0M5na0fBt4/CRe7Lrji0= -github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= -github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= @@ -307,13 +258,13 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20210801061803-8e322dfb79c4 h1:lS3P5Nw3oPO05Lk2gFiYUOL3QPaH+fRoI1wFOc4G1UY= +github.com/elazarl/goproxy v0.0.0-20210801061803-8e322dfb79c4/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emirpasic/gods v1.9.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= -github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -321,7 +272,10 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdRwPr2TU5ThnS43puaKEMpja1uw= github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= @@ -336,7 +290,8 @@ github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+ne github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flosch/pongo2 v0.0.0-20181225140029-79872a7b2769/go.mod h1:tbAXHifHQWNSpWbiJHpJTZH5fi3XHhDMdP//vuz9WS4= @@ -345,11 +300,11 @@ github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/ github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM= @@ -358,39 +313,24 @@ github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49P github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew= github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= -github.com/git-chglog/git-chglog v0.0.0-20200414013904-db796966b373/go.mod h1:Dcsy1kii/xFyNad5JqY/d0GO5mu91sungp5xotbm3Yk= -github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= -github.com/go-critic/go-critic v0.5.0/go.mod h1:4jeRh3ZAVnRYhuWdOEvwzVqLUpxMSoAT0xZ74JsTPlo= -github.com/go-critic/go-critic v0.5.2/go.mod h1:cc0+HvdE3lFpqLecgqMaJcvWWH77sLdBp+wLGPM1Yyo= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= -github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= -github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= -github.com/go-git/go-git/v5 v5.1.0/go.mod h1:ZKfuPUoY1ZqIG4QG9BDBh3G4gLM5zvPuSJAozQrZuyM= -github.com/go-git/go-git/v5 v5.2.0/go.mod h1:kh02eMX+wdqqxgNMEyq8YgwlIOsDOa9homkUq1PoTMs= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v0.3.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro= -github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -401,40 +341,23 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU= -github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM= +github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.4.0 h1:Mr3JcvBjQEhCN9wld6OHKHuHxWaoXTaQfYKmj7QwP18= +github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.4.0/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8= github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4= -github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ= -github.com/go-toolsmith/astequal v0.0.0-20180903214952-dcb477bfacd6/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= -github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= -github.com/go-toolsmith/astfmt v0.0.0-20180903215011-8f8ee99c3086/go.mod h1:mP93XdblcopXwlyN4X4uodxXQhldPGZbcEJIimQHrkg= -github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw= -github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU= -github.com/go-toolsmith/astp v0.0.0-20180903215135-0af7e3c24f30/go.mod h1:SV2ur98SGypH1UjcPpCatrV5hPazG6+IfNHbkDXBRrk= -github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI= -github.com/go-toolsmith/pkgload v0.0.0-20181119091011-e9e65178eee8/go.mod h1:WoMrjiy4zvdS+Bg6z9jZH82QXwkcgCBX6nOfnmdaHks= -github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc= -github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= -github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= -github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= -github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.0.0 h1:RAqyYixv1p7uEnocuy8P1nru5wprCh/MH2BIlW5z5/o= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= @@ -452,8 +375,9 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -472,23 +396,7 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= -github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= -github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0= -github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8= -github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o= -github.com/golangci/gocyclo v0.0.0-20180528144436-0a533e8fa43d/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU= -github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU= -github.com/golangci/golangci-lint v1.30.0/go.mod h1:5t0i3wHlqQc9deBBvZsP+a/4xz7cfjV+zhp5U0Mzp14= -github.com/golangci/golangci-lint v1.31.0/go.mod h1:aMQuNCA+NDU5+4jLL5pEuFHoue0IznKE2+/GsFvvs8A= -github.com/golangci/golangci-lint v1.32.2/go.mod h1:ydr+IqtIVyAh72L16aK0bNdNg/YGa+AEgdbKj9MluzI= -github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU= -github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= -github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= -github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= -github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bzsHdTM0bsB7+8mt0GUMvjCgwLpTapNZHU8AajI= -github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4= -github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -510,76 +418,56 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM= -github.com/google/go-github/v29 v29.0.2 h1:opYN6Wc7DOz7Ku3Oh4l7prmkOMwEcQxpFtxdU8N8Pts= -github.com/google/go-github/v29 v29.0.2/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E= -github.com/google/go-github/v33 v33.0.0 h1:qAf9yP0qc54ufQxzwv+u9H0tiVOnPJxo0lI/JXqw3ZM= -github.com/google/go-github/v33 v33.0.0/go.mod h1:GMdDnVZY/2TsWgp/lkYnpSAh6TrzhANBBwm6k6TTEXg= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= +github.com/google/go-github/v41 v41.0.0 h1:HseJrM2JFf2vfiZJ8anY2hqBjdfY1Vlj/K27ueww4gg= +github.com/google/go-github/v41 v41.0.0/go.mod h1:XgmCA5H323A9rtgExdTcnDkcqp6S30AVACCBDOonIxg= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE= -github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/rpmpack v0.0.0-20200731134257-3685799e8fdf/go.mod h1:+y9lKiqDhR4zkLl+V9h4q0rdyrYVsWWm6LLCQP33DIk= -github.com/google/rpmpack v0.0.0-20200919095143-1c1eea455332/go.mod h1:+y9lKiqDhR4zkLl+V9h4q0rdyrYVsWWm6LLCQP33DIk= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/wire v0.4.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= -github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= -github.com/gookit/color v1.2.5/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg= -github.com/gookit/color v1.3.1/go.mod h1:R3ogXq2B9rTbXoSHJ1HyUVAZ3poOJHpd9nQmyGZsfvQ= github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4 h1:4EZlYQIiyecYJlUbVkFXCXHz1QPhVXcHnQKAzBTPfQo= github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4/go.mod h1:lEO7XoHJ/xNRBCxrn4h/CEB67h0kW1B0t4ooP2yrjUA= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/goreleaser/chglog v0.1.1/go.mod h1:xSDa/73C0TxBcLvoT2JHh47QyXpCx5rrNVzJKyeFGPw= -github.com/goreleaser/chglog v0.1.2/go.mod h1:tTZsFuSZK4epDXfjMkxzcGbrIOXprf0JFp47BjIr3B8= -github.com/goreleaser/fileglob v0.3.0/go.mod h1:kNcPrPzjCp+Ox3jmXLU5QEsjhqrtLBm6OnXAif8KRl8= -github.com/goreleaser/goreleaser v0.143.0/go.mod h1:/zq84GQ8WZFnspGTONdZO0Kgf5BzOD3CzufXyw+ut4A= -github.com/goreleaser/goreleaser v0.147.0/go.mod h1:AkI3X+mBaAEc99RDZgUGvjbUEqh/+t+EjNMaqUbd+3w= -github.com/goreleaser/nfpm v1.7.0/go.mod h1:V6xp021JRvYdBYpGFoP6m6YsuedzgB6IO2ub2NNBohs= -github.com/goreleaser/nfpm v1.10.1/go.mod h1:G0vvOjif+gnnTTWBtvYqMBh8nMGM7eNkrZU/W2gdM6o= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= -github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= -github.com/gostaticanalysis/analysisutil v0.1.0/go.mod h1:dMhHRU9KTiDcuLGdy87/2gTR8WruwYZrKdRq9m1O6uw= -github.com/gostaticanalysis/comment v1.3.0/go.mod h1:xMicKDx7XRXYdVwY9f9wQpDJVnqWxw9wCauCMKp+IBI= github.com/gregdel/pushover v1.1.0 h1:dwHyvrcpZCOS9V1fAnKPaGRRI5OC55cVaKhMybqNsKQ= github.com/gregdel/pushover v1.1.0/go.mod h1:EcaO66Nn1StkpEm1iKtBTV3d2A16SoMsVER1PthX7to= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= @@ -591,79 +479,81 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.0.0 h1:bkKf0BeBXcSYa7f5Fyi9gMuQ8gNsxeiNpZjR6VxNZeo= +github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-retryablehttp v0.5.1/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-retryablehttp v0.6.8 h1:92lWxgpa+fF3FozM4B3UZtHZMJX8T5XT+TFdCxsPyWs= -github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4= +github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= +github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/heketi/heketi v10.3.0+incompatible/go.mod h1:bB9ly3RchcQqsQ9CpyaQwvva7RS5ytVoSoholZQON6o= github.com/heketi/tests v0.0.0-20151005000721-f3775cbcefd6/go.mod h1:xGMAM8JLi7UkZt1i4FQeQy0R2T8GLUwQhOP5M1gBhy4= -github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= -github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/ishidawataru/sctp v0.0.0-20190723014705-7c296d48a2b5/go.mod h1:DM4VvS+hD/kDi1U1QsX2fnZowwBhqD0Dk3bRPKF/Oc8= -github.com/jarcoal/httpmock v1.0.6/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a/go.mod h1:xRskid8CManxVta/ALEhJha/pweKBaVG6fWgc0yH25s= -github.com/jirfag/go-printf-func-name v0.0.0-20191110105641-45db9963cdd3/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= -github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= -github.com/jmoiron/sqlx v1.2.1-0.20190826204134-d7d95172beb5/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -680,19 +570,10 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.10.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.10.5/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.11.0/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -706,16 +587,10 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kyoh86/exportloopref v0.1.7/go.mod h1:h1rDl2Kdj97+Kwh4gdz3ujE7XHmH51Q0lUiZ1z4NLj8= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/libopenstorage/openstorage v1.0.0/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= -github.com/llorllale/go-gitlint v0.0.0-20190914155841-58c0b8cef0e5/go.mod h1:omoASPlaaf3ECEhTMfLZVS6o550eBWI2YsM/saGEbVA= -github.com/llorllale/go-gitlint v0.0.0-20200802191503-5984945d4b80/go.mod h1:omoASPlaaf3ECEhTMfLZVS6o550eBWI2YsM/saGEbVA= -github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lpabon/godbc v0.1.1/go.mod h1:Jo9QV0cf3U6jZABgiJ2skINAXb9j8m51r07g4KI92ZA= github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= @@ -723,9 +598,9 @@ github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+L github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5/go.mod h1:c2mYKRyMb1BPkO5St0c/ps62L4S0W2NAkaTXj9qEI+0= github.com/lusis/slack-test v0.0.0-20190426140909-c40012f20018/go.mod h1:sFlOUpQL1YcjhFVXhg1CG8ZASEs/Mf1oVb6H75JL/zg= +github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailgun/mailgun-go v2.0.0+incompatible/go.mod h1:NWTyU+O4aczg/nsGhQnvHL6v2n5Gy6Sv5tNDVvC6FbU= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -733,39 +608,27 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpApTE5fXSKAqwDU= -github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= -github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= -github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= -github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-zglob v0.0.3/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/mbilski/exhaustivestruct v1.1.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/miekg/dns v1.1.45/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/mindprince/gonvml v0.0.0-20190828220739-9ebdce4bb989/go.mod h1:2eu9pRWp8mo84xCg6KswZ+USQHjwgRhNp06sozOdsTY= github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= @@ -773,11 +636,11 @@ github.com/minio/minio-go/v7 v7.0.2/go.mod h1:dJ80Mv2HeGkYLH1sqS/ksz07ON6csH3S6J github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= @@ -785,10 +648,10 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= @@ -809,10 +672,8 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= -github.com/moricho/tparallel v0.2.1/go.mod h1:fXEIZxG2vdfl0ZF8b42f5a78EhjjD5mX8qUplsoSU4k= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= -github.com/mozilla/tls-observatory v0.0.0-20200317151703-4fa42e1c2dee/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= @@ -821,16 +682,10 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/nakabonne/nestif v0.3.0/go.mod h1:dI314BppzXjJ4HsCnbo7XzrJHPszZsjnk5wEBSYHI2c= -github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= -github.com/newrelic/newrelic-client-go v0.49.0 h1:MnAK89AcdOqapfPGcsUzLdzTUmeIojBz1W9VbC4Llag= -github.com/newrelic/newrelic-client-go v0.49.0/go.mod h1://vEwOJWDi1nsSnmmdZrB8Kab9ibSfGcF0UmnwzoSNQ= -github.com/newrelic/tutone v0.2.5/go.mod h1:Jv8miaLyP2pjx4wqvAdx1nLXMx/Cl7kmsNiKZlCeIds= +github.com/newrelic/newrelic-client-go v0.71.0 h1:gDpryPJf1Jd/yA3BhSx67iMneTpuMNxOezISUk6j3SU= +github.com/newrelic/newrelic-client-go v0.71.0/go.mod h1:VXjhsfui0rvhM9cVwnKwlidF8NbXlHZvh63ZKi6fImA= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nishanths/exhaustive v0.0.0-20200708172631-8866003e3856/go.mod h1:wBEpHwM2OdmeNpdCvRPUlkEbBuaFmcK4Wv8Q7FuGW3c= -github.com/nishanths/exhaustive v0.0.0-20200811152831-6cf413ae40e0/go.mod h1:wBEpHwM2OdmeNpdCvRPUlkEbBuaFmcK4Wv8Q7FuGW3c= -github.com/nishanths/exhaustive v0.1.0/go.mod h1:S1j9110vxV1ECdCudXRkeMnFQ/DQk9ajLT0Uf2MYZQQ= github.com/nlopes/slack v0.5.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -842,7 +697,6 @@ github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4= github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= @@ -852,7 +706,6 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= @@ -866,15 +719,12 @@ github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFSt github.com/opsgenie/opsgenie-go-sdk-v2 v1.0.5 h1:AnS8ZCC5dle8P4X4FZ+IOlX9v0jAkCMiZDIzRnYwBbs= github.com/opsgenie/opsgenie-go-sdk-v2 v1.0.5/go.mod h1:f0ezb0R/mrB9Hpm5RrIS6EX3ydjsR2nAB88nYYXZcNY= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= -github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -883,12 +733,13 @@ github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZ github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/polyfloyd/go-errorlint v0.0.0-20201006195004-351e25ade6e3/go.mod h1:wi9BfjxjF/bwiZ701TzmfKu6UKC357IOAtNr0Td0Lvw= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= @@ -900,6 +751,7 @@ github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6T github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= @@ -909,51 +761,34 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/psampaz/go-mod-outdated v0.7.0/go.mod h1:r78NYWd1z+F9Zdsfy70svgXOz363B08BWnTyFSgEESs= -github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI= -github.com/quasilyte/go-ruleguard v0.1.2-0.20200318202121-b00d7a75d3d8/go.mod h1:CGFX09Ci3pq9QZdj86B+VGIdNj4VyCo2iPOGS9esB/k= -github.com/quasilyte/go-ruleguard v0.2.0/go.mod h1:2RT/tf0Ce0UDj5y243iWKosQogJd8+1G3Rs2fxmlYnw= -github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= github.com/quobyte/api v0.1.8/go.mod h1:jL7lIHrmqQ7yh05OJ+eEEdHr0u/kmT1Ff9iHd+4H6VI= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= github.com/rivo/tview v0.0.0-20200219210816-cd38d7432498/go.mod h1:6lkG1x+13OShEf0EaOCaTQYyB7d5nSbb181KtjlS+84= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= -github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.6.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rubiojr/go-vhd v0.0.0-20200706105327-02e210299021/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryancurrah/gomodguard v1.1.0/go.mod h1:4O8tr7hBODaGE6VIhfJDHcwzh5GUccKSJBU0UMXJFVM= -github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0KCtEdgEkHwDbigdA= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/sanity-io/litter v1.2.0/go.mod h1:JF6pZUFgu2Q0sBZ+HSV35P8TVPI1TTzEwyu9FXAw2W4= -github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b/go.mod h1:am+Fp8Bt506lA3Rk3QCmSqmYmLMnPDhdDUcosQCAx+I= -github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= -github.com/securego/gosec/v2 v2.4.0/go.mod h1:0/Q4cjmlFDfDUj1+Fib61sc+U5IQb2w+Iv9/C3wPVko= -github.com/securego/gosec/v2 v2.5.0/go.mod h1:L/CDXVntIff5ypVHIkqPXbtRpJiNCh6c6Amn68jXDjo= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/servicemeshinterface/smi-sdk-go v0.4.1 h1:L8nS7WtVlGoEJF7RdCbwh0Oj/JheGY+5fa3R+cA2ReY= github.com/servicemeshinterface/smi-sdk-go v0.4.1/go.mod h1:9rsLPBNcqfDNmEgyYwpopn93aE9yz46d2EHFBNOYj/w= -github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= -github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc= -github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= -github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= -github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= @@ -962,42 +797,35 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/slack-go/slack v0.6.6 h1:ln0fO794CudStSJEfhZ08Ok5JanMjvW6/k2xBuHqedU= -github.com/slack-go/slack v0.6.6/go.mod h1:FGqNzJBmxIsZURAxh2a8D21AnOVvvXZvGligs4npPUM= +github.com/slack-go/slack v0.10.1 h1:BGbxa0kMsGEvLOEoZmYs8T1wWfoZXwmQFBb6FgYCXUA= +github.com/slack-go/slack v0.10.1/go.mod h1:wWL//kk0ho+FcQXcBTmEafUI5dz4qz5f4mMk8oIkioQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= -github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4lqBjiZI= github.com/sony/sonyflake v1.0.0 h1:MpU6Ro7tfXwgn2l5eluf9xQvQJDROTBImNCfRXn/YeM= github.com/sony/sonyflake v1.0.0/go.mod h1:Jv3cfhf/UFtolOTTRd3q4Nl6ENqM+KfyZ5PseKfZGF4= -github.com/sourcegraph/go-diff v0.5.3/go.mod h1:v9JDtjCE4HHHCZGId75rg8gkKKa98RVjBcBGsVmMmak= -github.com/sourcegraph/go-diff v0.6.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= -github.com/sourcegraph/go-diff v0.6.1/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= github.com/spaceapegames/go-wavefront v1.8.1 h1:Xuby0uBfw1WVxD9d+l8Gh+zINqnBfd0RJT8e/3i3vBM= github.com/spaceapegames/go-wavefront v1.8.1/go.mod h1:GtdIjtJ0URkfPmaKx0+7vMSDvT/MON9v+4pbdagA8As= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/afero v1.3.2/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= -github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= +github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0= +github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -1006,11 +834,8 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= -github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= -github.com/ssgreg/nlreturn/v2 v2.0.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= -github.com/ssgreg/nlreturn/v2 v2.1.0/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= +github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/storageos/go-api v2.2.0+incompatible/go.mod h1:ZrLn+e0ZuF3Y65PNF6dIwbJPZqfmtCXxFm9ckv0agOY= @@ -1019,7 +844,6 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -1029,59 +853,27 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/tdakkota/asciicheck v0.0.0-20200416190851-d7f85be797a2/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= -github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM= -github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= -github.com/tetafro/godot v0.4.8/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0= -github.com/tetafro/godot v0.4.9/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0= -github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= -github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= -github.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj52Uc= -github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= -github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= -github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tomarrell/wrapcheck v0.0.0-20200807122107-df9e8bcb914d/go.mod h1:yiFB6fFoV7saXirUGfuK+cPtUh4NX/Hf5y2WC2lehu0= -github.com/tommy-muehle/go-mnd v1.3.1-0.20200224220436-e6f9a994e8fa/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= -github.com/tsuyoshiwada/go-gitcmd v0.0.0-20180205145712-5f1f5f9475df/go.mod h1:pnyouUty/nBr/zm3GYwTIt+qFTLWbdjeLjZmJdzJOu8= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= -github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= -github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= -github.com/uudashr/gocognit v1.0.1/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.12.0/go.mod h1:229t1eWu9UXTPmoUkbpN/fctKPBY4IJoFXQnxHGXy6E= -github.com/valyala/fasthttp v1.15.1/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA= -github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA= github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/valyala/quicktemplate v1.5.1/go.mod h1:v7yYWpBEiutDyNfVaph6oC/yKwejzVyTX/2cwwHxyok= -github.com/valyala/quicktemplate v1.6.2/go.mod h1:mtEJpQtUiBV0SHhMX6RtiJtqxncgrfmjcUy5T68X8TM= -github.com/valyala/quicktemplate v1.6.3/go.mod h1:fwPzK2fHuYEODzJ9pkw0ipCPNHZ2tD5KW4lOuSdPKzY= -github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/whilp/git-urls v0.0.0-20191001220047-6db9661140c0 h1:qqllXPzXh+So+mmANlX/gCJrgo+1kQyshMoQ+NASzm0= github.com/whilp/git-urls v0.0.0-20191001220047-6db9661140c0/go.mod h1:2rx5KE5FLD0HRfkkpyn8JwbVLBdhgeiOb2D2D9LLKM4= -github.com/xanzy/go-gitlab v0.37.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= -github.com/xanzy/go-gitlab v0.39.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= -github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8= -github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= -github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= -github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= @@ -1096,13 +888,15 @@ github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= -go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -1132,28 +926,19 @@ go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9i go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -gocloud.dev v0.20.0/go.mod h1:+Y/RpSXrJthIOM8uFNzWp6MRu9pFPNFEEZrQMxpkfIc= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1201,13 +986,13 @@ golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hM golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1220,13 +1005,10 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190607181551-461777fb6f67/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1239,7 +1021,6 @@ golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -1254,19 +1035,19 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba h1:6u6sik+bn/y7vILcYkK3iwTBWN7WtBvB0+SZswQnbf8= golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1279,8 +1060,12 @@ golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1292,10 +1077,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1304,7 +1087,6 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1321,9 +1103,9 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1333,12 +1115,12 @@ golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1346,7 +1128,6 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1356,8 +1137,6 @@ golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201109165425-215b40eba54c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1374,13 +1153,23 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1408,35 +1197,24 @@ golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190221204921-83362c3779f5/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190307163923-6a08e3108db3/go.mod h1:25r3+/G6/xytQM8iWZKq3Hn0kr0rgFKPUNVEL/dr3z4= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1448,7 +1226,6 @@ golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -1458,49 +1235,27 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200317043434-63da46f3035e/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200321224714-0d839f3cf2ed/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200414032229-332987a829c3/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200422022333-3d57cf2e726e/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200519015757-0d0afa43d58a/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200601175630-2caf76543d99/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200606014950-c42cb6316fb6/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200608174601-1b747fd94509/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200624225443-88f3c62a19ff/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200625211823-6506e20df31f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200701041122-1837592efa10/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200731060945-b5fad4ed8dd6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200812195022-5ae4c3c160a0/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200831203904-5a2aa26beb65/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201001104356-43ebab892c4c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.0.0-20201007032633-0806396f153e/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.0.0-20201011145850-ed2f50202694/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.0.0-20201013201025-64a9e34f3752/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM= @@ -1522,7 +1277,6 @@ gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6d gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -1535,7 +1289,6 @@ google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/ google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.26.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= @@ -1546,8 +1299,18 @@ google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBz google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/api v0.46.0/go.mod h1:ceL4oozhkAiTID8XMmJBsIxID/9wMXJVVFXPg4ylg3I= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= @@ -1560,8 +1323,6 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= @@ -1578,8 +1339,6 @@ google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200317114155-1f3552e48f24/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200325114520-5b2d0af7952b/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -1587,8 +1346,6 @@ google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200603110839-e855014d5736/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -1606,9 +1363,30 @@ google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2 h1:NHN4wOCScVzKhPenJ2dt+BTs3X/XkBVI/Rh4iDt55T8= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1630,9 +1408,15 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1647,7 +1431,6 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -gopkg.in/AlecAivazis/survey.v1 v1.8.7/go.mod h1:iBNOmqKz/NUbZx3bA+4hAGLRC7fSK7tgtVDT4tB22XA= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= @@ -1666,17 +1449,13 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/kyokomi/emoji.v1 v1.5.1/go.mod h1:N9AZ6hi1jHOPn34PsbpufQZUcKftSD7WgS2pgpmH4Lg= +gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/src-d/go-billy.v4 v4.2.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= -gopkg.in/src-d/go-git-fixtures.v3 v3.1.1/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= -gopkg.in/src-d/go-git.v4 v4.10.0/go.mod h1:Vtut8izDyrM8BUVQnzJ+YvmNcem2J89EmfZYCkLokZk= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1691,7 +1470,6 @@ gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/gotestsum v0.6.0/go.mod h1:LEX+ioCVdeWhZc8GYfiBRag360eBhwixWJ62R9eDQtI= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= @@ -1702,8 +1480,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.6/go.mod h1:pyyisuGw24ruLjrr1ddx39WE0y9OooInRzEYLhQB2YY= k8s.io/api v0.23.1 h1:ncu/qfBfUoClqwkTGbeRqqOqBCRoUAflMuOaOD7J0c8= k8s.io/api v0.23.1/go.mod h1:WfXnOnwSqNtG62Y1CdjoMxh7r7u9QXGCkA1u0na2jgo= k8s.io/apiextensions-apiserver v0.23.1 h1:xxE0q1vLOVZiWORu1KwNRQFsGWtImueOrqSl13sS5EU= @@ -1764,12 +1540,6 @@ modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= -mvdan.cc/gofumpt v0.0.0-20200709182408-4fd085cb6d5f/go.mod h1:9VQ397fNXEnF84t90W4r4TRCQK+pg9f8ugVfyj+S26w= -mvdan.cc/gofumpt v0.0.0-20200802201014-ab5a8192947d/go.mod h1:bzrjFmaD6+xqohD3KYP0H2FEuxknnBmyyOxdhLdaIws= -mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= -mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= -mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw= -mvdan.cc/unparam v0.0.0-20200501210554-b37ab49443f7/go.mod h1:HGC5lll35J70Y5v7vCGb9oLhHoScFwkHDJm/05RdSTc= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= @@ -1789,4 +1559,3 @@ sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZa sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= -sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/metricproviders/newrelic/mock_test.go b/metricproviders/newrelic/mock_test.go index 4f08173232..a96b4febbc 100644 --- a/metricproviders/newrelic/mock_test.go +++ b/metricproviders/newrelic/mock_test.go @@ -3,11 +3,11 @@ package newrelic import "github.com/newrelic/newrelic-client-go/pkg/nrdb" type mockAPI struct { - response []nrdb.NrdbResult + response []nrdb.NRDBResult err error } -func (m *mockAPI) Query(query string) ([]nrdb.NrdbResult, error) { +func (m *mockAPI) Query(query string) ([]nrdb.NRDBResult, error) { if m.err != nil { return nil, m.err } diff --git a/metricproviders/newrelic/newrelic.go b/metricproviders/newrelic/newrelic.go index 441c3a978e..599ba7a20c 100644 --- a/metricproviders/newrelic/newrelic.go +++ b/metricproviders/newrelic/newrelic.go @@ -31,7 +31,7 @@ const ( var userAgent = fmt.Sprintf("argo-rollouts/%s (%s)", version.GetVersion(), repoURL) type NewRelicClientAPI interface { - Query(query string) ([]nrdb.NrdbResult, error) + Query(query string) ([]nrdb.NRDBResult, error) } type NewRelicClient struct { @@ -40,8 +40,8 @@ type NewRelicClient struct { } //Query executes a NRQL query against the given New Relic account -func (n *NewRelicClient) Query(query string) ([]nrdb.NrdbResult, error) { - results, err := n.Nrdb.Query(n.AccountID, nrdb.Nrql(query)) +func (n *NewRelicClient) Query(query string) ([]nrdb.NRDBResult, error) { + results, err := n.Nrdb.Query(n.AccountID, nrdb.NRQL(query)) if err != nil { return nil, err } @@ -86,7 +86,7 @@ func toJSONString(v interface{}) (string, error) { return string(b), nil } -func (p *Provider) processResponse(metric v1alpha1.Metric, results []nrdb.NrdbResult) (string, v1alpha1.AnalysisPhase, error) { +func (p *Provider) processResponse(metric v1alpha1.Metric, results []nrdb.NRDBResult) (string, v1alpha1.AnalysisPhase, error) { if len(results) == 1 { result := results[0] if len(result) == 0 { diff --git a/metricproviders/newrelic/newrelic_test.go b/metricproviders/newrelic/newrelic_test.go index 54353ab288..b2ff051fba 100644 --- a/metricproviders/newrelic/newrelic_test.go +++ b/metricproviders/newrelic/newrelic_test.go @@ -31,7 +31,7 @@ func TestType(t *testing.T) { func TestRunSuccessfully(t *testing.T) { e := log.Entry{} mock := &mockAPI{ - response: []nrdb.NrdbResult{map[string]interface{}{"count": 10}}, + response: []nrdb.NRDBResult{map[string]interface{}{"count": 10}}, } p := NewNewRelicProvider(mock, e) metric := v1alpha1.Metric{ @@ -54,7 +54,7 @@ func TestRunSuccessfully(t *testing.T) { func TestRunWithTimeseries(t *testing.T) { e := log.NewEntry(log.New()) mock := &mockAPI{ - response: []nrdb.NrdbResult{ + response: []nrdb.NRDBResult{ map[string]interface{}{"count": 10}, map[string]interface{}{"count": 20}, map[string]interface{}{"count": 30}}, @@ -80,7 +80,7 @@ func TestRunWithTimeseries(t *testing.T) { func TestRunWithFacet(t *testing.T) { e := log.NewEntry(log.New()) mock := &mockAPI{ - response: []nrdb.NrdbResult{map[string]interface{}{"count": 10, "average.duration": 12.34}}, + response: []nrdb.NRDBResult{map[string]interface{}{"count": 10, "average.duration": 12.34}}, } p := NewNewRelicProvider(mock, *e) metric := v1alpha1.Metric{ @@ -103,7 +103,7 @@ func TestRunWithFacet(t *testing.T) { func TestRunWithMultipleSelectTerms(t *testing.T) { e := log.NewEntry(log.New()) mock := &mockAPI{ - response: []nrdb.NrdbResult{map[string]interface{}{"count": 10}}, + response: []nrdb.NRDBResult{map[string]interface{}{"count": 10}}, } p := NewNewRelicProvider(mock, *e) metric := v1alpha1.Metric{ @@ -127,7 +127,7 @@ func TestRunWithEmptyResult(t *testing.T) { e := log.NewEntry(log.New()) expectedErr := fmt.Errorf("no results returned from NRQL query") mock := &mockAPI{ - response: []nrdb.NrdbResult{make(map[string]interface{})}, + response: []nrdb.NRDBResult{make(map[string]interface{})}, } p := NewNewRelicProvider(mock, *e) metric := v1alpha1.Metric{ @@ -233,7 +233,7 @@ func TestRunWithInvalidJSON(t *testing.T) { } t.Run("with a single result map", func(t *testing.T) { mock := &mockAPI{ - response: []nrdb.NrdbResult{map[string]interface{}{"func": func() {}}}, + response: []nrdb.NRDBResult{map[string]interface{}{"func": func() {}}}, } p := NewNewRelicProvider(mock, *e) measurement := p.Run(newAnalysisRun(), metric) @@ -246,7 +246,7 @@ func TestRunWithInvalidJSON(t *testing.T) { t.Run("with multiple results", func(t *testing.T) { // cover branch where results slice is longer than 1 mock := &mockAPI{ - response: []nrdb.NrdbResult{map[string]interface{}{"key": "value"}, map[string]interface{}{"func": func() {}}}, + response: []nrdb.NRDBResult{map[string]interface{}{"key": "value"}, map[string]interface{}{"func": func() {}}}, } p := NewNewRelicProvider(mock, *e) measurement := p.Run(newAnalysisRun(), metric) From 822a5cf5a2fc4aee4af75a8987956bf0381eeee5 Mon Sep 17 00:00:00 2001 From: Rohit Agrawal Date: Sun, 7 Nov 2021 22:19:03 -0500 Subject: [PATCH 081/175] feat(analysis): Added additional metadata to the status of AnalysisRun Signed-off-by: Rohit Agrawal --- analysis/analysis.go | 9 ++--- analysis/analysis_test.go | 36 +++++++++++++++++++ hack/tools.go | 1 + manifests/crds/analysis-run-crd.yaml | 4 +++ manifests/install.yaml | 4 +++ manifests/namespace-install.yaml | 4 +++ metricproviders/cloudwatch/cloudwatch.go | 5 +++ metricproviders/cloudwatch/cloudwatch_test.go | 9 +++++ metricproviders/datadog/datadog.go | 5 +++ metricproviders/datadog/datadog_test.go | 3 ++ metricproviders/graphite/graphite.go | 5 +++ metricproviders/graphite/graphite_test.go | 6 ++++ metricproviders/job/job.go | 5 +++ metricproviders/job/job_test.go | 5 +++ metricproviders/kayenta/kayenta.go | 5 +++ metricproviders/kayenta/kayenta_test.go | 4 +++ metricproviders/metricproviders.go | 3 ++ metricproviders/mocks/Provider.go | 16 +++++++++ metricproviders/newrelic/newrelic.go | 5 +++ metricproviders/newrelic/newrelic_test.go | 12 +++++++ metricproviders/prometheus/prometheus.go | 14 +++++++- metricproviders/prometheus/prometheus_test.go | 17 +++++++++ metricproviders/wavefront/wavefront.go | 5 +++ metricproviders/wavefront/wavefront_test.go | 9 +++++ metricproviders/webmetric/webmetric.go | 5 +++ metricproviders/webmetric/webmetric_test.go | 3 ++ pkg/apis/rollouts/v1alpha1/analysis_types.go | 4 +++ .../v1alpha1/zz_generated.deepcopy.go | 7 ++++ test/e2e/aws_test.go | 23 ++++++------ test/e2e/bluegreen_test.go | 1 + test/e2e/canary_test.go | 1 + test/e2e/functional_test.go | 1 + test/e2e/smi_ingress_test.go | 1 + test/e2e/smi_test.go | 5 +-- 34 files changed, 223 insertions(+), 19 deletions(-) diff --git a/analysis/analysis.go b/analysis/analysis.go index 77a2081920..1ebee1ec2c 100644 --- a/analysis/analysis.go +++ b/analysis/analysis.go @@ -325,16 +325,17 @@ func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTa metricResult := analysisutil.GetResult(run, t.metric.Name) resultsLock.Unlock() + provider, err := c.newProvider(*logger, t.metric) if metricResult == nil { metricResult = &v1alpha1.MetricResult{ - Name: t.metric.Name, - Phase: v1alpha1.AnalysisPhaseRunning, - DryRun: dryRunMetricsMap[t.metric.Name], + Name: t.metric.Name, + Phase: v1alpha1.AnalysisPhaseRunning, + DryRun: dryRunMetricsMap[t.metric.Name], + Metadata: provider.GetMetadata(t.metric), } } var newMeasurement v1alpha1.Measurement - provider, err := c.newProvider(*logger, t.metric) if err != nil { if t.incompleteMeasurement != nil { newMeasurement = *t.incompleteMeasurement diff --git a/analysis/analysis_test.go b/analysis/analysis_test.go index 031e8f78eb..d4763f3e4b 100644 --- a/analysis/analysis_test.go +++ b/analysis/analysis_test.go @@ -892,6 +892,7 @@ func TestReconcileAnalysisRunInitial(t *testing.T) { }, } f.provider.On("Run", mock.Anything, mock.Anything, mock.Anything).Return(newMeasurement(v1alpha1.AnalysisPhaseSuccessful), nil) + f.provider.On("GetMetadata", mock.Anything, mock.Anything).Return(map[string]string{}, nil) { newRun := c.reconcileAnalysisRun(run) assert.Equal(t, v1alpha1.AnalysisPhaseRunning, newRun.Status.MetricResults[0].Phase) @@ -1128,6 +1129,38 @@ func TestResolveMetricArgsUnableToSubstitute(t *testing.T) { } } +func TestGetMetadataIsCalled(t *testing.T) { + f := newFixture(t) + defer f.Close() + c, _, _ := f.newController(noResyncPeriodFunc) + arg := "success-rate" + run := &v1alpha1.AnalysisRun{ + Spec: v1alpha1.AnalysisRunSpec{ + Args: []v1alpha1.Argument{ + { + Name: "metric-name", + Value: &arg, + }, + }, + Metrics: []v1alpha1.Metric{{ + Name: "rate", + SuccessCondition: "result[0] > 0", + Provider: v1alpha1.MetricProvider{ + Prometheus: &v1alpha1.PrometheusMetric{ + Query: "{{args.metric-name}}", + }, + }, + }}, + }, + } + metricMetadata := map[string]string{"foo": "bar"} + f.provider.On("Run", mock.Anything, mock.Anything, mock.Anything).Return(newMeasurement(v1alpha1.AnalysisPhaseSuccessful), nil) + f.provider.On("GetMetadata", mock.Anything, mock.Anything).Return(metricMetadata, nil) + newRun := c.reconcileAnalysisRun(run) + assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, newRun.Status.Phase) + assert.Equal(t, metricMetadata, newRun.Status.MetricResults[0].Metadata) +} + // TestSecretContentReferenceSuccess verifies that secret arguments are properly resolved func TestSecretContentReferenceSuccess(t *testing.T) { f := newFixture(t) @@ -1172,6 +1205,7 @@ func TestSecretContentReferenceSuccess(t *testing.T) { }, } f.provider.On("Run", mock.Anything, mock.Anything, mock.Anything).Return(newMeasurement(v1alpha1.AnalysisPhaseSuccessful), nil) + f.provider.On("GetMetadata", mock.Anything, mock.Anything).Return(map[string]string{}, nil) newRun := c.reconcileAnalysisRun(run) assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, newRun.Status.Phase) } @@ -1236,6 +1270,7 @@ func TestSecretContentReferenceProviderError(t *testing.T) { measurement.Message = error.Error() f.provider.On("Run", mock.Anything, mock.Anything, mock.Anything).Return(measurement) + f.provider.On("GetMetadata", mock.Anything, mock.Anything).Return(map[string]string{}, nil) newRun := c.reconcileAnalysisRun(run) logMessage := buf.String() @@ -1297,6 +1332,7 @@ func TestSecretContentReferenceAndMultipleArgResolutionSuccess(t *testing.T) { } f.provider.On("Run", mock.Anything, mock.Anything, mock.Anything).Return(newMeasurement(v1alpha1.AnalysisPhaseSuccessful), nil) + f.provider.On("GetMetadata", mock.Anything, mock.Anything).Return(map[string]string{}, nil) newRun := c.reconcileAnalysisRun(run) assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, newRun.Status.Phase) } diff --git a/hack/tools.go b/hack/tools.go index be7401da62..ac3872df7f 100644 --- a/hack/tools.go +++ b/hack/tools.go @@ -1,3 +1,4 @@ +//go:build tools // +build tools package tools diff --git a/manifests/crds/analysis-run-crd.yaml b/manifests/crds/analysis-run-crd.yaml index 416627dbab..29b474072e 100644 --- a/manifests/crds/analysis-run-crd.yaml +++ b/manifests/crds/analysis-run-crd.yaml @@ -2817,6 +2817,10 @@ spec: type: array message: type: string + metadata: + additionalProperties: + type: string + type: object name: type: string phase: diff --git a/manifests/install.yaml b/manifests/install.yaml index d4547cbe5a..b919668003 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -2818,6 +2818,10 @@ spec: type: array message: type: string + metadata: + additionalProperties: + type: string + type: object name: type: string phase: diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 71f6d0fa15..09cfdb3ae1 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -2818,6 +2818,10 @@ spec: type: array message: type: string + metadata: + additionalProperties: + type: string + type: object name: type: string phase: diff --git a/metricproviders/cloudwatch/cloudwatch.go b/metricproviders/cloudwatch/cloudwatch.go index 90569c1548..49e318e666 100644 --- a/metricproviders/cloudwatch/cloudwatch.go +++ b/metricproviders/cloudwatch/cloudwatch.go @@ -50,6 +50,11 @@ func (p *Provider) Type() string { return ProviderType } +// GetMetadata returns any additional metadata which needs to be stored & displayed as part of the metrics result. +func (p *Provider) GetMetadata(metric v1alpha1.Metric) map[string]string { + return nil +} + // Run queries with CloudWatch provider for the metric func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alpha1.Measurement { startTime := timeutil.MetaNow() diff --git a/metricproviders/cloudwatch/cloudwatch_test.go b/metricproviders/cloudwatch/cloudwatch_test.go index 0b52c0b112..cd55dcc41c 100644 --- a/metricproviders/cloudwatch/cloudwatch_test.go +++ b/metricproviders/cloudwatch/cloudwatch_test.go @@ -78,6 +78,9 @@ func TestRunWithQueryError(t *testing.T) { }, }, } + metricsMetadata := p.GetMetadata(metric) + assert.Nil(t, metricsMetadata) + measurement := p.Run(newAnalysisRun(), metric) assert.Equal(t, expectedErr.Error(), measurement.Message) assert.NotNil(t, measurement.StartedAt) @@ -103,6 +106,9 @@ func TestRunWithResolveArgsError(t *testing.T) { }, }, } + metricsMetadata := p.GetMetadata(metric) + assert.Nil(t, metricsMetadata) + measurement := p.Run(newAnalysisRun(), metric) assert.Equal(t, expectedErr.Error(), measurement.Message) assert.NotNil(t, measurement.StartedAt) @@ -131,6 +137,9 @@ constraint: Member must not be null'`) }, }, } + metricsMetadata := p.GetMetadata(metric) + assert.Nil(t, metricsMetadata) + measurement := p.Run(newAnalysisRun(), metric) assert.Equal(t, expectedErr.Error(), measurement.Message) assert.NotNil(t, measurement.StartedAt) diff --git a/metricproviders/datadog/datadog.go b/metricproviders/datadog/datadog.go index f8dc6eba12..9461a61ed6 100644 --- a/metricproviders/datadog/datadog.go +++ b/metricproviders/datadog/datadog.go @@ -59,6 +59,11 @@ func (p *Provider) Type() string { return ProviderType } +// GetMetadata returns any additional metadata which needs to be stored & displayed as part of the metrics result. +func (p *Provider) GetMetadata(metric v1alpha1.Metric) map[string]string { + return nil +} + func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alpha1.Measurement { startTime := timeutil.MetaNow() diff --git a/metricproviders/datadog/datadog_test.go b/metricproviders/datadog/datadog_test.go index 03142b4ae6..b4432f3260 100644 --- a/metricproviders/datadog/datadog_test.go +++ b/metricproviders/datadog/datadog_test.go @@ -314,6 +314,9 @@ func TestRunSuite(t *testing.T) { provider, _ := NewDatadogProvider(*logCtx, fakeClient) + metricsMetadata := provider.GetMetadata(test.metric) + assert.Nil(t, metricsMetadata) + // Get our result measurement := provider.Run(newAnalysisRun(), test.metric) diff --git a/metricproviders/graphite/graphite.go b/metricproviders/graphite/graphite.go index 8ad9de4b2c..d34a5ca7b2 100644 --- a/metricproviders/graphite/graphite.go +++ b/metricproviders/graphite/graphite.go @@ -49,6 +49,11 @@ func (p *Provider) Type() string { return ProviderType } +// GetMetadata returns any additional metadata which needs to be stored & displayed as part of the metrics result. +func (p *Provider) GetMetadata(metric v1alpha1.Metric) map[string]string { + return nil +} + // Run queries Graphite for the metric. func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alpha1.Measurement { startTime := timeutil.MetaNow() diff --git a/metricproviders/graphite/graphite_test.go b/metricproviders/graphite/graphite_test.go index 5d041aa328..d38555bca6 100644 --- a/metricproviders/graphite/graphite_test.go +++ b/metricproviders/graphite/graphite_test.go @@ -50,6 +50,9 @@ func TestType(t *testing.T) { func TestRunSuccessfulEvaluation(t *testing.T) { response := 10.000000 g := NewGraphiteProvider(newMockAPI(&response, nil), log.Entry{}) + metricsMetadata := g.GetMetadata(newTestingMetric()) + assert.Nil(t, metricsMetadata) + measurement := g.Run(&v1alpha1.AnalysisRun{}, newTestingMetric()) assert.NotNil(t, measurement.StartedAt) assert.Equal(t, "[10.000000]", measurement.Value) @@ -60,6 +63,9 @@ func TestRunSuccessfulEvaluation(t *testing.T) { func TestRunFailedEvaluation(t *testing.T) { response := 5.000000 g := NewGraphiteProvider(newMockAPI(&response, nil), log.Entry{}) + metricsMetadata := g.GetMetadata(newTestingMetric()) + assert.Nil(t, metricsMetadata) + measurement := g.Run(&v1alpha1.AnalysisRun{}, newTestingMetric()) assert.NotNil(t, measurement.StartedAt) assert.Equal(t, "[5.000000]", measurement.Value) diff --git a/metricproviders/job/job.go b/metricproviders/job/job.go index 10021c2324..046a9b098b 100644 --- a/metricproviders/job/job.go +++ b/metricproviders/job/job.go @@ -55,6 +55,11 @@ func (p *JobProvider) Type() string { return ProviderType } +// GetMetadata returns any additional metadata which needs to be stored & displayed as part of the metrics result. +func (p *JobProvider) GetMetadata(metric v1alpha1.Metric) map[string]string { + return nil +} + // newJobName returns a new job name for the run and metric. Names must be shortened so that it can // fit into a 63 character label, since the k8s job controller incorporates the job name into the // pod spec labels. diff --git a/metricproviders/job/job_test.go b/metricproviders/job/job_test.go index f2caa8ae8c..98d898f84d 100644 --- a/metricproviders/job/job_test.go +++ b/metricproviders/job/job_test.go @@ -120,6 +120,9 @@ func TestRun(t *testing.T) { p := newTestJobProvider() run := newRunWithJobMetric() metric := run.Spec.Metrics[0] + metricsMetadata := p.GetMetadata(metric) + assert.Nil(t, metricsMetadata) + measurement := p.Run(run, metric) assert.Equal(t, v1alpha1.AnalysisPhaseRunning, measurement.Phase) @@ -160,6 +163,8 @@ func TestRunCreateFail(t *testing.T) { fakeClient.PrependReactor("create", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { return true, nil, fmt.Errorf(errMsg) }) + metricsMetadata := p.GetMetadata(run.Spec.Metrics[0]) + assert.Nil(t, metricsMetadata) measurement := p.Run(run, run.Spec.Metrics[0]) assert.Equal(t, v1alpha1.AnalysisPhaseError, measurement.Phase) diff --git a/metricproviders/kayenta/kayenta.go b/metricproviders/kayenta/kayenta.go index e7d0980923..fbfbc42123 100644 --- a/metricproviders/kayenta/kayenta.go +++ b/metricproviders/kayenta/kayenta.go @@ -61,6 +61,11 @@ func (p *Provider) Type() string { return ProviderType } +// GetMetadata returns any additional metadata which needs to be stored & displayed as part of the metrics result. +func (p *Provider) GetMetadata(metric v1alpha1.Metric) map[string]string { + return nil +} + func getCanaryConfigId(metric v1alpha1.Metric, p *Provider) (string, error) { configIdLookupURL := fmt.Sprintf(configIdLookupURLFormat, metric.Provider.Kayenta.Address, metric.Provider.Kayenta.Application, metric.Provider.Kayenta.StorageAccountName) diff --git a/metricproviders/kayenta/kayenta_test.go b/metricproviders/kayenta/kayenta_test.go index 6e2f8769b5..5830d8294f 100644 --- a/metricproviders/kayenta/kayenta_test.go +++ b/metricproviders/kayenta/kayenta_test.go @@ -206,6 +206,8 @@ func TestRunSuccessfully(t *testing.T) { {Name: "stable-hash", Value: &stableHash}, {Name: "canary-hash", Value: &canaryHash}, } + metricsMetadata := p.GetMetadata(metric) + assert.Nil(t, metricsMetadata) measurement := p.Run(run, metric) @@ -268,6 +270,8 @@ func TestRunBadJobResponse(t *testing.T) { {Name: "stable-hash", Value: &stableHash}, {Name: "canary-hash", Value: &canaryHash}, } + metricsMetadata := p.GetMetadata(metric) + assert.Nil(t, metricsMetadata) measurement := p.Run(run, metric) diff --git a/metricproviders/metricproviders.go b/metricproviders/metricproviders.go index 06ecc04e96..c963a0c245 100644 --- a/metricproviders/metricproviders.go +++ b/metricproviders/metricproviders.go @@ -34,6 +34,9 @@ type Provider interface { GarbageCollect(*v1alpha1.AnalysisRun, v1alpha1.Metric, int) error // Type gets the provider type Type() string + // GetMetadata returns any additional metadata which providers need to store/display as part + // of the metric result. For example, Prometheus uses is to store the final resolved queries. + GetMetadata(metric v1alpha1.Metric) map[string]string } type ProviderFactory struct { diff --git a/metricproviders/mocks/Provider.go b/metricproviders/mocks/Provider.go index 56708feb0e..7e483078ae 100644 --- a/metricproviders/mocks/Provider.go +++ b/metricproviders/mocks/Provider.go @@ -26,6 +26,22 @@ func (_m *Provider) GarbageCollect(_a0 *v1alpha1.AnalysisRun, _a1 v1alpha1.Metri return r0 } +// GetMetadata provides a mock function with given fields: metric +func (_m *Provider) GetMetadata(metric v1alpha1.Metric) map[string]string { + ret := _m.Called(metric) + + var r0 map[string]string + if rf, ok := ret.Get(0).(func(v1alpha1.Metric) map[string]string); ok { + r0 = rf(metric) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[string]string) + } + } + + return r0 +} + // Resume provides a mock function with given fields: _a0, _a1, _a2 func (_m *Provider) Resume(_a0 *v1alpha1.AnalysisRun, _a1 v1alpha1.Metric, _a2 v1alpha1.Measurement) v1alpha1.Measurement { ret := _m.Called(_a0, _a1, _a2) diff --git a/metricproviders/newrelic/newrelic.go b/metricproviders/newrelic/newrelic.go index 599ba7a20c..6ec122f5df 100644 --- a/metricproviders/newrelic/newrelic.go +++ b/metricproviders/newrelic/newrelic.go @@ -131,6 +131,11 @@ func (p *Provider) Type() string { return ProviderType } +// GetMetadata returns any additional metadata which needs to be stored & displayed as part of the metrics result. +func (p *Provider) GetMetadata(metric v1alpha1.Metric) map[string]string { + return nil +} + //NewNewRelicProvider creates a new NewRelic provider func NewNewRelicProvider(api NewRelicClientAPI, logCtx log.Entry) *Provider { return &Provider{ diff --git a/metricproviders/newrelic/newrelic_test.go b/metricproviders/newrelic/newrelic_test.go index b2ff051fba..b483d96872 100644 --- a/metricproviders/newrelic/newrelic_test.go +++ b/metricproviders/newrelic/newrelic_test.go @@ -44,6 +44,9 @@ func TestRunSuccessfully(t *testing.T) { }, }, } + metricsMetadata := p.GetMetadata(metric) + assert.Nil(t, metricsMetadata) + measurement := p.Run(newAnalysisRun(), metric) assert.NotNil(t, measurement.StartedAt) assert.Equal(t, `{"count":10}`, measurement.Value) @@ -70,6 +73,9 @@ func TestRunWithTimeseries(t *testing.T) { }, }, } + metricsMetadata := p.GetMetadata(metric) + assert.Nil(t, metricsMetadata) + measurement := p.Run(newAnalysisRun(), metric) assert.NotNil(t, measurement.StartedAt) assert.Equal(t, `[{"count":10},{"count":20},{"count":30}]`, measurement.Value) @@ -93,6 +99,9 @@ func TestRunWithFacet(t *testing.T) { }, }, } + metricsMetadata := p.GetMetadata(metric) + assert.Nil(t, metricsMetadata) + measurement := p.Run(newAnalysisRun(), metric) assert.NotNil(t, measurement.StartedAt) assert.Equal(t, `{"average.duration":12.34,"count":10}`, measurement.Value) @@ -116,6 +125,9 @@ func TestRunWithMultipleSelectTerms(t *testing.T) { }, }, } + metricsMetadata := p.GetMetadata(metric) + assert.Nil(t, metricsMetadata) + measurement := p.Run(newAnalysisRun(), metric) assert.NotNil(t, measurement.StartedAt) assert.Equal(t, `{"count":10}`, measurement.Value) diff --git a/metricproviders/prometheus/prometheus.go b/metricproviders/prometheus/prometheus.go index 8334dc2a39..6646086eec 100644 --- a/metricproviders/prometheus/prometheus.go +++ b/metricproviders/prometheus/prometheus.go @@ -17,8 +17,11 @@ import ( ) const ( - //ProviderType indicates the provider is prometheus + // ProviderType indicates the provider is prometheus ProviderType = "Prometheus" + // ResolvedPrometheusQuery is used as the key for storing the resolved prometheus query in the metrics result + // metadata object. + ResolvedPrometheusQuery = "ResolvedPrometheusQuery" ) // Provider contains all the required components to run a prometheus query @@ -32,6 +35,15 @@ func (p *Provider) Type() string { return ProviderType } +// GetMetadata returns any additional metadata which needs to be stored & displayed as part of the metrics result. +func (p *Provider) GetMetadata(metric v1alpha1.Metric) map[string]string { + metricsMetadata := make(map[string]string) + if metric.Provider.Prometheus.Query != "" { + metricsMetadata[ResolvedPrometheusQuery] = metric.Provider.Prometheus.Query + } + return metricsMetadata +} + // Run queries prometheus for the metric func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alpha1.Measurement { startTime := timeutil.MetaNow() diff --git a/metricproviders/prometheus/prometheus_test.go b/metricproviders/prometheus/prometheus_test.go index b83b4a3934..4268fd92c2 100644 --- a/metricproviders/prometheus/prometheus_test.go +++ b/metricproviders/prometheus/prometheus_test.go @@ -131,6 +131,23 @@ func TestRunWithResolveArgsError(t *testing.T) { assert.Equal(t, v1alpha1.AnalysisPhaseError, measurement.Phase) } +func TestGetStatusReturnsResolvedQuery(t *testing.T) { + e := log.Entry{} + mock := mockAPI{} + p := NewPrometheusProvider(mock, e) + metric := v1alpha1.Metric{ + Name: "foo", + Provider: v1alpha1.MetricProvider{ + Prometheus: &v1alpha1.PrometheusMetric{ + Query: "resolved-query", + }, + }, + } + metricsMetadata := p.GetMetadata(metric) + assert.NotNil(t, metricsMetadata) + assert.Equal(t, "resolved-query", metricsMetadata["ResolvedPrometheusQuery"]) +} + func TestRunWithEvaluationError(t *testing.T) { e := log.WithField("", "") mock := mockAPI{} diff --git a/metricproviders/wavefront/wavefront.go b/metricproviders/wavefront/wavefront.go index 177d135769..94935a71a1 100644 --- a/metricproviders/wavefront/wavefront.go +++ b/metricproviders/wavefront/wavefront.go @@ -36,6 +36,11 @@ func (p *Provider) Type() string { return ProviderType } +// GetMetadata returns any additional metadata which needs to be stored & displayed as part of the metrics result. +func (p *Provider) GetMetadata(metric v1alpha1.Metric) map[string]string { + return nil +} + type WavefrontClientAPI interface { NewQuery(params *wavefrontapi.QueryParams) WavefrontQueryAPI } diff --git a/metricproviders/wavefront/wavefront_test.go b/metricproviders/wavefront/wavefront_test.go index a42a115db8..af8bd53e7f 100644 --- a/metricproviders/wavefront/wavefront_test.go +++ b/metricproviders/wavefront/wavefront_test.go @@ -57,6 +57,9 @@ func TestRunSuccessfully(t *testing.T) { }, }, } + metricsMetadata := p.GetMetadata(metric) + assert.Nil(t, metricsMetadata) + measurement := p.Run(newAnalysisRun(), metric) assert.NotNil(t, measurement.StartedAt) assert.Equal(t, "10.00", measurement.Value) @@ -81,6 +84,9 @@ func TestRunWithQueryError(t *testing.T) { }, }, } + metricsMetadata := p.GetMetadata(metric) + assert.Nil(t, metricsMetadata) + measurement := p.Run(newAnalysisRun(), metric) assert.Equal(t, expectedErr.Error(), measurement.Message) assert.NotNil(t, measurement.StartedAt) @@ -107,6 +113,9 @@ func TestRunWithEvaluationError(t *testing.T) { }, }, } + metricsMetadata := p.GetMetadata(metric) + assert.Nil(t, metricsMetadata) + measurement := p.Run(newAnalysisRun(), metric) assert.Equal(t, "No TimeSeries found in response from Wavefront", measurement.Message) assert.Equal(t, "No query provided", measurement.Metadata["warnings"]) diff --git a/metricproviders/webmetric/webmetric.go b/metricproviders/webmetric/webmetric.go index 18ce94a6dd..f1b215de81 100644 --- a/metricproviders/webmetric/webmetric.go +++ b/metricproviders/webmetric/webmetric.go @@ -39,6 +39,11 @@ func (p *Provider) Type() string { return ProviderType } +// GetMetadata returns any additional metadata which needs to be stored & displayed as part of the metrics result. +func (p *Provider) GetMetadata(metric v1alpha1.Metric) map[string]string { + return nil +} + func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alpha1.Measurement { startTime := timeutil.MetaNow() diff --git a/metricproviders/webmetric/webmetric_test.go b/metricproviders/webmetric/webmetric_test.go index a6107e9c00..66861478f5 100644 --- a/metricproviders/webmetric/webmetric_test.go +++ b/metricproviders/webmetric/webmetric_test.go @@ -613,6 +613,9 @@ func TestRunSuite(t *testing.T) { assert.NoError(t, err) provider := NewWebMetricProvider(*logCtx, server.Client(), jsonparser) + metricsMetadata := provider.GetMetadata(test.metric) + assert.Nil(t, metricsMetadata) + // Get our result measurement := provider.Run(newAnalysisRun(), test.metric) diff --git a/pkg/apis/rollouts/v1alpha1/analysis_types.go b/pkg/apis/rollouts/v1alpha1/analysis_types.go index 82d461cdcc..7b6b8e87c4 100644 --- a/pkg/apis/rollouts/v1alpha1/analysis_types.go +++ b/pkg/apis/rollouts/v1alpha1/analysis_types.go @@ -398,6 +398,10 @@ type MetricResult struct { ConsecutiveError int32 `json:"consecutiveError,omitempty" protobuf:"varint,10,opt,name=consecutiveError"` // DryRun indicates whether this metric is running in a dry-run mode or not DryRun bool `json:"dryRun,omitempty" protobuf:"varint,11,opt,name=dryRun"` + // Metadata stores additional metadata about this metric. It is used by different providers to store + // the final state which gets used while taking measurements. For example, Prometheus uses this field + // to store the final resolved query after substituting the template arguments. + Metadata map[string]string `json:"metadata,omitempty" protobuf:"bytes,12,rep,name=metadata"` } // Measurement is a point in time result value of a single metric, and the time it was measured diff --git a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go index dc0e4b7551..f29fe515e3 100644 --- a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go @@ -1470,6 +1470,13 @@ func (in *MetricResult) DeepCopyInto(out *MetricResult) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } return } diff --git a/test/e2e/aws_test.go b/test/e2e/aws_test.go index f367da7e7c..7f7ce5c4e8 100644 --- a/test/e2e/aws_test.go +++ b/test/e2e/aws_test.go @@ -1,3 +1,4 @@ +//go:build e2e // +build e2e package e2e @@ -27,7 +28,6 @@ const actionTemplate = `{"Type":"forward","ForwardConfig":{"TargetGroups":[{"Ser const actionTemplateWithExperiment = `{"Type":"forward","ForwardConfig":{"TargetGroups":[{"ServiceName":"%s","ServicePort":"%d","Weight":%d},{"ServiceName":"%s","ServicePort":"%d","Weight":%d},{"ServiceName":"%s","ServicePort":"%d","Weight":%d}]}}` const actionTemplateWithExperiments = `{"Type":"forward","ForwardConfig":{"TargetGroups":[{"ServiceName":"%s","ServicePort":"%d","Weight":%d},{"ServiceName":"%s","ServicePort":"%d","Weight":%d},{"ServiceName":"%s","ServicePort":"%d","Weight":%d},{"ServiceName":"%s","ServicePort":"%d","Weight":%d}]}}` - // TestALBUpdate is a simple integration test which verifies the controller can work in a real AWS // environment. It is intended to be run with the `--aws-verify-target-group` controller flag. Success of // this test against a controller using that flag, indicates that the controller was able to perform @@ -65,7 +65,7 @@ func (s *AWSSuite) TestALBExperimentStep() { Then(). Assert(func(t *fixtures.Then) { ingress := t.GetALBIngress() - action, ok := ingress.Annotations["alb.ingress.kubernetes.io/actions.alb-rollout-root"] + action, ok := ingress.Annotations["alb.ingress.kubernetes.io/actions.alb-rollout-root"] assert.True(s.T(), ok) port := 80 @@ -76,11 +76,11 @@ func (s *AWSSuite) TestALBExperimentStep() { When(). UpdateSpec(). WaitForRolloutCanaryStepIndex(1). - Sleep(10*time.Second). + Sleep(10 * time.Second). Then(). Assert(func(t *fixtures.Then) { ingress := t.GetALBIngress() - action, ok := ingress.Annotations["alb.ingress.kubernetes.io/actions.alb-rollout-root"] + action, ok := ingress.Annotations["alb.ingress.kubernetes.io/actions.alb-rollout-root"] assert.True(s.T(), ok) ex := t.GetRolloutExperiments().Items[0] @@ -93,11 +93,11 @@ func (s *AWSSuite) TestALBExperimentStep() { When(). PromoteRollout(). WaitForRolloutStatus("Healthy"). - Sleep(1*time.Second). // stable is currently set first, and then changes made to VirtualServices/DestinationRules + Sleep(1 * time.Second). // stable is currently set first, and then changes made to VirtualServices/DestinationRules Then(). Assert(func(t *fixtures.Then) { ingress := t.GetALBIngress() - action, ok := ingress.Annotations["alb.ingress.kubernetes.io/actions.alb-rollout-root"] + action, ok := ingress.Annotations["alb.ingress.kubernetes.io/actions.alb-rollout-root"] assert.True(s.T(), ok) port := 80 @@ -115,7 +115,7 @@ func (s *AWSSuite) TestALBExperimentStepNoSetWeight() { Then(). Assert(func(t *fixtures.Then) { ingress := t.GetALBIngress() - action, ok := ingress.Annotations["alb.ingress.kubernetes.io/actions.alb-rollout-root"] + action, ok := ingress.Annotations["alb.ingress.kubernetes.io/actions.alb-rollout-root"] assert.True(s.T(), ok) port := 80 @@ -125,11 +125,11 @@ func (s *AWSSuite) TestALBExperimentStepNoSetWeight() { ExpectExperimentCount(0). When(). UpdateSpec(). - Sleep(10*time.Second). + Sleep(10 * time.Second). Then(). Assert(func(t *fixtures.Then) { ingress := t.GetALBIngress() - action, ok := ingress.Annotations["alb.ingress.kubernetes.io/actions.alb-rollout-root"] + action, ok := ingress.Annotations["alb.ingress.kubernetes.io/actions.alb-rollout-root"] assert.True(s.T(), ok) experiment := t.GetRolloutExperiments().Items[0] @@ -142,11 +142,11 @@ func (s *AWSSuite) TestALBExperimentStepNoSetWeight() { When(). PromoteRollout(). WaitForRolloutStatus("Healthy"). - Sleep(1*time.Second). // stable is currently set first, and then changes made to VirtualServices/DestinationRules + Sleep(1 * time.Second). // stable is currently set first, and then changes made to VirtualServices/DestinationRules Then(). Assert(func(t *fixtures.Then) { ingress := t.GetALBIngress() - action, ok := ingress.Annotations["alb.ingress.kubernetes.io/actions.alb-rollout-root"] + action, ok := ingress.Annotations["alb.ingress.kubernetes.io/actions.alb-rollout-root"] assert.True(s.T(), ok) port := 80 @@ -154,4 +154,3 @@ func (s *AWSSuite) TestALBExperimentStepNoSetWeight() { assert.Equal(s.T(), expectedAction, action) }) } - diff --git a/test/e2e/bluegreen_test.go b/test/e2e/bluegreen_test.go index a7c263acb3..5ca433c3c7 100644 --- a/test/e2e/bluegreen_test.go +++ b/test/e2e/bluegreen_test.go @@ -1,3 +1,4 @@ +//go:build e2e // +build e2e package e2e diff --git a/test/e2e/canary_test.go b/test/e2e/canary_test.go index dd6a9c1c75..8732db50da 100644 --- a/test/e2e/canary_test.go +++ b/test/e2e/canary_test.go @@ -1,3 +1,4 @@ +//go:build e2e // +build e2e package e2e diff --git a/test/e2e/functional_test.go b/test/e2e/functional_test.go index 977335ba29..277a19c7f9 100644 --- a/test/e2e/functional_test.go +++ b/test/e2e/functional_test.go @@ -1,3 +1,4 @@ +//go:build e2e // +build e2e package e2e diff --git a/test/e2e/smi_ingress_test.go b/test/e2e/smi_ingress_test.go index 2086935f84..ca08bd4248 100644 --- a/test/e2e/smi_ingress_test.go +++ b/test/e2e/smi_ingress_test.go @@ -1,3 +1,4 @@ +//go:build e2e // +build e2e package e2e diff --git a/test/e2e/smi_test.go b/test/e2e/smi_test.go index ff92cbcc8e..28f50f15e8 100644 --- a/test/e2e/smi_test.go +++ b/test/e2e/smi_test.go @@ -1,3 +1,4 @@ +//go:build e2e // +build e2e package e2e @@ -60,7 +61,7 @@ func (s *SMISuite) TestSMIExperimentStep() { Assert(func(t *fixtures.Then) { ts := t.GetTrafficSplit() - assert.Len(s.T(), ts.Spec.Backends, 3) + assert.Len(s.T(), ts.Spec.Backends, 3) assert.Equal(s.T(), "rollout-smi-experiment-canary", ts.Spec.Backends[0].Service) assert.Equal(s.T(), int64(5), ts.Spec.Backends[0].Weight.Value()) @@ -87,7 +88,7 @@ func (s *SMISuite) TestSMIExperimentStep() { Assert(func(t *fixtures.Then) { ts := t.GetTrafficSplit() - assert.Len(s.T(), ts.Spec.Backends, 2) + assert.Len(s.T(), ts.Spec.Backends, 2) assert.Equal(s.T(), "rollout-smi-experiment-canary", ts.Spec.Backends[0].Service) assert.Equal(s.T(), int64(0), ts.Spec.Backends[0].Weight.Value()) From f3889370b1e6a954706e247a568d716b925142f6 Mon Sep 17 00:00:00 2001 From: Rohit Agrawal Date: Wed, 10 Nov 2021 20:19:49 -0500 Subject: [PATCH 082/175] Added Docs Signed-off-by: Rohit Agrawal --- docs/analysis/prometheus.md | 4 + pkg/apis/rollouts/v1alpha1/generated.pb.go | 1034 ++++++++++------- pkg/apis/rollouts/v1alpha1/generated.proto | 5 + .../rollouts/v1alpha1/openapi_generated.go | 16 + 4 files changed, 628 insertions(+), 431 deletions(-) diff --git a/docs/analysis/prometheus.md b/docs/analysis/prometheus.md index cbb70e87a9..56736f0257 100644 --- a/docs/analysis/prometheus.md +++ b/docs/analysis/prometheus.md @@ -34,3 +34,7 @@ you validate your [PromQL expression](https://prometheus.io/docs/prometheus/late See the [Analysis Overview page](../../features/analysis) for more details on the available options. +# Additional Metadata + +Any additional metadata from the Prometheus controller, like the resolved queries after substituting the template's +arguments, etc. will appear under the `Metadata` map in the `MetricsResult` object of `AnalysisRun`. \ No newline at end of file diff --git a/pkg/apis/rollouts/v1alpha1/generated.pb.go b/pkg/apis/rollouts/v1alpha1/generated.pb.go index 0810ed7716..73ec6853fc 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.pb.go +++ b/pkg/apis/rollouts/v1alpha1/generated.pb.go @@ -2627,6 +2627,7 @@ func init() { proto.RegisterType((*Metric)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.Metric") proto.RegisterType((*MetricProvider)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MetricProvider") proto.RegisterType((*MetricResult)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MetricResult") + proto.RegisterMapType((map[string]string)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MetricResult.MetadataEntry") proto.RegisterType((*NewRelicMetric)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.NewRelicMetric") proto.RegisterType((*NginxTrafficRouting)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.NginxTrafficRouting") proto.RegisterMapType((map[string]string)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.NginxTrafficRouting.AdditionalIngressAnnotationsEntry") @@ -2676,437 +2677,438 @@ func init() { } var fileDescriptor_e0e705f843545fab = []byte{ - // 6865 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3d, 0x5b, 0x8c, 0x24, 0x57, - 0x75, 0xae, 0x7e, 0xcc, 0xf4, 0x9c, 0x79, 0xdf, 0x9d, 0x65, 0xc7, 0x6b, 0xef, 0xb6, 0x29, 0x23, - 0xc7, 0x24, 0x30, 0x0b, 0x6b, 0x3b, 0x31, 0x18, 0x59, 0xe9, 0x9e, 0xd9, 0xf5, 0xce, 0x7a, 0x66, - 0x77, 0xf6, 0xf6, 0xac, 0x17, 0x0c, 0x26, 0xd4, 0x74, 0xdf, 0xe9, 0xa9, 0xdd, 0xea, 0xaa, 0xa6, - 0xaa, 0x7a, 0x76, 0xc7, 0x20, 0xb0, 0x83, 0xec, 0x90, 0x08, 0x84, 0x13, 0xe0, 0x23, 0x8a, 0x88, - 0x50, 0xc4, 0x47, 0x14, 0xf2, 0x11, 0xa1, 0x44, 0xf9, 0x41, 0x4a, 0x94, 0x80, 0x42, 0x3e, 0x12, - 0x11, 0x29, 0x09, 0x10, 0x41, 0x07, 0x37, 0xc9, 0x47, 0xa2, 0x48, 0x51, 0x24, 0xa2, 0x08, 0x7f, - 0x45, 0xf7, 0x59, 0xb7, 0xaa, 0xab, 0x67, 0xbb, 0xa7, 0x6b, 0x16, 0x2b, 0xe1, 0xaf, 0xfb, 0x9e, - 0x73, 0xcf, 0xb9, 0xcf, 0x73, 0xcf, 0x39, 0xf7, 0xdc, 0x53, 0xb0, 0xd1, 0xb4, 0xc3, 0xbd, 0xce, - 0xce, 0x4a, 0xdd, 0x6b, 0x9d, 0xb3, 0xfc, 0xa6, 0xd7, 0xf6, 0xbd, 0x9b, 0xec, 0xc7, 0x3b, 0x7d, - 0xcf, 0x71, 0xbc, 0x4e, 0x18, 0x9c, 0x6b, 0xdf, 0x6a, 0x9e, 0xb3, 0xda, 0x76, 0x70, 0x4e, 0x95, - 0xec, 0xbf, 0xdb, 0x72, 0xda, 0x7b, 0xd6, 0xbb, 0xcf, 0x35, 0x89, 0x4b, 0x7c, 0x2b, 0x24, 0x8d, - 0x95, 0xb6, 0xef, 0x85, 0x1e, 0x7a, 0x5f, 0x44, 0x6d, 0x45, 0x52, 0x63, 0x3f, 0x7e, 0x45, 0xd6, - 0x5d, 0x69, 0xdf, 0x6a, 0xae, 0x50, 0x6a, 0x2b, 0xaa, 0x44, 0x52, 0x3b, 0xfd, 0x4e, 0xad, 0x2d, - 0x4d, 0xaf, 0xe9, 0x9d, 0x63, 0x44, 0x77, 0x3a, 0xbb, 0xec, 0x1f, 0xfb, 0xc3, 0x7e, 0x71, 0x66, - 0xa7, 0x1f, 0xbe, 0xf5, 0x64, 0xb0, 0x62, 0x7b, 0xb4, 0x6d, 0xe7, 0x76, 0xac, 0xb0, 0xbe, 0x77, - 0x6e, 0xbf, 0xaf, 0x45, 0xa7, 0x4d, 0x0d, 0xa9, 0xee, 0xf9, 0x24, 0x0d, 0xe7, 0xf1, 0x08, 0xa7, - 0x65, 0xd5, 0xf7, 0x6c, 0x97, 0xf8, 0x07, 0x51, 0xaf, 0x5b, 0x24, 0xb4, 0xd2, 0x6a, 0x9d, 0x1b, - 0x54, 0xcb, 0xef, 0xb8, 0xa1, 0xdd, 0x22, 0x7d, 0x15, 0x7e, 0xf1, 0x6e, 0x15, 0x82, 0xfa, 0x1e, - 0x69, 0x59, 0x7d, 0xf5, 0x1e, 0x1b, 0x54, 0xaf, 0x13, 0xda, 0xce, 0x39, 0xdb, 0x0d, 0x83, 0xd0, - 0x4f, 0x56, 0x32, 0xbf, 0x91, 0x87, 0xa9, 0xca, 0x46, 0xb5, 0x16, 0x5a, 0x61, 0x27, 0x40, 0xaf, - 0x1a, 0x30, 0xe3, 0x78, 0x56, 0xa3, 0x6a, 0x39, 0x96, 0x5b, 0x27, 0xfe, 0xb2, 0xf1, 0x90, 0xf1, - 0xe8, 0xf4, 0xf9, 0x8d, 0x95, 0x71, 0xe6, 0x6b, 0xa5, 0x72, 0x3b, 0xc0, 0x24, 0xf0, 0x3a, 0x7e, - 0x9d, 0x60, 0xb2, 0x5b, 0x5d, 0xfa, 0x56, 0xb7, 0x7c, 0x5f, 0xaf, 0x5b, 0x9e, 0xd9, 0xd0, 0x38, - 0xe1, 0x18, 0x5f, 0xf4, 0x45, 0x03, 0x16, 0xeb, 0x96, 0x6b, 0xf9, 0x07, 0xdb, 0x96, 0xdf, 0x24, - 0xe1, 0x33, 0xbe, 0xd7, 0x69, 0x2f, 0xe7, 0x8e, 0xa1, 0x35, 0xf7, 0x8b, 0xd6, 0x2c, 0xae, 0x26, - 0xd9, 0xe1, 0xfe, 0x16, 0xb0, 0x76, 0x05, 0xa1, 0xb5, 0xe3, 0x10, 0xbd, 0x5d, 0xf9, 0xe3, 0x6c, - 0x57, 0x2d, 0xc9, 0x0e, 0xf7, 0xb7, 0xc0, 0x7c, 0x25, 0x0f, 0x8b, 0x95, 0x8d, 0xea, 0xb6, 0x6f, - 0xed, 0xee, 0xda, 0x75, 0xec, 0x75, 0x42, 0xdb, 0x6d, 0xa2, 0xb7, 0xc3, 0xa4, 0xed, 0x36, 0x7d, - 0x12, 0x04, 0x6c, 0x22, 0xa7, 0xaa, 0xf3, 0x82, 0xe8, 0xe4, 0x3a, 0x2f, 0xc6, 0x12, 0x8e, 0x9e, - 0x80, 0xe9, 0x80, 0xf8, 0xfb, 0x76, 0x9d, 0x6c, 0x79, 0x7e, 0xc8, 0x46, 0xba, 0x58, 0x3d, 0x21, - 0xd0, 0xa7, 0x6b, 0x11, 0x08, 0xeb, 0x78, 0xb4, 0x9a, 0xef, 0x79, 0xa1, 0x80, 0xb3, 0x81, 0x98, - 0x8a, 0xaa, 0xe1, 0x08, 0x84, 0x75, 0x3c, 0xf4, 0x9a, 0x01, 0x0b, 0x41, 0x68, 0xd7, 0x6f, 0xd9, - 0x2e, 0x09, 0x82, 0x55, 0xcf, 0xdd, 0xb5, 0x9b, 0xcb, 0x45, 0x36, 0x8a, 0x57, 0xc6, 0x1b, 0xc5, - 0x5a, 0x82, 0x6a, 0x75, 0xa9, 0xd7, 0x2d, 0x2f, 0x24, 0x4b, 0x71, 0x1f, 0x77, 0xb4, 0x06, 0x0b, - 0x96, 0xeb, 0x7a, 0xa1, 0x15, 0xda, 0x9e, 0xbb, 0xe5, 0x93, 0x5d, 0xfb, 0xce, 0x72, 0x81, 0x75, - 0x67, 0x59, 0x74, 0x67, 0xa1, 0x92, 0x80, 0xe3, 0xbe, 0x1a, 0xe6, 0x1a, 0x2c, 0x57, 0x5a, 0x3b, - 0x56, 0x10, 0x58, 0x0d, 0xcf, 0x4f, 0xcc, 0xc6, 0xa3, 0x50, 0x6a, 0x59, 0xed, 0xb6, 0xed, 0x36, - 0xe9, 0x74, 0xe4, 0x1f, 0x9d, 0xaa, 0xce, 0xf4, 0xba, 0xe5, 0xd2, 0xa6, 0x28, 0xc3, 0x0a, 0x6a, - 0x7e, 0x2f, 0x07, 0xd3, 0x15, 0xd7, 0x72, 0x0e, 0x02, 0x3b, 0xc0, 0x1d, 0x17, 0x7d, 0x04, 0x4a, - 0x54, 0xba, 0x34, 0xac, 0xd0, 0x12, 0x3b, 0xf2, 0x5d, 0x2b, 0x7c, 0xb3, 0xaf, 0xe8, 0x9b, 0x3d, - 0x1a, 0x17, 0x8a, 0xbd, 0xb2, 0xff, 0xee, 0x95, 0xab, 0x3b, 0x37, 0x49, 0x3d, 0xdc, 0x24, 0xa1, - 0x55, 0x45, 0xa2, 0x17, 0x10, 0x95, 0x61, 0x45, 0x15, 0x79, 0x50, 0x08, 0xda, 0xa4, 0x2e, 0x76, - 0xd8, 0xe6, 0x98, 0x2b, 0x39, 0x6a, 0x7a, 0xad, 0x4d, 0xea, 0xd5, 0x19, 0xc1, 0xba, 0x40, 0xff, - 0x61, 0xc6, 0x08, 0xdd, 0x86, 0x89, 0x80, 0xc9, 0x1c, 0xb1, 0x79, 0xae, 0x66, 0xc7, 0x92, 0x91, - 0xad, 0xce, 0x09, 0xa6, 0x13, 0xfc, 0x3f, 0x16, 0xec, 0xcc, 0x7f, 0x32, 0xe0, 0x84, 0x86, 0x5d, - 0xf1, 0x9b, 0x9d, 0x16, 0x71, 0x43, 0xf4, 0x10, 0x14, 0x5c, 0xab, 0x45, 0xc4, 0x46, 0x51, 0x4d, - 0xbe, 0x62, 0xb5, 0x08, 0x66, 0x10, 0xf4, 0x30, 0x14, 0xf7, 0x2d, 0xa7, 0x43, 0xd8, 0x20, 0x4d, - 0x55, 0x67, 0x05, 0x4a, 0xf1, 0x39, 0x5a, 0x88, 0x39, 0x0c, 0x7d, 0x1c, 0xa6, 0xd8, 0x8f, 0x8b, - 0xbe, 0xd7, 0xca, 0xa8, 0x6b, 0xa2, 0x85, 0xcf, 0x49, 0xb2, 0xd5, 0xd9, 0x5e, 0xb7, 0x3c, 0xa5, - 0xfe, 0xe2, 0x88, 0xa1, 0xf9, 0xcf, 0x06, 0xcc, 0x6b, 0x9d, 0xdb, 0xb0, 0x83, 0x10, 0x7d, 0xa8, - 0x6f, 0xf1, 0xac, 0x0c, 0xb7, 0x78, 0x68, 0x6d, 0xb6, 0x74, 0x16, 0x44, 0x4f, 0x4b, 0xb2, 0x44, - 0x5b, 0x38, 0x2e, 0x14, 0xed, 0x90, 0xb4, 0x82, 0xe5, 0xdc, 0x43, 0xf9, 0x47, 0xa7, 0xcf, 0xaf, - 0x67, 0x36, 0x8d, 0xd1, 0xf8, 0xae, 0x53, 0xfa, 0x98, 0xb3, 0x31, 0xbf, 0x56, 0x88, 0xf5, 0x90, - 0xae, 0x28, 0xe4, 0xc1, 0x64, 0x8b, 0x84, 0xbe, 0x5d, 0xe7, 0xfb, 0x6a, 0xfa, 0xfc, 0xda, 0x78, - 0xad, 0xd8, 0x64, 0xc4, 0x22, 0x61, 0xc9, 0xff, 0x07, 0x58, 0x72, 0x41, 0x7b, 0x50, 0xb0, 0xfc, - 0xa6, 0xec, 0xf3, 0xc5, 0x6c, 0xe6, 0x37, 0x5a, 0x73, 0x15, 0xbf, 0x19, 0x60, 0xc6, 0x01, 0x9d, - 0x83, 0xa9, 0x90, 0xf8, 0x2d, 0xdb, 0xb5, 0x42, 0x2e, 0x5d, 0x4b, 0xd5, 0x45, 0x81, 0x36, 0xb5, - 0x2d, 0x01, 0x38, 0xc2, 0x41, 0x0e, 0x4c, 0x34, 0xfc, 0x03, 0xdc, 0x71, 0x97, 0x0b, 0x59, 0x0c, - 0xc5, 0x1a, 0xa3, 0x15, 0x6d, 0x26, 0xfe, 0x1f, 0x0b, 0x1e, 0xe8, 0x2b, 0x06, 0x2c, 0xb5, 0x88, - 0x15, 0x74, 0x7c, 0x42, 0xbb, 0x80, 0x49, 0x48, 0x5c, 0x2a, 0x0d, 0x97, 0x8b, 0x8c, 0x39, 0x1e, - 0x77, 0x1e, 0xfa, 0x29, 0x57, 0x1f, 0x14, 0x4d, 0x59, 0x4a, 0x83, 0xe2, 0xd4, 0xd6, 0x98, 0xdf, - 0x2b, 0xc0, 0x62, 0x9f, 0x84, 0x40, 0x8f, 0x43, 0xb1, 0xbd, 0x67, 0x05, 0x72, 0xcb, 0x9f, 0x95, - 0xeb, 0x6d, 0x8b, 0x16, 0xbe, 0xd1, 0x2d, 0xcf, 0xca, 0x2a, 0xac, 0x00, 0x73, 0x64, 0x7a, 0xa6, - 0xb6, 0x48, 0x10, 0x58, 0x4d, 0x29, 0x07, 0xb4, 0x65, 0xc2, 0x8a, 0xb1, 0x84, 0xa3, 0x5f, 0x33, - 0x60, 0x96, 0x2f, 0x19, 0x4c, 0x82, 0x8e, 0x13, 0x52, 0x59, 0x47, 0x87, 0xe5, 0x72, 0x16, 0xcb, - 0x93, 0x93, 0xac, 0x9e, 0x14, 0xdc, 0x67, 0xf5, 0xd2, 0x00, 0xc7, 0xf9, 0xa2, 0x1b, 0x30, 0x15, - 0x84, 0x96, 0x1f, 0x92, 0x46, 0x25, 0x64, 0xa7, 0xda, 0xf4, 0xf9, 0x9f, 0x1f, 0x4e, 0x08, 0x6c, - 0xdb, 0x2d, 0xc2, 0x05, 0x4e, 0x4d, 0x12, 0xc0, 0x11, 0x2d, 0xf4, 0x71, 0x00, 0xbf, 0xe3, 0xd6, - 0x3a, 0xad, 0x96, 0xe5, 0x1f, 0x88, 0x13, 0xfc, 0xd2, 0x78, 0xdd, 0xc3, 0x8a, 0x5e, 0x74, 0x66, - 0x45, 0x65, 0x58, 0xe3, 0x87, 0x5e, 0x36, 0x60, 0x96, 0xaf, 0x44, 0xd9, 0x82, 0x89, 0x8c, 0x5b, - 0xb0, 0x48, 0x87, 0x76, 0x4d, 0x67, 0x81, 0xe3, 0x1c, 0xcd, 0x7f, 0x88, 0x9f, 0x27, 0xb5, 0x90, - 0x6a, 0xd7, 0xcd, 0x03, 0xf4, 0x41, 0xb8, 0x3f, 0xe8, 0xd4, 0xeb, 0x24, 0x08, 0x76, 0x3b, 0x0e, - 0xee, 0xb8, 0x97, 0xec, 0x20, 0xf4, 0xfc, 0x83, 0x0d, 0xbb, 0x65, 0x87, 0x6c, 0xc5, 0x15, 0xab, - 0x67, 0x7a, 0xdd, 0xf2, 0xfd, 0xb5, 0x41, 0x48, 0x78, 0x70, 0x7d, 0x64, 0xc1, 0x03, 0x1d, 0x77, - 0x30, 0x79, 0xae, 0xbd, 0x95, 0x7b, 0xdd, 0xf2, 0x03, 0xd7, 0x07, 0xa3, 0xe1, 0xc3, 0x68, 0x98, - 0xff, 0x6e, 0xc0, 0x82, 0xec, 0xd7, 0x36, 0x69, 0xb5, 0x1d, 0x2a, 0x5d, 0x8e, 0x5f, 0x11, 0x09, - 0x63, 0x8a, 0x08, 0xce, 0xe6, 0x38, 0x91, 0xed, 0x1f, 0xa4, 0x8d, 0x98, 0xff, 0x66, 0xc0, 0x52, - 0x12, 0xf9, 0x1e, 0x1c, 0x9e, 0x41, 0xfc, 0xf0, 0xbc, 0x92, 0x6d, 0x6f, 0x07, 0x9c, 0xa0, 0xaf, - 0x16, 0xfa, 0xfb, 0xfa, 0x7f, 0xfd, 0x18, 0x8d, 0x4e, 0xc5, 0xfc, 0x4f, 0xf3, 0x54, 0x2c, 0xbc, - 0xa9, 0x4e, 0xc5, 0xdf, 0x2f, 0xc0, 0x4c, 0xc5, 0x0d, 0xed, 0xca, 0xee, 0xae, 0xed, 0xda, 0xe1, - 0x01, 0xfa, 0x4c, 0x0e, 0xce, 0xb5, 0x7d, 0xb2, 0x4b, 0x7c, 0x9f, 0x34, 0xd6, 0x3a, 0xbe, 0xed, - 0x36, 0x6b, 0xf5, 0x3d, 0xd2, 0xe8, 0x38, 0xb6, 0xdb, 0x5c, 0x6f, 0xba, 0x9e, 0x2a, 0xbe, 0x70, - 0x87, 0xd4, 0x3b, 0xac, 0x4b, 0x7c, 0x53, 0xb4, 0xc6, 0xeb, 0xd2, 0xd6, 0x68, 0x4c, 0xab, 0x8f, - 0xf5, 0xba, 0xe5, 0x73, 0x23, 0x56, 0xc2, 0xa3, 0x76, 0x0d, 0x7d, 0x3a, 0x07, 0x2b, 0x3e, 0xf9, - 0x68, 0xc7, 0x1e, 0x7e, 0x34, 0xb8, 0xd4, 0x72, 0xc6, 0x3c, 0x7e, 0x46, 0xe2, 0x59, 0x3d, 0xdf, - 0xeb, 0x96, 0x47, 0xac, 0x83, 0x47, 0xec, 0x97, 0xf9, 0x97, 0x06, 0x94, 0x46, 0xb0, 0x94, 0xca, - 0x71, 0x4b, 0x69, 0xaa, 0xcf, 0x4a, 0x0a, 0xfb, 0xad, 0xa4, 0x67, 0xc6, 0x1b, 0xb4, 0x61, 0xac, - 0xa3, 0xff, 0x34, 0x60, 0xb1, 0xcf, 0x9a, 0x42, 0x7b, 0xb0, 0xd4, 0xf6, 0x1a, 0x52, 0x12, 0x5e, - 0xb2, 0x82, 0x3d, 0x06, 0x13, 0xdd, 0x7b, 0x9c, 0x6e, 0xaa, 0xad, 0x14, 0xf8, 0x1b, 0xdd, 0xf2, - 0xb2, 0x22, 0x92, 0x40, 0xc0, 0xa9, 0x14, 0x51, 0x1b, 0x4a, 0xbb, 0x36, 0x71, 0x1a, 0x98, 0xec, - 0x8a, 0x95, 0x32, 0xa6, 0xcc, 0xbb, 0x28, 0xa8, 0x71, 0x47, 0x82, 0xfc, 0x87, 0x15, 0x17, 0xf3, - 0x1a, 0xcc, 0xc5, 0xdd, 0x4a, 0x43, 0x4c, 0xde, 0x19, 0xc8, 0x5b, 0xbe, 0x2b, 0xa6, 0x6e, 0x5a, - 0x20, 0xe4, 0x2b, 0xf8, 0x0a, 0xa6, 0xe5, 0xe6, 0x4f, 0x0a, 0x30, 0x5f, 0x75, 0x3a, 0xe4, 0x19, - 0x9f, 0x10, 0xa9, 0x49, 0x57, 0x60, 0xbe, 0xed, 0x93, 0x7d, 0x9b, 0xdc, 0xae, 0x11, 0x87, 0xd4, - 0x43, 0xcf, 0x17, 0xf4, 0x4f, 0x89, 0xea, 0xf3, 0x5b, 0x71, 0x30, 0x4e, 0xe2, 0xa3, 0xa7, 0x61, - 0xce, 0xaa, 0x87, 0xf6, 0x3e, 0x51, 0x14, 0x78, 0x03, 0xde, 0x22, 0x28, 0xcc, 0x55, 0x62, 0x50, - 0x9c, 0xc0, 0x46, 0x1f, 0x82, 0xe5, 0xa0, 0x6e, 0x39, 0xe4, 0x7a, 0x5b, 0xb0, 0x5a, 0xdd, 0x23, - 0xf5, 0x5b, 0x5b, 0x9e, 0xed, 0x86, 0xc2, 0x6e, 0x7a, 0x48, 0x50, 0x5a, 0xae, 0x0d, 0xc0, 0xc3, - 0x03, 0x29, 0xa0, 0x3f, 0x33, 0xe0, 0x4c, 0xdb, 0x27, 0x5b, 0xbe, 0xd7, 0xf2, 0xe8, 0x86, 0xe8, - 0x33, 0x26, 0x84, 0x52, 0xfd, 0xdc, 0x98, 0x3b, 0x9f, 0x97, 0xf4, 0x3b, 0x33, 0xde, 0xda, 0xeb, - 0x96, 0xcf, 0x6c, 0x1d, 0xd6, 0x00, 0x7c, 0x78, 0xfb, 0xd0, 0x5f, 0x18, 0x70, 0xb6, 0xed, 0x05, - 0xe1, 0x21, 0x5d, 0x28, 0x1e, 0x6b, 0x17, 0xcc, 0x5e, 0xb7, 0x7c, 0x76, 0xeb, 0xd0, 0x16, 0xe0, - 0xbb, 0xb4, 0xd0, 0xec, 0x4d, 0xc3, 0xa2, 0xb6, 0xf6, 0x84, 0xa6, 0xfd, 0x14, 0xcc, 0xca, 0xc5, - 0xc0, 0xbd, 0x90, 0x7c, 0xed, 0x29, 0xcb, 0xa8, 0xa2, 0x03, 0x71, 0x1c, 0x97, 0xae, 0x3b, 0xb5, - 0x14, 0x79, 0xed, 0xc4, 0xba, 0xdb, 0x8a, 0x41, 0x71, 0x02, 0x1b, 0xad, 0xc3, 0x09, 0x51, 0x82, - 0x49, 0xdb, 0xb1, 0xeb, 0xd6, 0xaa, 0xd7, 0x11, 0x4b, 0xae, 0x58, 0x3d, 0xd5, 0xeb, 0x96, 0x4f, - 0x6c, 0xf5, 0x83, 0x71, 0x5a, 0x1d, 0xb4, 0x01, 0x4b, 0x56, 0x27, 0xf4, 0x54, 0xff, 0x2f, 0xb8, - 0xd6, 0x8e, 0x43, 0x1a, 0x6c, 0x69, 0x95, 0xaa, 0xcb, 0x54, 0x10, 0x55, 0x52, 0xe0, 0x38, 0xb5, - 0x16, 0xda, 0x4a, 0x50, 0xab, 0x91, 0xba, 0xe7, 0x36, 0xf8, 0x2c, 0x17, 0x23, 0x7d, 0xa1, 0x92, - 0x82, 0x83, 0x53, 0x6b, 0x22, 0x07, 0xe6, 0x5a, 0xd6, 0x9d, 0xeb, 0xae, 0xb5, 0x6f, 0xd9, 0x0e, - 0x65, 0x22, 0xac, 0xad, 0xc1, 0x26, 0x40, 0x27, 0xb4, 0x9d, 0x15, 0x7e, 0xf1, 0xb0, 0xb2, 0xee, - 0x86, 0x57, 0xfd, 0x5a, 0x48, 0xcf, 0x95, 0x2a, 0xa2, 0x03, 0xbb, 0x19, 0xa3, 0x85, 0x13, 0xb4, - 0xd1, 0x55, 0x38, 0xc9, 0xb6, 0xe3, 0x9a, 0x77, 0xdb, 0x5d, 0x23, 0x8e, 0x75, 0x20, 0x3b, 0x30, - 0xc9, 0x3a, 0x70, 0x7f, 0xaf, 0x5b, 0x3e, 0x59, 0x4b, 0x43, 0xc0, 0xe9, 0xf5, 0xa8, 0xcd, 0x14, - 0x07, 0x60, 0xb2, 0x6f, 0x07, 0xb6, 0xe7, 0x72, 0x9b, 0xa9, 0x14, 0xd9, 0x4c, 0xb5, 0xc1, 0x68, - 0xf8, 0x30, 0x1a, 0xe8, 0x77, 0x0c, 0x58, 0x4a, 0xdb, 0x86, 0xcb, 0x53, 0x59, 0xb8, 0x55, 0x13, - 0x5b, 0x8b, 0xaf, 0x88, 0x54, 0xa1, 0x90, 0xda, 0x08, 0xf4, 0x92, 0x01, 0x33, 0x96, 0xa6, 0xef, - 0x2d, 0x03, 0x6b, 0xd5, 0xe5, 0x71, 0xad, 0x8e, 0x88, 0x62, 0x75, 0xa1, 0xd7, 0x2d, 0xc7, 0x74, - 0x4a, 0x1c, 0xe3, 0x88, 0x7e, 0xd7, 0x80, 0x93, 0xa9, 0x7b, 0x7c, 0x79, 0xfa, 0x38, 0x46, 0x88, - 0x2d, 0x92, 0x74, 0x99, 0x93, 0xde, 0x0c, 0xf4, 0x9a, 0xa1, 0x8e, 0xb2, 0x4d, 0x69, 0xf7, 0xcd, - 0xb0, 0xa6, 0x5d, 0x1b, 0x53, 0xc5, 0x8d, 0x14, 0x02, 0x49, 0xb8, 0x7a, 0x42, 0x3b, 0x19, 0x65, - 0x21, 0x4e, 0xb2, 0x47, 0x9f, 0x35, 0xe4, 0xd1, 0xa8, 0x5a, 0x34, 0x7b, 0x5c, 0x2d, 0x42, 0xd1, - 0x49, 0xab, 0x1a, 0x94, 0x60, 0x8e, 0x3e, 0x0c, 0xa7, 0xad, 0x1d, 0xcf, 0x0f, 0x53, 0x37, 0xdf, - 0xf2, 0x1c, 0xdb, 0x46, 0x67, 0x7b, 0xdd, 0xf2, 0xe9, 0xca, 0x40, 0x2c, 0x7c, 0x08, 0x05, 0xf3, - 0xfb, 0x05, 0x98, 0xe1, 0x77, 0x71, 0xe2, 0xe8, 0xfa, 0xba, 0x01, 0x0f, 0xd6, 0x3b, 0xbe, 0x4f, - 0xdc, 0xb0, 0x16, 0x92, 0x76, 0xff, 0xc1, 0x65, 0x1c, 0xeb, 0xc1, 0xf5, 0x50, 0xaf, 0x5b, 0x7e, - 0x70, 0xf5, 0x10, 0xfe, 0xf8, 0xd0, 0xd6, 0xa1, 0xbf, 0x35, 0xc0, 0x14, 0x08, 0x55, 0xab, 0x7e, - 0xab, 0xe9, 0x7b, 0x1d, 0xb7, 0xd1, 0xdf, 0x89, 0xdc, 0xb1, 0x76, 0xe2, 0x91, 0x5e, 0xb7, 0x6c, - 0xae, 0xde, 0xb5, 0x15, 0x78, 0x88, 0x96, 0xa2, 0x67, 0x60, 0x51, 0x60, 0x5d, 0xb8, 0xd3, 0x26, - 0xbe, 0x4d, 0xd5, 0x69, 0x71, 0xf3, 0x17, 0x5d, 0xa6, 0x26, 0x11, 0x70, 0x7f, 0x1d, 0x14, 0xc0, - 0xe4, 0x6d, 0x62, 0x37, 0xf7, 0x42, 0xa9, 0x3e, 0x8d, 0x79, 0x83, 0x2a, 0xee, 0xdb, 0x6e, 0x70, - 0x9a, 0xd5, 0xe9, 0x5e, 0xb7, 0x3c, 0x29, 0xfe, 0x60, 0xc9, 0xc9, 0xfc, 0xa3, 0x02, 0x80, 0x5c, - 0x5e, 0xa4, 0x8d, 0x7e, 0x01, 0xa6, 0x02, 0x12, 0x72, 0x2c, 0xe1, 0x96, 0xe3, 0xde, 0x4e, 0x59, - 0x88, 0x23, 0x38, 0xba, 0x05, 0xc5, 0xb6, 0xd5, 0x09, 0x88, 0x98, 0xac, 0xcb, 0x99, 0x4c, 0xd6, - 0x16, 0xa5, 0xc8, 0x6d, 0x24, 0xf6, 0x13, 0x73, 0x1e, 0xe8, 0x53, 0x06, 0x00, 0x89, 0x0f, 0xf0, - 0xf4, 0xf9, 0x5a, 0x26, 0x2c, 0xa3, 0x39, 0xa0, 0x63, 0x50, 0x9d, 0xeb, 0x75, 0xcb, 0xa0, 0x4d, - 0x95, 0xc6, 0x16, 0xdd, 0x86, 0x92, 0x25, 0x65, 0x74, 0xe1, 0x38, 0x64, 0x34, 0x33, 0x5d, 0xd4, - 0x22, 0x53, 0xcc, 0xd0, 0xa7, 0x0d, 0x98, 0x0b, 0x48, 0x28, 0xa6, 0x8a, 0x4a, 0x0a, 0xa1, 0xa0, - 0x8e, 0xb9, 0x48, 0x6a, 0x31, 0x9a, 0x5c, 0xe2, 0xc5, 0xcb, 0x70, 0x82, 0xaf, 0xf9, 0xfd, 0x69, - 0x98, 0x93, 0x4b, 0x26, 0xd2, 0x39, 0x79, 0x70, 0xc0, 0x00, 0x9d, 0x73, 0x55, 0x07, 0xe2, 0x38, - 0x2e, 0xad, 0xcc, 0x6f, 0xf0, 0xe3, 0x2a, 0xa7, 0xaa, 0x5c, 0xd3, 0x81, 0x38, 0x8e, 0x8b, 0x5a, - 0x50, 0x0c, 0x42, 0xd2, 0x96, 0x77, 0x09, 0x63, 0xba, 0xba, 0xa3, 0x9d, 0x10, 0x79, 0x0b, 0xe9, - 0xbf, 0x00, 0x73, 0x2e, 0xe8, 0x73, 0x06, 0xcc, 0x85, 0xb1, 0x7b, 0x6c, 0xb1, 0x0c, 0xb2, 0x59, - 0x89, 0xf1, 0x2b, 0x72, 0x3e, 0x1b, 0xf1, 0x32, 0x9c, 0x60, 0x9f, 0xa2, 0x86, 0x16, 0x8f, 0x51, - 0x0d, 0x7d, 0x1e, 0x4a, 0x2d, 0xeb, 0x4e, 0xad, 0xe3, 0x37, 0x8f, 0xae, 0xee, 0x8a, 0x6b, 0x7e, - 0x4e, 0x05, 0x2b, 0x7a, 0xe8, 0x65, 0x43, 0xdb, 0x5c, 0x93, 0x8c, 0xf8, 0x8d, 0x6c, 0x37, 0x97, - 0x92, 0xe2, 0x03, 0xb7, 0x59, 0x9f, 0x52, 0x58, 0xba, 0xe7, 0x4a, 0x21, 0x55, 0x70, 0xf8, 0x06, - 0x51, 0x0a, 0xce, 0xd4, 0xb1, 0x2a, 0x38, 0xab, 0x31, 0x66, 0x38, 0xc1, 0x9c, 0xb5, 0x87, 0xef, - 0x39, 0xd5, 0x1e, 0x38, 0xd6, 0xf6, 0xd4, 0x62, 0xcc, 0x70, 0x82, 0xf9, 0x60, 0x4b, 0x68, 0xfa, - 0x78, 0x2c, 0xa1, 0x99, 0x0c, 0x2c, 0xa1, 0xc3, 0x95, 0xc4, 0xd9, 0x71, 0x95, 0x44, 0x74, 0x19, - 0x50, 0xe3, 0xc0, 0xb5, 0x5a, 0x76, 0x5d, 0x08, 0x4b, 0x76, 0x40, 0xcc, 0x31, 0x4b, 0xf9, 0xb4, - 0x10, 0x64, 0x68, 0xad, 0x0f, 0x03, 0xa7, 0xd4, 0x32, 0xff, 0xdb, 0x80, 0x85, 0x55, 0xc7, 0xeb, - 0x34, 0x6e, 0x58, 0x61, 0x7d, 0x8f, 0xdf, 0x52, 0xa0, 0xa7, 0xa1, 0x64, 0xbb, 0x21, 0xf1, 0xf7, - 0x2d, 0x47, 0xc8, 0x76, 0x53, 0x5e, 0xe4, 0xac, 0x8b, 0xf2, 0x37, 0xba, 0xe5, 0xb9, 0xb5, 0x8e, - 0xcf, 0xc2, 0x7f, 0xf8, 0x4e, 0xc7, 0xaa, 0x0e, 0xfa, 0xb2, 0x01, 0x8b, 0xfc, 0x9e, 0x63, 0xcd, - 0x0a, 0xad, 0x6b, 0x1d, 0xe2, 0xdb, 0x44, 0xde, 0x74, 0x8c, 0xb9, 0xc9, 0x93, 0x6d, 0x95, 0x0c, - 0x0e, 0x22, 0xf5, 0x6b, 0x33, 0xc9, 0x19, 0xf7, 0x37, 0xc6, 0xfc, 0x7c, 0x1e, 0xee, 0x1f, 0x48, - 0x0b, 0x9d, 0x86, 0x9c, 0xdd, 0x10, 0x5d, 0x07, 0x41, 0x37, 0xb7, 0xde, 0xc0, 0x39, 0xbb, 0x81, - 0x56, 0x98, 0x66, 0xe2, 0x93, 0x20, 0x90, 0x4e, 0xef, 0x29, 0xa5, 0x44, 0x88, 0x52, 0xac, 0x61, - 0xa0, 0x32, 0x14, 0x1d, 0x6b, 0x87, 0x38, 0x42, 0x4b, 0x64, 0xba, 0xce, 0x06, 0x2d, 0xc0, 0xbc, - 0x1c, 0xfd, 0xaa, 0x01, 0xc0, 0x1b, 0x48, 0x75, 0x4c, 0x71, 0xc2, 0xe0, 0x6c, 0x87, 0x89, 0x52, - 0xe6, 0xad, 0x8c, 0xfe, 0x63, 0x8d, 0x2b, 0xda, 0x86, 0x09, 0xaa, 0xf6, 0x78, 0x8d, 0x23, 0x1f, - 0x28, 0xd0, 0xeb, 0x96, 0x27, 0xb6, 0x18, 0x0d, 0x2c, 0x68, 0xd1, 0xb1, 0xf2, 0x49, 0xd8, 0xf1, - 0x5d, 0x3a, 0xb4, 0xec, 0x08, 0x29, 0xf1, 0x56, 0x60, 0x55, 0x8a, 0x35, 0x0c, 0xf3, 0x4f, 0x73, - 0xb0, 0x94, 0xd6, 0x74, 0x2a, 0xa9, 0x27, 0x78, 0x6b, 0x85, 0xc1, 0xf3, 0xfe, 0xec, 0xc7, 0x47, - 0x5c, 0xd9, 0xa9, 0x8b, 0x2d, 0x11, 0x54, 0x20, 0xf8, 0xa2, 0xf7, 0xab, 0x11, 0xca, 0x1d, 0x71, - 0x84, 0x14, 0xe5, 0xc4, 0x28, 0x3d, 0x04, 0x85, 0x80, 0xce, 0x7c, 0x3e, 0xee, 0x96, 0x66, 0x73, - 0xc4, 0x20, 0x14, 0xa3, 0xe3, 0xda, 0xa1, 0x88, 0xc9, 0x53, 0x18, 0xd7, 0x5d, 0x3b, 0xc4, 0x0c, - 0x62, 0x7e, 0x31, 0x07, 0xa7, 0x07, 0x77, 0x0a, 0x7d, 0xd1, 0x00, 0x68, 0x50, 0xa5, 0x96, 0x2e, - 0x49, 0x79, 0xc5, 0x69, 0x1d, 0xd7, 0x18, 0xae, 0x49, 0x4e, 0xd1, 0x7d, 0xb7, 0x2a, 0x0a, 0xb0, - 0xd6, 0x10, 0x74, 0x5e, 0x2e, 0xfd, 0x2b, 0x56, 0x4b, 0xaa, 0x82, 0xaa, 0xce, 0xa6, 0x82, 0x60, - 0x0d, 0x8b, 0x5a, 0x2d, 0xae, 0xd5, 0x22, 0x41, 0xdb, 0x52, 0x41, 0x97, 0xcc, 0x6a, 0xb9, 0x22, - 0x0b, 0x71, 0x04, 0x37, 0x1d, 0x78, 0x78, 0x88, 0x76, 0x66, 0x14, 0x00, 0x67, 0xfe, 0x97, 0x01, - 0xa7, 0x56, 0x9d, 0x4e, 0x10, 0x12, 0xff, 0xff, 0x4d, 0xf8, 0xc0, 0xff, 0x18, 0xf0, 0xc0, 0x80, - 0x3e, 0xdf, 0x83, 0x28, 0x82, 0x17, 0xe3, 0x51, 0x04, 0xd7, 0xc7, 0x5d, 0xd2, 0xa9, 0xfd, 0x18, - 0x10, 0x4c, 0x10, 0xc2, 0x2c, 0x95, 0x5a, 0x0d, 0xaf, 0x99, 0xd1, 0xb9, 0xf9, 0x30, 0x14, 0x3f, - 0x4a, 0xcf, 0x9f, 0xe4, 0x1a, 0x63, 0x87, 0x12, 0xe6, 0x30, 0xf3, 0x7d, 0x20, 0xae, 0xdc, 0x13, - 0x9b, 0xc7, 0x18, 0x66, 0xf3, 0x98, 0xff, 0x98, 0x03, 0xcd, 0xda, 0xbd, 0x07, 0x8b, 0xd2, 0x8d, - 0x2d, 0xca, 0x31, 0xed, 0x57, 0xcd, 0x76, 0x1f, 0x14, 0x5b, 0xbb, 0x9f, 0x88, 0xad, 0xbd, 0x92, - 0x19, 0xc7, 0xc3, 0x43, 0x6b, 0xbf, 0x63, 0xc0, 0x03, 0x11, 0x72, 0xbf, 0xe3, 0xe8, 0xee, 0x12, - 0xe6, 0x09, 0x98, 0xb6, 0xa2, 0x6a, 0x62, 0x0d, 0xa8, 0x70, 0x72, 0x8d, 0x22, 0xd6, 0xf1, 0xa2, - 0x48, 0xbe, 0xfc, 0x11, 0x23, 0xf9, 0x0a, 0x87, 0x47, 0xf2, 0x99, 0x3f, 0xce, 0xc1, 0x99, 0xfe, - 0x9e, 0xc9, 0xbd, 0x31, 0xdc, 0xbd, 0xea, 0x93, 0x30, 0x13, 0x8a, 0x0a, 0x9a, 0xa4, 0x57, 0x8f, - 0x21, 0xb6, 0x35, 0x18, 0x8e, 0x61, 0xd2, 0x9a, 0x75, 0xbe, 0x2b, 0x6b, 0x75, 0xaf, 0x2d, 0xe3, - 0x40, 0x55, 0xcd, 0x55, 0x0d, 0x86, 0x63, 0x98, 0x2a, 0xc2, 0xa6, 0x70, 0xec, 0x11, 0x36, 0x35, - 0x38, 0x29, 0x63, 0x0a, 0x2e, 0x7a, 0xfe, 0xaa, 0xd7, 0x6a, 0x3b, 0x44, 0x44, 0x82, 0xd2, 0xc6, - 0x9e, 0x11, 0x55, 0x4e, 0xe2, 0x34, 0x24, 0x9c, 0x5e, 0xd7, 0xfc, 0x4e, 0x1e, 0x4e, 0x44, 0xc3, - 0xbe, 0xea, 0xb9, 0x0d, 0x9b, 0x45, 0x66, 0x3c, 0x05, 0x85, 0xf0, 0xa0, 0x2d, 0x07, 0xfb, 0xe7, - 0x64, 0x73, 0xb6, 0x0f, 0xda, 0x74, 0xb6, 0x4f, 0xa5, 0x54, 0xa1, 0x20, 0xcc, 0x2a, 0xa1, 0x0d, - 0xb5, 0x3b, 0xf8, 0x0c, 0x3c, 0x1e, 0x5f, 0xcd, 0x6f, 0x74, 0xcb, 0x29, 0x6f, 0x81, 0x56, 0x14, - 0xa5, 0xf8, 0x9a, 0x47, 0x37, 0x61, 0xce, 0xb1, 0x82, 0xf0, 0x7a, 0xbb, 0x61, 0x85, 0x64, 0xdb, - 0x6e, 0x11, 0xb1, 0xe7, 0x46, 0x09, 0xaf, 0x54, 0x77, 0x8d, 0x1b, 0x31, 0x4a, 0x38, 0x41, 0x19, - 0xed, 0x03, 0xa2, 0x25, 0xdb, 0xbe, 0xe5, 0x06, 0xbc, 0x57, 0x94, 0xdf, 0xe8, 0xe1, 0x9c, 0xca, - 0x40, 0xda, 0xe8, 0xa3, 0x86, 0x53, 0x38, 0xa0, 0x47, 0x60, 0xc2, 0x27, 0x56, 0x20, 0x26, 0x73, - 0x2a, 0xda, 0xff, 0x98, 0x95, 0x62, 0x01, 0xd5, 0x37, 0xd4, 0xc4, 0x5d, 0x36, 0xd4, 0x0f, 0x0c, - 0x98, 0x8b, 0xa6, 0xe9, 0x1e, 0x1c, 0x92, 0xad, 0xf8, 0x21, 0x79, 0x29, 0x2b, 0x91, 0x38, 0xe0, - 0x5c, 0xfc, 0xab, 0x09, 0xbd, 0x7f, 0x2c, 0xbc, 0xee, 0x63, 0x30, 0x25, 0x77, 0xb5, 0xd4, 0x3e, - 0xc7, 0xf4, 0xb2, 0xc4, 0xf4, 0x12, 0x2d, 0x2c, 0x5c, 0x30, 0xc1, 0x11, 0x3f, 0x7a, 0x2c, 0x37, - 0xc4, 0x91, 0x2b, 0x96, 0xbd, 0x3a, 0x96, 0xe5, 0x51, 0x9c, 0x76, 0x2c, 0xcb, 0x3a, 0xe8, 0x3a, - 0x9c, 0x6a, 0xfb, 0x1e, 0x7b, 0x2a, 0xb4, 0x46, 0xac, 0x86, 0x63, 0xbb, 0x44, 0x1a, 0xf3, 0xfc, - 0xaa, 0xfb, 0x81, 0x5e, 0xb7, 0x7c, 0x6a, 0x2b, 0x1d, 0x05, 0x0f, 0xaa, 0x1b, 0x0f, 0x6f, 0x2f, - 0x0c, 0x11, 0xde, 0xfe, 0xeb, 0xca, 0x65, 0x46, 0x02, 0x11, 0x64, 0xfe, 0xc1, 0xac, 0xa6, 0x32, - 0x45, 0xac, 0x47, 0x4b, 0xaa, 0x22, 0x98, 0x62, 0xc5, 0x7e, 0xb0, 0x5f, 0x66, 0xe2, 0x88, 0x7e, - 0x99, 0x28, 0x4a, 0x71, 0xf2, 0xa7, 0x19, 0xa5, 0x58, 0x7a, 0x53, 0x45, 0x29, 0xbe, 0x52, 0x84, - 0x85, 0xa4, 0x06, 0x72, 0xfc, 0xa1, 0xfb, 0xbf, 0x65, 0xc0, 0x82, 0xdc, 0x3d, 0x9c, 0x27, 0x91, - 0x1e, 0xf7, 0x8d, 0x8c, 0x36, 0x2d, 0xd7, 0xa5, 0xd4, 0xe3, 0xb2, 0xed, 0x04, 0x37, 0xdc, 0xc7, - 0x1f, 0xbd, 0x00, 0xd3, 0xca, 0x31, 0x7d, 0xa4, 0x38, 0xfe, 0x79, 0xa6, 0x45, 0x45, 0x24, 0xb0, - 0x4e, 0x0f, 0xbd, 0x62, 0x00, 0xd4, 0xe5, 0x31, 0x27, 0x77, 0xd7, 0xb5, 0xac, 0x76, 0x97, 0x3a, - 0x40, 0x23, 0x65, 0x59, 0x15, 0x05, 0x58, 0x63, 0x8c, 0x3e, 0xcf, 0x5c, 0xd2, 0x4a, 0xbb, 0xa3, - 0xfb, 0x89, 0xb6, 0xe4, 0x03, 0x59, 0xef, 0xf3, 0xe8, 0x76, 0x54, 0xa9, 0x52, 0x1a, 0x28, 0xc0, - 0xb1, 0x46, 0x98, 0x4f, 0x81, 0x0a, 0xb0, 0xa3, 0x62, 0x8b, 0x85, 0xd8, 0x6d, 0x59, 0xe1, 0x9e, - 0x58, 0x82, 0x4a, 0x6c, 0x5d, 0x94, 0x00, 0x1c, 0xe1, 0x98, 0x1f, 0x81, 0xb9, 0x67, 0x7c, 0xab, - 0xbd, 0x67, 0x33, 0xd7, 0x2f, 0xb5, 0x93, 0xde, 0x0e, 0x93, 0x56, 0xa3, 0x91, 0xf6, 0x34, 0xb3, - 0xc2, 0x8b, 0xb1, 0x84, 0x0f, 0x67, 0x12, 0x7d, 0xc3, 0x80, 0xa5, 0xf5, 0x20, 0xb4, 0xbd, 0x35, - 0x12, 0x84, 0x54, 0x56, 0xd2, 0x1d, 0xd5, 0x71, 0xc8, 0x10, 0x8a, 0xe9, 0x1a, 0x2c, 0x88, 0xfb, - 0xa9, 0xce, 0x4e, 0x40, 0x42, 0x4d, 0x39, 0x55, 0x8b, 0x73, 0x35, 0x01, 0xc7, 0x7d, 0x35, 0x28, - 0x15, 0x71, 0x51, 0x15, 0x51, 0xc9, 0xc7, 0xa9, 0xd4, 0x12, 0x70, 0xdc, 0x57, 0xc3, 0xfc, 0x76, - 0x1e, 0x4e, 0xb0, 0x6e, 0x24, 0xde, 0x4e, 0x7e, 0xd6, 0x80, 0xb9, 0x7d, 0xdb, 0x0f, 0x3b, 0x96, - 0xa3, 0xdf, 0xb8, 0x8d, 0xbd, 0x3e, 0x19, 0xaf, 0xe7, 0x62, 0x84, 0xb9, 0x4f, 0x3e, 0x5e, 0x86, - 0x13, 0xcc, 0xd1, 0x6f, 0x1a, 0x30, 0xdf, 0x88, 0x8f, 0x74, 0x36, 0x3e, 0x87, 0xb4, 0x39, 0xe4, - 0x81, 0x22, 0x89, 0x42, 0x9c, 0xe4, 0x8f, 0xbe, 0x60, 0xc0, 0x7c, 0xbc, 0x99, 0x52, 0x64, 0x1d, - 0xc3, 0x20, 0xa9, 0xc8, 0xce, 0x78, 0x79, 0x80, 0x93, 0x4d, 0x30, 0xff, 0xde, 0x10, 0x53, 0x1a, - 0xc7, 0x1c, 0x62, 0x61, 0x9a, 0x30, 0xe1, 0x7b, 0x9d, 0x50, 0xf8, 0xcd, 0xa7, 0xb8, 0x7b, 0x15, - 0xb3, 0x12, 0x2c, 0x20, 0xe8, 0x36, 0x4c, 0x85, 0x4e, 0xc0, 0x0b, 0x45, 0x6f, 0xc7, 0x34, 0x73, - 0xb6, 0x37, 0x6a, 0x8c, 0x9c, 0xa6, 0x89, 0x88, 0x12, 0xaa, 0x51, 0x49, 0x5e, 0xe6, 0x57, 0x0d, - 0x98, 0xba, 0xec, 0xed, 0x88, 0xed, 0xfc, 0xe1, 0x0c, 0x9c, 0x08, 0x4a, 0xd7, 0x50, 0x37, 0x41, - 0x91, 0xfa, 0xfa, 0x74, 0xcc, 0x85, 0xf0, 0xa0, 0x46, 0x7b, 0x85, 0xa5, 0x34, 0xa0, 0xa4, 0x2e, - 0x7b, 0x3b, 0x03, 0x3d, 0x54, 0xbf, 0x57, 0x84, 0xd9, 0x67, 0xad, 0x03, 0xe2, 0x86, 0xd6, 0xe8, - 0x02, 0x88, 0x5a, 0xe5, 0x6d, 0x16, 0xa8, 0xa8, 0xe9, 0x8f, 0x91, 0x55, 0x1e, 0x81, 0xb0, 0x8e, - 0x17, 0xc9, 0x15, 0xfe, 0xc2, 0x3a, 0x4d, 0x22, 0xac, 0x26, 0xe0, 0xb8, 0xaf, 0x06, 0xba, 0x0c, - 0x48, 0xbc, 0x17, 0xa9, 0xd4, 0xeb, 0x5e, 0xc7, 0xe5, 0x92, 0x85, 0x1b, 0xec, 0xca, 0x90, 0xd9, - 0xec, 0xc3, 0xc0, 0x29, 0xb5, 0xd0, 0x87, 0x60, 0xb9, 0xce, 0x28, 0x0b, 0xb5, 0x56, 0xa7, 0xc8, - 0x4d, 0x1b, 0x15, 0x24, 0xbc, 0x3a, 0x00, 0x0f, 0x0f, 0xa4, 0x40, 0x5b, 0x1a, 0x84, 0x9e, 0x6f, - 0x35, 0x89, 0x4e, 0x77, 0x22, 0xde, 0xd2, 0x5a, 0x1f, 0x06, 0x4e, 0xa9, 0x85, 0x3e, 0x09, 0x53, - 0xe1, 0x9e, 0x4f, 0x82, 0x3d, 0xcf, 0x69, 0x88, 0xab, 0xe1, 0x31, 0xbd, 0x38, 0x62, 0xf6, 0xb7, - 0x25, 0x55, 0x6d, 0x79, 0xcb, 0x22, 0x1c, 0xf1, 0x44, 0x3e, 0x4c, 0x04, 0x75, 0xaf, 0x4d, 0x02, - 0xa1, 0x0e, 0x5e, 0xce, 0x84, 0x3b, 0xf3, 0x4a, 0x68, 0xfe, 0x23, 0xc6, 0x01, 0x0b, 0x4e, 0xe6, - 0x37, 0x73, 0x30, 0xa3, 0x23, 0x0e, 0x21, 0x22, 0x3e, 0x65, 0xc0, 0x4c, 0xdd, 0x73, 0x43, 0xdf, - 0x73, 0xb8, 0x6f, 0x84, 0x6f, 0x90, 0x31, 0x9f, 0x21, 0x33, 0x52, 0x6b, 0x24, 0xb4, 0x6c, 0x47, - 0x73, 0xb3, 0x68, 0x6c, 0x70, 0x8c, 0x29, 0xfa, 0x8c, 0x01, 0xf3, 0x51, 0xcc, 0x4c, 0xe4, 0xa4, - 0xc9, 0xb4, 0x21, 0x4a, 0xe2, 0x5e, 0x88, 0x73, 0xc2, 0x49, 0xd6, 0xe6, 0x0e, 0x2c, 0x24, 0x67, - 0x9b, 0x0e, 0x65, 0xdb, 0x12, 0x7b, 0x3d, 0x1f, 0x0d, 0xe5, 0x96, 0x15, 0x04, 0x98, 0x41, 0xd0, - 0x3b, 0xa0, 0xd4, 0xb2, 0xfc, 0xa6, 0xed, 0x5a, 0x0e, 0x1b, 0xc5, 0xbc, 0x26, 0x90, 0x44, 0x39, - 0x56, 0x18, 0xe6, 0x8f, 0x0a, 0x30, 0xad, 0x69, 0xf1, 0xc7, 0xaf, 0x91, 0xc7, 0x9e, 0xb0, 0xe6, - 0x33, 0x7c, 0xc2, 0xfa, 0x3c, 0xc0, 0xae, 0xed, 0xda, 0xc1, 0xde, 0x11, 0x1f, 0xc7, 0xb2, 0xcb, - 0xbc, 0x8b, 0x8a, 0x02, 0xd6, 0xa8, 0x45, 0x37, 0x26, 0xc5, 0x43, 0x52, 0x06, 0xbc, 0x62, 0x68, - 0x87, 0xc7, 0x44, 0x16, 0x37, 0xc4, 0xda, 0xc4, 0xac, 0xc8, 0xc3, 0xe4, 0x82, 0x1b, 0xfa, 0x07, - 0x87, 0x9e, 0x31, 0xdb, 0x50, 0xf2, 0x49, 0xd0, 0x69, 0x51, 0xdb, 0x62, 0x72, 0xe4, 0x61, 0x60, - 0x01, 0x26, 0x58, 0xd4, 0xc7, 0x8a, 0xd2, 0xe9, 0xa7, 0x60, 0x36, 0xd6, 0x04, 0xb4, 0x00, 0xf9, - 0x5b, 0xe4, 0x80, 0xaf, 0x13, 0x4c, 0x7f, 0xa2, 0xa5, 0xd8, 0xbd, 0x92, 0x18, 0x96, 0xf7, 0xe6, - 0x9e, 0x34, 0x4c, 0x0f, 0x52, 0x4d, 0xc5, 0xa3, 0xb8, 0xfd, 0xe9, 0x5c, 0x38, 0xda, 0xeb, 0x58, - 0x35, 0x17, 0x3c, 0x9a, 0x81, 0xc3, 0xcc, 0x1f, 0x4f, 0x80, 0xb8, 0xf4, 0x1c, 0x42, 0xf8, 0xe8, - 0x77, 0x1d, 0xb9, 0x23, 0xdc, 0x75, 0x5c, 0x86, 0x19, 0xdb, 0xb5, 0x43, 0xdb, 0x72, 0x98, 0x1b, - 0x40, 0x1c, 0x8e, 0x8f, 0x48, 0x81, 0xb3, 0xae, 0xc1, 0x52, 0xe8, 0xc4, 0xea, 0xa2, 0x6b, 0x50, - 0x64, 0xa7, 0x87, 0x58, 0xc0, 0xa3, 0xdf, 0xcc, 0xb2, 0x4b, 0x79, 0xfe, 0x3a, 0x81, 0x53, 0x62, - 0x1a, 0x3d, 0x7f, 0x1e, 0xac, 0x0c, 0x35, 0xb1, 0x8e, 0x23, 0x8d, 0x3e, 0x01, 0xc7, 0x7d, 0x35, - 0x28, 0x95, 0x5d, 0xcb, 0x76, 0x3a, 0x3e, 0x89, 0xa8, 0x4c, 0xc4, 0xa9, 0x5c, 0x4c, 0xc0, 0x71, - 0x5f, 0x0d, 0xb4, 0x0b, 0x33, 0xa2, 0x8c, 0xc7, 0xa8, 0x4c, 0x1e, 0xb1, 0x97, 0x2c, 0x16, 0xe9, - 0xa2, 0x46, 0x09, 0xc7, 0xe8, 0xa2, 0x0e, 0x2c, 0xda, 0x6e, 0xdd, 0x73, 0xeb, 0x4e, 0x27, 0xb0, - 0xf7, 0x49, 0xf4, 0x34, 0xe0, 0x28, 0xcc, 0x4e, 0xf6, 0xba, 0xe5, 0xc5, 0xf5, 0x24, 0x39, 0xdc, - 0xcf, 0x01, 0xbd, 0x6c, 0xc0, 0xc9, 0xba, 0xe7, 0x06, 0xec, 0xbd, 0xdd, 0x3e, 0xb9, 0xe0, 0xfb, - 0x9e, 0xcf, 0x79, 0x4f, 0x1d, 0x91, 0x37, 0xf3, 0x3e, 0xad, 0xa6, 0x91, 0xc4, 0xe9, 0x9c, 0xd0, - 0x8b, 0x50, 0x6a, 0xfb, 0xde, 0xbe, 0xdd, 0x20, 0xbe, 0x88, 0x77, 0xda, 0xc8, 0xe2, 0xfd, 0xef, - 0x96, 0xa0, 0x19, 0x89, 0x1e, 0x59, 0x82, 0x15, 0x3f, 0xf3, 0x0f, 0x4b, 0x30, 0x17, 0x47, 0x47, - 0x9f, 0x00, 0x68, 0xfb, 0x5e, 0x8b, 0x84, 0x7b, 0x44, 0x85, 0x78, 0x5f, 0x19, 0xf7, 0x99, 0xa9, - 0xa4, 0x27, 0xe3, 0x1c, 0xa8, 0xb8, 0x88, 0x4a, 0xb1, 0xc6, 0x11, 0xf9, 0x30, 0x79, 0x8b, 0x1f, - 0xa2, 0x42, 0xa7, 0x78, 0x36, 0x13, 0x0d, 0x48, 0x70, 0x66, 0xb1, 0xc9, 0xa2, 0x08, 0x4b, 0x46, - 0x68, 0x07, 0xf2, 0xb7, 0xc9, 0x4e, 0x36, 0x0f, 0x22, 0x6f, 0x10, 0x61, 0x9b, 0x54, 0x27, 0x7b, - 0xdd, 0x72, 0xfe, 0x06, 0xd9, 0xc1, 0x94, 0x38, 0xed, 0x57, 0x83, 0xdf, 0xd8, 0x0a, 0x51, 0x31, - 0x66, 0xbf, 0x62, 0xd7, 0xbf, 0xbc, 0x5f, 0xa2, 0x08, 0x4b, 0x46, 0xe8, 0x45, 0x98, 0xba, 0x6d, - 0xed, 0x93, 0x5d, 0xdf, 0x73, 0x43, 0x11, 0x5c, 0x33, 0x66, 0x14, 0xf1, 0x0d, 0x49, 0x4e, 0xf0, - 0x65, 0xc7, 0xbb, 0x2a, 0xc4, 0x11, 0x3b, 0xb4, 0x0f, 0x25, 0x97, 0xdc, 0xc6, 0xc4, 0xb1, 0xeb, - 0x22, 0x80, 0x73, 0xcc, 0x65, 0x7d, 0x45, 0x50, 0x13, 0x9c, 0xd9, 0xb9, 0x27, 0xcb, 0xb0, 0xe2, - 0x45, 0xe7, 0xf2, 0xa6, 0xb7, 0x23, 0x04, 0xd5, 0x98, 0x73, 0xa9, 0xec, 0x4c, 0x3e, 0x97, 0x97, - 0xbd, 0x1d, 0x4c, 0x89, 0xd3, 0x3d, 0x52, 0x57, 0x91, 0x1d, 0x42, 0x4c, 0x5d, 0xc9, 0x36, 0xa2, - 0x85, 0xef, 0x91, 0xa8, 0x14, 0x6b, 0x1c, 0xe9, 0xd8, 0x36, 0x85, 0x5b, 0x4b, 0x08, 0xaa, 0x31, - 0xc7, 0x36, 0xee, 0x24, 0xe3, 0x63, 0x2b, 0xcb, 0xb0, 0xe2, 0x65, 0xfe, 0x6b, 0x01, 0x66, 0xf4, - 0x7c, 0x27, 0x43, 0x9c, 0xd5, 0x4a, 0x3f, 0xcd, 0x8d, 0xa2, 0x9f, 0x52, 0xf3, 0x42, 0xf3, 0x4a, - 0x4b, 0x0f, 0xc3, 0x7a, 0x66, 0xea, 0x59, 0x64, 0x5e, 0x68, 0x85, 0x01, 0x8e, 0x31, 0x1d, 0xe1, - 0xa2, 0x9a, 0x2a, 0x39, 0x5c, 0x0d, 0x28, 0xc6, 0x95, 0x9c, 0xd8, 0xc1, 0x7e, 0x1e, 0x20, 0xca, - 0xfb, 0x21, 0x6e, 0x2b, 0x94, 0xf6, 0xa4, 0xe5, 0x23, 0xd1, 0xb0, 0xd0, 0x23, 0x30, 0x41, 0x0f, - 0x4a, 0xd2, 0x10, 0xef, 0xef, 0x94, 0x0d, 0x77, 0x91, 0x95, 0x62, 0x01, 0x45, 0x4f, 0x52, 0x9d, - 0x26, 0x3a, 0xde, 0xc4, 0xb3, 0xba, 0xa5, 0x48, 0xa7, 0x89, 0x60, 0x38, 0x86, 0x49, 0x9b, 0x4e, - 0xe8, 0x69, 0xc4, 0x56, 0x92, 0xd6, 0x74, 0x76, 0x44, 0x61, 0x0e, 0x63, 0x3e, 0x85, 0xc4, 0xe9, - 0xc5, 0x0e, 0xab, 0xa2, 0xe6, 0x53, 0x48, 0xc0, 0x71, 0x5f, 0x0d, 0xda, 0x19, 0x71, 0xd1, 0x32, - 0xcd, 0xe3, 0xf1, 0xd2, 0xaf, 0x48, 0xcc, 0x8f, 0xc0, 0x5c, 0x7c, 0xb7, 0xd3, 0xa9, 0x68, 0xfb, - 0xde, 0xae, 0xed, 0x90, 0xa4, 0xd7, 0x64, 0x8b, 0x17, 0x63, 0x09, 0x1f, 0xce, 0x6d, 0xfb, 0xd7, - 0x79, 0x38, 0x71, 0xa5, 0x69, 0xbb, 0x77, 0x12, 0xfe, 0xce, 0xb4, 0x6c, 0x74, 0xc6, 0xa8, 0xd9, - 0xe8, 0xa2, 0x87, 0x06, 0x22, 0xdd, 0x5f, 0xfa, 0x43, 0x03, 0x99, 0x0b, 0x30, 0x8e, 0x8b, 0x7e, - 0x60, 0xc0, 0x83, 0x56, 0x83, 0xeb, 0x5f, 0x96, 0x23, 0x4a, 0x23, 0xa6, 0x72, 0x2f, 0x04, 0x63, - 0x4a, 0xd3, 0xfe, 0xce, 0xaf, 0x54, 0x0e, 0xe1, 0xca, 0xcd, 0x98, 0xb7, 0x89, 0x1e, 0x3c, 0x78, - 0x18, 0x2a, 0x3e, 0xb4, 0xf9, 0xa7, 0xaf, 0xc2, 0x5b, 0xef, 0xca, 0x68, 0x24, 0x63, 0xe5, 0x53, - 0x06, 0x4c, 0x71, 0x77, 0x1e, 0x26, 0xbb, 0x74, 0x93, 0x59, 0x6d, 0xfb, 0x39, 0xe2, 0x07, 0x32, - 0x4d, 0x86, 0x66, 0xa2, 0x54, 0xb6, 0xd6, 0x05, 0x04, 0x6b, 0x58, 0x54, 0x8c, 0xdd, 0xb2, 0xdd, - 0x86, 0x98, 0x26, 0x25, 0xc6, 0x9e, 0xb5, 0xdd, 0x06, 0x66, 0x10, 0x25, 0xe8, 0xf2, 0x83, 0x04, - 0x9d, 0xf9, 0x15, 0x03, 0xe6, 0xd8, 0x3b, 0xa2, 0x48, 0x79, 0x7e, 0x42, 0xdd, 0xdf, 0xf3, 0x66, - 0x9c, 0x89, 0xdf, 0xdf, 0xbf, 0xd1, 0x2d, 0x4f, 0xf3, 0x97, 0x47, 0xf1, 0xeb, 0xfc, 0x0f, 0x0a, - 0x8b, 0x9b, 0x45, 0x19, 0xe4, 0x46, 0x36, 0x08, 0x95, 0x7f, 0xa9, 0x26, 0x89, 0xe0, 0x88, 0x9e, - 0xf9, 0xc7, 0x79, 0x38, 0x91, 0x12, 0x10, 0x4f, 0x8d, 0xe1, 0x09, 0x16, 0x13, 0x2c, 0xef, 0xc8, - 0x5f, 0xc8, 0x3c, 0xe8, 0x7e, 0x85, 0x85, 0x1e, 0x8b, 0x95, 0xa4, 0xb6, 0x3e, 0x2f, 0xc4, 0x82, - 0x39, 0xfa, 0x6d, 0x03, 0xa6, 0x2d, 0x6d, 0xb1, 0xf3, 0xb0, 0x81, 0x9d, 0xec, 0x1b, 0xd3, 0xb7, - 0xb6, 0xb5, 0x70, 0xa7, 0x68, 0x29, 0xeb, 0x6d, 0x39, 0xfd, 0x1e, 0x98, 0xd6, 0xba, 0x30, 0xca, - 0x1a, 0x3d, 0xfd, 0x34, 0x2c, 0x8c, 0xb5, 0xc6, 0x3f, 0x00, 0xa3, 0xe6, 0x5d, 0xa1, 0xc2, 0xf6, - 0xb6, 0xfe, 0xbc, 0x4e, 0x8d, 0xb8, 0x78, 0x5f, 0x27, 0xa0, 0xe6, 0x0e, 0x2c, 0x24, 0x15, 0xf4, - 0xcc, 0x6f, 0xc9, 0xde, 0x05, 0x23, 0x66, 0x4a, 0x31, 0xff, 0x26, 0x07, 0x93, 0xe2, 0x55, 0xcd, - 0x3d, 0x88, 0x14, 0xbc, 0x15, 0x73, 0xf3, 0xaf, 0x67, 0xf2, 0x18, 0x68, 0x60, 0x98, 0x60, 0x90, - 0x08, 0x13, 0x7c, 0x36, 0x1b, 0x76, 0x87, 0xc7, 0x08, 0x7e, 0xa5, 0x00, 0xf3, 0x89, 0x57, 0x4a, - 0xe8, 0x55, 0xa3, 0x3f, 0x34, 0xe6, 0x7a, 0xa6, 0x0f, 0xa1, 0x54, 0x14, 0xeb, 0xe1, 0x51, 0x32, - 0x41, 0x2c, 0x21, 0xd5, 0xb5, 0xcc, 0x72, 0x59, 0xfe, 0x2c, 0x37, 0xd5, 0xa8, 0x51, 0x1f, 0xff, - 0x62, 0xc0, 0xfd, 0x03, 0x1f, 0xb3, 0xb1, 0x57, 0xfa, 0x7e, 0x1c, 0x2a, 0x36, 0x64, 0xc6, 0x8f, - 0x53, 0x95, 0xcf, 0x3d, 0xf9, 0xb0, 0x3a, 0xc9, 0x1e, 0x3d, 0x0e, 0x33, 0xec, 0x70, 0xa3, 0x32, - 0x25, 0x24, 0x6d, 0xe1, 0x64, 0x64, 0xee, 0xa6, 0x9a, 0x56, 0x8e, 0x63, 0x58, 0xe6, 0x97, 0x0d, - 0x58, 0x1e, 0xf4, 0x66, 0x7b, 0x08, 0xa3, 0xe6, 0x97, 0x12, 0xa1, 0x8c, 0xe5, 0xbe, 0x50, 0xc6, - 0x84, 0x59, 0x23, 0xa3, 0x16, 0x35, 0x8b, 0x22, 0x7f, 0x97, 0x48, 0xbd, 0xcf, 0x1a, 0x70, 0x6a, - 0xc0, 0x6e, 0xea, 0x0b, 0x69, 0x35, 0x8e, 0x1c, 0xd2, 0x9a, 0x1b, 0x36, 0xa4, 0xd5, 0xfc, 0xbb, - 0x3c, 0x2c, 0x88, 0xf6, 0x44, 0x1a, 0xce, 0x93, 0xb1, 0x80, 0xd0, 0xb7, 0x25, 0x02, 0x42, 0x97, - 0x92, 0xf8, 0x3f, 0x8b, 0x06, 0x7d, 0x73, 0x45, 0x83, 0xfe, 0x24, 0x07, 0x27, 0x53, 0x9f, 0xa6, - 0xa3, 0x4f, 0xa7, 0x1c, 0x0d, 0x37, 0x32, 0x7e, 0x03, 0x3f, 0xe4, 0xe1, 0x30, 0x6e, 0x08, 0xe5, - 0x17, 0xf4, 0xd0, 0x45, 0x2e, 0xea, 0x77, 0x8f, 0xe1, 0x35, 0xff, 0x88, 0x51, 0x8c, 0xe6, 0x6f, - 0xe4, 0xe1, 0xd1, 0x61, 0x09, 0xbd, 0x49, 0xa3, 0xdc, 0x83, 0x58, 0x94, 0xfb, 0x3d, 0x3a, 0xb6, - 0x8f, 0x25, 0xe0, 0xfd, 0xab, 0x79, 0x75, 0xec, 0xf5, 0xaf, 0xcf, 0xa1, 0x6e, 0xa4, 0x26, 0xa9, - 0x6a, 0x27, 0x13, 0xcc, 0x45, 0xa2, 0x70, 0xb2, 0xc6, 0x8b, 0xdf, 0xe8, 0x96, 0x17, 0x45, 0xd2, - 0xa9, 0x1a, 0x09, 0x45, 0x21, 0x96, 0x95, 0xd0, 0xa3, 0x50, 0xf2, 0x39, 0x54, 0xc6, 0xf5, 0x8a, - 0x6b, 0x3d, 0x5e, 0x86, 0x15, 0x14, 0x7d, 0x52, 0xd3, 0x85, 0x0b, 0xc7, 0xf5, 0x3a, 0xfa, 0xb0, - 0xdb, 0xca, 0x17, 0xa0, 0x14, 0xc8, 0x54, 0x71, 0xdc, 0xa5, 0xfc, 0xd8, 0x90, 0xe1, 0xe2, 0xd4, - 0x74, 0x92, 0x79, 0xe3, 0x78, 0xff, 0x54, 0x56, 0x39, 0x45, 0x12, 0x99, 0xca, 0x6a, 0xe1, 0xfe, - 0x31, 0x48, 0xb1, 0x58, 0xbe, 0x63, 0xc0, 0xb4, 0x98, 0xad, 0x7b, 0x10, 0xc1, 0x7e, 0x33, 0x1e, - 0xc1, 0x7e, 0x21, 0x13, 0xd9, 0x31, 0x20, 0x7c, 0xfd, 0x26, 0xcc, 0xe8, 0xd9, 0x49, 0xd0, 0xf3, - 0x9a, 0xec, 0x33, 0xc6, 0xc9, 0x82, 0x20, 0xa5, 0x63, 0x24, 0x17, 0xcd, 0x2f, 0x95, 0xd4, 0x28, - 0xb2, 0x38, 0x79, 0x7d, 0x0d, 0x1a, 0x87, 0xae, 0x41, 0x7d, 0x09, 0xe4, 0xb2, 0x5f, 0x02, 0xd7, - 0xa0, 0x24, 0x05, 0x94, 0x38, 0xc6, 0x1f, 0xd6, 0xe3, 0xae, 0xa8, 0x2e, 0x40, 0x89, 0x69, 0x0b, - 0x97, 0x99, 0x5a, 0x6a, 0x0e, 0x95, 0xe0, 0x54, 0x64, 0xd0, 0x8b, 0x30, 0x7d, 0xdb, 0xf3, 0x6f, - 0x39, 0x9e, 0xc5, 0x92, 0x40, 0x42, 0x16, 0x97, 0x03, 0xca, 0xe5, 0xc4, 0xc3, 0x7b, 0x6f, 0x44, - 0xf4, 0xb1, 0xce, 0x0c, 0x55, 0x60, 0xbe, 0x65, 0xbb, 0x98, 0x58, 0x0d, 0x15, 0xa8, 0x5e, 0xe0, - 0x59, 0xea, 0xa4, 0x92, 0xbb, 0x19, 0x07, 0xe3, 0x24, 0x3e, 0xfa, 0x18, 0x94, 0x02, 0x91, 0x01, - 0x25, 0x9b, 0x6b, 0x1c, 0x65, 0x33, 0x72, 0xa2, 0xd1, 0xd8, 0xc9, 0x12, 0xac, 0x18, 0xa2, 0x0d, - 0x58, 0xf2, 0x45, 0x8e, 0x81, 0x58, 0xb2, 0x6b, 0xbe, 0x3f, 0x59, 0x32, 0x34, 0x9c, 0x02, 0xc7, - 0xa9, 0xb5, 0xa8, 0x16, 0xc3, 0xd2, 0xec, 0x70, 0x7f, 0xb6, 0xe6, 0x02, 0x66, 0x0b, 0xbe, 0x81, - 0x05, 0xf4, 0xb0, 0x87, 0x0f, 0xa5, 0x31, 0x1e, 0x3e, 0xd4, 0xe0, 0x64, 0x12, 0xc4, 0x32, 0x21, - 0xb0, 0xe4, 0x0b, 0xda, 0xe9, 0xb1, 0x95, 0x86, 0x84, 0xd3, 0xeb, 0xa2, 0x1b, 0x30, 0xe5, 0x13, - 0x66, 0x5f, 0x54, 0xe4, 0xc5, 0xf1, 0xc8, 0x21, 0x32, 0x58, 0x12, 0xc0, 0x11, 0x2d, 0x3a, 0xef, - 0x56, 0x3c, 0x51, 0xdb, 0xb5, 0x0c, 0x3f, 0xd7, 0x21, 0xe6, 0x7e, 0x40, 0x86, 0x12, 0xf3, 0xf5, - 0x39, 0x98, 0x8d, 0xf9, 0x16, 0xd0, 0xc3, 0x50, 0x64, 0xa9, 0x21, 0x98, 0x78, 0x28, 0x45, 0x22, - 0x8c, 0x0f, 0x0e, 0x87, 0xa1, 0xcf, 0x19, 0x30, 0xdf, 0x8e, 0xf9, 0x41, 0xa5, 0xe4, 0x1c, 0xf3, - 0x8e, 0x2a, 0xee, 0x5c, 0xd5, 0x52, 0x9c, 0xc6, 0x99, 0xe1, 0x24, 0x77, 0xba, 0x01, 0x45, 0xd4, - 0x98, 0x43, 0x7c, 0x86, 0x2d, 0x74, 0x1c, 0x45, 0x62, 0x35, 0x0e, 0xc6, 0x49, 0x7c, 0x3a, 0xc3, - 0xac, 0x77, 0xe3, 0xe4, 0xf1, 0xaf, 0x48, 0x02, 0x38, 0xa2, 0x85, 0x9e, 0x86, 0x39, 0x91, 0x9f, - 0x6b, 0xcb, 0x6b, 0x5c, 0xb2, 0x82, 0x3d, 0xa1, 0xdc, 0x2b, 0x63, 0x64, 0x35, 0x06, 0xc5, 0x09, - 0x6c, 0xd6, 0xb7, 0x28, 0x09, 0x1a, 0x23, 0x30, 0x11, 0xcf, 0x00, 0xbb, 0x1a, 0x07, 0xe3, 0x24, - 0x3e, 0x7a, 0x87, 0x26, 0xf7, 0xf9, 0x1d, 0x93, 0x92, 0x06, 0x29, 0xb2, 0xbf, 0x02, 0xf3, 0x1d, - 0x66, 0x0b, 0x35, 0x24, 0x50, 0xec, 0x47, 0xc5, 0xf0, 0x7a, 0x1c, 0x8c, 0x93, 0xf8, 0xe8, 0x29, - 0x98, 0xf5, 0xa9, 0x74, 0x53, 0x04, 0xf8, 0xc5, 0x93, 0xba, 0x1d, 0xc1, 0x3a, 0x10, 0xc7, 0x71, - 0xd1, 0x33, 0xb0, 0x18, 0x25, 0x0d, 0x92, 0x04, 0xf8, 0x4d, 0x94, 0xca, 0xc2, 0x51, 0x49, 0x22, - 0xe0, 0xfe, 0x3a, 0xe8, 0x97, 0x61, 0x41, 0x1b, 0x89, 0x75, 0xb7, 0x41, 0xee, 0x88, 0xc4, 0x2e, - 0xec, 0xcb, 0x45, 0xab, 0x09, 0x18, 0xee, 0xc3, 0x46, 0xef, 0x85, 0xb9, 0xba, 0xe7, 0x38, 0x4c, - 0xc6, 0xf1, 0xec, 0xa3, 0x3c, 0x83, 0x0b, 0xcf, 0x75, 0x13, 0x83, 0xe0, 0x04, 0x26, 0xba, 0x0c, - 0xc8, 0xdb, 0x09, 0x88, 0xbf, 0x4f, 0x1a, 0xcf, 0xf0, 0x2f, 0x83, 0xd1, 0x23, 0x7e, 0x36, 0x1e, - 0xb3, 0x7a, 0xb5, 0x0f, 0x03, 0xa7, 0xd4, 0x62, 0x49, 0x3c, 0xb4, 0xf7, 0x23, 0x73, 0x59, 0xe4, - 0xb4, 0x4f, 0x5a, 0xee, 0x77, 0x7d, 0x3c, 0xe2, 0xc3, 0x04, 0x0f, 0x21, 0x5e, 0x9e, 0xcf, 0x22, - 0x91, 0x91, 0x9e, 0x88, 0x30, 0x3a, 0x23, 0x78, 0x29, 0x16, 0x9c, 0xd0, 0x27, 0x60, 0x6a, 0x47, - 0x66, 0xa5, 0x5d, 0x5e, 0xc8, 0xe2, 0x5c, 0x4c, 0x24, 0x58, 0x8e, 0x2c, 0x53, 0x05, 0xc0, 0x11, - 0x4b, 0xf4, 0x08, 0x4c, 0x5f, 0xda, 0xaa, 0xa8, 0x55, 0xb8, 0xc8, 0x66, 0xbf, 0x40, 0xab, 0x60, - 0x1d, 0x40, 0x77, 0x98, 0xd2, 0x97, 0x10, 0x9b, 0xe2, 0xe8, 0xbc, 0xed, 0x57, 0x7f, 0x28, 0x36, - 0xbb, 0x10, 0xc4, 0xb5, 0xe5, 0x13, 0x09, 0x6c, 0x51, 0x8e, 0x15, 0x06, 0x7a, 0x01, 0xa6, 0xc5, - 0x79, 0xc1, 0x64, 0xd3, 0xd2, 0xd1, 0xde, 0x26, 0xe1, 0x88, 0x04, 0xd6, 0xe9, 0xa1, 0x27, 0x60, - 0xba, 0xcd, 0x92, 0x75, 0x92, 0x8b, 0x1d, 0xc7, 0x59, 0x3e, 0xc9, 0xe4, 0xa6, 0xba, 0x29, 0xd9, - 0x8a, 0x40, 0x58, 0xc7, 0x43, 0x8f, 0xc9, 0x5b, 0xff, 0xb7, 0xc4, 0x2e, 0xbe, 0xd4, 0xad, 0xbf, - 0xd2, 0x72, 0x07, 0x04, 0xa5, 0x9e, 0xba, 0xcb, 0x75, 0xfb, 0x0e, 0x9c, 0x96, 0x2a, 0x56, 0xff, - 0x26, 0x59, 0x5e, 0x8e, 0x79, 0x09, 0x4e, 0xdf, 0x18, 0x88, 0x89, 0x0f, 0xa1, 0x82, 0x76, 0x20, - 0x6f, 0x39, 0x3b, 0xcb, 0xf7, 0x67, 0xa1, 0x2b, 0xaa, 0x2f, 0xfd, 0xf1, 0x40, 0x92, 0xca, 0x46, - 0x15, 0x53, 0xe2, 0xe6, 0xcb, 0x39, 0xe5, 0x95, 0x57, 0x29, 0xee, 0x3e, 0xae, 0xaf, 0x6a, 0x23, - 0x8b, 0x2f, 0x59, 0xf5, 0xa5, 0x6e, 0xe6, 0x07, 0x52, 0xea, 0x9a, 0x6e, 0xab, 0x7d, 0x9c, 0x49, - 0xd6, 0x84, 0x78, 0xfa, 0x3e, 0x6e, 0xcd, 0xc5, 0x77, 0xb1, 0xf9, 0xc3, 0x82, 0x72, 0x42, 0x25, - 0x2e, 0xe3, 0x7d, 0x28, 0xda, 0x41, 0x68, 0x7b, 0x19, 0x3e, 0x39, 0x4a, 0xe4, 0xbd, 0x63, 0xc1, - 0x97, 0x0c, 0x80, 0x39, 0x2b, 0xca, 0xd3, 0x6d, 0xda, 0xee, 0x1d, 0xd1, 0xfd, 0x6b, 0x99, 0xdf, - 0xb2, 0x73, 0x9e, 0x0c, 0x80, 0x39, 0x2b, 0x74, 0x93, 0xaf, 0xb4, 0x6c, 0xbe, 0x5a, 0x96, 0xfc, - 0x18, 0x61, 0x7c, 0xc5, 0x51, 0x5e, 0x41, 0xcb, 0x16, 0x3a, 0xcc, 0x98, 0xbc, 0x6a, 0x9b, 0xeb, - 0x69, 0xbc, 0x6a, 0x9b, 0xeb, 0x98, 0x32, 0x41, 0xaf, 0x1a, 0x00, 0x96, 0xfa, 0x2a, 0x5f, 0x36, - 0x79, 0xce, 0x07, 0x7d, 0xe5, 0x8f, 0xc7, 0x4b, 0x45, 0x50, 0xac, 0x71, 0x36, 0xff, 0xc3, 0x00, - 0xed, 0x53, 0x46, 0x51, 0xb0, 0x8e, 0x31, 0x74, 0xb0, 0x4e, 0x6e, 0xc4, 0x60, 0x9d, 0xfc, 0x48, - 0xc1, 0x3a, 0x85, 0xd1, 0x83, 0x75, 0x8a, 0x83, 0x83, 0x75, 0xcc, 0xd7, 0x0c, 0x58, 0xec, 0x9b, - 0x9b, 0xe4, 0x27, 0x23, 0x8d, 0x21, 0x3f, 0x19, 0xb9, 0x06, 0x0b, 0x22, 0x11, 0x64, 0xad, 0xed, - 0xd8, 0xa9, 0xaf, 0x14, 0xb7, 0x13, 0x70, 0xdc, 0x57, 0xc3, 0xfc, 0x73, 0x03, 0xa6, 0xb5, 0x47, - 0x15, 0xb4, 0x1f, 0xec, 0xf1, 0x89, 0x68, 0x46, 0x94, 0x03, 0x93, 0xb9, 0x19, 0x39, 0x8c, 0x7b, - 0xbc, 0x9b, 0x5a, 0xaa, 0xb3, 0xc8, 0xe3, 0x4d, 0x4b, 0xb1, 0x80, 0xf2, 0x24, 0x56, 0x84, 0x7f, - 0x0e, 0x34, 0xaf, 0x27, 0xb1, 0x22, 0x6d, 0xcc, 0x20, 0x8c, 0x1d, 0x3d, 0xd3, 0x44, 0x1c, 0x97, - 0x96, 0x72, 0xd3, 0xa2, 0x96, 0x0b, 0x83, 0xa1, 0x33, 0x90, 0x27, 0x6e, 0x43, 0x28, 0xe0, 0xea, - 0x03, 0x0c, 0x17, 0xdc, 0x06, 0xa6, 0xe5, 0xe6, 0x55, 0x98, 0xa9, 0x91, 0xba, 0x4f, 0xc2, 0x67, - 0xc9, 0xc1, 0xd0, 0x5f, 0x74, 0xb8, 0x45, 0x0e, 0x92, 0x5f, 0x74, 0xa0, 0xd5, 0x69, 0xb9, 0xf9, - 0x07, 0x06, 0x24, 0x32, 0xa0, 0x6a, 0xde, 0x2f, 0x63, 0x90, 0xf7, 0x2b, 0xe6, 0xa7, 0xc9, 0x1d, - 0xea, 0xa7, 0xb9, 0x0c, 0xa8, 0x65, 0x85, 0xf5, 0xbd, 0x58, 0x7e, 0x5e, 0x61, 0xfb, 0x44, 0x4f, - 0xb8, 0xfa, 0x30, 0x70, 0x4a, 0x2d, 0xf3, 0x25, 0x03, 0xfa, 0xbe, 0xe6, 0x49, 0x4f, 0x6c, 0x22, - 0x92, 0xe5, 0x73, 0x93, 0x50, 0x9d, 0xd8, 0x32, 0x47, 0xbe, 0x84, 0x53, 0xbb, 0x41, 0x7a, 0x9e, - 0xa4, 0x1d, 0xcf, 0x1f, 0xbb, 0x28, 0xbb, 0x61, 0x2d, 0x0e, 0xc6, 0x49, 0x7c, 0xf3, 0x39, 0x28, - 0xc9, 0x17, 0x81, 0xec, 0x59, 0x8d, 0xb4, 0x44, 0xf5, 0x67, 0x35, 0xd4, 0x10, 0x65, 0x10, 0x3a, - 0x4c, 0x81, 0x6b, 0x5f, 0xf2, 0x82, 0x50, 0x3e, 0x63, 0xe4, 0xfe, 0xa6, 0x2b, 0xeb, 0xac, 0x0c, - 0x2b, 0xa8, 0xb9, 0x08, 0xf3, 0xca, 0x91, 0xc4, 0x17, 0xbd, 0xf9, 0xcd, 0x3c, 0xcc, 0xc4, 0xbe, - 0xd1, 0x74, 0xf7, 0xc9, 0x1e, 0x7e, 0x5a, 0x52, 0x1c, 0x42, 0xf9, 0x11, 0x1d, 0x42, 0xba, 0x07, - 0xae, 0x70, 0xbc, 0x1e, 0xb8, 0x62, 0x36, 0x1e, 0xb8, 0x10, 0x26, 0xc5, 0xf7, 0x6b, 0x45, 0x34, - 0xf0, 0x66, 0x46, 0xcf, 0xf9, 0xc5, 0xbb, 0x58, 0x16, 0x00, 0x2d, 0x05, 0x98, 0x64, 0x65, 0x7e, - 0xbd, 0x08, 0x73, 0xf1, 0x07, 0xfe, 0x43, 0xcc, 0xe4, 0x3b, 0xfa, 0x66, 0x72, 0x44, 0x83, 0x38, - 0x3f, 0xae, 0x41, 0x5c, 0x18, 0xd7, 0x20, 0x2e, 0x1e, 0xc1, 0x20, 0xee, 0x37, 0x67, 0x27, 0x86, - 0x36, 0x67, 0xdf, 0xa7, 0x6e, 0x73, 0x27, 0x63, 0xd7, 0x1f, 0xd1, 0x6d, 0x2e, 0x8a, 0x4f, 0xc3, - 0xaa, 0xd7, 0x48, 0xbd, 0x15, 0x2f, 0xdd, 0x45, 0xf1, 0xf7, 0x53, 0x2f, 0x5f, 0x47, 0xf7, 0xb9, - 0xbd, 0x65, 0x84, 0x8b, 0xd7, 0xe8, 0x13, 0xcd, 0xec, 0xf0, 0x83, 0xf8, 0xc1, 0x59, 0x8b, 0x40, - 0x58, 0xc7, 0x63, 0x1f, 0xe7, 0x89, 0x7f, 0x8d, 0x88, 0xf9, 0x17, 0xf4, 0x8f, 0xf3, 0x24, 0xbe, - 0x5e, 0x94, 0xc4, 0x37, 0xbf, 0x96, 0x87, 0xb9, 0x78, 0x72, 0x75, 0x74, 0x5b, 0xe9, 0xe7, 0x99, - 0x98, 0x06, 0x9c, 0xac, 0xf6, 0xc4, 0x7d, 0xa0, 0xb1, 0xcd, 0x3f, 0x1c, 0xbc, 0xa3, 0xde, 0xdb, - 0x1f, 0x1f, 0x63, 0x61, 0xe5, 0x0a, 0x76, 0x2c, 0x1f, 0x7b, 0x14, 0x50, 0x2a, 0x6e, 0x70, 0x33, - 0xe7, 0x1e, 0x85, 0x88, 0x2a, 0x56, 0x58, 0x63, 0x4b, 0xc5, 0xfb, 0x3e, 0xf1, 0xed, 0x5d, 0x5b, - 0x7d, 0x18, 0x86, 0x09, 0xcf, 0xe7, 0x44, 0x19, 0x56, 0x50, 0xf3, 0xa5, 0x1c, 0x44, 0x9f, 0xc1, - 0x62, 0x79, 0x9e, 0x03, 0x4d, 0x6d, 0x10, 0xd3, 0x76, 0x79, 0xdc, 0x64, 0xea, 0x11, 0x45, 0x11, - 0xec, 0xa2, 0x95, 0xe0, 0x18, 0xc7, 0x9f, 0xc2, 0xe7, 0xaf, 0x2c, 0x98, 0x4f, 0x3c, 0x14, 0xc9, - 0x3c, 0xa2, 0xf0, 0x4b, 0x79, 0x98, 0x52, 0x4f, 0x6d, 0xd0, 0x7b, 0x58, 0x8a, 0xd6, 0x3d, 0x4f, - 0x26, 0xce, 0x7d, 0xab, 0x96, 0x48, 0x75, 0xcf, 0x6b, 0xbc, 0xd1, 0x2d, 0xcf, 0x2b, 0x64, 0x5e, - 0x84, 0x45, 0x05, 0xaa, 0xa4, 0x75, 0x7c, 0x27, 0xa9, 0xa4, 0x5d, 0xc7, 0x1b, 0x98, 0x96, 0xa3, - 0x3b, 0x30, 0xb9, 0x47, 0xac, 0x06, 0xf1, 0x65, 0xec, 0xc0, 0x66, 0x46, 0xcf, 0x83, 0x2e, 0x31, - 0xaa, 0xd1, 0x30, 0xf0, 0xff, 0x01, 0x96, 0xec, 0xe8, 0x41, 0xb5, 0xe3, 0x35, 0x0e, 0x92, 0x89, - 0x57, 0xab, 0x5e, 0xe3, 0x00, 0x33, 0x08, 0x7a, 0x1a, 0xe6, 0x42, 0xbb, 0x45, 0xbc, 0x4e, 0xa8, - 0x7f, 0x64, 0x28, 0x1f, 0x39, 0x8f, 0xb7, 0x63, 0x50, 0x9c, 0xc0, 0xa6, 0x07, 0xdd, 0xcd, 0xc0, - 0x73, 0x59, 0x36, 0x95, 0x89, 0xb8, 0xa7, 0xe9, 0x72, 0xed, 0xea, 0x15, 0x96, 0x4c, 0x45, 0x61, - 0x50, 0x6c, 0x9b, 0xc5, 0xf3, 0xfb, 0x44, 0xdc, 0xdd, 0x2c, 0x44, 0xaf, 0x2e, 0x79, 0x39, 0x56, - 0x18, 0xe6, 0x75, 0x98, 0x4f, 0x74, 0x55, 0xaa, 0xc3, 0x46, 0xba, 0x3a, 0x3c, 0x5c, 0x96, 0xd3, - 0x3f, 0x31, 0x60, 0xb1, 0x6f, 0xf3, 0x0e, 0x1b, 0xea, 0x9a, 0x94, 0xe4, 0xb9, 0xa3, 0x4b, 0xf2, - 0xfc, 0x68, 0x92, 0xbc, 0xba, 0xf2, 0xad, 0xd7, 0xcf, 0xde, 0xf7, 0xed, 0xd7, 0xcf, 0xde, 0xf7, - 0xdd, 0xd7, 0xcf, 0xde, 0xf7, 0x52, 0xef, 0xac, 0xf1, 0xad, 0xde, 0x59, 0xe3, 0xdb, 0xbd, 0xb3, - 0xc6, 0x77, 0x7b, 0x67, 0x8d, 0x1f, 0xf6, 0xce, 0x1a, 0xaf, 0xfd, 0xe8, 0xec, 0x7d, 0xcf, 0x97, - 0xe4, 0x32, 0xf9, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xde, 0xbc, 0xf3, 0x4f, 0xf7, 0x83, 0x00, - 0x00, + // 6885 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x5d, 0x8c, 0x24, 0x57, + 0x75, 0xb0, 0xab, 0x7f, 0x66, 0x7a, 0xce, 0xfc, 0xdf, 0x9d, 0x65, 0xc7, 0x6b, 0xef, 0xb6, 0x29, + 0x23, 0x7f, 0xe6, 0xfb, 0x60, 0x16, 0xd6, 0xf6, 0xf7, 0x19, 0x8c, 0xac, 0xaf, 0x7b, 0x66, 0xd7, + 0x3b, 0xeb, 0x99, 0xdd, 0xd9, 0xdb, 0xb3, 0x5e, 0x30, 0x98, 0x50, 0xd3, 0x7d, 0xa7, 0xa7, 0x76, + 0xab, 0xab, 0x9a, 0xaa, 0xea, 0xd9, 0x1d, 0x83, 0xc0, 0x0e, 0xb2, 0x43, 0x22, 0x10, 0x4e, 0x80, + 0x87, 0x28, 0x22, 0x42, 0x11, 0x0f, 0x51, 0xc8, 0x43, 0x84, 0x12, 0xe5, 0x05, 0x29, 0x51, 0x02, + 0x0a, 0x79, 0x48, 0x44, 0xa4, 0x24, 0x40, 0x04, 0x1d, 0xdc, 0xe4, 0x25, 0x51, 0xa4, 0x28, 0x12, + 0x51, 0xc4, 0x3e, 0x45, 0xf7, 0xb7, 0x6e, 0x55, 0x57, 0xcf, 0x76, 0x4f, 0xd7, 0x2c, 0x56, 0xc2, + 0x5b, 0xf7, 0x3d, 0xe7, 0x9e, 0x73, 0x7f, 0xcf, 0x3d, 0xe7, 0xdc, 0x73, 0x4f, 0xc1, 0x46, 0xd3, + 0x0e, 0xf7, 0x3a, 0x3b, 0x2b, 0x75, 0xaf, 0x75, 0xce, 0xf2, 0x9b, 0x5e, 0xdb, 0xf7, 0x6e, 0xb2, + 0x1f, 0xef, 0xf6, 0x3d, 0xc7, 0xf1, 0x3a, 0x61, 0x70, 0xae, 0x7d, 0xab, 0x79, 0xce, 0x6a, 0xdb, + 0xc1, 0x39, 0x55, 0xb2, 0xff, 0x5e, 0xcb, 0x69, 0xef, 0x59, 0xef, 0x3d, 0xd7, 0x24, 0x2e, 0xf1, + 0xad, 0x90, 0x34, 0x56, 0xda, 0xbe, 0x17, 0x7a, 0xe8, 0x03, 0x11, 0xb5, 0x15, 0x49, 0x8d, 0xfd, + 0xf8, 0x25, 0x59, 0x77, 0xa5, 0x7d, 0xab, 0xb9, 0x42, 0xa9, 0xad, 0xa8, 0x12, 0x49, 0xed, 0xf4, + 0xbb, 0xb5, 0xb6, 0x34, 0xbd, 0xa6, 0x77, 0x8e, 0x11, 0xdd, 0xe9, 0xec, 0xb2, 0x7f, 0xec, 0x0f, + 0xfb, 0xc5, 0x99, 0x9d, 0x7e, 0xf4, 0xd6, 0xd3, 0xc1, 0x8a, 0xed, 0xd1, 0xb6, 0x9d, 0xdb, 0xb1, + 0xc2, 0xfa, 0xde, 0xb9, 0xfd, 0xbe, 0x16, 0x9d, 0x36, 0x35, 0xa4, 0xba, 0xe7, 0x93, 0x34, 0x9c, + 0x27, 0x23, 0x9c, 0x96, 0x55, 0xdf, 0xb3, 0x5d, 0xe2, 0x1f, 0x44, 0xbd, 0x6e, 0x91, 0xd0, 0x4a, + 0xab, 0x75, 0x6e, 0x50, 0x2d, 0xbf, 0xe3, 0x86, 0x76, 0x8b, 0xf4, 0x55, 0xf8, 0xbf, 0xf7, 0xaa, + 0x10, 0xd4, 0xf7, 0x48, 0xcb, 0xea, 0xab, 0xf7, 0xc4, 0xa0, 0x7a, 0x9d, 0xd0, 0x76, 0xce, 0xd9, + 0x6e, 0x18, 0x84, 0x7e, 0xb2, 0x92, 0xf9, 0xad, 0x3c, 0x4c, 0x55, 0x36, 0xaa, 0xb5, 0xd0, 0x0a, + 0x3b, 0x01, 0x7a, 0xdd, 0x80, 0x19, 0xc7, 0xb3, 0x1a, 0x55, 0xcb, 0xb1, 0xdc, 0x3a, 0xf1, 0x97, + 0x8d, 0x47, 0x8c, 0xc7, 0xa7, 0xcf, 0x6f, 0xac, 0x8c, 0x33, 0x5f, 0x2b, 0x95, 0xdb, 0x01, 0x26, + 0x81, 0xd7, 0xf1, 0xeb, 0x04, 0x93, 0xdd, 0xea, 0xd2, 0x77, 0xba, 0xe5, 0x07, 0x7a, 0xdd, 0xf2, + 0xcc, 0x86, 0xc6, 0x09, 0xc7, 0xf8, 0xa2, 0x2f, 0x1b, 0xb0, 0x58, 0xb7, 0x5c, 0xcb, 0x3f, 0xd8, + 0xb6, 0xfc, 0x26, 0x09, 0x9f, 0xf3, 0xbd, 0x4e, 0x7b, 0x39, 0x77, 0x0c, 0xad, 0x79, 0x50, 0xb4, + 0x66, 0x71, 0x35, 0xc9, 0x0e, 0xf7, 0xb7, 0x80, 0xb5, 0x2b, 0x08, 0xad, 0x1d, 0x87, 0xe8, 0xed, + 0xca, 0x1f, 0x67, 0xbb, 0x6a, 0x49, 0x76, 0xb8, 0xbf, 0x05, 0xe6, 0x6b, 0x79, 0x58, 0xac, 0x6c, + 0x54, 0xb7, 0x7d, 0x6b, 0x77, 0xd7, 0xae, 0x63, 0xaf, 0x13, 0xda, 0x6e, 0x13, 0xbd, 0x13, 0x26, + 0x6d, 0xb7, 0xe9, 0x93, 0x20, 0x60, 0x13, 0x39, 0x55, 0x9d, 0x17, 0x44, 0x27, 0xd7, 0x79, 0x31, + 0x96, 0x70, 0xf4, 0x14, 0x4c, 0x07, 0xc4, 0xdf, 0xb7, 0xeb, 0x64, 0xcb, 0xf3, 0x43, 0x36, 0xd2, + 0xc5, 0xea, 0x09, 0x81, 0x3e, 0x5d, 0x8b, 0x40, 0x58, 0xc7, 0xa3, 0xd5, 0x7c, 0xcf, 0x0b, 0x05, + 0x9c, 0x0d, 0xc4, 0x54, 0x54, 0x0d, 0x47, 0x20, 0xac, 0xe3, 0xa1, 0x37, 0x0c, 0x58, 0x08, 0x42, + 0xbb, 0x7e, 0xcb, 0x76, 0x49, 0x10, 0xac, 0x7a, 0xee, 0xae, 0xdd, 0x5c, 0x2e, 0xb2, 0x51, 0xbc, + 0x32, 0xde, 0x28, 0xd6, 0x12, 0x54, 0xab, 0x4b, 0xbd, 0x6e, 0x79, 0x21, 0x59, 0x8a, 0xfb, 0xb8, + 0xa3, 0x35, 0x58, 0xb0, 0x5c, 0xd7, 0x0b, 0xad, 0xd0, 0xf6, 0xdc, 0x2d, 0x9f, 0xec, 0xda, 0x77, + 0x96, 0x0b, 0xac, 0x3b, 0xcb, 0xa2, 0x3b, 0x0b, 0x95, 0x04, 0x1c, 0xf7, 0xd5, 0x30, 0xd7, 0x60, + 0xb9, 0xd2, 0xda, 0xb1, 0x82, 0xc0, 0x6a, 0x78, 0x7e, 0x62, 0x36, 0x1e, 0x87, 0x52, 0xcb, 0x6a, + 0xb7, 0x6d, 0xb7, 0x49, 0xa7, 0x23, 0xff, 0xf8, 0x54, 0x75, 0xa6, 0xd7, 0x2d, 0x97, 0x36, 0x45, + 0x19, 0x56, 0x50, 0xf3, 0x07, 0x39, 0x98, 0xae, 0xb8, 0x96, 0x73, 0x10, 0xd8, 0x01, 0xee, 0xb8, + 0xe8, 0x63, 0x50, 0xa2, 0xd2, 0xa5, 0x61, 0x85, 0x96, 0xd8, 0x91, 0xef, 0x59, 0xe1, 0x9b, 0x7d, + 0x45, 0xdf, 0xec, 0xd1, 0xb8, 0x50, 0xec, 0x95, 0xfd, 0xf7, 0xae, 0x5c, 0xdd, 0xb9, 0x49, 0xea, + 0xe1, 0x26, 0x09, 0xad, 0x2a, 0x12, 0xbd, 0x80, 0xa8, 0x0c, 0x2b, 0xaa, 0xc8, 0x83, 0x42, 0xd0, + 0x26, 0x75, 0xb1, 0xc3, 0x36, 0xc7, 0x5c, 0xc9, 0x51, 0xd3, 0x6b, 0x6d, 0x52, 0xaf, 0xce, 0x08, + 0xd6, 0x05, 0xfa, 0x0f, 0x33, 0x46, 0xe8, 0x36, 0x4c, 0x04, 0x4c, 0xe6, 0x88, 0xcd, 0x73, 0x35, + 0x3b, 0x96, 0x8c, 0x6c, 0x75, 0x4e, 0x30, 0x9d, 0xe0, 0xff, 0xb1, 0x60, 0x67, 0xfe, 0x83, 0x01, + 0x27, 0x34, 0xec, 0x8a, 0xdf, 0xec, 0xb4, 0x88, 0x1b, 0xa2, 0x47, 0xa0, 0xe0, 0x5a, 0x2d, 0x22, + 0x36, 0x8a, 0x6a, 0xf2, 0x15, 0xab, 0x45, 0x30, 0x83, 0xa0, 0x47, 0xa1, 0xb8, 0x6f, 0x39, 0x1d, + 0xc2, 0x06, 0x69, 0xaa, 0x3a, 0x2b, 0x50, 0x8a, 0x2f, 0xd0, 0x42, 0xcc, 0x61, 0xe8, 0x93, 0x30, + 0xc5, 0x7e, 0x5c, 0xf4, 0xbd, 0x56, 0x46, 0x5d, 0x13, 0x2d, 0x7c, 0x41, 0x92, 0xad, 0xce, 0xf6, + 0xba, 0xe5, 0x29, 0xf5, 0x17, 0x47, 0x0c, 0xcd, 0x7f, 0x34, 0x60, 0x5e, 0xeb, 0xdc, 0x86, 0x1d, + 0x84, 0xe8, 0x23, 0x7d, 0x8b, 0x67, 0x65, 0xb8, 0xc5, 0x43, 0x6b, 0xb3, 0xa5, 0xb3, 0x20, 0x7a, + 0x5a, 0x92, 0x25, 0xda, 0xc2, 0x71, 0xa1, 0x68, 0x87, 0xa4, 0x15, 0x2c, 0xe7, 0x1e, 0xc9, 0x3f, + 0x3e, 0x7d, 0x7e, 0x3d, 0xb3, 0x69, 0x8c, 0xc6, 0x77, 0x9d, 0xd2, 0xc7, 0x9c, 0x8d, 0xf9, 0x8d, + 0x42, 0xac, 0x87, 0x74, 0x45, 0x21, 0x0f, 0x26, 0x5b, 0x24, 0xf4, 0xed, 0x3a, 0xdf, 0x57, 0xd3, + 0xe7, 0xd7, 0xc6, 0x6b, 0xc5, 0x26, 0x23, 0x16, 0x09, 0x4b, 0xfe, 0x3f, 0xc0, 0x92, 0x0b, 0xda, + 0x83, 0x82, 0xe5, 0x37, 0x65, 0x9f, 0x2f, 0x66, 0x33, 0xbf, 0xd1, 0x9a, 0xab, 0xf8, 0xcd, 0x00, + 0x33, 0x0e, 0xe8, 0x1c, 0x4c, 0x85, 0xc4, 0x6f, 0xd9, 0xae, 0x15, 0x72, 0xe9, 0x5a, 0xaa, 0x2e, + 0x0a, 0xb4, 0xa9, 0x6d, 0x09, 0xc0, 0x11, 0x0e, 0x72, 0x60, 0xa2, 0xe1, 0x1f, 0xe0, 0x8e, 0xbb, + 0x5c, 0xc8, 0x62, 0x28, 0xd6, 0x18, 0xad, 0x68, 0x33, 0xf1, 0xff, 0x58, 0xf0, 0x40, 0x5f, 0x33, + 0x60, 0xa9, 0x45, 0xac, 0xa0, 0xe3, 0x13, 0xda, 0x05, 0x4c, 0x42, 0xe2, 0x52, 0x69, 0xb8, 0x5c, + 0x64, 0xcc, 0xf1, 0xb8, 0xf3, 0xd0, 0x4f, 0xb9, 0xfa, 0xb0, 0x68, 0xca, 0x52, 0x1a, 0x14, 0xa7, + 0xb6, 0xc6, 0xfc, 0x41, 0x01, 0x16, 0xfb, 0x24, 0x04, 0x7a, 0x12, 0x8a, 0xed, 0x3d, 0x2b, 0x90, + 0x5b, 0xfe, 0xac, 0x5c, 0x6f, 0x5b, 0xb4, 0xf0, 0x6e, 0xb7, 0x3c, 0x2b, 0xab, 0xb0, 0x02, 0xcc, + 0x91, 0xe9, 0x99, 0xda, 0x22, 0x41, 0x60, 0x35, 0xa5, 0x1c, 0xd0, 0x96, 0x09, 0x2b, 0xc6, 0x12, + 0x8e, 0x7e, 0xc5, 0x80, 0x59, 0xbe, 0x64, 0x30, 0x09, 0x3a, 0x4e, 0x48, 0x65, 0x1d, 0x1d, 0x96, + 0xcb, 0x59, 0x2c, 0x4f, 0x4e, 0xb2, 0x7a, 0x52, 0x70, 0x9f, 0xd5, 0x4b, 0x03, 0x1c, 0xe7, 0x8b, + 0x6e, 0xc0, 0x54, 0x10, 0x5a, 0x7e, 0x48, 0x1a, 0x95, 0x90, 0x9d, 0x6a, 0xd3, 0xe7, 0xff, 0xf7, + 0x70, 0x42, 0x60, 0xdb, 0x6e, 0x11, 0x2e, 0x70, 0x6a, 0x92, 0x00, 0x8e, 0x68, 0xa1, 0x4f, 0x02, + 0xf8, 0x1d, 0xb7, 0xd6, 0x69, 0xb5, 0x2c, 0xff, 0x40, 0x9c, 0xe0, 0x97, 0xc6, 0xeb, 0x1e, 0x56, + 0xf4, 0xa2, 0x33, 0x2b, 0x2a, 0xc3, 0x1a, 0x3f, 0xf4, 0xaa, 0x01, 0xb3, 0x7c, 0x25, 0xca, 0x16, + 0x4c, 0x64, 0xdc, 0x82, 0x45, 0x3a, 0xb4, 0x6b, 0x3a, 0x0b, 0x1c, 0xe7, 0x68, 0xfe, 0x5d, 0xfc, + 0x3c, 0xa9, 0x85, 0x54, 0xbb, 0x6e, 0x1e, 0xa0, 0x0f, 0xc3, 0x83, 0x41, 0xa7, 0x5e, 0x27, 0x41, + 0xb0, 0xdb, 0x71, 0x70, 0xc7, 0xbd, 0x64, 0x07, 0xa1, 0xe7, 0x1f, 0x6c, 0xd8, 0x2d, 0x3b, 0x64, + 0x2b, 0xae, 0x58, 0x3d, 0xd3, 0xeb, 0x96, 0x1f, 0xac, 0x0d, 0x42, 0xc2, 0x83, 0xeb, 0x23, 0x0b, + 0x1e, 0xea, 0xb8, 0x83, 0xc9, 0x73, 0xed, 0xad, 0xdc, 0xeb, 0x96, 0x1f, 0xba, 0x3e, 0x18, 0x0d, + 0x1f, 0x46, 0xc3, 0xfc, 0x17, 0x03, 0x16, 0x64, 0xbf, 0xb6, 0x49, 0xab, 0xed, 0x50, 0xe9, 0x72, + 0xfc, 0x8a, 0x48, 0x18, 0x53, 0x44, 0x70, 0x36, 0xc7, 0x89, 0x6c, 0xff, 0x20, 0x6d, 0xc4, 0xfc, + 0x67, 0x03, 0x96, 0x92, 0xc8, 0xf7, 0xe1, 0xf0, 0x0c, 0xe2, 0x87, 0xe7, 0x95, 0x6c, 0x7b, 0x3b, + 0xe0, 0x04, 0x7d, 0xbd, 0xd0, 0xdf, 0xd7, 0xff, 0xee, 0xc7, 0x68, 0x74, 0x2a, 0xe6, 0x7f, 0x9e, + 0xa7, 0x62, 0xe1, 0x2d, 0x75, 0x2a, 0xfe, 0x6e, 0x01, 0x66, 0x2a, 0x6e, 0x68, 0x57, 0x76, 0x77, + 0x6d, 0xd7, 0x0e, 0x0f, 0xd0, 0xe7, 0x72, 0x70, 0xae, 0xed, 0x93, 0x5d, 0xe2, 0xfb, 0xa4, 0xb1, + 0xd6, 0xf1, 0x6d, 0xb7, 0x59, 0xab, 0xef, 0x91, 0x46, 0xc7, 0xb1, 0xdd, 0xe6, 0x7a, 0xd3, 0xf5, + 0x54, 0xf1, 0x85, 0x3b, 0xa4, 0xde, 0x61, 0x5d, 0xe2, 0x9b, 0xa2, 0x35, 0x5e, 0x97, 0xb6, 0x46, + 0x63, 0x5a, 0x7d, 0xa2, 0xd7, 0x2d, 0x9f, 0x1b, 0xb1, 0x12, 0x1e, 0xb5, 0x6b, 0xe8, 0xb3, 0x39, + 0x58, 0xf1, 0xc9, 0xc7, 0x3b, 0xf6, 0xf0, 0xa3, 0xc1, 0xa5, 0x96, 0x33, 0xe6, 0xf1, 0x33, 0x12, + 0xcf, 0xea, 0xf9, 0x5e, 0xb7, 0x3c, 0x62, 0x1d, 0x3c, 0x62, 0xbf, 0xcc, 0x3f, 0x37, 0xa0, 0x34, + 0x82, 0xa5, 0x54, 0x8e, 0x5b, 0x4a, 0x53, 0x7d, 0x56, 0x52, 0xd8, 0x6f, 0x25, 0x3d, 0x37, 0xde, + 0xa0, 0x0d, 0x63, 0x1d, 0xfd, 0x9b, 0x01, 0x8b, 0x7d, 0xd6, 0x14, 0xda, 0x83, 0xa5, 0xb6, 0xd7, + 0x90, 0x92, 0xf0, 0x92, 0x15, 0xec, 0x31, 0x98, 0xe8, 0xde, 0x93, 0x74, 0x53, 0x6d, 0xa5, 0xc0, + 0xef, 0x76, 0xcb, 0xcb, 0x8a, 0x48, 0x02, 0x01, 0xa7, 0x52, 0x44, 0x6d, 0x28, 0xed, 0xda, 0xc4, + 0x69, 0x60, 0xb2, 0x2b, 0x56, 0xca, 0x98, 0x32, 0xef, 0xa2, 0xa0, 0xc6, 0x1d, 0x09, 0xf2, 0x1f, + 0x56, 0x5c, 0xcc, 0x6b, 0x30, 0x17, 0x77, 0x2b, 0x0d, 0x31, 0x79, 0x67, 0x20, 0x6f, 0xf9, 0xae, + 0x98, 0xba, 0x69, 0x81, 0x90, 0xaf, 0xe0, 0x2b, 0x98, 0x96, 0x9b, 0x3f, 0x2b, 0xc0, 0x7c, 0xd5, + 0xe9, 0x90, 0xe7, 0x7c, 0x42, 0xa4, 0x26, 0x5d, 0x81, 0xf9, 0xb6, 0x4f, 0xf6, 0x6d, 0x72, 0xbb, + 0x46, 0x1c, 0x52, 0x0f, 0x3d, 0x5f, 0xd0, 0x3f, 0x25, 0xaa, 0xcf, 0x6f, 0xc5, 0xc1, 0x38, 0x89, + 0x8f, 0x9e, 0x85, 0x39, 0xab, 0x1e, 0xda, 0xfb, 0x44, 0x51, 0xe0, 0x0d, 0x78, 0x9b, 0xa0, 0x30, + 0x57, 0x89, 0x41, 0x71, 0x02, 0x1b, 0x7d, 0x04, 0x96, 0x83, 0xba, 0xe5, 0x90, 0xeb, 0x6d, 0xc1, + 0x6a, 0x75, 0x8f, 0xd4, 0x6f, 0x6d, 0x79, 0xb6, 0x1b, 0x0a, 0xbb, 0xe9, 0x11, 0x41, 0x69, 0xb9, + 0x36, 0x00, 0x0f, 0x0f, 0xa4, 0x80, 0xfe, 0xc4, 0x80, 0x33, 0x6d, 0x9f, 0x6c, 0xf9, 0x5e, 0xcb, + 0xa3, 0x1b, 0xa2, 0xcf, 0x98, 0x10, 0x4a, 0xf5, 0x0b, 0x63, 0xee, 0x7c, 0x5e, 0xd2, 0xef, 0xcc, + 0x78, 0x7b, 0xaf, 0x5b, 0x3e, 0xb3, 0x75, 0x58, 0x03, 0xf0, 0xe1, 0xed, 0x43, 0x7f, 0x66, 0xc0, + 0xd9, 0xb6, 0x17, 0x84, 0x87, 0x74, 0xa1, 0x78, 0xac, 0x5d, 0x30, 0x7b, 0xdd, 0xf2, 0xd9, 0xad, + 0x43, 0x5b, 0x80, 0xef, 0xd1, 0x42, 0xb3, 0x37, 0x0d, 0x8b, 0xda, 0xda, 0x13, 0x9a, 0xf6, 0x33, + 0x30, 0x2b, 0x17, 0x03, 0xf7, 0x42, 0xf2, 0xb5, 0xa7, 0x2c, 0xa3, 0x8a, 0x0e, 0xc4, 0x71, 0x5c, + 0xba, 0xee, 0xd4, 0x52, 0xe4, 0xb5, 0x13, 0xeb, 0x6e, 0x2b, 0x06, 0xc5, 0x09, 0x6c, 0xb4, 0x0e, + 0x27, 0x44, 0x09, 0x26, 0x6d, 0xc7, 0xae, 0x5b, 0xab, 0x5e, 0x47, 0x2c, 0xb9, 0x62, 0xf5, 0x54, + 0xaf, 0x5b, 0x3e, 0xb1, 0xd5, 0x0f, 0xc6, 0x69, 0x75, 0xd0, 0x06, 0x2c, 0x59, 0x9d, 0xd0, 0x53, + 0xfd, 0xbf, 0xe0, 0x5a, 0x3b, 0x0e, 0x69, 0xb0, 0xa5, 0x55, 0xaa, 0x2e, 0x53, 0x41, 0x54, 0x49, + 0x81, 0xe3, 0xd4, 0x5a, 0x68, 0x2b, 0x41, 0xad, 0x46, 0xea, 0x9e, 0xdb, 0xe0, 0xb3, 0x5c, 0x8c, + 0xf4, 0x85, 0x4a, 0x0a, 0x0e, 0x4e, 0xad, 0x89, 0x1c, 0x98, 0x6b, 0x59, 0x77, 0xae, 0xbb, 0xd6, + 0xbe, 0x65, 0x3b, 0x94, 0x89, 0xb0, 0xb6, 0x06, 0x9b, 0x00, 0x9d, 0xd0, 0x76, 0x56, 0xf8, 0xc5, + 0xc3, 0xca, 0xba, 0x1b, 0x5e, 0xf5, 0x6b, 0x21, 0x3d, 0x57, 0xaa, 0x88, 0x0e, 0xec, 0x66, 0x8c, + 0x16, 0x4e, 0xd0, 0x46, 0x57, 0xe1, 0x24, 0xdb, 0x8e, 0x6b, 0xde, 0x6d, 0x77, 0x8d, 0x38, 0xd6, + 0x81, 0xec, 0xc0, 0x24, 0xeb, 0xc0, 0x83, 0xbd, 0x6e, 0xf9, 0x64, 0x2d, 0x0d, 0x01, 0xa7, 0xd7, + 0xa3, 0x36, 0x53, 0x1c, 0x80, 0xc9, 0xbe, 0x1d, 0xd8, 0x9e, 0xcb, 0x6d, 0xa6, 0x52, 0x64, 0x33, + 0xd5, 0x06, 0xa3, 0xe1, 0xc3, 0x68, 0xa0, 0xdf, 0x32, 0x60, 0x29, 0x6d, 0x1b, 0x2e, 0x4f, 0x65, + 0xe1, 0x56, 0x4d, 0x6c, 0x2d, 0xbe, 0x22, 0x52, 0x85, 0x42, 0x6a, 0x23, 0xd0, 0x2b, 0x06, 0xcc, + 0x58, 0x9a, 0xbe, 0xb7, 0x0c, 0xac, 0x55, 0x97, 0xc7, 0xb5, 0x3a, 0x22, 0x8a, 0xd5, 0x85, 0x5e, + 0xb7, 0x1c, 0xd3, 0x29, 0x71, 0x8c, 0x23, 0xfa, 0x6d, 0x03, 0x4e, 0xa6, 0xee, 0xf1, 0xe5, 0xe9, + 0xe3, 0x18, 0x21, 0xb6, 0x48, 0xd2, 0x65, 0x4e, 0x7a, 0x33, 0xd0, 0x1b, 0x86, 0x3a, 0xca, 0x36, + 0xa5, 0xdd, 0x37, 0xc3, 0x9a, 0x76, 0x6d, 0x4c, 0x15, 0x37, 0x52, 0x08, 0x24, 0xe1, 0xea, 0x09, + 0xed, 0x64, 0x94, 0x85, 0x38, 0xc9, 0x1e, 0x7d, 0xde, 0x90, 0x47, 0xa3, 0x6a, 0xd1, 0xec, 0x71, + 0xb5, 0x08, 0x45, 0x27, 0xad, 0x6a, 0x50, 0x82, 0x39, 0xfa, 0x28, 0x9c, 0xb6, 0x76, 0x3c, 0x3f, + 0x4c, 0xdd, 0x7c, 0xcb, 0x73, 0x6c, 0x1b, 0x9d, 0xed, 0x75, 0xcb, 0xa7, 0x2b, 0x03, 0xb1, 0xf0, + 0x21, 0x14, 0xcc, 0x1f, 0x16, 0x60, 0x86, 0xdf, 0xc5, 0x89, 0xa3, 0xeb, 0x9b, 0x06, 0x3c, 0x5c, + 0xef, 0xf8, 0x3e, 0x71, 0xc3, 0x5a, 0x48, 0xda, 0xfd, 0x07, 0x97, 0x71, 0xac, 0x07, 0xd7, 0x23, + 0xbd, 0x6e, 0xf9, 0xe1, 0xd5, 0x43, 0xf8, 0xe3, 0x43, 0x5b, 0x87, 0xfe, 0xda, 0x00, 0x53, 0x20, + 0x54, 0xad, 0xfa, 0xad, 0xa6, 0xef, 0x75, 0xdc, 0x46, 0x7f, 0x27, 0x72, 0xc7, 0xda, 0x89, 0xc7, + 0x7a, 0xdd, 0xb2, 0xb9, 0x7a, 0xcf, 0x56, 0xe0, 0x21, 0x5a, 0x8a, 0x9e, 0x83, 0x45, 0x81, 0x75, + 0xe1, 0x4e, 0x9b, 0xf8, 0x36, 0x55, 0xa7, 0xc5, 0xcd, 0x5f, 0x74, 0x99, 0x9a, 0x44, 0xc0, 0xfd, + 0x75, 0x50, 0x00, 0x93, 0xb7, 0x89, 0xdd, 0xdc, 0x0b, 0xa5, 0xfa, 0x34, 0xe6, 0x0d, 0xaa, 0xb8, + 0x6f, 0xbb, 0xc1, 0x69, 0x56, 0xa7, 0x7b, 0xdd, 0xf2, 0xa4, 0xf8, 0x83, 0x25, 0x27, 0xf3, 0x0f, + 0x0a, 0x00, 0x72, 0x79, 0x91, 0x36, 0xfa, 0x3f, 0x30, 0x15, 0x90, 0x90, 0x63, 0x09, 0xb7, 0x1c, + 0xf7, 0x76, 0xca, 0x42, 0x1c, 0xc1, 0xd1, 0x2d, 0x28, 0xb6, 0xad, 0x4e, 0x40, 0xc4, 0x64, 0x5d, + 0xce, 0x64, 0xb2, 0xb6, 0x28, 0x45, 0x6e, 0x23, 0xb1, 0x9f, 0x98, 0xf3, 0x40, 0x9f, 0x31, 0x00, + 0x48, 0x7c, 0x80, 0xa7, 0xcf, 0xd7, 0x32, 0x61, 0x19, 0xcd, 0x01, 0x1d, 0x83, 0xea, 0x5c, 0xaf, + 0x5b, 0x06, 0x6d, 0xaa, 0x34, 0xb6, 0xe8, 0x36, 0x94, 0x2c, 0x29, 0xa3, 0x0b, 0xc7, 0x21, 0xa3, + 0x99, 0xe9, 0xa2, 0x16, 0x99, 0x62, 0x86, 0x3e, 0x6b, 0xc0, 0x5c, 0x40, 0x42, 0x31, 0x55, 0x54, + 0x52, 0x08, 0x05, 0x75, 0xcc, 0x45, 0x52, 0x8b, 0xd1, 0xe4, 0x12, 0x2f, 0x5e, 0x86, 0x13, 0x7c, + 0xcd, 0x1f, 0x4e, 0xc3, 0x9c, 0x5c, 0x32, 0x91, 0xce, 0xc9, 0x83, 0x03, 0x06, 0xe8, 0x9c, 0xab, + 0x3a, 0x10, 0xc7, 0x71, 0x69, 0x65, 0x7e, 0x83, 0x1f, 0x57, 0x39, 0x55, 0xe5, 0x9a, 0x0e, 0xc4, + 0x71, 0x5c, 0xd4, 0x82, 0x62, 0x10, 0x92, 0xb6, 0xbc, 0x4b, 0x18, 0xd3, 0xd5, 0x1d, 0xed, 0x84, + 0xc8, 0x5b, 0x48, 0xff, 0x05, 0x98, 0x73, 0x41, 0x5f, 0x30, 0x60, 0x2e, 0x8c, 0xdd, 0x63, 0x8b, + 0x65, 0x90, 0xcd, 0x4a, 0x8c, 0x5f, 0x91, 0xf3, 0xd9, 0x88, 0x97, 0xe1, 0x04, 0xfb, 0x14, 0x35, + 0xb4, 0x78, 0x8c, 0x6a, 0xe8, 0x8b, 0x50, 0x6a, 0x59, 0x77, 0x6a, 0x1d, 0xbf, 0x79, 0x74, 0x75, + 0x57, 0x5c, 0xf3, 0x73, 0x2a, 0x58, 0xd1, 0x43, 0xaf, 0x1a, 0xda, 0xe6, 0x9a, 0x64, 0xc4, 0x6f, + 0x64, 0xbb, 0xb9, 0x94, 0x14, 0x1f, 0xb8, 0xcd, 0xfa, 0x94, 0xc2, 0xd2, 0x7d, 0x57, 0x0a, 0xa9, + 0x82, 0xc3, 0x37, 0x88, 0x52, 0x70, 0xa6, 0x8e, 0x55, 0xc1, 0x59, 0x8d, 0x31, 0xc3, 0x09, 0xe6, + 0xac, 0x3d, 0x7c, 0xcf, 0xa9, 0xf6, 0xc0, 0xb1, 0xb6, 0xa7, 0x16, 0x63, 0x86, 0x13, 0xcc, 0x07, + 0x5b, 0x42, 0xd3, 0xc7, 0x63, 0x09, 0xcd, 0x64, 0x60, 0x09, 0x1d, 0xae, 0x24, 0xce, 0x8e, 0xab, + 0x24, 0xa2, 0xcb, 0x80, 0x1a, 0x07, 0xae, 0xd5, 0xb2, 0xeb, 0x42, 0x58, 0xb2, 0x03, 0x62, 0x8e, + 0x59, 0xca, 0xa7, 0x85, 0x20, 0x43, 0x6b, 0x7d, 0x18, 0x38, 0xa5, 0x96, 0xf9, 0x1f, 0x06, 0x2c, + 0xac, 0x3a, 0x5e, 0xa7, 0x71, 0xc3, 0x0a, 0xeb, 0x7b, 0xfc, 0x96, 0x02, 0x3d, 0x0b, 0x25, 0xdb, + 0x0d, 0x89, 0xbf, 0x6f, 0x39, 0x42, 0xb6, 0x9b, 0xf2, 0x22, 0x67, 0x5d, 0x94, 0xdf, 0xed, 0x96, + 0xe7, 0xd6, 0x3a, 0x3e, 0x0b, 0xff, 0xe1, 0x3b, 0x1d, 0xab, 0x3a, 0xe8, 0xab, 0x06, 0x2c, 0xf2, + 0x7b, 0x8e, 0x35, 0x2b, 0xb4, 0xae, 0x75, 0x88, 0x6f, 0x13, 0x79, 0xd3, 0x31, 0xe6, 0x26, 0x4f, + 0xb6, 0x55, 0x32, 0x38, 0x88, 0xd4, 0xaf, 0xcd, 0x24, 0x67, 0xdc, 0xdf, 0x18, 0xf3, 0x8b, 0x79, + 0x78, 0x70, 0x20, 0x2d, 0x74, 0x1a, 0x72, 0x76, 0x43, 0x74, 0x1d, 0x04, 0xdd, 0xdc, 0x7a, 0x03, + 0xe7, 0xec, 0x06, 0x5a, 0x61, 0x9a, 0x89, 0x4f, 0x82, 0x40, 0x3a, 0xbd, 0xa7, 0x94, 0x12, 0x21, + 0x4a, 0xb1, 0x86, 0x81, 0xca, 0x50, 0x74, 0xac, 0x1d, 0xe2, 0x08, 0x2d, 0x91, 0xe9, 0x3a, 0x1b, + 0xb4, 0x00, 0xf3, 0x72, 0xf4, 0xcb, 0x06, 0x00, 0x6f, 0x20, 0xd5, 0x31, 0xc5, 0x09, 0x83, 0xb3, + 0x1d, 0x26, 0x4a, 0x99, 0xb7, 0x32, 0xfa, 0x8f, 0x35, 0xae, 0x68, 0x1b, 0x26, 0xa8, 0xda, 0xe3, + 0x35, 0x8e, 0x7c, 0xa0, 0x40, 0xaf, 0x5b, 0x9e, 0xd8, 0x62, 0x34, 0xb0, 0xa0, 0x45, 0xc7, 0xca, + 0x27, 0x61, 0xc7, 0x77, 0xe9, 0xd0, 0xb2, 0x23, 0xa4, 0xc4, 0x5b, 0x81, 0x55, 0x29, 0xd6, 0x30, + 0xcc, 0x3f, 0xce, 0xc1, 0x52, 0x5a, 0xd3, 0xa9, 0xa4, 0x9e, 0xe0, 0xad, 0x15, 0x06, 0xcf, 0x07, + 0xb3, 0x1f, 0x1f, 0x71, 0x65, 0xa7, 0x2e, 0xb6, 0x44, 0x50, 0x81, 0xe0, 0x8b, 0x3e, 0xa8, 0x46, + 0x28, 0x77, 0xc4, 0x11, 0x52, 0x94, 0x13, 0xa3, 0xf4, 0x08, 0x14, 0x02, 0x3a, 0xf3, 0xf9, 0xb8, + 0x5b, 0x9a, 0xcd, 0x11, 0x83, 0x50, 0x8c, 0x8e, 0x6b, 0x87, 0x22, 0x26, 0x4f, 0x61, 0x5c, 0x77, + 0xed, 0x10, 0x33, 0x88, 0xf9, 0xe5, 0x1c, 0x9c, 0x1e, 0xdc, 0x29, 0xf4, 0x65, 0x03, 0xa0, 0x41, + 0x95, 0x5a, 0xba, 0x24, 0xe5, 0x15, 0xa7, 0x75, 0x5c, 0x63, 0xb8, 0x26, 0x39, 0x45, 0xf7, 0xdd, + 0xaa, 0x28, 0xc0, 0x5a, 0x43, 0xd0, 0x79, 0xb9, 0xf4, 0xaf, 0x58, 0x2d, 0xa9, 0x0a, 0xaa, 0x3a, + 0x9b, 0x0a, 0x82, 0x35, 0x2c, 0x6a, 0xb5, 0xb8, 0x56, 0x8b, 0x04, 0x6d, 0x4b, 0x05, 0x5d, 0x32, + 0xab, 0xe5, 0x8a, 0x2c, 0xc4, 0x11, 0xdc, 0x74, 0xe0, 0xd1, 0x21, 0xda, 0x99, 0x51, 0x00, 0x9c, + 0xf9, 0xef, 0x06, 0x9c, 0x5a, 0x75, 0x3a, 0x41, 0x48, 0xfc, 0xff, 0x31, 0xe1, 0x03, 0xff, 0x69, + 0xc0, 0x43, 0x03, 0xfa, 0x7c, 0x1f, 0xa2, 0x08, 0x5e, 0x8e, 0x47, 0x11, 0x5c, 0x1f, 0x77, 0x49, + 0xa7, 0xf6, 0x63, 0x40, 0x30, 0x41, 0x08, 0xb3, 0x54, 0x6a, 0x35, 0xbc, 0x66, 0x46, 0xe7, 0xe6, + 0xa3, 0x50, 0xfc, 0x38, 0x3d, 0x7f, 0x92, 0x6b, 0x8c, 0x1d, 0x4a, 0x98, 0xc3, 0xcc, 0x0f, 0x80, + 0xb8, 0x72, 0x4f, 0x6c, 0x1e, 0x63, 0x98, 0xcd, 0x63, 0xfe, 0x7d, 0x0e, 0x34, 0x6b, 0xf7, 0x3e, + 0x2c, 0x4a, 0x37, 0xb6, 0x28, 0xc7, 0xb4, 0x5f, 0x35, 0xdb, 0x7d, 0x50, 0x6c, 0xed, 0x7e, 0x22, + 0xb6, 0xf6, 0x4a, 0x66, 0x1c, 0x0f, 0x0f, 0xad, 0xfd, 0x9e, 0x01, 0x0f, 0x45, 0xc8, 0xfd, 0x8e, + 0xa3, 0x7b, 0x4b, 0x98, 0xa7, 0x60, 0xda, 0x8a, 0xaa, 0x89, 0x35, 0xa0, 0xc2, 0xc9, 0x35, 0x8a, + 0x58, 0xc7, 0x8b, 0x22, 0xf9, 0xf2, 0x47, 0x8c, 0xe4, 0x2b, 0x1c, 0x1e, 0xc9, 0x67, 0xfe, 0x34, + 0x07, 0x67, 0xfa, 0x7b, 0x26, 0xf7, 0xc6, 0x70, 0xf7, 0xaa, 0x4f, 0xc3, 0x4c, 0x28, 0x2a, 0x68, + 0x92, 0x5e, 0x3d, 0x86, 0xd8, 0xd6, 0x60, 0x38, 0x86, 0x49, 0x6b, 0xd6, 0xf9, 0xae, 0xac, 0xd5, + 0xbd, 0xb6, 0x8c, 0x03, 0x55, 0x35, 0x57, 0x35, 0x18, 0x8e, 0x61, 0xaa, 0x08, 0x9b, 0xc2, 0xb1, + 0x47, 0xd8, 0xd4, 0xe0, 0xa4, 0x8c, 0x29, 0xb8, 0xe8, 0xf9, 0xab, 0x5e, 0xab, 0xed, 0x10, 0x11, + 0x09, 0x4a, 0x1b, 0x7b, 0x46, 0x54, 0x39, 0x89, 0xd3, 0x90, 0x70, 0x7a, 0x5d, 0xf3, 0x7b, 0x79, + 0x38, 0x11, 0x0d, 0xfb, 0xaa, 0xe7, 0x36, 0x6c, 0x16, 0x99, 0xf1, 0x0c, 0x14, 0xc2, 0x83, 0xb6, + 0x1c, 0xec, 0xff, 0x25, 0x9b, 0xb3, 0x7d, 0xd0, 0xa6, 0xb3, 0x7d, 0x2a, 0xa5, 0x0a, 0x05, 0x61, + 0x56, 0x09, 0x6d, 0xa8, 0xdd, 0xc1, 0x67, 0xe0, 0xc9, 0xf8, 0x6a, 0xbe, 0xdb, 0x2d, 0xa7, 0xbc, + 0x05, 0x5a, 0x51, 0x94, 0xe2, 0x6b, 0x1e, 0xdd, 0x84, 0x39, 0xc7, 0x0a, 0xc2, 0xeb, 0xed, 0x86, + 0x15, 0x92, 0x6d, 0xbb, 0x45, 0xc4, 0x9e, 0x1b, 0x25, 0xbc, 0x52, 0xdd, 0x35, 0x6e, 0xc4, 0x28, + 0xe1, 0x04, 0x65, 0xb4, 0x0f, 0x88, 0x96, 0x6c, 0xfb, 0x96, 0x1b, 0xf0, 0x5e, 0x51, 0x7e, 0xa3, + 0x87, 0x73, 0x2a, 0x03, 0x69, 0xa3, 0x8f, 0x1a, 0x4e, 0xe1, 0x80, 0x1e, 0x83, 0x09, 0x9f, 0x58, + 0x81, 0x98, 0xcc, 0xa9, 0x68, 0xff, 0x63, 0x56, 0x8a, 0x05, 0x54, 0xdf, 0x50, 0x13, 0xf7, 0xd8, + 0x50, 0x3f, 0x32, 0x60, 0x2e, 0x9a, 0xa6, 0xfb, 0x70, 0x48, 0xb6, 0xe2, 0x87, 0xe4, 0xa5, 0xac, + 0x44, 0xe2, 0x80, 0x73, 0xf1, 0x2f, 0x26, 0xf4, 0xfe, 0xb1, 0xf0, 0xba, 0x4f, 0xc0, 0x94, 0xdc, + 0xd5, 0x52, 0xfb, 0x1c, 0xd3, 0xcb, 0x12, 0xd3, 0x4b, 0xb4, 0xb0, 0x70, 0xc1, 0x04, 0x47, 0xfc, + 0xe8, 0xb1, 0xdc, 0x10, 0x47, 0xae, 0x58, 0xf6, 0xea, 0x58, 0x96, 0x47, 0x71, 0xda, 0xb1, 0x2c, + 0xeb, 0xa0, 0xeb, 0x70, 0xaa, 0xed, 0x7b, 0xec, 0xa9, 0xd0, 0x1a, 0xb1, 0x1a, 0x8e, 0xed, 0x12, + 0x69, 0xcc, 0xf3, 0xab, 0xee, 0x87, 0x7a, 0xdd, 0xf2, 0xa9, 0xad, 0x74, 0x14, 0x3c, 0xa8, 0x6e, + 0x3c, 0xbc, 0xbd, 0x30, 0x44, 0x78, 0xfb, 0xaf, 0x2a, 0x97, 0x19, 0x09, 0x44, 0x90, 0xf9, 0x87, + 0xb3, 0x9a, 0xca, 0x14, 0xb1, 0x1e, 0x2d, 0xa9, 0x8a, 0x60, 0x8a, 0x15, 0xfb, 0xc1, 0x7e, 0x99, + 0x89, 0x23, 0xfa, 0x65, 0xa2, 0x28, 0xc5, 0xc9, 0x9f, 0x67, 0x94, 0x62, 0xe9, 0x2d, 0x15, 0xa5, + 0xf8, 0x5a, 0x11, 0x16, 0x92, 0x1a, 0xc8, 0xf1, 0x87, 0xee, 0xff, 0x86, 0x01, 0x0b, 0x72, 0xf7, + 0x70, 0x9e, 0x44, 0x7a, 0xdc, 0x37, 0x32, 0xda, 0xb4, 0x5c, 0x97, 0x52, 0x8f, 0xcb, 0xb6, 0x13, + 0xdc, 0x70, 0x1f, 0x7f, 0xf4, 0x12, 0x4c, 0x2b, 0xc7, 0xf4, 0x91, 0xe2, 0xf8, 0xe7, 0x99, 0x16, + 0x15, 0x91, 0xc0, 0x3a, 0x3d, 0xf4, 0x9a, 0x01, 0x50, 0x97, 0xc7, 0x9c, 0xdc, 0x5d, 0xd7, 0xb2, + 0xda, 0x5d, 0xea, 0x00, 0x8d, 0x94, 0x65, 0x55, 0x14, 0x60, 0x8d, 0x31, 0xfa, 0x22, 0x73, 0x49, + 0x2b, 0xed, 0x8e, 0xee, 0x27, 0xda, 0x92, 0x0f, 0x65, 0xbd, 0xcf, 0xa3, 0xdb, 0x51, 0xa5, 0x4a, + 0x69, 0xa0, 0x00, 0xc7, 0x1a, 0x61, 0x3e, 0x03, 0x2a, 0xc0, 0x8e, 0x8a, 0x2d, 0x16, 0x62, 0xb7, + 0x65, 0x85, 0x7b, 0x62, 0x09, 0x2a, 0xb1, 0x75, 0x51, 0x02, 0x70, 0x84, 0x63, 0x7e, 0x0c, 0xe6, + 0x9e, 0xf3, 0xad, 0xf6, 0x9e, 0xcd, 0x5c, 0xbf, 0xd4, 0x4e, 0x7a, 0x27, 0x4c, 0x5a, 0x8d, 0x46, + 0xda, 0xd3, 0xcc, 0x0a, 0x2f, 0xc6, 0x12, 0x3e, 0x9c, 0x49, 0xf4, 0x2d, 0x03, 0x96, 0xd6, 0x83, + 0xd0, 0xf6, 0xd6, 0x48, 0x10, 0x52, 0x59, 0x49, 0x77, 0x54, 0xc7, 0x21, 0x43, 0x28, 0xa6, 0x6b, + 0xb0, 0x20, 0xee, 0xa7, 0x3a, 0x3b, 0x01, 0x09, 0x35, 0xe5, 0x54, 0x2d, 0xce, 0xd5, 0x04, 0x1c, + 0xf7, 0xd5, 0xa0, 0x54, 0xc4, 0x45, 0x55, 0x44, 0x25, 0x1f, 0xa7, 0x52, 0x4b, 0xc0, 0x71, 0x5f, + 0x0d, 0xf3, 0xbb, 0x79, 0x38, 0xc1, 0xba, 0x91, 0x78, 0x3b, 0xf9, 0x79, 0x03, 0xe6, 0xf6, 0x6d, + 0x3f, 0xec, 0x58, 0x8e, 0x7e, 0xe3, 0x36, 0xf6, 0xfa, 0x64, 0xbc, 0x5e, 0x88, 0x11, 0xe6, 0x3e, + 0xf9, 0x78, 0x19, 0x4e, 0x30, 0x47, 0xbf, 0x6e, 0xc0, 0x7c, 0x23, 0x3e, 0xd2, 0xd9, 0xf8, 0x1c, + 0xd2, 0xe6, 0x90, 0x07, 0x8a, 0x24, 0x0a, 0x71, 0x92, 0x3f, 0xfa, 0x92, 0x01, 0xf3, 0xf1, 0x66, + 0x4a, 0x91, 0x75, 0x0c, 0x83, 0xa4, 0x22, 0x3b, 0xe3, 0xe5, 0x01, 0x4e, 0x36, 0xc1, 0xfc, 0x5b, + 0x43, 0x4c, 0x69, 0x1c, 0x73, 0x88, 0x85, 0x69, 0xc2, 0x84, 0xef, 0x75, 0x42, 0xe1, 0x37, 0x9f, + 0xe2, 0xee, 0x55, 0xcc, 0x4a, 0xb0, 0x80, 0xa0, 0xdb, 0x30, 0x15, 0x3a, 0x01, 0x2f, 0x14, 0xbd, + 0x1d, 0xd3, 0xcc, 0xd9, 0xde, 0xa8, 0x31, 0x72, 0x9a, 0x26, 0x22, 0x4a, 0xa8, 0x46, 0x25, 0x79, + 0x99, 0x5f, 0x37, 0x60, 0xea, 0xb2, 0xb7, 0x23, 0xb6, 0xf3, 0x47, 0x33, 0x70, 0x22, 0x28, 0x5d, + 0x43, 0xdd, 0x04, 0x45, 0xea, 0xeb, 0xb3, 0x31, 0x17, 0xc2, 0xc3, 0x1a, 0xed, 0x15, 0x96, 0xd2, + 0x80, 0x92, 0xba, 0xec, 0xed, 0x0c, 0xf4, 0x50, 0xfd, 0x4e, 0x11, 0x66, 0x9f, 0xb7, 0x0e, 0x88, + 0x1b, 0x5a, 0xa3, 0x0b, 0x20, 0x6a, 0x95, 0xb7, 0x59, 0xa0, 0xa2, 0xa6, 0x3f, 0x46, 0x56, 0x79, + 0x04, 0xc2, 0x3a, 0x5e, 0x24, 0x57, 0xf8, 0x0b, 0xeb, 0x34, 0x89, 0xb0, 0x9a, 0x80, 0xe3, 0xbe, + 0x1a, 0xe8, 0x32, 0x20, 0xf1, 0x5e, 0xa4, 0x52, 0xaf, 0x7b, 0x1d, 0x97, 0x4b, 0x16, 0x6e, 0xb0, + 0x2b, 0x43, 0x66, 0xb3, 0x0f, 0x03, 0xa7, 0xd4, 0x42, 0x1f, 0x81, 0xe5, 0x3a, 0xa3, 0x2c, 0xd4, + 0x5a, 0x9d, 0x22, 0x37, 0x6d, 0x54, 0x90, 0xf0, 0xea, 0x00, 0x3c, 0x3c, 0x90, 0x02, 0x6d, 0x69, + 0x10, 0x7a, 0xbe, 0xd5, 0x24, 0x3a, 0xdd, 0x89, 0x78, 0x4b, 0x6b, 0x7d, 0x18, 0x38, 0xa5, 0x16, + 0xfa, 0x34, 0x4c, 0x85, 0x7b, 0x3e, 0x09, 0xf6, 0x3c, 0xa7, 0x21, 0xae, 0x86, 0xc7, 0xf4, 0xe2, + 0x88, 0xd9, 0xdf, 0x96, 0x54, 0xb5, 0xe5, 0x2d, 0x8b, 0x70, 0xc4, 0x13, 0xf9, 0x30, 0x11, 0xd4, + 0xbd, 0x36, 0x09, 0x84, 0x3a, 0x78, 0x39, 0x13, 0xee, 0xcc, 0x2b, 0xa1, 0xf9, 0x8f, 0x18, 0x07, + 0x2c, 0x38, 0x99, 0xdf, 0xce, 0xc1, 0x8c, 0x8e, 0x38, 0x84, 0x88, 0xf8, 0x8c, 0x01, 0x33, 0x75, + 0xcf, 0x0d, 0x7d, 0xcf, 0xe1, 0xbe, 0x11, 0xbe, 0x41, 0xc6, 0x7c, 0x86, 0xcc, 0x48, 0xad, 0x91, + 0xd0, 0xb2, 0x1d, 0xcd, 0xcd, 0xa2, 0xb1, 0xc1, 0x31, 0xa6, 0xe8, 0x73, 0x06, 0xcc, 0x47, 0x31, + 0x33, 0x91, 0x93, 0x26, 0xd3, 0x86, 0x28, 0x89, 0x7b, 0x21, 0xce, 0x09, 0x27, 0x59, 0x9b, 0x3b, + 0xb0, 0x90, 0x9c, 0x6d, 0x3a, 0x94, 0x6d, 0x4b, 0xec, 0xf5, 0x7c, 0x34, 0x94, 0x5b, 0x56, 0x10, + 0x60, 0x06, 0x41, 0xef, 0x82, 0x52, 0xcb, 0xf2, 0x9b, 0xb6, 0x6b, 0x39, 0x6c, 0x14, 0xf3, 0x9a, + 0x40, 0x12, 0xe5, 0x58, 0x61, 0x98, 0x3f, 0x29, 0xc0, 0xb4, 0xa6, 0xc5, 0x1f, 0xbf, 0x46, 0x1e, + 0x7b, 0xc2, 0x9a, 0xcf, 0xf0, 0x09, 0xeb, 0x8b, 0x00, 0xbb, 0xb6, 0x6b, 0x07, 0x7b, 0x47, 0x7c, + 0x1c, 0xcb, 0x2e, 0xf3, 0x2e, 0x2a, 0x0a, 0x58, 0xa3, 0x16, 0xdd, 0x98, 0x14, 0x0f, 0x49, 0x19, + 0xf0, 0x9a, 0xa1, 0x1d, 0x1e, 0x13, 0x59, 0xdc, 0x10, 0x6b, 0x13, 0xb3, 0x22, 0x0f, 0x93, 0x0b, + 0x6e, 0xe8, 0x1f, 0x1c, 0x7a, 0xc6, 0x6c, 0x43, 0xc9, 0x27, 0x41, 0xa7, 0x45, 0x6d, 0x8b, 0xc9, + 0x91, 0x87, 0x81, 0x05, 0x98, 0x60, 0x51, 0x1f, 0x2b, 0x4a, 0xa7, 0x9f, 0x81, 0xd9, 0x58, 0x13, + 0xd0, 0x02, 0xe4, 0x6f, 0x91, 0x03, 0xbe, 0x4e, 0x30, 0xfd, 0x89, 0x96, 0x62, 0xf7, 0x4a, 0x62, + 0x58, 0xde, 0x9f, 0x7b, 0xda, 0x30, 0x3d, 0x48, 0x35, 0x15, 0x8f, 0xe2, 0xf6, 0xa7, 0x73, 0xe1, + 0x68, 0xaf, 0x63, 0xd5, 0x5c, 0xf0, 0x68, 0x06, 0x0e, 0x33, 0x7f, 0x3a, 0x01, 0xe2, 0xd2, 0x73, + 0x08, 0xe1, 0xa3, 0xdf, 0x75, 0xe4, 0x8e, 0x70, 0xd7, 0x71, 0x19, 0x66, 0x6c, 0xd7, 0x0e, 0x6d, + 0xcb, 0x61, 0x6e, 0x00, 0x71, 0x38, 0x3e, 0x26, 0x05, 0xce, 0xba, 0x06, 0x4b, 0xa1, 0x13, 0xab, + 0x8b, 0xae, 0x41, 0x91, 0x9d, 0x1e, 0x62, 0x01, 0x8f, 0x7e, 0x33, 0xcb, 0x2e, 0xe5, 0xf9, 0xeb, + 0x04, 0x4e, 0x89, 0x69, 0xf4, 0xfc, 0x79, 0xb0, 0x32, 0xd4, 0xc4, 0x3a, 0x8e, 0x34, 0xfa, 0x04, + 0x1c, 0xf7, 0xd5, 0xa0, 0x54, 0x76, 0x2d, 0xdb, 0xe9, 0xf8, 0x24, 0xa2, 0x32, 0x11, 0xa7, 0x72, + 0x31, 0x01, 0xc7, 0x7d, 0x35, 0xd0, 0x2e, 0xcc, 0x88, 0x32, 0x1e, 0xa3, 0x32, 0x79, 0xc4, 0x5e, + 0xb2, 0x58, 0xa4, 0x8b, 0x1a, 0x25, 0x1c, 0xa3, 0x8b, 0x3a, 0xb0, 0x68, 0xbb, 0x75, 0xcf, 0xad, + 0x3b, 0x9d, 0xc0, 0xde, 0x27, 0xd1, 0xd3, 0x80, 0xa3, 0x30, 0x3b, 0xd9, 0xeb, 0x96, 0x17, 0xd7, + 0x93, 0xe4, 0x70, 0x3f, 0x07, 0xf4, 0xaa, 0x01, 0x27, 0xeb, 0x9e, 0x1b, 0xb0, 0xf7, 0x76, 0xfb, + 0xe4, 0x82, 0xef, 0x7b, 0x3e, 0xe7, 0x3d, 0x75, 0x44, 0xde, 0xcc, 0xfb, 0xb4, 0x9a, 0x46, 0x12, + 0xa7, 0x73, 0x42, 0x2f, 0x43, 0xa9, 0xed, 0x7b, 0xfb, 0x76, 0x83, 0xf8, 0x22, 0xde, 0x69, 0x23, + 0x8b, 0xf7, 0xbf, 0x5b, 0x82, 0x66, 0x24, 0x7a, 0x64, 0x09, 0x56, 0xfc, 0xcc, 0xdf, 0x2f, 0xc1, + 0x5c, 0x1c, 0x1d, 0x7d, 0x0a, 0xa0, 0xed, 0x7b, 0x2d, 0x12, 0xee, 0x11, 0x15, 0xe2, 0x7d, 0x65, + 0xdc, 0x67, 0xa6, 0x92, 0x9e, 0x8c, 0x73, 0xa0, 0xe2, 0x22, 0x2a, 0xc5, 0x1a, 0x47, 0xe4, 0xc3, + 0xe4, 0x2d, 0x7e, 0x88, 0x0a, 0x9d, 0xe2, 0xf9, 0x4c, 0x34, 0x20, 0xc1, 0x99, 0xc5, 0x26, 0x8b, + 0x22, 0x2c, 0x19, 0xa1, 0x1d, 0xc8, 0xdf, 0x26, 0x3b, 0xd9, 0x3c, 0x88, 0xbc, 0x41, 0x84, 0x6d, + 0x52, 0x9d, 0xec, 0x75, 0xcb, 0xf9, 0x1b, 0x64, 0x07, 0x53, 0xe2, 0xb4, 0x5f, 0x0d, 0x7e, 0x63, + 0x2b, 0x44, 0xc5, 0x98, 0xfd, 0x8a, 0x5d, 0xff, 0xf2, 0x7e, 0x89, 0x22, 0x2c, 0x19, 0xa1, 0x97, + 0x61, 0xea, 0xb6, 0xb5, 0x4f, 0x76, 0x7d, 0xcf, 0x0d, 0x45, 0x70, 0xcd, 0x98, 0x51, 0xc4, 0x37, + 0x24, 0x39, 0xc1, 0x97, 0x1d, 0xef, 0xaa, 0x10, 0x47, 0xec, 0xd0, 0x3e, 0x94, 0x5c, 0x72, 0x1b, + 0x13, 0xc7, 0xae, 0x8b, 0x00, 0xce, 0x31, 0x97, 0xf5, 0x15, 0x41, 0x4d, 0x70, 0x66, 0xe7, 0x9e, + 0x2c, 0xc3, 0x8a, 0x17, 0x9d, 0xcb, 0x9b, 0xde, 0x8e, 0x10, 0x54, 0x63, 0xce, 0xa5, 0xb2, 0x33, + 0xf9, 0x5c, 0x5e, 0xf6, 0x76, 0x30, 0x25, 0x4e, 0xf7, 0x48, 0x5d, 0x45, 0x76, 0x08, 0x31, 0x75, + 0x25, 0xdb, 0x88, 0x16, 0xbe, 0x47, 0xa2, 0x52, 0xac, 0x71, 0xa4, 0x63, 0xdb, 0x14, 0x6e, 0x2d, + 0x21, 0xa8, 0xc6, 0x1c, 0xdb, 0xb8, 0x93, 0x8c, 0x8f, 0xad, 0x2c, 0xc3, 0x8a, 0x97, 0xf9, 0xf5, + 0x09, 0x98, 0xd1, 0xf3, 0x9d, 0x0c, 0x71, 0x56, 0x2b, 0xfd, 0x34, 0x37, 0x8a, 0x7e, 0x4a, 0xcd, + 0x0b, 0xcd, 0x2b, 0x2d, 0x3d, 0x0c, 0xeb, 0x99, 0xa9, 0x67, 0x91, 0x79, 0xa1, 0x15, 0x06, 0x38, + 0xc6, 0x74, 0x84, 0x8b, 0x6a, 0xaa, 0xe4, 0x70, 0x35, 0xa0, 0x18, 0x57, 0x72, 0x62, 0x07, 0xfb, + 0x79, 0x80, 0x28, 0xef, 0x87, 0xb8, 0xad, 0x50, 0xda, 0x93, 0x96, 0x8f, 0x44, 0xc3, 0x42, 0x8f, + 0xc1, 0x04, 0x3d, 0x28, 0x49, 0x43, 0xbc, 0xbf, 0x53, 0x36, 0xdc, 0x45, 0x56, 0x8a, 0x05, 0x14, + 0x3d, 0x4d, 0x75, 0x9a, 0xe8, 0x78, 0x13, 0xcf, 0xea, 0x96, 0x22, 0x9d, 0x26, 0x82, 0xe1, 0x18, + 0x26, 0x6d, 0x3a, 0xa1, 0xa7, 0x11, 0x5b, 0x49, 0x5a, 0xd3, 0xd9, 0x11, 0x85, 0x39, 0x8c, 0xf9, + 0x14, 0x12, 0xa7, 0x17, 0x3b, 0xac, 0x8a, 0x9a, 0x4f, 0x21, 0x01, 0xc7, 0x7d, 0x35, 0x68, 0x67, + 0xc4, 0x45, 0xcb, 0x34, 0x8f, 0xc7, 0x1b, 0x70, 0x45, 0xf2, 0xba, 0xae, 0x99, 0xcf, 0xb0, 0xa9, + 0xff, 0x60, 0x76, 0xb9, 0x7b, 0x86, 0x57, 0xcd, 0xc7, 0x53, 0xa2, 0x3f, 0x06, 0x73, 0x71, 0x99, + 0x45, 0x17, 0x54, 0xdb, 0xf7, 0x76, 0x6d, 0x87, 0x24, 0x7d, 0x3f, 0x5b, 0xbc, 0x18, 0x4b, 0xf8, + 0x70, 0xce, 0xe7, 0xbf, 0xcc, 0xc3, 0x89, 0x2b, 0x4d, 0xdb, 0xbd, 0x93, 0xf0, 0xda, 0xa6, 0xe5, + 0xd4, 0x33, 0x46, 0xcd, 0xa9, 0x17, 0x3d, 0x97, 0x10, 0x49, 0x0b, 0xd3, 0x9f, 0x4b, 0xc8, 0x8c, + 0x86, 0x71, 0x5c, 0xf4, 0x23, 0x03, 0x1e, 0xb6, 0x1a, 0x5c, 0x8b, 0xb4, 0x1c, 0x51, 0x1a, 0x31, + 0x95, 0x3b, 0x3a, 0x18, 0xf3, 0x4c, 0xe8, 0xef, 0xfc, 0x4a, 0xe5, 0x10, 0xae, 0x7c, 0xc6, 0xdf, + 0x21, 0x7a, 0xf0, 0xf0, 0x61, 0xa8, 0xf8, 0xd0, 0xe6, 0x9f, 0xbe, 0x0a, 0x6f, 0xbf, 0x27, 0xa3, + 0x91, 0x56, 0xcb, 0x67, 0x0c, 0x98, 0xe2, 0x4e, 0x49, 0x4c, 0x76, 0xa9, 0xa8, 0xb0, 0xda, 0xf6, + 0x0b, 0xc4, 0x0f, 0x64, 0xb2, 0x0f, 0xcd, 0xd0, 0xaa, 0x6c, 0xad, 0x0b, 0x08, 0xd6, 0xb0, 0xa8, + 0x30, 0xbe, 0x65, 0xbb, 0x0d, 0x31, 0x4d, 0x4a, 0x18, 0x3f, 0x6f, 0xbb, 0x0d, 0xcc, 0x20, 0x4a, + 0x5c, 0xe7, 0x07, 0x89, 0x6b, 0xf3, 0x6b, 0x06, 0xcc, 0xb1, 0xd7, 0x50, 0x91, 0x09, 0xf0, 0x94, + 0x8a, 0x42, 0xe0, 0xcd, 0x38, 0x13, 0x8f, 0x42, 0xb8, 0xdb, 0x2d, 0x4f, 0xf3, 0xf7, 0x53, 0xf1, + 0xa0, 0x84, 0x0f, 0x0b, 0xbf, 0x01, 0x8b, 0x95, 0xc8, 0x8d, 0x6c, 0xd6, 0x2a, 0x2f, 0x59, 0x4d, + 0x12, 0xc1, 0x11, 0x3d, 0xf3, 0x0f, 0xf3, 0x70, 0x22, 0x25, 0xac, 0x9f, 0x9a, 0xf4, 0x13, 0x2c, + 0xb2, 0x59, 0xde, 0xf4, 0xbf, 0x94, 0xf9, 0xd3, 0x81, 0x15, 0x16, 0x40, 0x2d, 0x56, 0x92, 0x12, + 0x60, 0xbc, 0x10, 0x0b, 0xe6, 0xe8, 0x37, 0x0d, 0x98, 0xb6, 0xb4, 0xc5, 0xce, 0x83, 0x1f, 0x76, + 0xb2, 0x6f, 0x4c, 0xdf, 0xda, 0xd6, 0x82, 0xb6, 0xa2, 0xa5, 0xac, 0xb7, 0xe5, 0xf4, 0xfb, 0x60, + 0x5a, 0xeb, 0xc2, 0x28, 0x6b, 0xf4, 0xf4, 0xb3, 0xb0, 0x30, 0xd6, 0x1a, 0xff, 0x10, 0x8c, 0x9a, + 0x3d, 0x86, 0x1e, 0x19, 0xb7, 0xf5, 0x47, 0x82, 0x6a, 0xc4, 0xc5, 0x2b, 0x41, 0x01, 0x35, 0x77, + 0x60, 0x21, 0x69, 0x66, 0x64, 0x7e, 0xd7, 0xf7, 0x1e, 0x18, 0x31, 0xdf, 0x8b, 0xf9, 0x57, 0x39, + 0x98, 0x14, 0x6f, 0x83, 0xee, 0x43, 0xbc, 0xe3, 0xad, 0xd8, 0x65, 0xc5, 0x7a, 0x26, 0x4f, 0x9a, + 0x06, 0x06, 0x3b, 0x06, 0x89, 0x60, 0xc7, 0xe7, 0xb3, 0x61, 0x77, 0x78, 0xa4, 0xe3, 0xd7, 0x0a, + 0x30, 0x9f, 0x78, 0x6b, 0x45, 0x95, 0x85, 0xbe, 0x00, 0x9f, 0xeb, 0x99, 0x3e, 0xe7, 0x52, 0xb1, + 0xb8, 0x87, 0xc7, 0xfa, 0x04, 0xb1, 0xb4, 0x5a, 0xd7, 0x32, 0xcb, 0xc8, 0xf9, 0x8b, 0x0c, 0x5b, + 0xa3, 0xc6, 0xae, 0xfc, 0x93, 0x01, 0x0f, 0x0e, 0x7c, 0x92, 0xc7, 0x72, 0x0d, 0xf8, 0x71, 0xa8, + 0xd8, 0x90, 0x19, 0x3f, 0xb1, 0x55, 0x37, 0x07, 0xc9, 0xe7, 0xe1, 0x49, 0xf6, 0xe8, 0x49, 0x98, + 0x61, 0x87, 0x1b, 0x95, 0x29, 0x21, 0x69, 0x0b, 0x57, 0x29, 0x73, 0x9a, 0xd5, 0xb4, 0x72, 0x1c, + 0xc3, 0x32, 0xbf, 0x6a, 0xc0, 0xf2, 0xa0, 0x97, 0xe7, 0x43, 0x98, 0x66, 0xff, 0x2f, 0x11, 0x90, + 0x59, 0xee, 0x0b, 0xc8, 0x4c, 0x18, 0x67, 0x32, 0xf6, 0x52, 0xb3, 0x8b, 0xf2, 0xf7, 0x88, 0x37, + 0xfc, 0xbc, 0x01, 0xa7, 0x06, 0xec, 0xa6, 0xbe, 0xc0, 0x5c, 0xe3, 0xc8, 0x81, 0xb9, 0xb9, 0x61, + 0x03, 0x73, 0xcd, 0xbf, 0xc9, 0xc3, 0x82, 0x68, 0x4f, 0xa4, 0xe1, 0x3c, 0x1d, 0x0b, 0x6b, 0x7d, + 0x47, 0x22, 0xac, 0x75, 0x29, 0x89, 0xff, 0x8b, 0x98, 0xd6, 0xb7, 0x56, 0x4c, 0xeb, 0xcf, 0x72, + 0x70, 0x32, 0xf5, 0x81, 0x3d, 0xfa, 0x6c, 0xca, 0xd1, 0x70, 0x23, 0xe3, 0x97, 0xfc, 0x43, 0x1e, + 0x0e, 0xe3, 0x06, 0x82, 0x7e, 0x49, 0x0f, 0xc0, 0xe4, 0xa2, 0x7e, 0xf7, 0x18, 0x72, 0x12, 0x8c, + 0x18, 0x8b, 0x69, 0xfe, 0x5a, 0x1e, 0x1e, 0x1f, 0x96, 0xd0, 0x5b, 0x34, 0x56, 0x3f, 0x88, 0xc5, + 0xea, 0xdf, 0xa7, 0x63, 0xfb, 0x58, 0xc2, 0xf6, 0xbf, 0x9e, 0x57, 0xc7, 0x5e, 0xff, 0xfa, 0x1c, + 0xea, 0x5e, 0x6d, 0x92, 0xaa, 0x76, 0x32, 0x4d, 0x5e, 0x24, 0x0a, 0x27, 0x6b, 0xbc, 0xf8, 0x6e, + 0xb7, 0xbc, 0x28, 0x52, 0x67, 0xd5, 0x48, 0x28, 0x0a, 0xb1, 0xac, 0x84, 0x1e, 0x87, 0x92, 0xcf, + 0xa1, 0x32, 0x3a, 0x59, 0x5c, 0x4e, 0xf2, 0x32, 0xac, 0xa0, 0xe8, 0xd3, 0x9a, 0x2e, 0x5c, 0x38, + 0xae, 0x37, 0xde, 0x87, 0xdd, 0xb9, 0xbe, 0x04, 0xa5, 0x40, 0x26, 0xbc, 0xe3, 0x8e, 0xf1, 0x27, + 0x86, 0x0c, 0x7a, 0xa7, 0xa6, 0x93, 0xcc, 0x7e, 0xc7, 0xfb, 0xa7, 0x72, 0xe3, 0x29, 0x92, 0xc8, + 0x54, 0x56, 0x0b, 0xf7, 0xf2, 0x41, 0x8a, 0xc5, 0xf2, 0x3d, 0x03, 0xa6, 0xc5, 0x6c, 0xdd, 0x87, + 0x38, 0xfc, 0x9b, 0xf1, 0x38, 0xfc, 0x0b, 0x99, 0xc8, 0x8e, 0x01, 0x41, 0xf8, 0x37, 0x61, 0x46, + 0xcf, 0xb1, 0x82, 0x5e, 0xd4, 0x64, 0x9f, 0x31, 0x4e, 0x2e, 0x07, 0x29, 0x1d, 0x23, 0xb9, 0x68, + 0x7e, 0xa5, 0xa4, 0x46, 0x91, 0x45, 0xfb, 0xeb, 0x6b, 0xd0, 0x38, 0x74, 0x0d, 0xea, 0x4b, 0x20, + 0x97, 0xfd, 0x12, 0xb8, 0x06, 0x25, 0x29, 0xa0, 0xc4, 0x31, 0xfe, 0xa8, 0x1e, 0x3d, 0x46, 0x75, + 0x01, 0x4a, 0x4c, 0x5b, 0xb8, 0xcc, 0xd4, 0x52, 0x73, 0xa8, 0x04, 0xa7, 0x22, 0x83, 0x5e, 0x86, + 0xe9, 0xdb, 0x9e, 0x7f, 0xcb, 0xf1, 0x2c, 0x96, 0xca, 0x12, 0xb2, 0xb8, 0xe2, 0x50, 0x2e, 0x27, + 0x1e, 0xa4, 0x7c, 0x23, 0xa2, 0x8f, 0x75, 0x66, 0xa8, 0x02, 0xf3, 0x2d, 0xdb, 0xc5, 0xc4, 0x6a, + 0xa8, 0x70, 0xfb, 0x02, 0xcf, 0xb5, 0x27, 0x95, 0xdc, 0xcd, 0x38, 0x18, 0x27, 0xf1, 0xd1, 0x27, + 0xa0, 0x14, 0x88, 0x3c, 0x2e, 0xd9, 0x5c, 0x46, 0x29, 0x9b, 0x91, 0x13, 0x8d, 0xc6, 0x4e, 0x96, + 0x60, 0xc5, 0x10, 0x6d, 0xc0, 0x92, 0x2f, 0x32, 0x25, 0xc4, 0x52, 0x76, 0xf3, 0xfd, 0xc9, 0x52, + 0xba, 0xe1, 0x14, 0x38, 0x4e, 0xad, 0x45, 0xb5, 0x18, 0x96, 0x2c, 0x88, 0x7b, 0xe5, 0x35, 0x47, + 0x36, 0x5b, 0xf0, 0x0d, 0x2c, 0xa0, 0x87, 0x3d, 0xdf, 0x28, 0x8d, 0xf1, 0x7c, 0xa3, 0x06, 0x27, + 0x93, 0x20, 0x96, 0xcf, 0x81, 0xa5, 0x90, 0xd0, 0x4e, 0x8f, 0xad, 0x34, 0x24, 0x9c, 0x5e, 0x17, + 0xdd, 0x80, 0x29, 0x9f, 0x30, 0xfb, 0xa2, 0x22, 0xaf, 0xbf, 0x47, 0x0e, 0xf4, 0xc1, 0x92, 0x00, + 0x8e, 0x68, 0xd1, 0x79, 0xb7, 0xe2, 0xe9, 0xe6, 0xae, 0x65, 0xf8, 0xd1, 0x11, 0x31, 0xf7, 0x03, + 0xf2, 0xac, 0x98, 0x6f, 0xce, 0xc1, 0x6c, 0xcc, 0xb7, 0x80, 0x1e, 0x85, 0x22, 0x4b, 0x70, 0xc1, + 0xc4, 0x43, 0x29, 0x12, 0x61, 0x7c, 0x70, 0x38, 0x0c, 0x7d, 0xc1, 0x80, 0xf9, 0x76, 0xcc, 0x0f, + 0x2a, 0x25, 0xe7, 0x98, 0x37, 0x6d, 0x71, 0xe7, 0xaa, 0x96, 0xa8, 0x35, 0xce, 0x0c, 0x27, 0xb9, + 0xd3, 0x0d, 0x28, 0x62, 0xdf, 0x1c, 0xe2, 0x33, 0x6c, 0xa1, 0xe3, 0x28, 0x12, 0xab, 0x71, 0x30, + 0x4e, 0xe2, 0xd3, 0x19, 0x66, 0xbd, 0x1b, 0xe7, 0x6b, 0x04, 0x15, 0x49, 0x00, 0x47, 0xb4, 0xd0, + 0xb3, 0x30, 0x27, 0xb2, 0x8c, 0x6d, 0x79, 0x8d, 0x4b, 0x56, 0xb0, 0x27, 0x94, 0x7b, 0x65, 0x8c, + 0xac, 0xc6, 0xa0, 0x38, 0x81, 0xcd, 0xfa, 0x16, 0xa5, 0x72, 0x63, 0x04, 0x26, 0xe2, 0x79, 0x6c, + 0x57, 0xe3, 0x60, 0x9c, 0xc4, 0x47, 0xef, 0xd2, 0xe4, 0x3e, 0xbf, 0x29, 0x53, 0xd2, 0x20, 0x45, + 0xf6, 0x57, 0x60, 0xbe, 0xc3, 0x6c, 0xa1, 0x86, 0x04, 0x8a, 0xfd, 0xa8, 0x18, 0x5e, 0x8f, 0x83, + 0x71, 0x12, 0x1f, 0x3d, 0x03, 0xb3, 0x3e, 0x95, 0x6e, 0x8a, 0x00, 0xbf, 0x3e, 0x53, 0xb7, 0x23, + 0x58, 0x07, 0xe2, 0x38, 0x2e, 0x7a, 0x0e, 0x16, 0xa3, 0xd4, 0x47, 0x92, 0x00, 0xbf, 0x4f, 0x53, + 0xb9, 0x44, 0x2a, 0x49, 0x04, 0xdc, 0x5f, 0x07, 0xfd, 0x7f, 0x58, 0xd0, 0x46, 0x62, 0xdd, 0x6d, + 0x90, 0x3b, 0x22, 0x3d, 0x0d, 0xfb, 0xfe, 0xd2, 0x6a, 0x02, 0x86, 0xfb, 0xb0, 0xd1, 0xfb, 0x61, + 0xae, 0xee, 0x39, 0x0e, 0x93, 0x71, 0x3c, 0x87, 0x2a, 0xcf, 0x43, 0xc3, 0x33, 0xf6, 0xc4, 0x20, + 0x38, 0x81, 0x89, 0x2e, 0x03, 0xf2, 0x76, 0x02, 0xe2, 0xef, 0x93, 0xc6, 0x73, 0xfc, 0xfb, 0x66, + 0xf4, 0x88, 0x9f, 0x8d, 0x47, 0xde, 0x5e, 0xed, 0xc3, 0xc0, 0x29, 0xb5, 0x58, 0x2a, 0x12, 0xed, + 0x15, 0xcc, 0x5c, 0x16, 0x99, 0xf9, 0x93, 0x96, 0xfb, 0x3d, 0x9f, 0xc0, 0xf8, 0x30, 0xc1, 0x03, + 0xa1, 0x97, 0xe7, 0xb3, 0x48, 0xc7, 0xa4, 0xa7, 0x53, 0x8c, 0xce, 0x08, 0x5e, 0x8a, 0x05, 0x27, + 0xf4, 0x29, 0x98, 0xda, 0x91, 0xb9, 0x75, 0x97, 0x17, 0xb2, 0x38, 0x17, 0x13, 0x69, 0xa2, 0x23, + 0xcb, 0x54, 0x01, 0x70, 0xc4, 0x12, 0x3d, 0x06, 0xd3, 0x97, 0xb6, 0x2a, 0x6a, 0x15, 0x2e, 0xb2, + 0xd9, 0x2f, 0xd0, 0x2a, 0x58, 0x07, 0xd0, 0x1d, 0xa6, 0xf4, 0x25, 0xc4, 0xa6, 0x38, 0x3a, 0x6f, + 0xfb, 0xd5, 0x1f, 0x8a, 0xcd, 0x2e, 0x04, 0x71, 0x6d, 0xf9, 0x44, 0x02, 0x5b, 0x94, 0x63, 0x85, + 0x81, 0x5e, 0x82, 0x69, 0x71, 0x5e, 0x30, 0xd9, 0xb4, 0x74, 0xb4, 0x17, 0x56, 0x38, 0x22, 0x81, + 0x75, 0x7a, 0xe8, 0x29, 0x98, 0x6e, 0xb3, 0x94, 0xa3, 0xe4, 0x62, 0xc7, 0x71, 0x96, 0x4f, 0x32, + 0xb9, 0xa9, 0x6e, 0x4a, 0xb6, 0x22, 0x10, 0xd6, 0xf1, 0xd0, 0x13, 0x32, 0x76, 0xe1, 0x6d, 0xb1, + 0x8b, 0x2f, 0x15, 0xbb, 0xa0, 0xb4, 0xdc, 0x01, 0xa1, 0xb5, 0xa7, 0xee, 0x11, 0x34, 0xb0, 0x03, + 0xa7, 0xa5, 0x8a, 0xd5, 0xbf, 0x49, 0x96, 0x97, 0x63, 0x5e, 0x82, 0xd3, 0x37, 0x06, 0x62, 0xe2, + 0x43, 0xa8, 0xa0, 0x1d, 0xc8, 0x5b, 0xce, 0xce, 0xf2, 0x83, 0x59, 0xe8, 0x8a, 0xea, 0x7b, 0x85, + 0x3c, 0x1c, 0xa6, 0xb2, 0x51, 0xc5, 0x94, 0xb8, 0xf9, 0x6a, 0x4e, 0x79, 0xe5, 0x55, 0xa2, 0xbe, + 0x4f, 0xea, 0xab, 0xda, 0xc8, 0xe2, 0x7b, 0x5c, 0x7d, 0x09, 0xa8, 0xf9, 0x81, 0x94, 0xba, 0xa6, + 0xdb, 0x6a, 0x1f, 0x67, 0x92, 0xfb, 0x21, 0x9e, 0x84, 0x90, 0x5b, 0x73, 0xf1, 0x5d, 0x6c, 0xfe, + 0xb8, 0xa0, 0x9c, 0x50, 0x89, 0xcb, 0x78, 0x1f, 0x8a, 0x76, 0x10, 0xda, 0x5e, 0x86, 0x0f, 0xa7, + 0x12, 0xd9, 0xfb, 0x58, 0x08, 0x29, 0x03, 0x60, 0xce, 0x8a, 0xf2, 0x74, 0x9b, 0xb6, 0x7b, 0x47, + 0x74, 0xff, 0x5a, 0xe6, 0xb7, 0xec, 0x9c, 0x27, 0x03, 0x60, 0xce, 0x0a, 0xdd, 0xe4, 0x2b, 0x2d, + 0x9b, 0x6f, 0xaf, 0x25, 0x3f, 0xa9, 0x18, 0x5f, 0x71, 0x94, 0x57, 0xd0, 0xb2, 0x85, 0x0e, 0x33, + 0x26, 0xaf, 0xda, 0xe6, 0x7a, 0x1a, 0xaf, 0xda, 0xe6, 0x3a, 0xa6, 0x4c, 0xd0, 0xeb, 0x06, 0x80, + 0xa5, 0xbe, 0x2d, 0x98, 0x4d, 0xb6, 0xf6, 0x41, 0xdf, 0x2a, 0xe4, 0x51, 0x5f, 0x11, 0x14, 0x6b, + 0x9c, 0xcd, 0x7f, 0x35, 0x40, 0xfb, 0x20, 0x53, 0x14, 0x72, 0x64, 0x0c, 0x1d, 0x72, 0x94, 0x1b, + 0x31, 0xe4, 0x28, 0x3f, 0x52, 0xc8, 0x51, 0x61, 0xf4, 0x90, 0xa3, 0xe2, 0xe0, 0x90, 0x23, 0xf3, + 0x0d, 0x03, 0x16, 0xfb, 0xe6, 0x26, 0xf9, 0xe1, 0x4b, 0x63, 0xc8, 0x0f, 0x5f, 0xae, 0xc1, 0x82, + 0x48, 0x67, 0x59, 0x6b, 0x3b, 0x76, 0xea, 0x5b, 0xcb, 0xed, 0x04, 0x1c, 0xf7, 0xd5, 0x30, 0xff, + 0xd4, 0x80, 0x69, 0xed, 0x69, 0x08, 0xed, 0x07, 0x7b, 0x42, 0x23, 0x9a, 0x11, 0x65, 0xf2, 0x64, + 0x6e, 0x46, 0x0e, 0xe3, 0x1e, 0xef, 0xa6, 0x96, 0xb0, 0x2d, 0xf2, 0x78, 0xd3, 0x52, 0x2c, 0xa0, + 0x3c, 0x15, 0x17, 0xe1, 0x1f, 0x35, 0xcd, 0xeb, 0xa9, 0xb8, 0x48, 0x1b, 0x33, 0x08, 0x63, 0x47, + 0xcf, 0x34, 0x11, 0x8d, 0xa6, 0x25, 0x0e, 0xb5, 0xa8, 0xe5, 0xc2, 0x60, 0xe8, 0x0c, 0xe4, 0x89, + 0xdb, 0x10, 0x0a, 0xb8, 0xfa, 0x8c, 0xc4, 0x05, 0xb7, 0x81, 0x69, 0xb9, 0x79, 0x15, 0x66, 0x6a, + 0xa4, 0xee, 0x93, 0xf0, 0x79, 0x72, 0x30, 0xf4, 0x77, 0x29, 0x6e, 0x91, 0x83, 0xe4, 0x77, 0x29, + 0x68, 0x75, 0x5a, 0x6e, 0xfe, 0x9e, 0x01, 0x89, 0x3c, 0xae, 0x9a, 0xf7, 0xcb, 0x18, 0xe4, 0xfd, + 0x8a, 0xf9, 0x69, 0x72, 0x87, 0xfa, 0x69, 0x2e, 0x03, 0x6a, 0x59, 0x61, 0x7d, 0x2f, 0x96, 0x65, + 0x58, 0xd8, 0x3e, 0xd1, 0x43, 0xb4, 0x3e, 0x0c, 0x9c, 0x52, 0xcb, 0x7c, 0xc5, 0x80, 0xbe, 0x6f, + 0x92, 0xd2, 0x13, 0x9b, 0x88, 0x94, 0xff, 0xdc, 0x24, 0x54, 0x27, 0xb6, 0xcc, 0xf4, 0x2f, 0xe1, + 0xd4, 0x6e, 0x90, 0x9e, 0x27, 0x69, 0xc7, 0xf3, 0x27, 0x3b, 0xca, 0x6e, 0x58, 0x8b, 0x83, 0x71, + 0x12, 0xdf, 0x7c, 0x01, 0x4a, 0xf2, 0x5d, 0x23, 0x7b, 0x1c, 0x24, 0x2d, 0x51, 0xfd, 0x71, 0x10, + 0x35, 0x44, 0x19, 0x84, 0x0e, 0x53, 0xe0, 0xda, 0x97, 0xbc, 0x20, 0x94, 0x8f, 0x31, 0xb9, 0xbf, + 0xe9, 0xca, 0x3a, 0x2b, 0xc3, 0x0a, 0x6a, 0x2e, 0xc2, 0xbc, 0x72, 0x24, 0xf1, 0x45, 0x6f, 0x7e, + 0x3b, 0x0f, 0x33, 0xb1, 0x2f, 0x4d, 0xdd, 0x7b, 0xb2, 0x87, 0x9f, 0x96, 0x14, 0x87, 0x50, 0x7e, + 0x44, 0x87, 0x90, 0xee, 0x81, 0x2b, 0x1c, 0xaf, 0x07, 0xae, 0x98, 0x8d, 0x07, 0x2e, 0x84, 0x49, + 0xf1, 0x15, 0x5e, 0x11, 0xd3, 0xbc, 0x99, 0x51, 0x52, 0x02, 0xf1, 0xba, 0x97, 0x85, 0x71, 0x4b, + 0x01, 0x26, 0x59, 0x99, 0xdf, 0x2c, 0xc2, 0x5c, 0x3c, 0x4d, 0xc1, 0x10, 0x33, 0xf9, 0xae, 0xbe, + 0x99, 0x1c, 0xd1, 0x20, 0xce, 0x8f, 0x6b, 0x10, 0x17, 0xc6, 0x35, 0x88, 0x8b, 0x47, 0x30, 0x88, + 0xfb, 0xcd, 0xd9, 0x89, 0xa1, 0xcd, 0xd9, 0x0f, 0xa8, 0xdb, 0xdc, 0xc9, 0xd8, 0xf5, 0x47, 0x74, + 0x9b, 0x8b, 0xe2, 0xd3, 0xb0, 0xea, 0x35, 0x52, 0x6f, 0xc5, 0x4b, 0xf7, 0x50, 0xfc, 0xfd, 0xd4, + 0xcb, 0xd7, 0xd1, 0x7d, 0x6e, 0x6f, 0x1b, 0xe1, 0xe2, 0x35, 0xfa, 0xd0, 0x34, 0x3b, 0xfc, 0x20, + 0x7e, 0x70, 0xd6, 0x22, 0x10, 0xd6, 0xf1, 0xd8, 0x27, 0x86, 0xe2, 0xdf, 0x54, 0x62, 0xfe, 0x05, + 0xfd, 0x13, 0x43, 0x89, 0x6f, 0x30, 0x25, 0xf1, 0xcd, 0x6f, 0xe4, 0x61, 0x2e, 0x9e, 0x22, 0x1e, + 0xdd, 0x56, 0xfa, 0x79, 0x26, 0xa6, 0x01, 0x27, 0xab, 0x3d, 0xd4, 0x1f, 0x68, 0x6c, 0xf3, 0xcf, + 0x1f, 0xef, 0xa8, 0xac, 0x01, 0xc7, 0xc7, 0x58, 0x58, 0xb9, 0x82, 0x1d, 0xcb, 0x2a, 0x1f, 0x05, + 0x94, 0x8a, 0x1b, 0xdc, 0xcc, 0xb9, 0x47, 0x21, 0xa2, 0x8a, 0x15, 0xd6, 0xd8, 0x52, 0xf1, 0xbe, + 0x4f, 0x7c, 0x7b, 0xd7, 0x56, 0x9f, 0xb7, 0x61, 0xc2, 0xf3, 0x05, 0x51, 0x86, 0x15, 0xd4, 0x7c, + 0x25, 0x07, 0xd1, 0xc7, 0xbc, 0x58, 0xb6, 0xea, 0x40, 0x53, 0x1b, 0xc4, 0xb4, 0x5d, 0x1e, 0x37, + 0x25, 0x7c, 0x44, 0x51, 0x04, 0xbb, 0x68, 0x25, 0x38, 0xc6, 0xf1, 0xe7, 0xf0, 0x11, 0x2f, 0x0b, + 0xe6, 0x13, 0xcf, 0x5d, 0x32, 0x8f, 0x28, 0xfc, 0x4a, 0x1e, 0xa6, 0xd4, 0x83, 0x21, 0xf4, 0x3e, + 0x96, 0x68, 0x76, 0xcf, 0x93, 0xe9, 0x7f, 0xdf, 0xae, 0xa5, 0x83, 0xdd, 0xf3, 0x1a, 0x77, 0xbb, + 0xe5, 0x79, 0x85, 0xcc, 0x8b, 0xb0, 0xa8, 0x40, 0x95, 0xb4, 0x8e, 0xef, 0x24, 0x95, 0xb4, 0xeb, + 0x78, 0x03, 0xd3, 0x72, 0x74, 0x07, 0x26, 0xf7, 0x88, 0xd5, 0x20, 0xbe, 0x8c, 0x1d, 0xd8, 0xcc, + 0xe8, 0x91, 0xd3, 0x25, 0x46, 0x35, 0x1a, 0x06, 0xfe, 0x3f, 0xc0, 0x92, 0x1d, 0x3d, 0xa8, 0x76, + 0xbc, 0xc6, 0x41, 0x32, 0x7d, 0x6c, 0xd5, 0x6b, 0x1c, 0x60, 0x06, 0x41, 0xcf, 0xc2, 0x5c, 0x68, + 0xb7, 0x88, 0xd7, 0x09, 0xf5, 0x4f, 0x25, 0xe5, 0x23, 0xe7, 0xf1, 0x76, 0x0c, 0x8a, 0x13, 0xd8, + 0xf4, 0xa0, 0xbb, 0x19, 0x78, 0x2e, 0xcb, 0x09, 0x33, 0x11, 0xf7, 0x34, 0x5d, 0xae, 0x5d, 0xbd, + 0xc2, 0x52, 0xc2, 0x28, 0x0c, 0x8a, 0x6d, 0xb3, 0x57, 0x09, 0x3e, 0x11, 0x77, 0x37, 0x0b, 0xd1, + 0xdb, 0x51, 0x5e, 0x8e, 0x15, 0x86, 0x79, 0x1d, 0xe6, 0x13, 0x5d, 0x95, 0xea, 0xb0, 0x91, 0xae, + 0x0e, 0x0f, 0x97, 0xab, 0xf5, 0x8f, 0x0c, 0x58, 0xec, 0xdb, 0xbc, 0xc3, 0x86, 0xba, 0x26, 0x25, + 0x79, 0xee, 0xe8, 0x92, 0x3c, 0x3f, 0x9a, 0x24, 0xaf, 0xae, 0x7c, 0xe7, 0xcd, 0xb3, 0x0f, 0x7c, + 0xf7, 0xcd, 0xb3, 0x0f, 0x7c, 0xff, 0xcd, 0xb3, 0x0f, 0xbc, 0xd2, 0x3b, 0x6b, 0x7c, 0xa7, 0x77, + 0xd6, 0xf8, 0x6e, 0xef, 0xac, 0xf1, 0xfd, 0xde, 0x59, 0xe3, 0xc7, 0xbd, 0xb3, 0xc6, 0x1b, 0x3f, + 0x39, 0xfb, 0xc0, 0x8b, 0x25, 0xb9, 0x4c, 0xfe, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x98, 0xf2, 0x6f, + 0x46, 0xbd, 0x84, 0x00, 0x00, } func (m *ALBStatus) Marshal() (dAtA []byte, err error) { @@ -6084,6 +6086,30 @@ func (m *MetricResult) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.Metadata) > 0 { + keysForMetadata := make([]string, 0, len(m.Metadata)) + for k := range m.Metadata { + keysForMetadata = append(keysForMetadata, string(k)) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForMetadata) + for iNdEx := len(keysForMetadata) - 1; iNdEx >= 0; iNdEx-- { + v := m.Metadata[string(keysForMetadata[iNdEx])] + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintGenerated(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(keysForMetadata[iNdEx]) + copy(dAtA[i:], keysForMetadata[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(keysForMetadata[iNdEx]))) + i-- + dAtA[i] = 0xa + i = encodeVarintGenerated(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x62 + } + } i-- if m.DryRun { dAtA[i] = 1 @@ -9346,6 +9372,14 @@ func (m *MetricResult) Size() (n int) { n += 1 + sovGenerated(uint64(m.Error)) n += 1 + sovGenerated(uint64(m.ConsecutiveError)) n += 2 + if len(m.Metadata) > 0 { + for k, v := range m.Metadata { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovGenerated(uint64(len(k))) + 1 + len(v) + sovGenerated(uint64(len(v))) + n += mapEntrySize + 1 + sovGenerated(uint64(mapEntrySize)) + } + } return n } @@ -10912,6 +10946,16 @@ func (this *MetricResult) String() string { repeatedStringForMeasurements += strings.Replace(strings.Replace(f.String(), "Measurement", "Measurement", 1), `&`, ``, 1) + "," } repeatedStringForMeasurements += "}" + keysForMetadata := make([]string, 0, len(this.Metadata)) + for k := range this.Metadata { + keysForMetadata = append(keysForMetadata, k) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForMetadata) + mapStringForMetadata := "map[string]string{" + for _, k := range keysForMetadata { + mapStringForMetadata += fmt.Sprintf("%v: %v,", k, this.Metadata[k]) + } + mapStringForMetadata += "}" s := strings.Join([]string{`&MetricResult{`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, `Phase:` + fmt.Sprintf("%v", this.Phase) + `,`, @@ -10924,6 +10968,7 @@ func (this *MetricResult) String() string { `Error:` + fmt.Sprintf("%v", this.Error) + `,`, `ConsecutiveError:` + fmt.Sprintf("%v", this.ConsecutiveError) + `,`, `DryRun:` + fmt.Sprintf("%v", this.DryRun) + `,`, + `Metadata:` + mapStringForMetadata + `,`, `}`, }, "") return s @@ -20871,6 +20916,133 @@ func (m *MetricResult) Unmarshal(dAtA []byte) error { } } m.DryRun = bool(v != 0) + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Metadata", 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.Metadata == nil { + m.Metadata = make(map[string]string) + } + var mapkey string + var mapvalue string + for iNdEx < postIndex { + entryPreIndex := 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) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthGenerated + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthGenerated + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthGenerated + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthGenerated + } + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + } else { + iNdEx = entryPreIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Metadata[mapkey] = mapvalue + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) diff --git a/pkg/apis/rollouts/v1alpha1/generated.proto b/pkg/apis/rollouts/v1alpha1/generated.proto index f8277f9f84..e4e18c0d55 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.proto +++ b/pkg/apis/rollouts/v1alpha1/generated.proto @@ -922,6 +922,11 @@ message MetricResult { // DryRun indicates whether this metric is running in a dry-run mode or not optional bool dryRun = 11; + + // Metadata stores additional metadata about this metric. It is used by different providers to store + // the final state which gets used while taking measurements. For example, Prometheus uses this field + // to store the final resolved query after substituting the template arguments. + map metadata = 12; } // NewRelicMetric defines the newrelic query to perform canary analysis diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index 398d3eee33..42164f2606 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -2709,6 +2709,22 @@ func schema_pkg_apis_rollouts_v1alpha1_MetricResult(ref common.ReferenceCallback Format: "", }, }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "Metadata stores additional metadata about this metric. It is used by different providers to store the final state which gets used while taking measurements. For example, Prometheus uses this field to store the final resolved query after substituting the template arguments.", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, }, Required: []string{"name", "phase"}, }, From e79296a4699be4b15cc1cf16025b668c8355dbfb Mon Sep 17 00:00:00 2001 From: Andrii Perenesenko Date: Wed, 2 Feb 2022 15:01:34 -0800 Subject: [PATCH 083/175] fix: using our own pod template hashing (#1809) * fix: implement pod template hash calculate function Signed-off-by: Andrii Perenesenko * fix: using new hashing for FindNewReplicaSet and other places Signed-off-by: Andrii Perenesenko * fix tests Signed-off-by: Andrii Perenesenko * fix tests with deprecated hash Signed-off-by: Andrii Perenesenko * test TestFindNewReplicaSet, TestHashUtils Signed-off-by: Andrii Perenesenko * fix the doc for ComputePodTemplateHash Signed-off-by: Andrii Perenesenko * test for ComputePodTemplateHash with collisionCount Signed-off-by: Andrii Perenesenko * refactoring avoid double FindNewReplicaSet call: pass newRS as a parameter to the FindOldReplicaSets as it using only right after the FindNewReplicaSet Signed-off-by: Andrii Perenesenko * fix time dependent flaky test Signed-off-by: Andrii Perenesenko --- experiments/replicaset.go | 4 +-- rollout/analysis_test.go | 6 ++-- rollout/bluegreen_test.go | 4 +-- rollout/canary_test.go | 10 +++--- rollout/controller.go | 2 +- rollout/controller_test.go | 6 ++-- rollout/experiment.go | 15 ++++----- rollout/sync.go | 5 +-- utils/conditions/rollouts_test.go | 8 ++--- utils/experiment/experiment.go | 5 +-- utils/experiment/experiment_test.go | 10 +++--- utils/hash/hash.go | 34 ++++++++++++++++++++ utils/hash/hash_test.go | 48 +++++++++++++++++++++++++++++ utils/replicaset/replicaset.go | 38 +++++++++++++++-------- utils/replicaset/replicaset_test.go | 33 ++++++++++++++++---- 15 files changed, 175 insertions(+), 53 deletions(-) create mode 100644 utils/hash/hash.go create mode 100644 utils/hash/hash_test.go diff --git a/experiments/replicaset.go b/experiments/replicaset.go index 1b9bd7c16f..d91843a03a 100644 --- a/experiments/replicaset.go +++ b/experiments/replicaset.go @@ -13,13 +13,13 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" patchtypes "k8s.io/apimachinery/pkg/types" - "k8s.io/kubernetes/pkg/controller" labelsutil "k8s.io/kubernetes/pkg/util/labels" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/conditions" "github.com/argoproj/argo-rollouts/utils/defaults" experimentutil "github.com/argoproj/argo-rollouts/utils/experiment" + "github.com/argoproj/argo-rollouts/utils/hash" logutil "github.com/argoproj/argo-rollouts/utils/log" "github.com/argoproj/argo-rollouts/utils/record" replicasetutil "github.com/argoproj/argo-rollouts/utils/replicaset" @@ -161,7 +161,7 @@ func newReplicaSetFromTemplate(experiment *v1alpha1.Experiment, template v1alpha delete(newRSTemplate.Labels, v1alpha1.DefaultRolloutUniqueLabelKey) } } - podHash := controller.ComputeHash(&newRSTemplate, collisionCount) + podHash := hash.ComputePodTemplateHash(&newRSTemplate, collisionCount) newRSTemplate.Labels = labelsutil.CloneAndAddLabel(newRSTemplate.Labels, v1alpha1.DefaultRolloutUniqueLabelKey, podHash) // Add podTemplateHash label to selector. diff --git a/rollout/analysis_test.go b/rollout/analysis_test.go index 9f25d1c5f7..ed21a4c848 100644 --- a/rollout/analysis_test.go +++ b/rollout/analysis_test.go @@ -8,13 +8,13 @@ import ( "testing" "time" + "github.com/argoproj/argo-rollouts/utils/hash" timeutil "github.com/argoproj/argo-rollouts/utils/time" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" - "k8s.io/kubernetes/pkg/controller" "k8s.io/utils/pointer" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" @@ -58,7 +58,7 @@ func clusterAnalysisTemplate(name string) *v1alpha1.ClusterAnalysisTemplate { func clusterAnalysisRun(cat *v1alpha1.ClusterAnalysisTemplate, analysisRunType string, r *v1alpha1.Rollout) *v1alpha1.AnalysisRun { labels := map[string]string{} - podHash := controller.ComputeHash(&r.Spec.Template, r.Status.CollisionCount) + podHash := hash.ComputePodTemplateHash(&r.Spec.Template, r.Status.CollisionCount) var name string if analysisRunType == v1alpha1.RolloutTypeStepLabel { labels = analysisutil.StepLabels(*r.Status.CurrentStepIndex, podHash, "") @@ -89,7 +89,7 @@ func clusterAnalysisRun(cat *v1alpha1.ClusterAnalysisTemplate, analysisRunType s func analysisRun(at *v1alpha1.AnalysisTemplate, analysisRunType string, r *v1alpha1.Rollout) *v1alpha1.AnalysisRun { labels := map[string]string{} - podHash := controller.ComputeHash(&r.Spec.Template, r.Status.CollisionCount) + podHash := hash.ComputePodTemplateHash(&r.Spec.Template, r.Status.CollisionCount) var name string if analysisRunType == v1alpha1.RolloutTypeStepLabel { labels = analysisutil.StepLabels(*r.Status.CurrentStepIndex, podHash, "") diff --git a/rollout/bluegreen_test.go b/rollout/bluegreen_test.go index 5bd965df61..5cae668da3 100644 --- a/rollout/bluegreen_test.go +++ b/rollout/bluegreen_test.go @@ -11,12 +11,12 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" core "k8s.io/client-go/testing" - "k8s.io/kubernetes/pkg/controller" "k8s.io/utils/pointer" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/annotations" "github.com/argoproj/argo-rollouts/utils/conditions" + "github.com/argoproj/argo-rollouts/utils/hash" rolloututil "github.com/argoproj/argo-rollouts/utils/rollout" timeutil "github.com/argoproj/argo-rollouts/utils/time" ) @@ -34,7 +34,7 @@ func newBlueGreenRollout(name string, replicas int, revisionHistoryLimit *int32, AbortScaleDownDelaySeconds: &abortScaleDownDelaySeconds, } rollout.Status.CurrentStepHash = conditions.ComputeStepHash(rollout) - rollout.Status.CurrentPodHash = controller.ComputeHash(&rollout.Spec.Template, rollout.Status.CollisionCount) + rollout.Status.CurrentPodHash = hash.ComputePodTemplateHash(&rollout.Spec.Template, rollout.Status.CollisionCount) return rollout } diff --git a/rollout/canary_test.go b/rollout/canary_test.go index 0961dad44c..9b4504000d 100644 --- a/rollout/canary_test.go +++ b/rollout/canary_test.go @@ -15,13 +15,13 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" k8sinformers "k8s.io/client-go/informers" k8sfake "k8s.io/client-go/kubernetes/fake" - "k8s.io/kubernetes/pkg/controller" "k8s.io/utils/pointer" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned/fake" "github.com/argoproj/argo-rollouts/utils/annotations" "github.com/argoproj/argo-rollouts/utils/conditions" + "github.com/argoproj/argo-rollouts/utils/hash" logutil "github.com/argoproj/argo-rollouts/utils/log" "github.com/argoproj/argo-rollouts/utils/record" replicasetutil "github.com/argoproj/argo-rollouts/utils/replicaset" @@ -39,7 +39,7 @@ func newCanaryRollout(name string, replicas int, revisionHistoryLimit *int32, st } rollout.Status.CurrentStepIndex = stepIndex rollout.Status.CurrentStepHash = conditions.ComputeStepHash(rollout) - rollout.Status.CurrentPodHash = controller.ComputeHash(&rollout.Spec.Template, rollout.Status.CollisionCount) + rollout.Status.CurrentPodHash = hash.ComputePodTemplateHash(&rollout.Spec.Template, rollout.Status.CollisionCount) rollout.Status.Selector = metav1.FormatLabelSelector(rollout.Spec.Selector) rollout.Status.Phase, rollout.Status.Message = rolloututil.CalculateRolloutPhase(rollout.Spec, rollout.Status) return rollout @@ -54,7 +54,7 @@ func bumpVersion(rollout *v1alpha1.Rollout) *v1alpha1.Rollout { newRevisionStr := strconv.FormatInt(int64(newRevision), 10) annotations.SetRolloutRevision(newRollout, newRevisionStr) newRollout.Spec.Template.Spec.Containers[0].Image = "foo/bar" + newRevisionStr - newRollout.Status.CurrentPodHash = controller.ComputeHash(&newRollout.Spec.Template, newRollout.Status.CollisionCount) + newRollout.Status.CurrentPodHash = hash.ComputePodTemplateHash(&newRollout.Spec.Template, newRollout.Status.CollisionCount) newRollout.Status.CurrentStepHash = conditions.ComputeStepHash(newRollout) newRollout.Status.Phase, newRollout.Status.Message = rolloututil.CalculateRolloutPhase(newRollout.Spec, newRollout.Status) return newRollout @@ -841,7 +841,7 @@ func TestRollBackToStable(t *testing.T) { } }` newConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs1, false, "") - expectedPatch := fmt.Sprintf(expectedPatchWithoutSub, controller.ComputeHash(&r2.Spec.Template, r2.Status.CollisionCount), newConditions) + expectedPatch := fmt.Sprintf(expectedPatchWithoutSub, hash.ComputePodTemplateHash(&r2.Spec.Template, r2.Status.CollisionCount), newConditions) patch := f.getPatchedRollout(patchIndex) assert.Equal(t, calculatePatch(r2, expectedPatch), patch) } @@ -929,7 +929,7 @@ func TestRollBackToStableAndStepChange(t *testing.T) { "conditions": %s } }` - newPodHash := controller.ComputeHash(&r2.Spec.Template, r2.Status.CollisionCount) + newPodHash := hash.ComputePodTemplateHash(&r2.Spec.Template, r2.Status.CollisionCount) newStepHash := conditions.ComputeStepHash(r2) newConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs1, false, "") expectedPatch := fmt.Sprintf(expectedPatchWithoutSub, newPodHash, newStepHash, newConditions) diff --git a/rollout/controller.go b/rollout/controller.go index 46ca2e1099..e17fbafc37 100644 --- a/rollout/controller.go +++ b/rollout/controller.go @@ -433,7 +433,7 @@ func (c *Controller) newRolloutContext(rollout *v1alpha1.Rollout) (*rolloutConte } newRS := replicasetutil.FindNewReplicaSet(rollout, rsList) - olderRSs := replicasetutil.FindOldReplicaSets(rollout, rsList) + olderRSs := replicasetutil.FindOldReplicaSets(rollout, rsList, newRS) stableRS := replicasetutil.GetStableRS(rollout, newRS, olderRSs) otherRSs := replicasetutil.GetOtherRSs(rollout, newRS, stableRS, rsList) diff --git a/rollout/controller_test.go b/rollout/controller_test.go index acb3c6b395..f8e922ee3b 100644 --- a/rollout/controller_test.go +++ b/rollout/controller_test.go @@ -34,7 +34,6 @@ import ( "k8s.io/client-go/tools/cache" "k8s.io/client-go/util/workqueue" corev1defaults "k8s.io/kubernetes/pkg/apis/core/v1" - "k8s.io/kubernetes/pkg/controller" "k8s.io/utils/pointer" "github.com/argoproj/argo-rollouts/controller/metrics" @@ -47,6 +46,7 @@ import ( "github.com/argoproj/argo-rollouts/utils/annotations" "github.com/argoproj/argo-rollouts/utils/conditions" "github.com/argoproj/argo-rollouts/utils/defaults" + "github.com/argoproj/argo-rollouts/utils/hash" ingressutil "github.com/argoproj/argo-rollouts/utils/ingress" istioutil "github.com/argoproj/argo-rollouts/utils/istio" "github.com/argoproj/argo-rollouts/utils/queue" @@ -401,7 +401,7 @@ func updateBaseRolloutStatus(r *v1alpha1.Rollout, availableReplicas, updatedRepl } func newReplicaSet(r *v1alpha1.Rollout, replicas int) *appsv1.ReplicaSet { - podHash := controller.ComputeHash(&r.Spec.Template, r.Status.CollisionCount) + podHash := hash.ComputePodTemplateHash(&r.Spec.Template, r.Status.CollisionCount) rsLabels := map[string]string{ v1alpha1.DefaultRolloutUniqueLabelKey: podHash, } @@ -1300,7 +1300,7 @@ func TestPodTemplateHashEquivalence(t *testing.T) { var err error // NOTE: This test will fail on every k8s library upgrade. // To fix it, update expectedReplicaSetName to match the new hash. - expectedReplicaSetName := "guestbook-859fc5d686" + expectedReplicaSetName := "guestbook-6c5667f666" r1 := newBlueGreenRollout("guestbook", 1, nil, "active", "") r1Resources := ` diff --git a/rollout/experiment.go b/rollout/experiment.go index 67b7e534b4..aeac6e8049 100644 --- a/rollout/experiment.go +++ b/rollout/experiment.go @@ -4,19 +4,20 @@ import ( "context" "fmt" + appsv1 "k8s.io/api/apps/v1" + "k8s.io/apimachinery/pkg/api/errors" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" analysisutil "github.com/argoproj/argo-rollouts/utils/analysis" "github.com/argoproj/argo-rollouts/utils/annotations" "github.com/argoproj/argo-rollouts/utils/defaults" experimentutil "github.com/argoproj/argo-rollouts/utils/experiment" + "github.com/argoproj/argo-rollouts/utils/hash" "github.com/argoproj/argo-rollouts/utils/record" replicasetutil "github.com/argoproj/argo-rollouts/utils/replicaset" - appsv1 "k8s.io/api/apps/v1" - "k8s.io/apimachinery/pkg/api/errors" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/kubernetes/pkg/controller" ) // GetExperimentFromTemplate takes the canary experiment step and converts it to an experiment @@ -25,7 +26,7 @@ func GetExperimentFromTemplate(r *v1alpha1.Rollout, stableRS, newRS *appsv1.Repl if step == nil { return nil, nil } - podHash := controller.ComputeHash(&r.Spec.Template, r.Status.CollisionCount) + podHash := hash.ComputePodTemplateHash(&r.Spec.Template, r.Status.CollisionCount) currentStep := int32(0) if r.Status.CurrentStepIndex != nil { currentStep = *r.Status.CurrentStepIndex diff --git a/rollout/sync.go b/rollout/sync.go index 337cfa462a..5472dbb526 100644 --- a/rollout/sync.go +++ b/rollout/sync.go @@ -23,6 +23,7 @@ import ( "github.com/argoproj/argo-rollouts/utils/defaults" "github.com/argoproj/argo-rollouts/utils/diff" experimentutil "github.com/argoproj/argo-rollouts/utils/experiment" + "github.com/argoproj/argo-rollouts/utils/hash" logutil "github.com/argoproj/argo-rollouts/utils/log" "github.com/argoproj/argo-rollouts/utils/record" replicasetutil "github.com/argoproj/argo-rollouts/utils/replicaset" @@ -139,7 +140,7 @@ func (c *rolloutContext) createDesiredReplicaSet() (*appsv1.ReplicaSet, error) { newRSTemplate := *c.rollout.Spec.Template.DeepCopy() // Add default anti-affinity rule if antiAffinity bool set and RSTemplate meets requirements newRSTemplate.Spec.Affinity = replicasetutil.GenerateReplicaSetAffinity(*c.rollout) - podTemplateSpecHash := controller.ComputeHash(&c.rollout.Spec.Template, c.rollout.Status.CollisionCount) + podTemplateSpecHash := hash.ComputePodTemplateHash(&c.rollout.Spec.Template, c.rollout.Status.CollisionCount) newRSTemplate.Labels = labelsutil.CloneAndAddLabel(c.rollout.Spec.Template.Labels, v1alpha1.DefaultRolloutUniqueLabelKey, podTemplateSpecHash) // Add podTemplateHash label to selector. newRSSelector := labelsutil.CloneSelectorAndAddLabel(c.rollout.Spec.Selector, v1alpha1.DefaultRolloutUniqueLabelKey, podTemplateSpecHash) @@ -378,7 +379,7 @@ func (c *rolloutContext) calculateBaseStatus() v1alpha1.RolloutStatus { // newRS potentially might be nil when called by syncReplicasOnly(). For this // to happen, the user would have had to simultaneously change the number of replicas, and // the pod template spec at the same time. - currentPodHash = controller.ComputeHash(&c.rollout.Spec.Template, c.rollout.Status.CollisionCount) + currentPodHash = hash.ComputePodTemplateHash(&c.rollout.Spec.Template, c.rollout.Status.CollisionCount) c.log.Infof("Assuming %s for new replicaset pod hash", currentPodHash) } else { currentPodHash = c.newRS.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] diff --git a/utils/conditions/rollouts_test.go b/utils/conditions/rollouts_test.go index b8376a027f..f6e3e02550 100644 --- a/utils/conditions/rollouts_test.go +++ b/utils/conditions/rollouts_test.go @@ -8,10 +8,10 @@ import ( "github.com/stretchr/testify/assert" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/kubernetes/pkg/controller" "k8s.io/utils/pointer" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + "github.com/argoproj/argo-rollouts/utils/hash" ) var ( @@ -363,7 +363,7 @@ func TestRolloutComplete(t *testing.T) { }, } r.Generation = 123 - podHash := controller.ComputeHash(&r.Spec.Template, r.Status.CollisionCount) + podHash := hash.ComputePodTemplateHash(&r.Spec.Template, r.Status.CollisionCount) r.Status.CurrentPodHash = podHash return r } @@ -411,13 +411,13 @@ func TestRolloutComplete(t *testing.T) { { name: "BlueGreen complete", // update hash to status.CurrentPodHash after k8s library update - r: blueGreenRollout(5, 5, 5, 5, true, "78957574d7", "78957574d7"), + r: blueGreenRollout(5, 5, 5, 5, true, "76bbb58f74", "76bbb58f74"), expected: true, }, { name: "BlueGreen complete with extra old replicas", // update hash to status.CurrentPodHash after k8s library update - r: blueGreenRollout(5, 6, 5, 5, true, "78957574d7", "78957574d7"), + r: blueGreenRollout(5, 6, 5, 5, true, "76bbb58f74", "76bbb58f74"), expected: true, }, { diff --git a/utils/experiment/experiment.go b/utils/experiment/experiment.go index cf7b4b6344..3bd3d07a96 100644 --- a/utils/experiment/experiment.go +++ b/utils/experiment/experiment.go @@ -8,11 +8,11 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" patchtypes "k8s.io/apimachinery/pkg/types" - "k8s.io/kubernetes/pkg/controller" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" rolloutsclient "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned/typed/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/defaults" + "github.com/argoproj/argo-rollouts/utils/hash" timeutil "github.com/argoproj/argo-rollouts/utils/time" ) @@ -131,8 +131,9 @@ func GetCollisionCountForTemplate(experiment *v1alpha1.Experiment, template v1al // ReplicasetNameFromExperiment gets the replicaset name based off of the experiment and the template func ReplicasetNameFromExperiment(experiment *v1alpha1.Experiment, template v1alpha1.TemplateSpec) string { + // todo: review this method for deletion as it's not using collisionCount := GetCollisionCountForTemplate(experiment, template) - podTemplateSpecHash := controller.ComputeHash(&template.Template, collisionCount) + podTemplateSpecHash := hash.ComputePodTemplateHash(&template.Template, collisionCount) return fmt.Sprintf("%s-%s-%s", experiment.Name, template.Name, podTemplateSpecHash) } diff --git a/utils/experiment/experiment_test.go b/utils/experiment/experiment_test.go index 1b9ed861da..2c87bda888 100644 --- a/utils/experiment/experiment_test.go +++ b/utils/experiment/experiment_test.go @@ -5,13 +5,14 @@ import ( "testing" "time" - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" - "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned/fake" "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" kubetesting "k8s.io/client-go/testing" "k8s.io/utils/pointer" + + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned/fake" ) func TestHasFinished(t *testing.T) { @@ -90,6 +91,7 @@ func TestGetTemplateStatusMapping(t *testing.T) { assert.Equal(t, int32(1), mapping["test"].Replicas) assert.Equal(t, int32(2), mapping["test2"].Replicas) } + func TestReplicaSetNameFromExperiment(t *testing.T) { templateName := "template" template := v1alpha1.TemplateSpec{ @@ -100,14 +102,14 @@ func TestReplicaSetNameFromExperiment(t *testing.T) { Name: "foo", }, } - assert.Equal(t, "foo-template-78957574d7", ReplicasetNameFromExperiment(e, template)) + assert.Equal(t, "foo-template-76bbb58f74", ReplicasetNameFromExperiment(e, template)) newTemplateStatus := v1alpha1.TemplateStatus{ Name: templateName, CollisionCount: pointer.Int32Ptr(1), } e.Status.TemplateStatuses = append(e.Status.TemplateStatuses, newTemplateStatus) - assert.Equal(t, "foo-template-db98f55f8", ReplicasetNameFromExperiment(e, template)) + assert.Equal(t, "foo-template-688c48b575", ReplicasetNameFromExperiment(e, template)) } func TestExperimentByCreationTimestamp(t *testing.T) { diff --git a/utils/hash/hash.go b/utils/hash/hash.go new file mode 100644 index 0000000000..52d82d3cc7 --- /dev/null +++ b/utils/hash/hash.go @@ -0,0 +1,34 @@ +package hash + +import ( + "encoding/binary" + "encoding/json" + "fmt" + "hash/fnv" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/rand" +) + +// ComputePodTemplateHash returns a hash value calculated from pod template. +// The hash will be safe encoded to avoid bad words. +func ComputePodTemplateHash(template *corev1.PodTemplateSpec, collisionCount *int32) string { + podTemplateSpecHasher := fnv.New32a() + stepsBytes, err := json.Marshal(template) + if err != nil { + panic(err) + } + _, err = podTemplateSpecHasher.Write(stepsBytes) + if err != nil { + panic(err) + } + if collisionCount != nil { + collisionCountBytes := make([]byte, 8) + binary.LittleEndian.PutUint32(collisionCountBytes, uint32(*collisionCount)) + _, err = podTemplateSpecHasher.Write(collisionCountBytes) + if err != nil { + panic(err) + } + } + return rand.SafeEncodeString(fmt.Sprint(podTemplateSpecHasher.Sum32())) +} diff --git a/utils/hash/hash_test.go b/utils/hash/hash_test.go new file mode 100644 index 0000000000..8a0edf11f4 --- /dev/null +++ b/utils/hash/hash_test.go @@ -0,0 +1,48 @@ +package hash + +import ( + "testing" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/pointer" +) + +func TestHashUtils(t *testing.T) { + templateRed := generatePodTemplate("red") + hashRed := ComputePodTemplateHash(&templateRed, nil) + template := generatePodTemplate("red") + + t.Run("HashForSameTemplates", func(t *testing.T) { + podHash := ComputePodTemplateHash(&template, nil) + assert.Equal(t, hashRed, podHash) + }) + t.Run("HashForDifferentTemplates", func(t *testing.T) { + podHash := ComputePodTemplateHash(&template, pointer.Int32(1)) + assert.NotEqual(t, hashRed, podHash) + }) +} + +func generatePodTemplate(image string) corev1.PodTemplateSpec { + podLabels := map[string]string{"name": image} + + return corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: podLabels, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: image, + Image: image, + ImagePullPolicy: corev1.PullAlways, + TerminationMessagePath: corev1.TerminationMessagePathDefault, + }, + }, + DNSPolicy: corev1.DNSClusterFirst, + RestartPolicy: corev1.RestartPolicyAlways, + SecurityContext: &corev1.PodSecurityContext{}, + }, + } +} diff --git a/utils/replicaset/replicaset.go b/utils/replicaset/replicaset.go index 2292eaa1bc..333b5117fd 100644 --- a/utils/replicaset/replicaset.go +++ b/utils/replicaset/replicaset.go @@ -24,6 +24,7 @@ import ( "github.com/argoproj/argo-rollouts/utils/annotations" "github.com/argoproj/argo-rollouts/utils/conditions" "github.com/argoproj/argo-rollouts/utils/defaults" + "github.com/argoproj/argo-rollouts/utils/hash" logutil "github.com/argoproj/argo-rollouts/utils/log" timeutil "github.com/argoproj/argo-rollouts/utils/time" ) @@ -39,12 +40,17 @@ func FindNewReplicaSet(rollout *v1alpha1.Rollout, rsList []*appsv1.ReplicaSet) * } rsList = newRSList sort.Sort(controller.ReplicaSetsByCreationTimestamp(rsList)) - // First, attempt to find the replicaset by the replicaset naming formula - replicaSetName := fmt.Sprintf("%s-%s", rollout.Name, controller.ComputeHash(&rollout.Spec.Template, rollout.Status.CollisionCount)) - for _, rs := range rsList { - if rs.Name == replicaSetName { - return rs - } + // First, attempt to find the replicaset using our own hashing + podHash := hash.ComputePodTemplateHash(&rollout.Spec.Template, rollout.Status.CollisionCount) + if rs := searchRsByHash(rsList, podHash); rs != nil { + return rs + } + // Second, attempt to find the replicaset with old hash implementation + oldHash := controller.ComputeHash(&rollout.Spec.Template, rollout.Status.CollisionCount) + if rs := searchRsByHash(rsList, oldHash); rs != nil { + logCtx := logutil.WithRollout(rollout) + logCtx.Infof("ComputePodTemplateHash hash changed (new hash: %s, old hash: %s)", podHash, oldHash) + return rs } // Iterate the ReplicaSet list again, this time doing a deep equal against the template specs. // This covers the corner case in which the reason we did not find the replicaset, was because @@ -61,7 +67,7 @@ func FindNewReplicaSet(rollout *v1alpha1.Rollout, rsList []*appsv1.ReplicaSet) * desired := rollout.Spec.Template.DeepCopy() if PodTemplateEqualIgnoreHash(live, desired) { logCtx := logutil.WithRollout(rollout) - logCtx.Infof("ComputeHash change detected (expected: %s, actual: %s)", replicaSetName, rs.Name) + logCtx.Infof("ComputePodTemplateHash hash changed (expected: %s, actual: %s)", podHash, rs.Labels[v1alpha1.DefaultRolloutUniqueLabelKey]) return rs } } @@ -69,6 +75,15 @@ func FindNewReplicaSet(rollout *v1alpha1.Rollout, rsList []*appsv1.ReplicaSet) * return nil } +func searchRsByHash(rsList []*appsv1.ReplicaSet, hash string) *appsv1.ReplicaSet { + for _, rs := range rsList { + if rs.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] == hash { + return rs + } + } + return nil +} + func GetRolloutAffinity(rollout v1alpha1.Rollout) *v1alpha1.AntiAffinity { var antiAffinityStrategy *v1alpha1.AntiAffinity if rollout.Spec.Strategy.BlueGreen != nil && rollout.Spec.Strategy.BlueGreen.AntiAffinity != nil { @@ -87,7 +102,7 @@ func GetRolloutAffinity(rollout v1alpha1.Rollout) *v1alpha1.AntiAffinity { func GenerateReplicaSetAffinity(rollout v1alpha1.Rollout) *corev1.Affinity { antiAffinityStrategy := GetRolloutAffinity(rollout) - currentPodHash := controller.ComputeHash(&rollout.Spec.Template, rollout.Status.CollisionCount) + currentPodHash := hash.ComputePodTemplateHash(&rollout.Spec.Template, rollout.Status.CollisionCount) affinitySpec := rollout.Spec.Template.Spec.Affinity.DeepCopy() if antiAffinityStrategy != nil && rollout.Status.StableRS != "" && rollout.Status.StableRS != currentPodHash { antiAffinityRule := CreateInjectedAntiAffinityRule(rollout) @@ -193,7 +208,7 @@ func RemoveInjectedAntiAffinityRule(affinity *corev1.Affinity, rollout v1alpha1. func IfInjectedAntiAffinityRuleNeedsUpdate(affinity *corev1.Affinity, rollout v1alpha1.Rollout) bool { _, podAffinityTerm := HasInjectedAntiAffinityRule(affinity, rollout) - currentPodHash := controller.ComputeHash(&rollout.Spec.Template, rollout.Status.CollisionCount) + currentPodHash := hash.ComputePodTemplateHash(&rollout.Spec.Template, rollout.Status.CollisionCount) if podAffinityTerm != nil && rollout.Status.StableRS != currentPodHash { for _, labelSelectorRequirement := range podAffinityTerm.LabelSelector.MatchExpressions { if labelSelectorRequirement.Key == v1alpha1.DefaultRolloutUniqueLabelKey && labelSelectorRequirement.Values[0] != rollout.Status.StableRS { @@ -216,9 +231,8 @@ func NeedsRestart(rollout *v1alpha1.Rollout) bool { } // FindOldReplicaSets returns the old replica sets targeted by the given Rollout, with the given slice of RSes. -func FindOldReplicaSets(rollout *v1alpha1.Rollout, rsList []*appsv1.ReplicaSet) []*appsv1.ReplicaSet { +func FindOldReplicaSets(rollout *v1alpha1.Rollout, rsList []*appsv1.ReplicaSet, newRS *appsv1.ReplicaSet) []*appsv1.ReplicaSet { var allRSs []*appsv1.ReplicaSet - newRS := FindNewReplicaSet(rollout, rsList) for _, rs := range rsList { // Filter out new replica set if newRS != nil && rs.UID == newRS.UID { @@ -456,7 +470,7 @@ func CheckPodSpecChange(rollout *v1alpha1.Rollout, newRS *appsv1.ReplicaSet) boo if rollout.Status.CurrentPodHash == "" { return false } - podHash := controller.ComputeHash(&rollout.Spec.Template, rollout.Status.CollisionCount) + podHash := hash.ComputePodTemplateHash(&rollout.Spec.Template, rollout.Status.CollisionCount) if newRS != nil { podHash = GetPodTemplateHash(newRS) } diff --git a/utils/replicaset/replicaset_test.go b/utils/replicaset/replicaset_test.go index ada18a8c1b..f1a2a80fd7 100644 --- a/utils/replicaset/replicaset_test.go +++ b/utils/replicaset/replicaset_test.go @@ -23,6 +23,7 @@ import ( "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/annotations" "github.com/argoproj/argo-rollouts/utils/conditions" + "github.com/argoproj/argo-rollouts/utils/hash" timeutil "github.com/argoproj/argo-rollouts/utils/time" ) @@ -60,14 +61,14 @@ func generateRollout(image string) v1alpha1.Rollout { // generateRS creates a replica set, with the input rollout's template as its template func generateRS(rollout v1alpha1.Rollout) appsv1.ReplicaSet { template := rollout.Spec.Template.DeepCopy() - podTemplateHash := controller.ComputeHash(&rollout.Spec.Template, nil) + podTemplateHash := hash.ComputePodTemplateHash(&rollout.Spec.Template, nil) template.Labels = map[string]string{ v1alpha1.DefaultRolloutUniqueLabelKey: podTemplateHash, } return appsv1.ReplicaSet{ ObjectMeta: metav1.ObjectMeta{ UID: uuid.NewUUID(), - Name: fmt.Sprintf("%s-%s", rollout.Name, controller.ComputeHash(&rollout.Spec.Template, nil)), + Name: fmt.Sprintf("%s-%s", rollout.Name, podTemplateHash), Labels: template.Labels, }, Spec: appsv1.ReplicaSetSpec{ @@ -78,6 +79,26 @@ func generateRS(rollout v1alpha1.Rollout) appsv1.ReplicaSet { } } +func TestFindNewReplicaSet(t *testing.T) { + ro := generateRollout("red") + rs1 := generateRS(ro) + rs1.Labels["name"] = "red" + *(rs1.Spec.Replicas) = 1 + + t.Run("FindNewReplicaSet by hash", func(t *testing.T) { + // rs has the current hash + rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] = hash.ComputePodTemplateHash(&ro.Spec.Template, ro.Status.CollisionCount) + actual := FindNewReplicaSet(&ro, []*appsv1.ReplicaSet{&rs1}) + assert.Equal(t, &rs1, actual) + }) + t.Run("FindNewReplicaSet by deprecated hash", func(t *testing.T) { + // rs has the deprecated hash + rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] = controller.ComputeHash(&ro.Spec.Template, ro.Status.CollisionCount) + actual := FindNewReplicaSet(&ro, []*appsv1.ReplicaSet{&rs1}) + assert.Equal(t, &rs1, actual) + }) +} + func TestFindOldReplicaSets(t *testing.T) { now := metav1.Now() before := metav1.Time{Time: now.Add(-time.Minute)} @@ -85,7 +106,7 @@ func TestFindOldReplicaSets(t *testing.T) { rollout := generateRollout("nginx") newRS := generateRS(rollout) *(newRS.Spec.Replicas) = 1 - newRS.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] = "hash" + newRS.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] = hash.ComputePodTemplateHash(&rollout.Spec.Template, rollout.Status.CollisionCount) newRS.CreationTimestamp = now oldRollout := generateRollout("nginx") @@ -122,7 +143,7 @@ func TestFindOldReplicaSets(t *testing.T) { for _, test := range tests { t.Run(test.Name, func(t *testing.T) { - allRS := FindOldReplicaSets(&test.rollout, test.rsList) + allRS := FindOldReplicaSets(&test.rollout, test.rsList, &newRS) sort.Sort(controller.ReplicaSetsByCreationTimestamp(allRS)) sort.Sort(controller.ReplicaSetsByCreationTimestamp(test.expected)) if !reflect.DeepEqual(allRS, test.expected) { @@ -637,7 +658,7 @@ func TestCheckPodSpecChange(t *testing.T) { ro := generateRollout("nginx") rs := generateRS(ro) assert.False(t, CheckPodSpecChange(&ro, &rs)) - ro.Status.CurrentPodHash = controller.ComputeHash(&ro.Spec.Template, ro.Status.CollisionCount) + ro.Status.CurrentPodHash = hash.ComputePodTemplateHash(&ro.Spec.Template, ro.Status.CollisionCount) assert.False(t, CheckPodSpecChange(&ro, &rs)) ro.Status.CurrentPodHash = "different-hash" @@ -828,7 +849,7 @@ func TestGenerateReplicaSetAffinity(t *testing.T) { assert.Equal(t, "", ro.Status.StableRS) assert.Nil(t, GenerateReplicaSetAffinity(ro)) // StableRS is equal to CurrentPodHash - ro.Status.StableRS = controller.ComputeHash(&ro.Spec.Template, nil) + ro.Status.StableRS = hash.ComputePodTemplateHash(&ro.Spec.Template, nil) assert.Nil(t, GenerateReplicaSetAffinity(ro)) // Injects anti-affinity rule with RequiredDuringSchedulingIgnoredDuringExecution into empty RS Affinity object From 5f0f8b4558467f5a1a09e7d08057ccf9973c01c7 Mon Sep 17 00:00:00 2001 From: Kiran Meduri Date: Thu, 3 Feb 2022 15:16:33 -0800 Subject: [PATCH 084/175] feat: TrafficRouting support with AWS App Mesh (#1401) (#1606) Signed-off-by: Kiran Meduri --- cmd/rollouts-controller/main.go | 3 + controller/metrics/rollout_test.go | 11 + controller/metrics/rollouts.go | 3 + docs/getting-started/appmesh/index.md | 123 + examples/appmesh/canary-rollout.yaml | 71 + examples/appmesh/canary-service.yaml | 183 ++ manifests/crds/rollout-crd.yaml | 34 + manifests/install.yaml | 53 + manifests/namespace-install.yaml | 53 + manifests/role/argo-rollouts-clusterrole.yaml | 24 + pkg/apiclient/rollout/rollout.swagger.json | 59 + pkg/apis/api-rules/violation_exceptions.list | 1 + pkg/apis/rollouts/v1alpha1/generated.pb.go | 2142 ++++++++++++----- pkg/apis/rollouts/v1alpha1/generated.proto | 36 + .../rollouts/v1alpha1/openapi_generated.go | 126 +- pkg/apis/rollouts/v1alpha1/types.go | 32 + .../v1alpha1/zz_generated.deepcopy.go | 94 + .../validation/validation_references.go | 56 + .../validation/validation_references_test.go | 197 ++ .../rollouts/validation/validation_test.go | 21 +- rollout/controller.go | 41 + rollout/controller_test.go | 130 + rollout/trafficrouting.go | 8 + rollout/trafficrouting/appmesh/appmesh.go | 388 +++ .../trafficrouting/appmesh/appmesh_test.go | 828 +++++++ .../trafficrouting/appmesh/resource_client.go | 74 + rollout/trafficrouting_test.go | 18 + test/e2e/appmesh/appmesh-canary-rollout.yaml | 163 ++ test/e2e/appmesh_test.go | 97 + test/fixtures/common.go | 14 + test/fixtures/e2e_suite.go | 10 +- utils/appmesh/appmesh.go | 44 + utils/defaults/defaults.go | 10 + utils/defaults/defaults_test.go | 5 + 34 files changed, 4516 insertions(+), 636 deletions(-) create mode 100644 docs/getting-started/appmesh/index.md create mode 100644 examples/appmesh/canary-rollout.yaml create mode 100644 examples/appmesh/canary-service.yaml create mode 100644 rollout/trafficrouting/appmesh/appmesh.go create mode 100644 rollout/trafficrouting/appmesh/appmesh_test.go create mode 100644 rollout/trafficrouting/appmesh/resource_client.go create mode 100644 test/e2e/appmesh/appmesh-canary-rollout.yaml create mode 100644 test/e2e/appmesh_test.go create mode 100644 utils/appmesh/appmesh.go diff --git a/cmd/rollouts-controller/main.go b/cmd/rollouts-controller/main.go index a55e1f5f2c..048df53db6 100644 --- a/cmd/rollouts-controller/main.go +++ b/cmd/rollouts-controller/main.go @@ -59,6 +59,7 @@ func newCommand() *cobra.Command { trafficSplitVersion string ambassadorVersion string ingressVersion string + appmeshCRDVersion string albIngressClasses []string nginxIngressClasses []string awsVerifyTargetGroup bool @@ -89,6 +90,7 @@ func newCommand() *cobra.Command { defaults.SetIstioAPIVersion(istioVersion) defaults.SetAmbassadorAPIVersion(ambassadorVersion) defaults.SetSMIAPIVersion(trafficSplitVersion) + defaults.SetAppMeshCRDVersion(appmeshCRDVersion) config, err := clientConfig.ClientConfig() checkError(err) @@ -228,6 +230,7 @@ func newCommand() *cobra.Command { command.Flags().StringVar(&ambassadorVersion, "ambassador-api-version", defaults.DefaultAmbassadorVersion, "Set the Ambassador apiVersion that controller should look when manipulating Ambassador Mappings.") command.Flags().StringVar(&trafficSplitVersion, "traffic-split-api-version", defaults.DefaultSMITrafficSplitVersion, "Set the default TrafficSplit apiVersion that controller uses when creating TrafficSplits.") command.Flags().StringVar(&ingressVersion, "ingress-api-version", "", "Set the Ingress apiVersion that the controller should use.") + command.Flags().StringVar(&appmeshCRDVersion, "appmesh-crd-version", defaults.DefaultAppMeshCRDVersion, "Set the default AppMesh CRD Version that controller uses when manipulating resources.") command.Flags().StringArrayVar(&albIngressClasses, "alb-ingress-classes", defaultALBIngressClass, "Defines all the ingress class annotations that the alb ingress controller operates on. Defaults to alb") command.Flags().StringArrayVar(&nginxIngressClasses, "nginx-ingress-classes", defaultNGINXIngressClass, "Defines all the ingress class annotations that the nginx ingress controller operates on. Defaults to nginx") command.Flags().BoolVar(&awsVerifyTargetGroup, "alb-verify-weight", false, "Verify ALB target group weights before progressing through steps (requires AWS privileges)") diff --git a/controller/metrics/rollout_test.go b/controller/metrics/rollout_test.go index 1ee7ac9776..1ff2495d14 100644 --- a/controller/metrics/rollout_test.go +++ b/controller/metrics/rollout_test.go @@ -271,6 +271,17 @@ func TestGetStrategyAndTrafficRouter(t *testing.T) { expectedStrategy: "canary", expectedTrafficRouter: "Nginx", }, + { + strategy: v1alpha1.RolloutStrategy{ + Canary: &v1alpha1.CanaryStrategy{ + TrafficRouting: &v1alpha1.RolloutTrafficRouting{ + AppMesh: &v1alpha1.AppMeshTrafficRouting{}, + }, + }, + }, + expectedStrategy: "canary", + expectedTrafficRouter: "AppMesh", + }, } for _, test := range tests { diff --git a/controller/metrics/rollouts.go b/controller/metrics/rollouts.go index 1d2de7d5b9..54a0c8af01 100644 --- a/controller/metrics/rollouts.go +++ b/controller/metrics/rollouts.go @@ -111,6 +111,9 @@ func getStrategyAndTrafficRouter(rollout *v1alpha1.Rollout) (string, string) { if rollout.Spec.Strategy.Canary.TrafficRouting.SMI != nil { trafficRouter = "SMI" } + if rollout.Spec.Strategy.Canary.TrafficRouting.AppMesh != nil { + trafficRouter = "AppMesh" + } } } return strategy, trafficRouter diff --git a/docs/getting-started/appmesh/index.md b/docs/getting-started/appmesh/index.md new file mode 100644 index 0000000000..7378f85820 --- /dev/null +++ b/docs/getting-started/appmesh/index.md @@ -0,0 +1,123 @@ +# Getting Started - App Mesh + +This guide covers how Argo Rollouts integrates with service-meshes managed by [AWS App Mesh](https://docs.aws.amazon.com/app-mesh/latest/userguide/what-is-app-mesh.html). This guide builds upon the concepts of the [basic getting started guide](../../getting-started.md). + +## Requirements +- Kubernetes cluster with AWS App Mesh Controller for K8s installed + +!!! tip + + See the [App Mesh Controler Installation instructions](https://docs.aws.amazon.com/app-mesh/latest/userguide/getting-started-kubernetes.html) on how to get started using App Mesh with Kubernetes. + +## 1. Deploy the Rollout, Services, App Mesh CRD + +When App Mesh is used as the traffic router, the Rollout canary strategy must define the following mandatory fields: + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: my-rollout +spec: + strategy: + canary: + # canaryService and stableService are references to Services which the Rollout will modify + # to target the canary ReplicaSet and stable ReplicaSet respectively (required). + canaryService: my-svc-canary + stableService: my-svc-stable + trafficRouting: + appMesh: + # The referenced virtual-service will be used to determine the virtual-router that is + # manipulated to update canary weights. + virtualService: + # name of the virtual-service App Mesh CR + name: my-svc + # Optional set of routes to update. If empty, all routes associated with the virtual-service are updated. + routes: + - http-primary + # virtualNodeGroup is a structure to refer App Mesh virtual-node CR corresponding to Canary and Stable versions + virtualNodeGroup: + # canaryVirtualNodeRef refers to virtual-node corresponding to canary version. Rollouts controller will + # update the podSelector of this virtual-node to latest canary pod-hash generated by controller. + canaryVirtualNodeRef: + name: my-vn-canary + # stableVirtualNodeRef refers to virtual-node corresponding to stable version. Rollouts controller will + # update the podSelector of this virtual-node to latest stable pod-hash generated by controller. + stableVirtualNodeRef: + name: my-vn-stable + steps: + - setWeight: 25 + - pause: {} + ... +``` + +In this guide, the two services are: `my-svc-canary` and `my-svc-stable` respectively. There are two +virtual-node CRs corresponding to these services named `my-vn-canary` and `my-vn-stable` +respectively. In addition, there is a virtual-service named `rollout-demo-vsvc` that is provided by a +virtual-router CR named `rollout-demo-vrouter`. This virtual-router need have at least one route with action to forward +traffic to the canary and stable virtual-nodes. Initially weight for canary is set to 0% while for stable it is 100%. +During rollout, controller will modify the weights on route(s) based on the configuraiton defined in +`steps[N].setWeight`. + +To summarize, run the following commands to deploy a service: + +* Two services (stable and canary) +* One service (for VIP and DNS lookup) +* Two App Mesh virtual-nodes (stable and canary) +* One App Mesh virtual-router with routes to virtual-nodes +* One App Mesh virtual-service corresponding to VIP service +* A rollout + +```shell +kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-rollouts/master/docs/getting-started/appmesh/canary-service.yaml +kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-rollouts/master/docs/getting-started/appmesh/canary-rollout.yaml +``` +## 2. Verify service + +First make sure that rollout is stable. + +```shell +kubectl argo rollouts get rollout my-rollout -n argo-examples -w +``` + +Then make sure the service is functional. + +```shell +kubectl -n argo-examples port-forward svc/my-svc 8181:80 +``` + +## 3. Rollout new version + +Now its time to deploy new version. Update the rollout with new image. + +```shell +kubectl argo rollouts set image my-rollout demo=argoproj/rollouts-demo:green -n argo-examples +``` + +Rollout should deploy a new canary revision and update the weights under virtual-router. + +```shell +kubectl get -n argo-examples virtualrouter my-vrouter -o json | jq ".spec.routes[0].httpRoute.action.weightedTargets" +[ + { + "virtualNodeRef": { + "name": "my-vn-canary" + }, + "weight": 25 + }, + { + "virtualNodeRef": { + "name": "my-vn-stable" + }, + "weight": 75 + } +] +``` + +Now manually approve the rollout that is paused indefinitely, and continue watching the routes get updated + +```shell +kubectl argo rollouts promote my-rollout -n argo-examples + +watch -d 'kubectl get -n argo-examples virtualrouter my-vrouter -o json | jq ".spec.routes[0].httpRoute.action.weightedTargets"' +``` diff --git a/examples/appmesh/canary-rollout.yaml b/examples/appmesh/canary-rollout.yaml new file mode 100644 index 0000000000..5f6f79cdd1 --- /dev/null +++ b/examples/appmesh/canary-rollout.yaml @@ -0,0 +1,71 @@ +apiVersion: argoproj.io/v1alpha1 +kind: AnalysisTemplate +metadata: + name: success-rate + namespace: argo-examples +spec: + args: + - name: envoy_cluster_name + metrics: + - name: success-rate + interval: 5m + successCondition: result[0] >= 0.99 + failureLimit: 3 + provider: + prometheus: + address: http://appmesh-prometheus.appmesh-system:9090 + query: | + sum(irate(envoy_cluster_upstream_rq_xx{app="wrk-tester",envoy_cluster_name="{{args.envoy_cluster_name}}",envoy_response_code_class!~"5.*"}[5m])) / + sum(irate(envoy_cluster_upstream_rq_xx{app="wrk-tester",envoy_cluster_name="{{args.envoy_cluster_name}}"}[5m])) + +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: my-rollout + namespace: argo-examples +spec: + replicas: 4 + selector: + matchLabels: + app: my-app + template: + metadata: + labels: + app: my-app + spec: + containers: + - name: demo + image: argoproj/rollouts-demo:blue + imagePullPolicy: Always + ports: + - name: http + containerPort: 8080 + strategy: + canary: + canaryService: my-svc-canary + stableService: my-svc-stable + trafficRouting: + appMesh: + virtualService: + name: my-svc + virtualNodeGroup: + canaryVirtualNodeRef: + name: my-vn-canary + stableVirtualNodeRef: + name: my-vn-stable + steps: + - setWeight: 25 + - pause: {} + - setWeight: 50 + - pause: {duration: 10m} + - setWeight: 75 + - pause: {duration: 10m} + # Uncomment below to enable analysis +# analysis: +# templates: +# - templateName: success-rate +# startingStep: 2 +# args: +# - name: envoy_cluster_name +# value: cds_egress_argo-examples_my-vn-canary_argo-examples_http_80 diff --git a/examples/appmesh/canary-service.yaml b/examples/appmesh/canary-service.yaml new file mode 100644 index 0000000000..1523266471 --- /dev/null +++ b/examples/appmesh/canary-service.yaml @@ -0,0 +1,183 @@ +apiVersion: appmesh.k8s.aws/v1beta2 +kind: Mesh +metadata: + name: argo-examples +spec: + namespaceSelector: + matchLabels: + mesh: argo-examples + +--- +apiVersion: v1 +kind: Namespace +metadata: + name: argo-examples + labels: + mesh: argo-examples + appmesh.k8s.aws/sidecarInjectorWebhook: enabled + +--- +# This service is used by virtual-service to resolve initial dns requests done by app container +apiVersion: v1 +kind: Service +metadata: + name: my-svc + namespace: argo-examples +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: my-app + +--- +apiVersion: v1 +kind: Service +metadata: + name: my-svc-canary + namespace: argo-examples +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + # This selector will be updated with the pod-template-hash of the canary ReplicaSet. + app: my-app + +--- +apiVersion: v1 +kind: Service +metadata: + name: my-svc-stable + namespace: argo-examples +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + # This selector will be updated with the pod-template-hash of the stable ReplicaSet. + app: my-app + +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualService +metadata: + name: my-svc + namespace: argo-examples +spec: + provider: + virtualRouter: + virtualRouterRef: + name: my-vrouter + +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualRouter +metadata: + name: my-vrouter + namespace: argo-examples +spec: + listeners: + - portMapping: + port: 80 + protocol: http + routes: + - name: primary + httpRoute: + match: + prefix: / + action: + weightedTargets: + - virtualNodeRef: + name: my-vn-canary + weight: 0 + - virtualNodeRef: + name: my-vn-stable + weight: 100 + +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualNode +metadata: + name: my-vn-canary + namespace: argo-examples +spec: + podSelector: + matchLabels: + app: my-app + rollouts-pod-template-hash: canary-tbd + listeners: + - portMapping: + port: 80 + protocol: http + serviceDiscovery: + dns: + hostname: my-svc-canary.argo-examples.svc.cluster.local + +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualNode +metadata: + name: my-vn-stable + namespace: argo-examples +spec: + podSelector: + matchLabels: + app: my-app + rollouts-pod-template-hash: stable-tbd + listeners: + - portMapping: + port: 80 + protocol: http + serviceDiscovery: + dns: + hostname: my-svc-stable.argo-examples.svc.cluster.local + +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualNode +metadata: + name: wrk-tester + namespace: argo-examples +spec: + podSelector: + matchLabels: + app: wrk-tester + backends: + - virtualService: + virtualServiceRef: + name: my-svc + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: wrk-tester + namespace: argo-examples + labels: + app: wrk-tester +spec: + replicas: 1 + selector: + matchLabels: + app: wrk-tester + template: + metadata: + name: wrk-tester + labels: + app: wrk-tester + spec: + containers: + - name: wrk + image: argoproj/load-tester:latest + command: + - /bin/sh + - -c + - -x + - "while true; do wrk -t10 -c40 -d2m -s report.lua http://my-svc.argo-examples/color; jq -e '.errors_ratio <= 0.35 and .latency_avg_ms < 100' report.json; done" diff --git a/manifests/crds/rollout-crd.yaml b/manifests/crds/rollout-crd.yaml index 5665fa4f47..5fc2803570 100644 --- a/manifests/crds/rollout-crd.yaml +++ b/manifests/crds/rollout-crd.yaml @@ -625,6 +625,40 @@ spec: required: - mappings type: object + appMesh: + properties: + virtualNodeGroup: + properties: + canaryVirtualNodeRef: + properties: + name: + type: string + required: + - name + type: object + stableVirtualNodeRef: + properties: + name: + type: string + required: + - name + type: object + required: + - canaryVirtualNodeRef + - stableVirtualNodeRef + type: object + virtualService: + properties: + name: + type: string + routes: + items: + type: string + type: array + required: + - name + type: object + type: object istio: properties: destinationRule: diff --git a/manifests/install.yaml b/manifests/install.yaml index b919668003..dbefccff0c 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -11593,6 +11593,40 @@ spec: required: - mappings type: object + appMesh: + properties: + virtualNodeGroup: + properties: + canaryVirtualNodeRef: + properties: + name: + type: string + required: + - name + type: object + stableVirtualNodeRef: + properties: + name: + type: string + required: + - name + type: object + required: + - canaryVirtualNodeRef + - stableVirtualNodeRef + type: object + virtualService: + properties: + name: + type: string + routes: + items: + type: string + type: array + required: + - name + type: object + type: object istio: properties: destinationRule: @@ -14468,6 +14502,25 @@ rules: verbs: - list - get +- apiGroups: + - appmesh.k8s.aws + resources: + - virtualservices + verbs: + - watch + - get + - list +- apiGroups: + - appmesh.k8s.aws + resources: + - virtualnodes + - virtualrouters + verbs: + - watch + - get + - list + - update + - patch --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 09cfdb3ae1..9f48ae0d96 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -11593,6 +11593,40 @@ spec: required: - mappings type: object + appMesh: + properties: + virtualNodeGroup: + properties: + canaryVirtualNodeRef: + properties: + name: + type: string + required: + - name + type: object + stableVirtualNodeRef: + properties: + name: + type: string + required: + - name + type: object + required: + - canaryVirtualNodeRef + - stableVirtualNodeRef + type: object + virtualService: + properties: + name: + type: string + routes: + items: + type: string + type: array + required: + - name + type: object + type: object istio: properties: destinationRule: @@ -14468,6 +14502,25 @@ rules: verbs: - list - get +- apiGroups: + - appmesh.k8s.aws + resources: + - virtualservices + verbs: + - watch + - get + - list +- apiGroups: + - appmesh.k8s.aws + resources: + - virtualnodes + - virtualrouters + verbs: + - watch + - get + - list + - update + - patch --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole diff --git a/manifests/role/argo-rollouts-clusterrole.yaml b/manifests/role/argo-rollouts-clusterrole.yaml index 9b90538a1a..692299af0f 100644 --- a/manifests/role/argo-rollouts-clusterrole.yaml +++ b/manifests/role/argo-rollouts-clusterrole.yaml @@ -199,3 +199,27 @@ rules: verbs: - list - get +# AppMesh virtualservices/virtualrouter CRD read-only access needed for using the App Mesh provider +- apiGroups: + - appmesh.k8s.aws + resources: + - virtualservices + verbs: + - watch + - get + - list +# AppMesh virtualnode CRD r/w access needed for using the App Mesh provider +- apiGroups: + - appmesh.k8s.aws + resources: + - virtualnodes + - virtualrouters + verbs: + - watch + - get + - list + - update + - patch + + + diff --git a/pkg/apiclient/rollout/rollout.swagger.json b/pkg/apiclient/rollout/rollout.swagger.json index 28b07ad208..99fc79a04c 100644 --- a/pkg/apiclient/rollout/rollout.swagger.json +++ b/pkg/apiclient/rollout/rollout.swagger.json @@ -598,6 +598,61 @@ }, "title": "AntiAffinity defines which inter-pod scheduling rule to use for anti-affinity injection" }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AppMeshTrafficRouting": { + "type": "object", + "properties": { + "virtualService": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AppMeshVirtualService", + "title": "VirtualService references an AppMesh VirtualService and VirtualRouter to modify to shape traffic" + }, + "virtualNodeGroup": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AppMeshVirtualNodeGroup", + "title": "VirtualNodeGroup references an AppMesh Route targets that are formed by a set of VirtualNodes that are used to shape traffic" + } + }, + "title": "AppMeshTrafficRouting configuration for AWS AppMesh service mesh to enable fine grain configuration" + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AppMeshVirtualNodeGroup": { + "type": "object", + "properties": { + "canaryVirtualNodeRef": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AppMeshVirtualNodeReference", + "title": "CanaryVirtualNodeRef is the virtual node ref to modify labels with canary ReplicaSet pod template hash value" + }, + "stableVirtualNodeRef": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AppMeshVirtualNodeReference", + "title": "StableVirtualNodeRef is the virtual node name to modify labels with stable ReplicaSet pod template hash value" + } + }, + "title": "AppMeshVirtualNodeGroup holds information about targets used for routing traffic to a virtual service" + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AppMeshVirtualNodeReference": { + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "Name is the name of VirtualNode CR" + } + }, + "title": "AppMeshVirtualNodeReference holds a reference to VirtualNode.appmesh.k8s.aws" + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AppMeshVirtualService": { + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "Name is the name of virtual service" + }, + "routes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Routes is list of HTTP routes within virtual router associated with virtual service to edit. If omitted, virtual service must have a single route of this type." + } + }, + "title": "AppMeshVirtualService holds information on the virtual service the rollout needs to modify" + }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ArgumentValueFrom": { "type": "object", "properties": { @@ -1443,6 +1498,10 @@ "ambassador": { "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AmbassadorTrafficRouting", "title": "Ambassador holds specific configuration to use Ambassador to route traffic" + }, + "appMesh": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AppMeshTrafficRouting", + "title": "AppMesh holds specific configuration to use AppMesh to route traffic" } }, "title": "RolloutTrafficRouting hosts all the different configuration for supported service meshes to enable more fine-grained traffic routing" diff --git a/pkg/apis/api-rules/violation_exceptions.list b/pkg/apis/api-rules/violation_exceptions.list index b69a0e1854..5c7b1d8311 100644 --- a/pkg/apis/api-rules/violation_exceptions.list +++ b/pkg/apis/api-rules/violation_exceptions.list @@ -8,6 +8,7 @@ API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AnalysisTemplateSpec,DryRun API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AnalysisTemplateSpec,MeasurementRetention API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AnalysisTemplateSpec,Metrics +API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,AppMeshVirtualService,Routes API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,CanaryStrategy,Steps API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,CloudWatchMetric,MetricDataQueries API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,CloudWatchMetricStatMetric,Dimensions diff --git a/pkg/apis/rollouts/v1alpha1/generated.pb.go b/pkg/apis/rollouts/v1alpha1/generated.pb.go index 73ec6853fc..1124c687f0 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.pb.go +++ b/pkg/apis/rollouts/v1alpha1/generated.pb.go @@ -412,10 +412,122 @@ func (m *AntiAffinity) XXX_DiscardUnknown() { var xxx_messageInfo_AntiAffinity proto.InternalMessageInfo +func (m *AppMeshTrafficRouting) Reset() { *m = AppMeshTrafficRouting{} } +func (*AppMeshTrafficRouting) ProtoMessage() {} +func (*AppMeshTrafficRouting) Descriptor() ([]byte, []int) { + return fileDescriptor_e0e705f843545fab, []int{13} +} +func (m *AppMeshTrafficRouting) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AppMeshTrafficRouting) 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 *AppMeshTrafficRouting) XXX_Merge(src proto.Message) { + xxx_messageInfo_AppMeshTrafficRouting.Merge(m, src) +} +func (m *AppMeshTrafficRouting) XXX_Size() int { + return m.Size() +} +func (m *AppMeshTrafficRouting) XXX_DiscardUnknown() { + xxx_messageInfo_AppMeshTrafficRouting.DiscardUnknown(m) +} + +var xxx_messageInfo_AppMeshTrafficRouting proto.InternalMessageInfo + +func (m *AppMeshVirtualNodeGroup) Reset() { *m = AppMeshVirtualNodeGroup{} } +func (*AppMeshVirtualNodeGroup) ProtoMessage() {} +func (*AppMeshVirtualNodeGroup) Descriptor() ([]byte, []int) { + return fileDescriptor_e0e705f843545fab, []int{14} +} +func (m *AppMeshVirtualNodeGroup) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AppMeshVirtualNodeGroup) 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 *AppMeshVirtualNodeGroup) XXX_Merge(src proto.Message) { + xxx_messageInfo_AppMeshVirtualNodeGroup.Merge(m, src) +} +func (m *AppMeshVirtualNodeGroup) XXX_Size() int { + return m.Size() +} +func (m *AppMeshVirtualNodeGroup) XXX_DiscardUnknown() { + xxx_messageInfo_AppMeshVirtualNodeGroup.DiscardUnknown(m) +} + +var xxx_messageInfo_AppMeshVirtualNodeGroup proto.InternalMessageInfo + +func (m *AppMeshVirtualNodeReference) Reset() { *m = AppMeshVirtualNodeReference{} } +func (*AppMeshVirtualNodeReference) ProtoMessage() {} +func (*AppMeshVirtualNodeReference) Descriptor() ([]byte, []int) { + return fileDescriptor_e0e705f843545fab, []int{15} +} +func (m *AppMeshVirtualNodeReference) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AppMeshVirtualNodeReference) 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 *AppMeshVirtualNodeReference) XXX_Merge(src proto.Message) { + xxx_messageInfo_AppMeshVirtualNodeReference.Merge(m, src) +} +func (m *AppMeshVirtualNodeReference) XXX_Size() int { + return m.Size() +} +func (m *AppMeshVirtualNodeReference) XXX_DiscardUnknown() { + xxx_messageInfo_AppMeshVirtualNodeReference.DiscardUnknown(m) +} + +var xxx_messageInfo_AppMeshVirtualNodeReference proto.InternalMessageInfo + +func (m *AppMeshVirtualService) Reset() { *m = AppMeshVirtualService{} } +func (*AppMeshVirtualService) ProtoMessage() {} +func (*AppMeshVirtualService) Descriptor() ([]byte, []int) { + return fileDescriptor_e0e705f843545fab, []int{16} +} +func (m *AppMeshVirtualService) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AppMeshVirtualService) 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 *AppMeshVirtualService) XXX_Merge(src proto.Message) { + xxx_messageInfo_AppMeshVirtualService.Merge(m, src) +} +func (m *AppMeshVirtualService) XXX_Size() int { + return m.Size() +} +func (m *AppMeshVirtualService) XXX_DiscardUnknown() { + xxx_messageInfo_AppMeshVirtualService.DiscardUnknown(m) +} + +var xxx_messageInfo_AppMeshVirtualService proto.InternalMessageInfo + func (m *Argument) Reset() { *m = Argument{} } func (*Argument) ProtoMessage() {} func (*Argument) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{13} + return fileDescriptor_e0e705f843545fab, []int{17} } func (m *Argument) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -443,7 +555,7 @@ var xxx_messageInfo_Argument proto.InternalMessageInfo func (m *ArgumentValueFrom) Reset() { *m = ArgumentValueFrom{} } func (*ArgumentValueFrom) ProtoMessage() {} func (*ArgumentValueFrom) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{14} + return fileDescriptor_e0e705f843545fab, []int{18} } func (m *ArgumentValueFrom) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -471,7 +583,7 @@ var xxx_messageInfo_ArgumentValueFrom proto.InternalMessageInfo func (m *AwsResourceRef) Reset() { *m = AwsResourceRef{} } func (*AwsResourceRef) ProtoMessage() {} func (*AwsResourceRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{15} + return fileDescriptor_e0e705f843545fab, []int{19} } func (m *AwsResourceRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -499,7 +611,7 @@ var xxx_messageInfo_AwsResourceRef proto.InternalMessageInfo func (m *BlueGreenStatus) Reset() { *m = BlueGreenStatus{} } func (*BlueGreenStatus) ProtoMessage() {} func (*BlueGreenStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{16} + return fileDescriptor_e0e705f843545fab, []int{20} } func (m *BlueGreenStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -527,7 +639,7 @@ var xxx_messageInfo_BlueGreenStatus proto.InternalMessageInfo func (m *BlueGreenStrategy) Reset() { *m = BlueGreenStrategy{} } func (*BlueGreenStrategy) ProtoMessage() {} func (*BlueGreenStrategy) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{17} + return fileDescriptor_e0e705f843545fab, []int{21} } func (m *BlueGreenStrategy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -555,7 +667,7 @@ var xxx_messageInfo_BlueGreenStrategy proto.InternalMessageInfo func (m *CanaryStatus) Reset() { *m = CanaryStatus{} } func (*CanaryStatus) ProtoMessage() {} func (*CanaryStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{18} + return fileDescriptor_e0e705f843545fab, []int{22} } func (m *CanaryStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -583,7 +695,7 @@ var xxx_messageInfo_CanaryStatus proto.InternalMessageInfo func (m *CanaryStep) Reset() { *m = CanaryStep{} } func (*CanaryStep) ProtoMessage() {} func (*CanaryStep) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{19} + return fileDescriptor_e0e705f843545fab, []int{23} } func (m *CanaryStep) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -611,7 +723,7 @@ var xxx_messageInfo_CanaryStep proto.InternalMessageInfo func (m *CanaryStrategy) Reset() { *m = CanaryStrategy{} } func (*CanaryStrategy) ProtoMessage() {} func (*CanaryStrategy) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{20} + return fileDescriptor_e0e705f843545fab, []int{24} } func (m *CanaryStrategy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -639,7 +751,7 @@ var xxx_messageInfo_CanaryStrategy proto.InternalMessageInfo func (m *CloudWatchMetric) Reset() { *m = CloudWatchMetric{} } func (*CloudWatchMetric) ProtoMessage() {} func (*CloudWatchMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{21} + return fileDescriptor_e0e705f843545fab, []int{25} } func (m *CloudWatchMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -667,7 +779,7 @@ var xxx_messageInfo_CloudWatchMetric proto.InternalMessageInfo func (m *CloudWatchMetricDataQuery) Reset() { *m = CloudWatchMetricDataQuery{} } func (*CloudWatchMetricDataQuery) ProtoMessage() {} func (*CloudWatchMetricDataQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{22} + return fileDescriptor_e0e705f843545fab, []int{26} } func (m *CloudWatchMetricDataQuery) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -695,7 +807,7 @@ var xxx_messageInfo_CloudWatchMetricDataQuery proto.InternalMessageInfo func (m *CloudWatchMetricStat) Reset() { *m = CloudWatchMetricStat{} } func (*CloudWatchMetricStat) ProtoMessage() {} func (*CloudWatchMetricStat) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{23} + return fileDescriptor_e0e705f843545fab, []int{27} } func (m *CloudWatchMetricStat) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -723,7 +835,7 @@ var xxx_messageInfo_CloudWatchMetricStat proto.InternalMessageInfo func (m *CloudWatchMetricStatMetric) Reset() { *m = CloudWatchMetricStatMetric{} } func (*CloudWatchMetricStatMetric) ProtoMessage() {} func (*CloudWatchMetricStatMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{24} + return fileDescriptor_e0e705f843545fab, []int{28} } func (m *CloudWatchMetricStatMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -751,7 +863,7 @@ var xxx_messageInfo_CloudWatchMetricStatMetric proto.InternalMessageInfo func (m *CloudWatchMetricStatMetricDimension) Reset() { *m = CloudWatchMetricStatMetricDimension{} } func (*CloudWatchMetricStatMetricDimension) ProtoMessage() {} func (*CloudWatchMetricStatMetricDimension) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{25} + return fileDescriptor_e0e705f843545fab, []int{29} } func (m *CloudWatchMetricStatMetricDimension) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -779,7 +891,7 @@ var xxx_messageInfo_CloudWatchMetricStatMetricDimension proto.InternalMessageInf func (m *ClusterAnalysisTemplate) Reset() { *m = ClusterAnalysisTemplate{} } func (*ClusterAnalysisTemplate) ProtoMessage() {} func (*ClusterAnalysisTemplate) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{26} + return fileDescriptor_e0e705f843545fab, []int{30} } func (m *ClusterAnalysisTemplate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -807,7 +919,7 @@ var xxx_messageInfo_ClusterAnalysisTemplate proto.InternalMessageInfo func (m *ClusterAnalysisTemplateList) Reset() { *m = ClusterAnalysisTemplateList{} } func (*ClusterAnalysisTemplateList) ProtoMessage() {} func (*ClusterAnalysisTemplateList) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{27} + return fileDescriptor_e0e705f843545fab, []int{31} } func (m *ClusterAnalysisTemplateList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -835,7 +947,7 @@ var xxx_messageInfo_ClusterAnalysisTemplateList proto.InternalMessageInfo func (m *DatadogMetric) Reset() { *m = DatadogMetric{} } func (*DatadogMetric) ProtoMessage() {} func (*DatadogMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{28} + return fileDescriptor_e0e705f843545fab, []int{32} } func (m *DatadogMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -863,7 +975,7 @@ var xxx_messageInfo_DatadogMetric proto.InternalMessageInfo func (m *DryRun) Reset() { *m = DryRun{} } func (*DryRun) ProtoMessage() {} func (*DryRun) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{29} + return fileDescriptor_e0e705f843545fab, []int{33} } func (m *DryRun) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -891,7 +1003,7 @@ var xxx_messageInfo_DryRun proto.InternalMessageInfo func (m *Experiment) Reset() { *m = Experiment{} } func (*Experiment) ProtoMessage() {} func (*Experiment) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{30} + return fileDescriptor_e0e705f843545fab, []int{34} } func (m *Experiment) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -919,7 +1031,7 @@ var xxx_messageInfo_Experiment proto.InternalMessageInfo func (m *ExperimentAnalysisRunStatus) Reset() { *m = ExperimentAnalysisRunStatus{} } func (*ExperimentAnalysisRunStatus) ProtoMessage() {} func (*ExperimentAnalysisRunStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{31} + return fileDescriptor_e0e705f843545fab, []int{35} } func (m *ExperimentAnalysisRunStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -947,7 +1059,7 @@ var xxx_messageInfo_ExperimentAnalysisRunStatus proto.InternalMessageInfo func (m *ExperimentAnalysisTemplateRef) Reset() { *m = ExperimentAnalysisTemplateRef{} } func (*ExperimentAnalysisTemplateRef) ProtoMessage() {} func (*ExperimentAnalysisTemplateRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{32} + return fileDescriptor_e0e705f843545fab, []int{36} } func (m *ExperimentAnalysisTemplateRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -975,7 +1087,7 @@ var xxx_messageInfo_ExperimentAnalysisTemplateRef proto.InternalMessageInfo func (m *ExperimentCondition) Reset() { *m = ExperimentCondition{} } func (*ExperimentCondition) ProtoMessage() {} func (*ExperimentCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{33} + return fileDescriptor_e0e705f843545fab, []int{37} } func (m *ExperimentCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1003,7 +1115,7 @@ var xxx_messageInfo_ExperimentCondition proto.InternalMessageInfo func (m *ExperimentList) Reset() { *m = ExperimentList{} } func (*ExperimentList) ProtoMessage() {} func (*ExperimentList) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{34} + return fileDescriptor_e0e705f843545fab, []int{38} } func (m *ExperimentList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1031,7 +1143,7 @@ var xxx_messageInfo_ExperimentList proto.InternalMessageInfo func (m *ExperimentSpec) Reset() { *m = ExperimentSpec{} } func (*ExperimentSpec) ProtoMessage() {} func (*ExperimentSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{35} + return fileDescriptor_e0e705f843545fab, []int{39} } func (m *ExperimentSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1059,7 +1171,7 @@ var xxx_messageInfo_ExperimentSpec proto.InternalMessageInfo func (m *ExperimentStatus) Reset() { *m = ExperimentStatus{} } func (*ExperimentStatus) ProtoMessage() {} func (*ExperimentStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{36} + return fileDescriptor_e0e705f843545fab, []int{40} } func (m *ExperimentStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1087,7 +1199,7 @@ var xxx_messageInfo_ExperimentStatus proto.InternalMessageInfo func (m *FieldRef) Reset() { *m = FieldRef{} } func (*FieldRef) ProtoMessage() {} func (*FieldRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{37} + return fileDescriptor_e0e705f843545fab, []int{41} } func (m *FieldRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1115,7 +1227,7 @@ var xxx_messageInfo_FieldRef proto.InternalMessageInfo func (m *GraphiteMetric) Reset() { *m = GraphiteMetric{} } func (*GraphiteMetric) ProtoMessage() {} func (*GraphiteMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{38} + return fileDescriptor_e0e705f843545fab, []int{42} } func (m *GraphiteMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1143,7 +1255,7 @@ var xxx_messageInfo_GraphiteMetric proto.InternalMessageInfo func (m *IstioDestinationRule) Reset() { *m = IstioDestinationRule{} } func (*IstioDestinationRule) ProtoMessage() {} func (*IstioDestinationRule) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{39} + return fileDescriptor_e0e705f843545fab, []int{43} } func (m *IstioDestinationRule) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1171,7 +1283,7 @@ var xxx_messageInfo_IstioDestinationRule proto.InternalMessageInfo func (m *IstioTrafficRouting) Reset() { *m = IstioTrafficRouting{} } func (*IstioTrafficRouting) ProtoMessage() {} func (*IstioTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{40} + return fileDescriptor_e0e705f843545fab, []int{44} } func (m *IstioTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1199,7 +1311,7 @@ var xxx_messageInfo_IstioTrafficRouting proto.InternalMessageInfo func (m *IstioVirtualService) Reset() { *m = IstioVirtualService{} } func (*IstioVirtualService) ProtoMessage() {} func (*IstioVirtualService) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{41} + return fileDescriptor_e0e705f843545fab, []int{45} } func (m *IstioVirtualService) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1227,7 +1339,7 @@ var xxx_messageInfo_IstioVirtualService proto.InternalMessageInfo func (m *JobMetric) Reset() { *m = JobMetric{} } func (*JobMetric) ProtoMessage() {} func (*JobMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{42} + return fileDescriptor_e0e705f843545fab, []int{46} } func (m *JobMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1255,7 +1367,7 @@ var xxx_messageInfo_JobMetric proto.InternalMessageInfo func (m *KayentaMetric) Reset() { *m = KayentaMetric{} } func (*KayentaMetric) ProtoMessage() {} func (*KayentaMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{43} + return fileDescriptor_e0e705f843545fab, []int{47} } func (m *KayentaMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1283,7 +1395,7 @@ var xxx_messageInfo_KayentaMetric proto.InternalMessageInfo func (m *KayentaScope) Reset() { *m = KayentaScope{} } func (*KayentaScope) ProtoMessage() {} func (*KayentaScope) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{44} + return fileDescriptor_e0e705f843545fab, []int{48} } func (m *KayentaScope) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1311,7 +1423,7 @@ var xxx_messageInfo_KayentaScope proto.InternalMessageInfo func (m *KayentaThreshold) Reset() { *m = KayentaThreshold{} } func (*KayentaThreshold) ProtoMessage() {} func (*KayentaThreshold) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{45} + return fileDescriptor_e0e705f843545fab, []int{49} } func (m *KayentaThreshold) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1339,7 +1451,7 @@ var xxx_messageInfo_KayentaThreshold proto.InternalMessageInfo func (m *Measurement) Reset() { *m = Measurement{} } func (*Measurement) ProtoMessage() {} func (*Measurement) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{46} + return fileDescriptor_e0e705f843545fab, []int{50} } func (m *Measurement) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1367,7 +1479,7 @@ var xxx_messageInfo_Measurement proto.InternalMessageInfo func (m *MeasurementRetention) Reset() { *m = MeasurementRetention{} } func (*MeasurementRetention) ProtoMessage() {} func (*MeasurementRetention) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{47} + return fileDescriptor_e0e705f843545fab, []int{51} } func (m *MeasurementRetention) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1395,7 +1507,7 @@ var xxx_messageInfo_MeasurementRetention proto.InternalMessageInfo func (m *Metric) Reset() { *m = Metric{} } func (*Metric) ProtoMessage() {} func (*Metric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{48} + return fileDescriptor_e0e705f843545fab, []int{52} } func (m *Metric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1423,7 +1535,7 @@ var xxx_messageInfo_Metric proto.InternalMessageInfo func (m *MetricProvider) Reset() { *m = MetricProvider{} } func (*MetricProvider) ProtoMessage() {} func (*MetricProvider) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{49} + return fileDescriptor_e0e705f843545fab, []int{53} } func (m *MetricProvider) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1451,7 +1563,7 @@ var xxx_messageInfo_MetricProvider proto.InternalMessageInfo func (m *MetricResult) Reset() { *m = MetricResult{} } func (*MetricResult) ProtoMessage() {} func (*MetricResult) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{50} + return fileDescriptor_e0e705f843545fab, []int{54} } func (m *MetricResult) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1479,7 +1591,7 @@ var xxx_messageInfo_MetricResult proto.InternalMessageInfo func (m *NewRelicMetric) Reset() { *m = NewRelicMetric{} } func (*NewRelicMetric) ProtoMessage() {} func (*NewRelicMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{51} + return fileDescriptor_e0e705f843545fab, []int{55} } func (m *NewRelicMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1507,7 +1619,7 @@ var xxx_messageInfo_NewRelicMetric proto.InternalMessageInfo func (m *NginxTrafficRouting) Reset() { *m = NginxTrafficRouting{} } func (*NginxTrafficRouting) ProtoMessage() {} func (*NginxTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{52} + return fileDescriptor_e0e705f843545fab, []int{56} } func (m *NginxTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1535,7 +1647,7 @@ var xxx_messageInfo_NginxTrafficRouting proto.InternalMessageInfo func (m *ObjectRef) Reset() { *m = ObjectRef{} } func (*ObjectRef) ProtoMessage() {} func (*ObjectRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{53} + return fileDescriptor_e0e705f843545fab, []int{57} } func (m *ObjectRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1563,7 +1675,7 @@ var xxx_messageInfo_ObjectRef proto.InternalMessageInfo func (m *PauseCondition) Reset() { *m = PauseCondition{} } func (*PauseCondition) ProtoMessage() {} func (*PauseCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{54} + return fileDescriptor_e0e705f843545fab, []int{58} } func (m *PauseCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1591,7 +1703,7 @@ var xxx_messageInfo_PauseCondition proto.InternalMessageInfo func (m *PodTemplateMetadata) Reset() { *m = PodTemplateMetadata{} } func (*PodTemplateMetadata) ProtoMessage() {} func (*PodTemplateMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{55} + return fileDescriptor_e0e705f843545fab, []int{59} } func (m *PodTemplateMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1621,7 +1733,7 @@ func (m *PreferredDuringSchedulingIgnoredDuringExecution) Reset() { } func (*PreferredDuringSchedulingIgnoredDuringExecution) ProtoMessage() {} func (*PreferredDuringSchedulingIgnoredDuringExecution) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{56} + return fileDescriptor_e0e705f843545fab, []int{60} } func (m *PreferredDuringSchedulingIgnoredDuringExecution) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1649,7 +1761,7 @@ var xxx_messageInfo_PreferredDuringSchedulingIgnoredDuringExecution proto.Intern func (m *PrometheusMetric) Reset() { *m = PrometheusMetric{} } func (*PrometheusMetric) ProtoMessage() {} func (*PrometheusMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{57} + return fileDescriptor_e0e705f843545fab, []int{61} } func (m *PrometheusMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1679,7 +1791,7 @@ func (m *RequiredDuringSchedulingIgnoredDuringExecution) Reset() { } func (*RequiredDuringSchedulingIgnoredDuringExecution) ProtoMessage() {} func (*RequiredDuringSchedulingIgnoredDuringExecution) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{58} + return fileDescriptor_e0e705f843545fab, []int{62} } func (m *RequiredDuringSchedulingIgnoredDuringExecution) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1707,7 +1819,7 @@ var xxx_messageInfo_RequiredDuringSchedulingIgnoredDuringExecution proto.Interna func (m *Rollout) Reset() { *m = Rollout{} } func (*Rollout) ProtoMessage() {} func (*Rollout) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{59} + return fileDescriptor_e0e705f843545fab, []int{63} } func (m *Rollout) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1735,7 +1847,7 @@ var xxx_messageInfo_Rollout proto.InternalMessageInfo func (m *RolloutAnalysis) Reset() { *m = RolloutAnalysis{} } func (*RolloutAnalysis) ProtoMessage() {} func (*RolloutAnalysis) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{60} + return fileDescriptor_e0e705f843545fab, []int{64} } func (m *RolloutAnalysis) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1763,7 +1875,7 @@ var xxx_messageInfo_RolloutAnalysis proto.InternalMessageInfo func (m *RolloutAnalysisBackground) Reset() { *m = RolloutAnalysisBackground{} } func (*RolloutAnalysisBackground) ProtoMessage() {} func (*RolloutAnalysisBackground) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{61} + return fileDescriptor_e0e705f843545fab, []int{65} } func (m *RolloutAnalysisBackground) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1791,7 +1903,7 @@ var xxx_messageInfo_RolloutAnalysisBackground proto.InternalMessageInfo func (m *RolloutAnalysisRunStatus) Reset() { *m = RolloutAnalysisRunStatus{} } func (*RolloutAnalysisRunStatus) ProtoMessage() {} func (*RolloutAnalysisRunStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{62} + return fileDescriptor_e0e705f843545fab, []int{66} } func (m *RolloutAnalysisRunStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1819,7 +1931,7 @@ var xxx_messageInfo_RolloutAnalysisRunStatus proto.InternalMessageInfo func (m *RolloutAnalysisTemplate) Reset() { *m = RolloutAnalysisTemplate{} } func (*RolloutAnalysisTemplate) ProtoMessage() {} func (*RolloutAnalysisTemplate) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{63} + return fileDescriptor_e0e705f843545fab, []int{67} } func (m *RolloutAnalysisTemplate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1847,7 +1959,7 @@ var xxx_messageInfo_RolloutAnalysisTemplate proto.InternalMessageInfo func (m *RolloutCondition) Reset() { *m = RolloutCondition{} } func (*RolloutCondition) ProtoMessage() {} func (*RolloutCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{64} + return fileDescriptor_e0e705f843545fab, []int{68} } func (m *RolloutCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1875,7 +1987,7 @@ var xxx_messageInfo_RolloutCondition proto.InternalMessageInfo func (m *RolloutExperimentStep) Reset() { *m = RolloutExperimentStep{} } func (*RolloutExperimentStep) ProtoMessage() {} func (*RolloutExperimentStep) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{65} + return fileDescriptor_e0e705f843545fab, []int{69} } func (m *RolloutExperimentStep) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1905,7 +2017,7 @@ func (m *RolloutExperimentStepAnalysisTemplateRef) Reset() { } func (*RolloutExperimentStepAnalysisTemplateRef) ProtoMessage() {} func (*RolloutExperimentStepAnalysisTemplateRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{66} + return fileDescriptor_e0e705f843545fab, []int{70} } func (m *RolloutExperimentStepAnalysisTemplateRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1933,7 +2045,7 @@ var xxx_messageInfo_RolloutExperimentStepAnalysisTemplateRef proto.InternalMessa func (m *RolloutExperimentTemplate) Reset() { *m = RolloutExperimentTemplate{} } func (*RolloutExperimentTemplate) ProtoMessage() {} func (*RolloutExperimentTemplate) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{67} + return fileDescriptor_e0e705f843545fab, []int{71} } func (m *RolloutExperimentTemplate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1961,7 +2073,7 @@ var xxx_messageInfo_RolloutExperimentTemplate proto.InternalMessageInfo func (m *RolloutList) Reset() { *m = RolloutList{} } func (*RolloutList) ProtoMessage() {} func (*RolloutList) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{68} + return fileDescriptor_e0e705f843545fab, []int{72} } func (m *RolloutList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1989,7 +2101,7 @@ var xxx_messageInfo_RolloutList proto.InternalMessageInfo func (m *RolloutPause) Reset() { *m = RolloutPause{} } func (*RolloutPause) ProtoMessage() {} func (*RolloutPause) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{69} + return fileDescriptor_e0e705f843545fab, []int{73} } func (m *RolloutPause) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2017,7 +2129,7 @@ var xxx_messageInfo_RolloutPause proto.InternalMessageInfo func (m *RolloutSpec) Reset() { *m = RolloutSpec{} } func (*RolloutSpec) ProtoMessage() {} func (*RolloutSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{70} + return fileDescriptor_e0e705f843545fab, []int{74} } func (m *RolloutSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2045,7 +2157,7 @@ var xxx_messageInfo_RolloutSpec proto.InternalMessageInfo func (m *RolloutStatus) Reset() { *m = RolloutStatus{} } func (*RolloutStatus) ProtoMessage() {} func (*RolloutStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{71} + return fileDescriptor_e0e705f843545fab, []int{75} } func (m *RolloutStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2073,7 +2185,7 @@ var xxx_messageInfo_RolloutStatus proto.InternalMessageInfo func (m *RolloutStrategy) Reset() { *m = RolloutStrategy{} } func (*RolloutStrategy) ProtoMessage() {} func (*RolloutStrategy) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{72} + return fileDescriptor_e0e705f843545fab, []int{76} } func (m *RolloutStrategy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2101,7 +2213,7 @@ var xxx_messageInfo_RolloutStrategy proto.InternalMessageInfo func (m *RolloutTrafficRouting) Reset() { *m = RolloutTrafficRouting{} } func (*RolloutTrafficRouting) ProtoMessage() {} func (*RolloutTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{73} + return fileDescriptor_e0e705f843545fab, []int{77} } func (m *RolloutTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2129,7 +2241,7 @@ var xxx_messageInfo_RolloutTrafficRouting proto.InternalMessageInfo func (m *RunSummary) Reset() { *m = RunSummary{} } func (*RunSummary) ProtoMessage() {} func (*RunSummary) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{74} + return fileDescriptor_e0e705f843545fab, []int{78} } func (m *RunSummary) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2157,7 +2269,7 @@ var xxx_messageInfo_RunSummary proto.InternalMessageInfo func (m *SMITrafficRouting) Reset() { *m = SMITrafficRouting{} } func (*SMITrafficRouting) ProtoMessage() {} func (*SMITrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{75} + return fileDescriptor_e0e705f843545fab, []int{79} } func (m *SMITrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2185,7 +2297,7 @@ var xxx_messageInfo_SMITrafficRouting proto.InternalMessageInfo func (m *ScopeDetail) Reset() { *m = ScopeDetail{} } func (*ScopeDetail) ProtoMessage() {} func (*ScopeDetail) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{76} + return fileDescriptor_e0e705f843545fab, []int{80} } func (m *ScopeDetail) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2213,7 +2325,7 @@ var xxx_messageInfo_ScopeDetail proto.InternalMessageInfo func (m *SecretKeyRef) Reset() { *m = SecretKeyRef{} } func (*SecretKeyRef) ProtoMessage() {} func (*SecretKeyRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{77} + return fileDescriptor_e0e705f843545fab, []int{81} } func (m *SecretKeyRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2241,7 +2353,7 @@ var xxx_messageInfo_SecretKeyRef proto.InternalMessageInfo func (m *SetCanaryScale) Reset() { *m = SetCanaryScale{} } func (*SetCanaryScale) ProtoMessage() {} func (*SetCanaryScale) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{78} + return fileDescriptor_e0e705f843545fab, []int{82} } func (m *SetCanaryScale) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2269,7 +2381,7 @@ var xxx_messageInfo_SetCanaryScale proto.InternalMessageInfo func (m *StickinessConfig) Reset() { *m = StickinessConfig{} } func (*StickinessConfig) ProtoMessage() {} func (*StickinessConfig) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{79} + return fileDescriptor_e0e705f843545fab, []int{83} } func (m *StickinessConfig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2297,7 +2409,7 @@ var xxx_messageInfo_StickinessConfig proto.InternalMessageInfo func (m *TLSRoute) Reset() { *m = TLSRoute{} } func (*TLSRoute) ProtoMessage() {} func (*TLSRoute) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{80} + return fileDescriptor_e0e705f843545fab, []int{84} } func (m *TLSRoute) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2325,7 +2437,7 @@ var xxx_messageInfo_TLSRoute proto.InternalMessageInfo func (m *TemplateService) Reset() { *m = TemplateService{} } func (*TemplateService) ProtoMessage() {} func (*TemplateService) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{81} + return fileDescriptor_e0e705f843545fab, []int{85} } func (m *TemplateService) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2353,7 +2465,7 @@ var xxx_messageInfo_TemplateService proto.InternalMessageInfo func (m *TemplateSpec) Reset() { *m = TemplateSpec{} } func (*TemplateSpec) ProtoMessage() {} func (*TemplateSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{82} + return fileDescriptor_e0e705f843545fab, []int{86} } func (m *TemplateSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2381,7 +2493,7 @@ var xxx_messageInfo_TemplateSpec proto.InternalMessageInfo func (m *TemplateStatus) Reset() { *m = TemplateStatus{} } func (*TemplateStatus) ProtoMessage() {} func (*TemplateStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{83} + return fileDescriptor_e0e705f843545fab, []int{87} } func (m *TemplateStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2409,7 +2521,7 @@ var xxx_messageInfo_TemplateStatus proto.InternalMessageInfo func (m *TrafficWeights) Reset() { *m = TrafficWeights{} } func (*TrafficWeights) ProtoMessage() {} func (*TrafficWeights) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{84} + return fileDescriptor_e0e705f843545fab, []int{88} } func (m *TrafficWeights) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2437,7 +2549,7 @@ var xxx_messageInfo_TrafficWeights proto.InternalMessageInfo func (m *ValueFrom) Reset() { *m = ValueFrom{} } func (*ValueFrom) ProtoMessage() {} func (*ValueFrom) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{85} + return fileDescriptor_e0e705f843545fab, []int{89} } func (m *ValueFrom) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2465,7 +2577,7 @@ var xxx_messageInfo_ValueFrom proto.InternalMessageInfo func (m *WavefrontMetric) Reset() { *m = WavefrontMetric{} } func (*WavefrontMetric) ProtoMessage() {} func (*WavefrontMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{86} + return fileDescriptor_e0e705f843545fab, []int{90} } func (m *WavefrontMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2493,7 +2605,7 @@ var xxx_messageInfo_WavefrontMetric proto.InternalMessageInfo func (m *WebMetric) Reset() { *m = WebMetric{} } func (*WebMetric) ProtoMessage() {} func (*WebMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{87} + return fileDescriptor_e0e705f843545fab, []int{91} } func (m *WebMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2521,7 +2633,7 @@ var xxx_messageInfo_WebMetric proto.InternalMessageInfo func (m *WebMetricHeader) Reset() { *m = WebMetricHeader{} } func (*WebMetricHeader) ProtoMessage() {} func (*WebMetricHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{88} + return fileDescriptor_e0e705f843545fab, []int{92} } func (m *WebMetricHeader) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2549,7 +2661,7 @@ var xxx_messageInfo_WebMetricHeader proto.InternalMessageInfo func (m *WeightDestination) Reset() { *m = WeightDestination{} } func (*WeightDestination) ProtoMessage() {} func (*WeightDestination) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{89} + return fileDescriptor_e0e705f843545fab, []int{93} } func (m *WeightDestination) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2588,6 +2700,10 @@ func init() { proto.RegisterType((*AnalysisTemplateList)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AnalysisTemplateList") proto.RegisterType((*AnalysisTemplateSpec)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AnalysisTemplateSpec") proto.RegisterType((*AntiAffinity)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AntiAffinity") + proto.RegisterType((*AppMeshTrafficRouting)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AppMeshTrafficRouting") + proto.RegisterType((*AppMeshVirtualNodeGroup)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AppMeshVirtualNodeGroup") + proto.RegisterType((*AppMeshVirtualNodeReference)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AppMeshVirtualNodeReference") + proto.RegisterType((*AppMeshVirtualService)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AppMeshVirtualService") proto.RegisterType((*Argument)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.Argument") proto.RegisterType((*ArgumentValueFrom)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ArgumentValueFrom") proto.RegisterType((*AwsResourceRef)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AwsResourceRef") @@ -2677,438 +2793,447 @@ func init() { } var fileDescriptor_e0e705f843545fab = []byte{ - // 6885 bytes of a gzipped FileDescriptorProto + // 7031 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x5d, 0x8c, 0x24, 0x57, - 0x75, 0xb0, 0xab, 0x7f, 0x66, 0x7a, 0xce, 0xfc, 0xdf, 0x9d, 0x65, 0xc7, 0x6b, 0xef, 0xb6, 0x29, - 0x23, 0x7f, 0xe6, 0xfb, 0x60, 0x16, 0xd6, 0xf6, 0xf7, 0x19, 0x8c, 0xac, 0xaf, 0x7b, 0x66, 0xd7, - 0x3b, 0xeb, 0x99, 0xdd, 0xd9, 0xdb, 0xb3, 0x5e, 0x30, 0x98, 0x50, 0xd3, 0x7d, 0xa7, 0xa7, 0x76, - 0xab, 0xab, 0x9a, 0xaa, 0xea, 0xd9, 0x1d, 0x83, 0xc0, 0x0e, 0xb2, 0x43, 0x22, 0x10, 0x4e, 0x80, - 0x87, 0x28, 0x22, 0x42, 0x11, 0x0f, 0x51, 0xc8, 0x43, 0x84, 0x12, 0xe5, 0x05, 0x29, 0x51, 0x02, - 0x0a, 0x79, 0x48, 0x44, 0xa4, 0x24, 0x40, 0x04, 0x1d, 0xdc, 0xe4, 0x25, 0x51, 0xa4, 0x28, 0x12, - 0x51, 0xc4, 0x3e, 0x45, 0xf7, 0xb7, 0x6e, 0x55, 0x57, 0xcf, 0x76, 0x4f, 0xd7, 0x2c, 0x56, 0xc2, - 0x5b, 0xf7, 0x3d, 0xe7, 0x9e, 0x73, 0x7f, 0xcf, 0x3d, 0xe7, 0xdc, 0x73, 0x4f, 0xc1, 0x46, 0xd3, - 0x0e, 0xf7, 0x3a, 0x3b, 0x2b, 0x75, 0xaf, 0x75, 0xce, 0xf2, 0x9b, 0x5e, 0xdb, 0xf7, 0x6e, 0xb2, - 0x1f, 0xef, 0xf6, 0x3d, 0xc7, 0xf1, 0x3a, 0x61, 0x70, 0xae, 0x7d, 0xab, 0x79, 0xce, 0x6a, 0xdb, - 0xc1, 0x39, 0x55, 0xb2, 0xff, 0x5e, 0xcb, 0x69, 0xef, 0x59, 0xef, 0x3d, 0xd7, 0x24, 0x2e, 0xf1, - 0xad, 0x90, 0x34, 0x56, 0xda, 0xbe, 0x17, 0x7a, 0xe8, 0x03, 0x11, 0xb5, 0x15, 0x49, 0x8d, 0xfd, - 0xf8, 0x25, 0x59, 0x77, 0xa5, 0x7d, 0xab, 0xb9, 0x42, 0xa9, 0xad, 0xa8, 0x12, 0x49, 0xed, 0xf4, - 0xbb, 0xb5, 0xb6, 0x34, 0xbd, 0xa6, 0x77, 0x8e, 0x11, 0xdd, 0xe9, 0xec, 0xb2, 0x7f, 0xec, 0x0f, - 0xfb, 0xc5, 0x99, 0x9d, 0x7e, 0xf4, 0xd6, 0xd3, 0xc1, 0x8a, 0xed, 0xd1, 0xb6, 0x9d, 0xdb, 0xb1, - 0xc2, 0xfa, 0xde, 0xb9, 0xfd, 0xbe, 0x16, 0x9d, 0x36, 0x35, 0xa4, 0xba, 0xe7, 0x93, 0x34, 0x9c, - 0x27, 0x23, 0x9c, 0x96, 0x55, 0xdf, 0xb3, 0x5d, 0xe2, 0x1f, 0x44, 0xbd, 0x6e, 0x91, 0xd0, 0x4a, - 0xab, 0x75, 0x6e, 0x50, 0x2d, 0xbf, 0xe3, 0x86, 0x76, 0x8b, 0xf4, 0x55, 0xf8, 0xbf, 0xf7, 0xaa, - 0x10, 0xd4, 0xf7, 0x48, 0xcb, 0xea, 0xab, 0xf7, 0xc4, 0xa0, 0x7a, 0x9d, 0xd0, 0x76, 0xce, 0xd9, - 0x6e, 0x18, 0x84, 0x7e, 0xb2, 0x92, 0xf9, 0xad, 0x3c, 0x4c, 0x55, 0x36, 0xaa, 0xb5, 0xd0, 0x0a, - 0x3b, 0x01, 0x7a, 0xdd, 0x80, 0x19, 0xc7, 0xb3, 0x1a, 0x55, 0xcb, 0xb1, 0xdc, 0x3a, 0xf1, 0x97, - 0x8d, 0x47, 0x8c, 0xc7, 0xa7, 0xcf, 0x6f, 0xac, 0x8c, 0x33, 0x5f, 0x2b, 0x95, 0xdb, 0x01, 0x26, - 0x81, 0xd7, 0xf1, 0xeb, 0x04, 0x93, 0xdd, 0xea, 0xd2, 0x77, 0xba, 0xe5, 0x07, 0x7a, 0xdd, 0xf2, - 0xcc, 0x86, 0xc6, 0x09, 0xc7, 0xf8, 0xa2, 0x2f, 0x1b, 0xb0, 0x58, 0xb7, 0x5c, 0xcb, 0x3f, 0xd8, - 0xb6, 0xfc, 0x26, 0x09, 0x9f, 0xf3, 0xbd, 0x4e, 0x7b, 0x39, 0x77, 0x0c, 0xad, 0x79, 0x50, 0xb4, - 0x66, 0x71, 0x35, 0xc9, 0x0e, 0xf7, 0xb7, 0x80, 0xb5, 0x2b, 0x08, 0xad, 0x1d, 0x87, 0xe8, 0xed, - 0xca, 0x1f, 0x67, 0xbb, 0x6a, 0x49, 0x76, 0xb8, 0xbf, 0x05, 0xe6, 0x6b, 0x79, 0x58, 0xac, 0x6c, - 0x54, 0xb7, 0x7d, 0x6b, 0x77, 0xd7, 0xae, 0x63, 0xaf, 0x13, 0xda, 0x6e, 0x13, 0xbd, 0x13, 0x26, - 0x6d, 0xb7, 0xe9, 0x93, 0x20, 0x60, 0x13, 0x39, 0x55, 0x9d, 0x17, 0x44, 0x27, 0xd7, 0x79, 0x31, - 0x96, 0x70, 0xf4, 0x14, 0x4c, 0x07, 0xc4, 0xdf, 0xb7, 0xeb, 0x64, 0xcb, 0xf3, 0x43, 0x36, 0xd2, - 0xc5, 0xea, 0x09, 0x81, 0x3e, 0x5d, 0x8b, 0x40, 0x58, 0xc7, 0xa3, 0xd5, 0x7c, 0xcf, 0x0b, 0x05, - 0x9c, 0x0d, 0xc4, 0x54, 0x54, 0x0d, 0x47, 0x20, 0xac, 0xe3, 0xa1, 0x37, 0x0c, 0x58, 0x08, 0x42, - 0xbb, 0x7e, 0xcb, 0x76, 0x49, 0x10, 0xac, 0x7a, 0xee, 0xae, 0xdd, 0x5c, 0x2e, 0xb2, 0x51, 0xbc, - 0x32, 0xde, 0x28, 0xd6, 0x12, 0x54, 0xab, 0x4b, 0xbd, 0x6e, 0x79, 0x21, 0x59, 0x8a, 0xfb, 0xb8, - 0xa3, 0x35, 0x58, 0xb0, 0x5c, 0xd7, 0x0b, 0xad, 0xd0, 0xf6, 0xdc, 0x2d, 0x9f, 0xec, 0xda, 0x77, - 0x96, 0x0b, 0xac, 0x3b, 0xcb, 0xa2, 0x3b, 0x0b, 0x95, 0x04, 0x1c, 0xf7, 0xd5, 0x30, 0xd7, 0x60, - 0xb9, 0xd2, 0xda, 0xb1, 0x82, 0xc0, 0x6a, 0x78, 0x7e, 0x62, 0x36, 0x1e, 0x87, 0x52, 0xcb, 0x6a, - 0xb7, 0x6d, 0xb7, 0x49, 0xa7, 0x23, 0xff, 0xf8, 0x54, 0x75, 0xa6, 0xd7, 0x2d, 0x97, 0x36, 0x45, - 0x19, 0x56, 0x50, 0xf3, 0x07, 0x39, 0x98, 0xae, 0xb8, 0x96, 0x73, 0x10, 0xd8, 0x01, 0xee, 0xb8, - 0xe8, 0x63, 0x50, 0xa2, 0xd2, 0xa5, 0x61, 0x85, 0x96, 0xd8, 0x91, 0xef, 0x59, 0xe1, 0x9b, 0x7d, - 0x45, 0xdf, 0xec, 0xd1, 0xb8, 0x50, 0xec, 0x95, 0xfd, 0xf7, 0xae, 0x5c, 0xdd, 0xb9, 0x49, 0xea, - 0xe1, 0x26, 0x09, 0xad, 0x2a, 0x12, 0xbd, 0x80, 0xa8, 0x0c, 0x2b, 0xaa, 0xc8, 0x83, 0x42, 0xd0, - 0x26, 0x75, 0xb1, 0xc3, 0x36, 0xc7, 0x5c, 0xc9, 0x51, 0xd3, 0x6b, 0x6d, 0x52, 0xaf, 0xce, 0x08, - 0xd6, 0x05, 0xfa, 0x0f, 0x33, 0x46, 0xe8, 0x36, 0x4c, 0x04, 0x4c, 0xe6, 0x88, 0xcd, 0x73, 0x35, - 0x3b, 0x96, 0x8c, 0x6c, 0x75, 0x4e, 0x30, 0x9d, 0xe0, 0xff, 0xb1, 0x60, 0x67, 0xfe, 0x83, 0x01, - 0x27, 0x34, 0xec, 0x8a, 0xdf, 0xec, 0xb4, 0x88, 0x1b, 0xa2, 0x47, 0xa0, 0xe0, 0x5a, 0x2d, 0x22, - 0x36, 0x8a, 0x6a, 0xf2, 0x15, 0xab, 0x45, 0x30, 0x83, 0xa0, 0x47, 0xa1, 0xb8, 0x6f, 0x39, 0x1d, - 0xc2, 0x06, 0x69, 0xaa, 0x3a, 0x2b, 0x50, 0x8a, 0x2f, 0xd0, 0x42, 0xcc, 0x61, 0xe8, 0x93, 0x30, - 0xc5, 0x7e, 0x5c, 0xf4, 0xbd, 0x56, 0x46, 0x5d, 0x13, 0x2d, 0x7c, 0x41, 0x92, 0xad, 0xce, 0xf6, - 0xba, 0xe5, 0x29, 0xf5, 0x17, 0x47, 0x0c, 0xcd, 0x7f, 0x34, 0x60, 0x5e, 0xeb, 0xdc, 0x86, 0x1d, - 0x84, 0xe8, 0x23, 0x7d, 0x8b, 0x67, 0x65, 0xb8, 0xc5, 0x43, 0x6b, 0xb3, 0xa5, 0xb3, 0x20, 0x7a, - 0x5a, 0x92, 0x25, 0xda, 0xc2, 0x71, 0xa1, 0x68, 0x87, 0xa4, 0x15, 0x2c, 0xe7, 0x1e, 0xc9, 0x3f, - 0x3e, 0x7d, 0x7e, 0x3d, 0xb3, 0x69, 0x8c, 0xc6, 0x77, 0x9d, 0xd2, 0xc7, 0x9c, 0x8d, 0xf9, 0x8d, - 0x42, 0xac, 0x87, 0x74, 0x45, 0x21, 0x0f, 0x26, 0x5b, 0x24, 0xf4, 0xed, 0x3a, 0xdf, 0x57, 0xd3, - 0xe7, 0xd7, 0xc6, 0x6b, 0xc5, 0x26, 0x23, 0x16, 0x09, 0x4b, 0xfe, 0x3f, 0xc0, 0x92, 0x0b, 0xda, - 0x83, 0x82, 0xe5, 0x37, 0x65, 0x9f, 0x2f, 0x66, 0x33, 0xbf, 0xd1, 0x9a, 0xab, 0xf8, 0xcd, 0x00, - 0x33, 0x0e, 0xe8, 0x1c, 0x4c, 0x85, 0xc4, 0x6f, 0xd9, 0xae, 0x15, 0x72, 0xe9, 0x5a, 0xaa, 0x2e, - 0x0a, 0xb4, 0xa9, 0x6d, 0x09, 0xc0, 0x11, 0x0e, 0x72, 0x60, 0xa2, 0xe1, 0x1f, 0xe0, 0x8e, 0xbb, - 0x5c, 0xc8, 0x62, 0x28, 0xd6, 0x18, 0xad, 0x68, 0x33, 0xf1, 0xff, 0x58, 0xf0, 0x40, 0x5f, 0x33, - 0x60, 0xa9, 0x45, 0xac, 0xa0, 0xe3, 0x13, 0xda, 0x05, 0x4c, 0x42, 0xe2, 0x52, 0x69, 0xb8, 0x5c, - 0x64, 0xcc, 0xf1, 0xb8, 0xf3, 0xd0, 0x4f, 0xb9, 0xfa, 0xb0, 0x68, 0xca, 0x52, 0x1a, 0x14, 0xa7, - 0xb6, 0xc6, 0xfc, 0x41, 0x01, 0x16, 0xfb, 0x24, 0x04, 0x7a, 0x12, 0x8a, 0xed, 0x3d, 0x2b, 0x90, - 0x5b, 0xfe, 0xac, 0x5c, 0x6f, 0x5b, 0xb4, 0xf0, 0x6e, 0xb7, 0x3c, 0x2b, 0xab, 0xb0, 0x02, 0xcc, - 0x91, 0xe9, 0x99, 0xda, 0x22, 0x41, 0x60, 0x35, 0xa5, 0x1c, 0xd0, 0x96, 0x09, 0x2b, 0xc6, 0x12, - 0x8e, 0x7e, 0xc5, 0x80, 0x59, 0xbe, 0x64, 0x30, 0x09, 0x3a, 0x4e, 0x48, 0x65, 0x1d, 0x1d, 0x96, - 0xcb, 0x59, 0x2c, 0x4f, 0x4e, 0xb2, 0x7a, 0x52, 0x70, 0x9f, 0xd5, 0x4b, 0x03, 0x1c, 0xe7, 0x8b, - 0x6e, 0xc0, 0x54, 0x10, 0x5a, 0x7e, 0x48, 0x1a, 0x95, 0x90, 0x9d, 0x6a, 0xd3, 0xe7, 0xff, 0xf7, - 0x70, 0x42, 0x60, 0xdb, 0x6e, 0x11, 0x2e, 0x70, 0x6a, 0x92, 0x00, 0x8e, 0x68, 0xa1, 0x4f, 0x02, - 0xf8, 0x1d, 0xb7, 0xd6, 0x69, 0xb5, 0x2c, 0xff, 0x40, 0x9c, 0xe0, 0x97, 0xc6, 0xeb, 0x1e, 0x56, - 0xf4, 0xa2, 0x33, 0x2b, 0x2a, 0xc3, 0x1a, 0x3f, 0xf4, 0xaa, 0x01, 0xb3, 0x7c, 0x25, 0xca, 0x16, - 0x4c, 0x64, 0xdc, 0x82, 0x45, 0x3a, 0xb4, 0x6b, 0x3a, 0x0b, 0x1c, 0xe7, 0x68, 0xfe, 0x5d, 0xfc, - 0x3c, 0xa9, 0x85, 0x54, 0xbb, 0x6e, 0x1e, 0xa0, 0x0f, 0xc3, 0x83, 0x41, 0xa7, 0x5e, 0x27, 0x41, - 0xb0, 0xdb, 0x71, 0x70, 0xc7, 0xbd, 0x64, 0x07, 0xa1, 0xe7, 0x1f, 0x6c, 0xd8, 0x2d, 0x3b, 0x64, - 0x2b, 0xae, 0x58, 0x3d, 0xd3, 0xeb, 0x96, 0x1f, 0xac, 0x0d, 0x42, 0xc2, 0x83, 0xeb, 0x23, 0x0b, - 0x1e, 0xea, 0xb8, 0x83, 0xc9, 0x73, 0xed, 0xad, 0xdc, 0xeb, 0x96, 0x1f, 0xba, 0x3e, 0x18, 0x0d, - 0x1f, 0x46, 0xc3, 0xfc, 0x17, 0x03, 0x16, 0x64, 0xbf, 0xb6, 0x49, 0xab, 0xed, 0x50, 0xe9, 0x72, - 0xfc, 0x8a, 0x48, 0x18, 0x53, 0x44, 0x70, 0x36, 0xc7, 0x89, 0x6c, 0xff, 0x20, 0x6d, 0xc4, 0xfc, - 0x67, 0x03, 0x96, 0x92, 0xc8, 0xf7, 0xe1, 0xf0, 0x0c, 0xe2, 0x87, 0xe7, 0x95, 0x6c, 0x7b, 0x3b, - 0xe0, 0x04, 0x7d, 0xbd, 0xd0, 0xdf, 0xd7, 0xff, 0xee, 0xc7, 0x68, 0x74, 0x2a, 0xe6, 0x7f, 0x9e, - 0xa7, 0x62, 0xe1, 0x2d, 0x75, 0x2a, 0xfe, 0x6e, 0x01, 0x66, 0x2a, 0x6e, 0x68, 0x57, 0x76, 0x77, - 0x6d, 0xd7, 0x0e, 0x0f, 0xd0, 0xe7, 0x72, 0x70, 0xae, 0xed, 0x93, 0x5d, 0xe2, 0xfb, 0xa4, 0xb1, - 0xd6, 0xf1, 0x6d, 0xb7, 0x59, 0xab, 0xef, 0x91, 0x46, 0xc7, 0xb1, 0xdd, 0xe6, 0x7a, 0xd3, 0xf5, - 0x54, 0xf1, 0x85, 0x3b, 0xa4, 0xde, 0x61, 0x5d, 0xe2, 0x9b, 0xa2, 0x35, 0x5e, 0x97, 0xb6, 0x46, - 0x63, 0x5a, 0x7d, 0xa2, 0xd7, 0x2d, 0x9f, 0x1b, 0xb1, 0x12, 0x1e, 0xb5, 0x6b, 0xe8, 0xb3, 0x39, - 0x58, 0xf1, 0xc9, 0xc7, 0x3b, 0xf6, 0xf0, 0xa3, 0xc1, 0xa5, 0x96, 0x33, 0xe6, 0xf1, 0x33, 0x12, - 0xcf, 0xea, 0xf9, 0x5e, 0xb7, 0x3c, 0x62, 0x1d, 0x3c, 0x62, 0xbf, 0xcc, 0x3f, 0x37, 0xa0, 0x34, - 0x82, 0xa5, 0x54, 0x8e, 0x5b, 0x4a, 0x53, 0x7d, 0x56, 0x52, 0xd8, 0x6f, 0x25, 0x3d, 0x37, 0xde, - 0xa0, 0x0d, 0x63, 0x1d, 0xfd, 0x9b, 0x01, 0x8b, 0x7d, 0xd6, 0x14, 0xda, 0x83, 0xa5, 0xb6, 0xd7, - 0x90, 0x92, 0xf0, 0x92, 0x15, 0xec, 0x31, 0x98, 0xe8, 0xde, 0x93, 0x74, 0x53, 0x6d, 0xa5, 0xc0, - 0xef, 0x76, 0xcb, 0xcb, 0x8a, 0x48, 0x02, 0x01, 0xa7, 0x52, 0x44, 0x6d, 0x28, 0xed, 0xda, 0xc4, - 0x69, 0x60, 0xb2, 0x2b, 0x56, 0xca, 0x98, 0x32, 0xef, 0xa2, 0xa0, 0xc6, 0x1d, 0x09, 0xf2, 0x1f, - 0x56, 0x5c, 0xcc, 0x6b, 0x30, 0x17, 0x77, 0x2b, 0x0d, 0x31, 0x79, 0x67, 0x20, 0x6f, 0xf9, 0xae, - 0x98, 0xba, 0x69, 0x81, 0x90, 0xaf, 0xe0, 0x2b, 0x98, 0x96, 0x9b, 0x3f, 0x2b, 0xc0, 0x7c, 0xd5, - 0xe9, 0x90, 0xe7, 0x7c, 0x42, 0xa4, 0x26, 0x5d, 0x81, 0xf9, 0xb6, 0x4f, 0xf6, 0x6d, 0x72, 0xbb, - 0x46, 0x1c, 0x52, 0x0f, 0x3d, 0x5f, 0xd0, 0x3f, 0x25, 0xaa, 0xcf, 0x6f, 0xc5, 0xc1, 0x38, 0x89, - 0x8f, 0x9e, 0x85, 0x39, 0xab, 0x1e, 0xda, 0xfb, 0x44, 0x51, 0xe0, 0x0d, 0x78, 0x9b, 0xa0, 0x30, - 0x57, 0x89, 0x41, 0x71, 0x02, 0x1b, 0x7d, 0x04, 0x96, 0x83, 0xba, 0xe5, 0x90, 0xeb, 0x6d, 0xc1, - 0x6a, 0x75, 0x8f, 0xd4, 0x6f, 0x6d, 0x79, 0xb6, 0x1b, 0x0a, 0xbb, 0xe9, 0x11, 0x41, 0x69, 0xb9, - 0x36, 0x00, 0x0f, 0x0f, 0xa4, 0x80, 0xfe, 0xc4, 0x80, 0x33, 0x6d, 0x9f, 0x6c, 0xf9, 0x5e, 0xcb, - 0xa3, 0x1b, 0xa2, 0xcf, 0x98, 0x10, 0x4a, 0xf5, 0x0b, 0x63, 0xee, 0x7c, 0x5e, 0xd2, 0xef, 0xcc, - 0x78, 0x7b, 0xaf, 0x5b, 0x3e, 0xb3, 0x75, 0x58, 0x03, 0xf0, 0xe1, 0xed, 0x43, 0x7f, 0x66, 0xc0, - 0xd9, 0xb6, 0x17, 0x84, 0x87, 0x74, 0xa1, 0x78, 0xac, 0x5d, 0x30, 0x7b, 0xdd, 0xf2, 0xd9, 0xad, - 0x43, 0x5b, 0x80, 0xef, 0xd1, 0x42, 0xb3, 0x37, 0x0d, 0x8b, 0xda, 0xda, 0x13, 0x9a, 0xf6, 0x33, - 0x30, 0x2b, 0x17, 0x03, 0xf7, 0x42, 0xf2, 0xb5, 0xa7, 0x2c, 0xa3, 0x8a, 0x0e, 0xc4, 0x71, 0x5c, - 0xba, 0xee, 0xd4, 0x52, 0xe4, 0xb5, 0x13, 0xeb, 0x6e, 0x2b, 0x06, 0xc5, 0x09, 0x6c, 0xb4, 0x0e, - 0x27, 0x44, 0x09, 0x26, 0x6d, 0xc7, 0xae, 0x5b, 0xab, 0x5e, 0x47, 0x2c, 0xb9, 0x62, 0xf5, 0x54, - 0xaf, 0x5b, 0x3e, 0xb1, 0xd5, 0x0f, 0xc6, 0x69, 0x75, 0xd0, 0x06, 0x2c, 0x59, 0x9d, 0xd0, 0x53, - 0xfd, 0xbf, 0xe0, 0x5a, 0x3b, 0x0e, 0x69, 0xb0, 0xa5, 0x55, 0xaa, 0x2e, 0x53, 0x41, 0x54, 0x49, - 0x81, 0xe3, 0xd4, 0x5a, 0x68, 0x2b, 0x41, 0xad, 0x46, 0xea, 0x9e, 0xdb, 0xe0, 0xb3, 0x5c, 0x8c, - 0xf4, 0x85, 0x4a, 0x0a, 0x0e, 0x4e, 0xad, 0x89, 0x1c, 0x98, 0x6b, 0x59, 0x77, 0xae, 0xbb, 0xd6, - 0xbe, 0x65, 0x3b, 0x94, 0x89, 0xb0, 0xb6, 0x06, 0x9b, 0x00, 0x9d, 0xd0, 0x76, 0x56, 0xf8, 0xc5, - 0xc3, 0xca, 0xba, 0x1b, 0x5e, 0xf5, 0x6b, 0x21, 0x3d, 0x57, 0xaa, 0x88, 0x0e, 0xec, 0x66, 0x8c, - 0x16, 0x4e, 0xd0, 0x46, 0x57, 0xe1, 0x24, 0xdb, 0x8e, 0x6b, 0xde, 0x6d, 0x77, 0x8d, 0x38, 0xd6, - 0x81, 0xec, 0xc0, 0x24, 0xeb, 0xc0, 0x83, 0xbd, 0x6e, 0xf9, 0x64, 0x2d, 0x0d, 0x01, 0xa7, 0xd7, - 0xa3, 0x36, 0x53, 0x1c, 0x80, 0xc9, 0xbe, 0x1d, 0xd8, 0x9e, 0xcb, 0x6d, 0xa6, 0x52, 0x64, 0x33, - 0xd5, 0x06, 0xa3, 0xe1, 0xc3, 0x68, 0xa0, 0xdf, 0x32, 0x60, 0x29, 0x6d, 0x1b, 0x2e, 0x4f, 0x65, - 0xe1, 0x56, 0x4d, 0x6c, 0x2d, 0xbe, 0x22, 0x52, 0x85, 0x42, 0x6a, 0x23, 0xd0, 0x2b, 0x06, 0xcc, - 0x58, 0x9a, 0xbe, 0xb7, 0x0c, 0xac, 0x55, 0x97, 0xc7, 0xb5, 0x3a, 0x22, 0x8a, 0xd5, 0x85, 0x5e, - 0xb7, 0x1c, 0xd3, 0x29, 0x71, 0x8c, 0x23, 0xfa, 0x6d, 0x03, 0x4e, 0xa6, 0xee, 0xf1, 0xe5, 0xe9, - 0xe3, 0x18, 0x21, 0xb6, 0x48, 0xd2, 0x65, 0x4e, 0x7a, 0x33, 0xd0, 0x1b, 0x86, 0x3a, 0xca, 0x36, - 0xa5, 0xdd, 0x37, 0xc3, 0x9a, 0x76, 0x6d, 0x4c, 0x15, 0x37, 0x52, 0x08, 0x24, 0xe1, 0xea, 0x09, - 0xed, 0x64, 0x94, 0x85, 0x38, 0xc9, 0x1e, 0x7d, 0xde, 0x90, 0x47, 0xa3, 0x6a, 0xd1, 0xec, 0x71, - 0xb5, 0x08, 0x45, 0x27, 0xad, 0x6a, 0x50, 0x82, 0x39, 0xfa, 0x28, 0x9c, 0xb6, 0x76, 0x3c, 0x3f, - 0x4c, 0xdd, 0x7c, 0xcb, 0x73, 0x6c, 0x1b, 0x9d, 0xed, 0x75, 0xcb, 0xa7, 0x2b, 0x03, 0xb1, 0xf0, - 0x21, 0x14, 0xcc, 0x1f, 0x16, 0x60, 0x86, 0xdf, 0xc5, 0x89, 0xa3, 0xeb, 0x9b, 0x06, 0x3c, 0x5c, - 0xef, 0xf8, 0x3e, 0x71, 0xc3, 0x5a, 0x48, 0xda, 0xfd, 0x07, 0x97, 0x71, 0xac, 0x07, 0xd7, 0x23, - 0xbd, 0x6e, 0xf9, 0xe1, 0xd5, 0x43, 0xf8, 0xe3, 0x43, 0x5b, 0x87, 0xfe, 0xda, 0x00, 0x53, 0x20, - 0x54, 0xad, 0xfa, 0xad, 0xa6, 0xef, 0x75, 0xdc, 0x46, 0x7f, 0x27, 0x72, 0xc7, 0xda, 0x89, 0xc7, - 0x7a, 0xdd, 0xb2, 0xb9, 0x7a, 0xcf, 0x56, 0xe0, 0x21, 0x5a, 0x8a, 0x9e, 0x83, 0x45, 0x81, 0x75, - 0xe1, 0x4e, 0x9b, 0xf8, 0x36, 0x55, 0xa7, 0xc5, 0xcd, 0x5f, 0x74, 0x99, 0x9a, 0x44, 0xc0, 0xfd, - 0x75, 0x50, 0x00, 0x93, 0xb7, 0x89, 0xdd, 0xdc, 0x0b, 0xa5, 0xfa, 0x34, 0xe6, 0x0d, 0xaa, 0xb8, - 0x6f, 0xbb, 0xc1, 0x69, 0x56, 0xa7, 0x7b, 0xdd, 0xf2, 0xa4, 0xf8, 0x83, 0x25, 0x27, 0xf3, 0x0f, - 0x0a, 0x00, 0x72, 0x79, 0x91, 0x36, 0xfa, 0x3f, 0x30, 0x15, 0x90, 0x90, 0x63, 0x09, 0xb7, 0x1c, - 0xf7, 0x76, 0xca, 0x42, 0x1c, 0xc1, 0xd1, 0x2d, 0x28, 0xb6, 0xad, 0x4e, 0x40, 0xc4, 0x64, 0x5d, - 0xce, 0x64, 0xb2, 0xb6, 0x28, 0x45, 0x6e, 0x23, 0xb1, 0x9f, 0x98, 0xf3, 0x40, 0x9f, 0x31, 0x00, - 0x48, 0x7c, 0x80, 0xa7, 0xcf, 0xd7, 0x32, 0x61, 0x19, 0xcd, 0x01, 0x1d, 0x83, 0xea, 0x5c, 0xaf, - 0x5b, 0x06, 0x6d, 0xaa, 0x34, 0xb6, 0xe8, 0x36, 0x94, 0x2c, 0x29, 0xa3, 0x0b, 0xc7, 0x21, 0xa3, - 0x99, 0xe9, 0xa2, 0x16, 0x99, 0x62, 0x86, 0x3e, 0x6b, 0xc0, 0x5c, 0x40, 0x42, 0x31, 0x55, 0x54, - 0x52, 0x08, 0x05, 0x75, 0xcc, 0x45, 0x52, 0x8b, 0xd1, 0xe4, 0x12, 0x2f, 0x5e, 0x86, 0x13, 0x7c, - 0xcd, 0x1f, 0x4e, 0xc3, 0x9c, 0x5c, 0x32, 0x91, 0xce, 0xc9, 0x83, 0x03, 0x06, 0xe8, 0x9c, 0xab, - 0x3a, 0x10, 0xc7, 0x71, 0x69, 0x65, 0x7e, 0x83, 0x1f, 0x57, 0x39, 0x55, 0xe5, 0x9a, 0x0e, 0xc4, - 0x71, 0x5c, 0xd4, 0x82, 0x62, 0x10, 0x92, 0xb6, 0xbc, 0x4b, 0x18, 0xd3, 0xd5, 0x1d, 0xed, 0x84, - 0xc8, 0x5b, 0x48, 0xff, 0x05, 0x98, 0x73, 0x41, 0x5f, 0x30, 0x60, 0x2e, 0x8c, 0xdd, 0x63, 0x8b, - 0x65, 0x90, 0xcd, 0x4a, 0x8c, 0x5f, 0x91, 0xf3, 0xd9, 0x88, 0x97, 0xe1, 0x04, 0xfb, 0x14, 0x35, - 0xb4, 0x78, 0x8c, 0x6a, 0xe8, 0x8b, 0x50, 0x6a, 0x59, 0x77, 0x6a, 0x1d, 0xbf, 0x79, 0x74, 0x75, - 0x57, 0x5c, 0xf3, 0x73, 0x2a, 0x58, 0xd1, 0x43, 0xaf, 0x1a, 0xda, 0xe6, 0x9a, 0x64, 0xc4, 0x6f, - 0x64, 0xbb, 0xb9, 0x94, 0x14, 0x1f, 0xb8, 0xcd, 0xfa, 0x94, 0xc2, 0xd2, 0x7d, 0x57, 0x0a, 0xa9, - 0x82, 0xc3, 0x37, 0x88, 0x52, 0x70, 0xa6, 0x8e, 0x55, 0xc1, 0x59, 0x8d, 0x31, 0xc3, 0x09, 0xe6, - 0xac, 0x3d, 0x7c, 0xcf, 0xa9, 0xf6, 0xc0, 0xb1, 0xb6, 0xa7, 0x16, 0x63, 0x86, 0x13, 0xcc, 0x07, - 0x5b, 0x42, 0xd3, 0xc7, 0x63, 0x09, 0xcd, 0x64, 0x60, 0x09, 0x1d, 0xae, 0x24, 0xce, 0x8e, 0xab, - 0x24, 0xa2, 0xcb, 0x80, 0x1a, 0x07, 0xae, 0xd5, 0xb2, 0xeb, 0x42, 0x58, 0xb2, 0x03, 0x62, 0x8e, - 0x59, 0xca, 0xa7, 0x85, 0x20, 0x43, 0x6b, 0x7d, 0x18, 0x38, 0xa5, 0x96, 0xf9, 0x1f, 0x06, 0x2c, - 0xac, 0x3a, 0x5e, 0xa7, 0x71, 0xc3, 0x0a, 0xeb, 0x7b, 0xfc, 0x96, 0x02, 0x3d, 0x0b, 0x25, 0xdb, - 0x0d, 0x89, 0xbf, 0x6f, 0x39, 0x42, 0xb6, 0x9b, 0xf2, 0x22, 0x67, 0x5d, 0x94, 0xdf, 0xed, 0x96, - 0xe7, 0xd6, 0x3a, 0x3e, 0x0b, 0xff, 0xe1, 0x3b, 0x1d, 0xab, 0x3a, 0xe8, 0xab, 0x06, 0x2c, 0xf2, - 0x7b, 0x8e, 0x35, 0x2b, 0xb4, 0xae, 0x75, 0x88, 0x6f, 0x13, 0x79, 0xd3, 0x31, 0xe6, 0x26, 0x4f, - 0xb6, 0x55, 0x32, 0x38, 0x88, 0xd4, 0xaf, 0xcd, 0x24, 0x67, 0xdc, 0xdf, 0x18, 0xf3, 0x8b, 0x79, - 0x78, 0x70, 0x20, 0x2d, 0x74, 0x1a, 0x72, 0x76, 0x43, 0x74, 0x1d, 0x04, 0xdd, 0xdc, 0x7a, 0x03, - 0xe7, 0xec, 0x06, 0x5a, 0x61, 0x9a, 0x89, 0x4f, 0x82, 0x40, 0x3a, 0xbd, 0xa7, 0x94, 0x12, 0x21, - 0x4a, 0xb1, 0x86, 0x81, 0xca, 0x50, 0x74, 0xac, 0x1d, 0xe2, 0x08, 0x2d, 0x91, 0xe9, 0x3a, 0x1b, - 0xb4, 0x00, 0xf3, 0x72, 0xf4, 0xcb, 0x06, 0x00, 0x6f, 0x20, 0xd5, 0x31, 0xc5, 0x09, 0x83, 0xb3, - 0x1d, 0x26, 0x4a, 0x99, 0xb7, 0x32, 0xfa, 0x8f, 0x35, 0xae, 0x68, 0x1b, 0x26, 0xa8, 0xda, 0xe3, - 0x35, 0x8e, 0x7c, 0xa0, 0x40, 0xaf, 0x5b, 0x9e, 0xd8, 0x62, 0x34, 0xb0, 0xa0, 0x45, 0xc7, 0xca, - 0x27, 0x61, 0xc7, 0x77, 0xe9, 0xd0, 0xb2, 0x23, 0xa4, 0xc4, 0x5b, 0x81, 0x55, 0x29, 0xd6, 0x30, - 0xcc, 0x3f, 0xce, 0xc1, 0x52, 0x5a, 0xd3, 0xa9, 0xa4, 0x9e, 0xe0, 0xad, 0x15, 0x06, 0xcf, 0x07, - 0xb3, 0x1f, 0x1f, 0x71, 0x65, 0xa7, 0x2e, 0xb6, 0x44, 0x50, 0x81, 0xe0, 0x8b, 0x3e, 0xa8, 0x46, - 0x28, 0x77, 0xc4, 0x11, 0x52, 0x94, 0x13, 0xa3, 0xf4, 0x08, 0x14, 0x02, 0x3a, 0xf3, 0xf9, 0xb8, - 0x5b, 0x9a, 0xcd, 0x11, 0x83, 0x50, 0x8c, 0x8e, 0x6b, 0x87, 0x22, 0x26, 0x4f, 0x61, 0x5c, 0x77, - 0xed, 0x10, 0x33, 0x88, 0xf9, 0xe5, 0x1c, 0x9c, 0x1e, 0xdc, 0x29, 0xf4, 0x65, 0x03, 0xa0, 0x41, - 0x95, 0x5a, 0xba, 0x24, 0xe5, 0x15, 0xa7, 0x75, 0x5c, 0x63, 0xb8, 0x26, 0x39, 0x45, 0xf7, 0xdd, - 0xaa, 0x28, 0xc0, 0x5a, 0x43, 0xd0, 0x79, 0xb9, 0xf4, 0xaf, 0x58, 0x2d, 0xa9, 0x0a, 0xaa, 0x3a, - 0x9b, 0x0a, 0x82, 0x35, 0x2c, 0x6a, 0xb5, 0xb8, 0x56, 0x8b, 0x04, 0x6d, 0x4b, 0x05, 0x5d, 0x32, - 0xab, 0xe5, 0x8a, 0x2c, 0xc4, 0x11, 0xdc, 0x74, 0xe0, 0xd1, 0x21, 0xda, 0x99, 0x51, 0x00, 0x9c, - 0xf9, 0xef, 0x06, 0x9c, 0x5a, 0x75, 0x3a, 0x41, 0x48, 0xfc, 0xff, 0x31, 0xe1, 0x03, 0xff, 0x69, - 0xc0, 0x43, 0x03, 0xfa, 0x7c, 0x1f, 0xa2, 0x08, 0x5e, 0x8e, 0x47, 0x11, 0x5c, 0x1f, 0x77, 0x49, - 0xa7, 0xf6, 0x63, 0x40, 0x30, 0x41, 0x08, 0xb3, 0x54, 0x6a, 0x35, 0xbc, 0x66, 0x46, 0xe7, 0xe6, - 0xa3, 0x50, 0xfc, 0x38, 0x3d, 0x7f, 0x92, 0x6b, 0x8c, 0x1d, 0x4a, 0x98, 0xc3, 0xcc, 0x0f, 0x80, - 0xb8, 0x72, 0x4f, 0x6c, 0x1e, 0x63, 0x98, 0xcd, 0x63, 0xfe, 0x7d, 0x0e, 0x34, 0x6b, 0xf7, 0x3e, - 0x2c, 0x4a, 0x37, 0xb6, 0x28, 0xc7, 0xb4, 0x5f, 0x35, 0xdb, 0x7d, 0x50, 0x6c, 0xed, 0x7e, 0x22, - 0xb6, 0xf6, 0x4a, 0x66, 0x1c, 0x0f, 0x0f, 0xad, 0xfd, 0x9e, 0x01, 0x0f, 0x45, 0xc8, 0xfd, 0x8e, - 0xa3, 0x7b, 0x4b, 0x98, 0xa7, 0x60, 0xda, 0x8a, 0xaa, 0x89, 0x35, 0xa0, 0xc2, 0xc9, 0x35, 0x8a, - 0x58, 0xc7, 0x8b, 0x22, 0xf9, 0xf2, 0x47, 0x8c, 0xe4, 0x2b, 0x1c, 0x1e, 0xc9, 0x67, 0xfe, 0x34, - 0x07, 0x67, 0xfa, 0x7b, 0x26, 0xf7, 0xc6, 0x70, 0xf7, 0xaa, 0x4f, 0xc3, 0x4c, 0x28, 0x2a, 0x68, - 0x92, 0x5e, 0x3d, 0x86, 0xd8, 0xd6, 0x60, 0x38, 0x86, 0x49, 0x6b, 0xd6, 0xf9, 0xae, 0xac, 0xd5, - 0xbd, 0xb6, 0x8c, 0x03, 0x55, 0x35, 0x57, 0x35, 0x18, 0x8e, 0x61, 0xaa, 0x08, 0x9b, 0xc2, 0xb1, - 0x47, 0xd8, 0xd4, 0xe0, 0xa4, 0x8c, 0x29, 0xb8, 0xe8, 0xf9, 0xab, 0x5e, 0xab, 0xed, 0x10, 0x11, - 0x09, 0x4a, 0x1b, 0x7b, 0x46, 0x54, 0x39, 0x89, 0xd3, 0x90, 0x70, 0x7a, 0x5d, 0xf3, 0x7b, 0x79, - 0x38, 0x11, 0x0d, 0xfb, 0xaa, 0xe7, 0x36, 0x6c, 0x16, 0x99, 0xf1, 0x0c, 0x14, 0xc2, 0x83, 0xb6, - 0x1c, 0xec, 0xff, 0x25, 0x9b, 0xb3, 0x7d, 0xd0, 0xa6, 0xb3, 0x7d, 0x2a, 0xa5, 0x0a, 0x05, 0x61, - 0x56, 0x09, 0x6d, 0xa8, 0xdd, 0xc1, 0x67, 0xe0, 0xc9, 0xf8, 0x6a, 0xbe, 0xdb, 0x2d, 0xa7, 0xbc, - 0x05, 0x5a, 0x51, 0x94, 0xe2, 0x6b, 0x1e, 0xdd, 0x84, 0x39, 0xc7, 0x0a, 0xc2, 0xeb, 0xed, 0x86, - 0x15, 0x92, 0x6d, 0xbb, 0x45, 0xc4, 0x9e, 0x1b, 0x25, 0xbc, 0x52, 0xdd, 0x35, 0x6e, 0xc4, 0x28, - 0xe1, 0x04, 0x65, 0xb4, 0x0f, 0x88, 0x96, 0x6c, 0xfb, 0x96, 0x1b, 0xf0, 0x5e, 0x51, 0x7e, 0xa3, - 0x87, 0x73, 0x2a, 0x03, 0x69, 0xa3, 0x8f, 0x1a, 0x4e, 0xe1, 0x80, 0x1e, 0x83, 0x09, 0x9f, 0x58, - 0x81, 0x98, 0xcc, 0xa9, 0x68, 0xff, 0x63, 0x56, 0x8a, 0x05, 0x54, 0xdf, 0x50, 0x13, 0xf7, 0xd8, - 0x50, 0x3f, 0x32, 0x60, 0x2e, 0x9a, 0xa6, 0xfb, 0x70, 0x48, 0xb6, 0xe2, 0x87, 0xe4, 0xa5, 0xac, - 0x44, 0xe2, 0x80, 0x73, 0xf1, 0x2f, 0x26, 0xf4, 0xfe, 0xb1, 0xf0, 0xba, 0x4f, 0xc0, 0x94, 0xdc, - 0xd5, 0x52, 0xfb, 0x1c, 0xd3, 0xcb, 0x12, 0xd3, 0x4b, 0xb4, 0xb0, 0x70, 0xc1, 0x04, 0x47, 0xfc, - 0xe8, 0xb1, 0xdc, 0x10, 0x47, 0xae, 0x58, 0xf6, 0xea, 0x58, 0x96, 0x47, 0x71, 0xda, 0xb1, 0x2c, - 0xeb, 0xa0, 0xeb, 0x70, 0xaa, 0xed, 0x7b, 0xec, 0xa9, 0xd0, 0x1a, 0xb1, 0x1a, 0x8e, 0xed, 0x12, - 0x69, 0xcc, 0xf3, 0xab, 0xee, 0x87, 0x7a, 0xdd, 0xf2, 0xa9, 0xad, 0x74, 0x14, 0x3c, 0xa8, 0x6e, - 0x3c, 0xbc, 0xbd, 0x30, 0x44, 0x78, 0xfb, 0xaf, 0x2a, 0x97, 0x19, 0x09, 0x44, 0x90, 0xf9, 0x87, - 0xb3, 0x9a, 0xca, 0x14, 0xb1, 0x1e, 0x2d, 0xa9, 0x8a, 0x60, 0x8a, 0x15, 0xfb, 0xc1, 0x7e, 0x99, - 0x89, 0x23, 0xfa, 0x65, 0xa2, 0x28, 0xc5, 0xc9, 0x9f, 0x67, 0x94, 0x62, 0xe9, 0x2d, 0x15, 0xa5, - 0xf8, 0x5a, 0x11, 0x16, 0x92, 0x1a, 0xc8, 0xf1, 0x87, 0xee, 0xff, 0x86, 0x01, 0x0b, 0x72, 0xf7, - 0x70, 0x9e, 0x44, 0x7a, 0xdc, 0x37, 0x32, 0xda, 0xb4, 0x5c, 0x97, 0x52, 0x8f, 0xcb, 0xb6, 0x13, - 0xdc, 0x70, 0x1f, 0x7f, 0xf4, 0x12, 0x4c, 0x2b, 0xc7, 0xf4, 0x91, 0xe2, 0xf8, 0xe7, 0x99, 0x16, - 0x15, 0x91, 0xc0, 0x3a, 0x3d, 0xf4, 0x9a, 0x01, 0x50, 0x97, 0xc7, 0x9c, 0xdc, 0x5d, 0xd7, 0xb2, - 0xda, 0x5d, 0xea, 0x00, 0x8d, 0x94, 0x65, 0x55, 0x14, 0x60, 0x8d, 0x31, 0xfa, 0x22, 0x73, 0x49, - 0x2b, 0xed, 0x8e, 0xee, 0x27, 0xda, 0x92, 0x0f, 0x65, 0xbd, 0xcf, 0xa3, 0xdb, 0x51, 0xa5, 0x4a, - 0x69, 0xa0, 0x00, 0xc7, 0x1a, 0x61, 0x3e, 0x03, 0x2a, 0xc0, 0x8e, 0x8a, 0x2d, 0x16, 0x62, 0xb7, - 0x65, 0x85, 0x7b, 0x62, 0x09, 0x2a, 0xb1, 0x75, 0x51, 0x02, 0x70, 0x84, 0x63, 0x7e, 0x0c, 0xe6, - 0x9e, 0xf3, 0xad, 0xf6, 0x9e, 0xcd, 0x5c, 0xbf, 0xd4, 0x4e, 0x7a, 0x27, 0x4c, 0x5a, 0x8d, 0x46, - 0xda, 0xd3, 0xcc, 0x0a, 0x2f, 0xc6, 0x12, 0x3e, 0x9c, 0x49, 0xf4, 0x2d, 0x03, 0x96, 0xd6, 0x83, - 0xd0, 0xf6, 0xd6, 0x48, 0x10, 0x52, 0x59, 0x49, 0x77, 0x54, 0xc7, 0x21, 0x43, 0x28, 0xa6, 0x6b, - 0xb0, 0x20, 0xee, 0xa7, 0x3a, 0x3b, 0x01, 0x09, 0x35, 0xe5, 0x54, 0x2d, 0xce, 0xd5, 0x04, 0x1c, - 0xf7, 0xd5, 0xa0, 0x54, 0xc4, 0x45, 0x55, 0x44, 0x25, 0x1f, 0xa7, 0x52, 0x4b, 0xc0, 0x71, 0x5f, - 0x0d, 0xf3, 0xbb, 0x79, 0x38, 0xc1, 0xba, 0x91, 0x78, 0x3b, 0xf9, 0x79, 0x03, 0xe6, 0xf6, 0x6d, - 0x3f, 0xec, 0x58, 0x8e, 0x7e, 0xe3, 0x36, 0xf6, 0xfa, 0x64, 0xbc, 0x5e, 0x88, 0x11, 0xe6, 0x3e, - 0xf9, 0x78, 0x19, 0x4e, 0x30, 0x47, 0xbf, 0x6e, 0xc0, 0x7c, 0x23, 0x3e, 0xd2, 0xd9, 0xf8, 0x1c, - 0xd2, 0xe6, 0x90, 0x07, 0x8a, 0x24, 0x0a, 0x71, 0x92, 0x3f, 0xfa, 0x92, 0x01, 0xf3, 0xf1, 0x66, - 0x4a, 0x91, 0x75, 0x0c, 0x83, 0xa4, 0x22, 0x3b, 0xe3, 0xe5, 0x01, 0x4e, 0x36, 0xc1, 0xfc, 0x5b, - 0x43, 0x4c, 0x69, 0x1c, 0x73, 0x88, 0x85, 0x69, 0xc2, 0x84, 0xef, 0x75, 0x42, 0xe1, 0x37, 0x9f, - 0xe2, 0xee, 0x55, 0xcc, 0x4a, 0xb0, 0x80, 0xa0, 0xdb, 0x30, 0x15, 0x3a, 0x01, 0x2f, 0x14, 0xbd, - 0x1d, 0xd3, 0xcc, 0xd9, 0xde, 0xa8, 0x31, 0x72, 0x9a, 0x26, 0x22, 0x4a, 0xa8, 0x46, 0x25, 0x79, - 0x99, 0x5f, 0x37, 0x60, 0xea, 0xb2, 0xb7, 0x23, 0xb6, 0xf3, 0x47, 0x33, 0x70, 0x22, 0x28, 0x5d, - 0x43, 0xdd, 0x04, 0x45, 0xea, 0xeb, 0xb3, 0x31, 0x17, 0xc2, 0xc3, 0x1a, 0xed, 0x15, 0x96, 0xd2, - 0x80, 0x92, 0xba, 0xec, 0xed, 0x0c, 0xf4, 0x50, 0xfd, 0x4e, 0x11, 0x66, 0x9f, 0xb7, 0x0e, 0x88, - 0x1b, 0x5a, 0xa3, 0x0b, 0x20, 0x6a, 0x95, 0xb7, 0x59, 0xa0, 0xa2, 0xa6, 0x3f, 0x46, 0x56, 0x79, - 0x04, 0xc2, 0x3a, 0x5e, 0x24, 0x57, 0xf8, 0x0b, 0xeb, 0x34, 0x89, 0xb0, 0x9a, 0x80, 0xe3, 0xbe, - 0x1a, 0xe8, 0x32, 0x20, 0xf1, 0x5e, 0xa4, 0x52, 0xaf, 0x7b, 0x1d, 0x97, 0x4b, 0x16, 0x6e, 0xb0, - 0x2b, 0x43, 0x66, 0xb3, 0x0f, 0x03, 0xa7, 0xd4, 0x42, 0x1f, 0x81, 0xe5, 0x3a, 0xa3, 0x2c, 0xd4, - 0x5a, 0x9d, 0x22, 0x37, 0x6d, 0x54, 0x90, 0xf0, 0xea, 0x00, 0x3c, 0x3c, 0x90, 0x02, 0x6d, 0x69, - 0x10, 0x7a, 0xbe, 0xd5, 0x24, 0x3a, 0xdd, 0x89, 0x78, 0x4b, 0x6b, 0x7d, 0x18, 0x38, 0xa5, 0x16, - 0xfa, 0x34, 0x4c, 0x85, 0x7b, 0x3e, 0x09, 0xf6, 0x3c, 0xa7, 0x21, 0xae, 0x86, 0xc7, 0xf4, 0xe2, - 0x88, 0xd9, 0xdf, 0x96, 0x54, 0xb5, 0xe5, 0x2d, 0x8b, 0x70, 0xc4, 0x13, 0xf9, 0x30, 0x11, 0xd4, - 0xbd, 0x36, 0x09, 0x84, 0x3a, 0x78, 0x39, 0x13, 0xee, 0xcc, 0x2b, 0xa1, 0xf9, 0x8f, 0x18, 0x07, - 0x2c, 0x38, 0x99, 0xdf, 0xce, 0xc1, 0x8c, 0x8e, 0x38, 0x84, 0x88, 0xf8, 0x8c, 0x01, 0x33, 0x75, - 0xcf, 0x0d, 0x7d, 0xcf, 0xe1, 0xbe, 0x11, 0xbe, 0x41, 0xc6, 0x7c, 0x86, 0xcc, 0x48, 0xad, 0x91, - 0xd0, 0xb2, 0x1d, 0xcd, 0xcd, 0xa2, 0xb1, 0xc1, 0x31, 0xa6, 0xe8, 0x73, 0x06, 0xcc, 0x47, 0x31, - 0x33, 0x91, 0x93, 0x26, 0xd3, 0x86, 0x28, 0x89, 0x7b, 0x21, 0xce, 0x09, 0x27, 0x59, 0x9b, 0x3b, - 0xb0, 0x90, 0x9c, 0x6d, 0x3a, 0x94, 0x6d, 0x4b, 0xec, 0xf5, 0x7c, 0x34, 0x94, 0x5b, 0x56, 0x10, - 0x60, 0x06, 0x41, 0xef, 0x82, 0x52, 0xcb, 0xf2, 0x9b, 0xb6, 0x6b, 0x39, 0x6c, 0x14, 0xf3, 0x9a, - 0x40, 0x12, 0xe5, 0x58, 0x61, 0x98, 0x3f, 0x29, 0xc0, 0xb4, 0xa6, 0xc5, 0x1f, 0xbf, 0x46, 0x1e, - 0x7b, 0xc2, 0x9a, 0xcf, 0xf0, 0x09, 0xeb, 0x8b, 0x00, 0xbb, 0xb6, 0x6b, 0x07, 0x7b, 0x47, 0x7c, - 0x1c, 0xcb, 0x2e, 0xf3, 0x2e, 0x2a, 0x0a, 0x58, 0xa3, 0x16, 0xdd, 0x98, 0x14, 0x0f, 0x49, 0x19, - 0xf0, 0x9a, 0xa1, 0x1d, 0x1e, 0x13, 0x59, 0xdc, 0x10, 0x6b, 0x13, 0xb3, 0x22, 0x0f, 0x93, 0x0b, - 0x6e, 0xe8, 0x1f, 0x1c, 0x7a, 0xc6, 0x6c, 0x43, 0xc9, 0x27, 0x41, 0xa7, 0x45, 0x6d, 0x8b, 0xc9, - 0x91, 0x87, 0x81, 0x05, 0x98, 0x60, 0x51, 0x1f, 0x2b, 0x4a, 0xa7, 0x9f, 0x81, 0xd9, 0x58, 0x13, - 0xd0, 0x02, 0xe4, 0x6f, 0x91, 0x03, 0xbe, 0x4e, 0x30, 0xfd, 0x89, 0x96, 0x62, 0xf7, 0x4a, 0x62, - 0x58, 0xde, 0x9f, 0x7b, 0xda, 0x30, 0x3d, 0x48, 0x35, 0x15, 0x8f, 0xe2, 0xf6, 0xa7, 0x73, 0xe1, - 0x68, 0xaf, 0x63, 0xd5, 0x5c, 0xf0, 0x68, 0x06, 0x0e, 0x33, 0x7f, 0x3a, 0x01, 0xe2, 0xd2, 0x73, - 0x08, 0xe1, 0xa3, 0xdf, 0x75, 0xe4, 0x8e, 0x70, 0xd7, 0x71, 0x19, 0x66, 0x6c, 0xd7, 0x0e, 0x6d, - 0xcb, 0x61, 0x6e, 0x00, 0x71, 0x38, 0x3e, 0x26, 0x05, 0xce, 0xba, 0x06, 0x4b, 0xa1, 0x13, 0xab, - 0x8b, 0xae, 0x41, 0x91, 0x9d, 0x1e, 0x62, 0x01, 0x8f, 0x7e, 0x33, 0xcb, 0x2e, 0xe5, 0xf9, 0xeb, - 0x04, 0x4e, 0x89, 0x69, 0xf4, 0xfc, 0x79, 0xb0, 0x32, 0xd4, 0xc4, 0x3a, 0x8e, 0x34, 0xfa, 0x04, - 0x1c, 0xf7, 0xd5, 0xa0, 0x54, 0x76, 0x2d, 0xdb, 0xe9, 0xf8, 0x24, 0xa2, 0x32, 0x11, 0xa7, 0x72, - 0x31, 0x01, 0xc7, 0x7d, 0x35, 0xd0, 0x2e, 0xcc, 0x88, 0x32, 0x1e, 0xa3, 0x32, 0x79, 0xc4, 0x5e, - 0xb2, 0x58, 0xa4, 0x8b, 0x1a, 0x25, 0x1c, 0xa3, 0x8b, 0x3a, 0xb0, 0x68, 0xbb, 0x75, 0xcf, 0xad, - 0x3b, 0x9d, 0xc0, 0xde, 0x27, 0xd1, 0xd3, 0x80, 0xa3, 0x30, 0x3b, 0xd9, 0xeb, 0x96, 0x17, 0xd7, - 0x93, 0xe4, 0x70, 0x3f, 0x07, 0xf4, 0xaa, 0x01, 0x27, 0xeb, 0x9e, 0x1b, 0xb0, 0xf7, 0x76, 0xfb, - 0xe4, 0x82, 0xef, 0x7b, 0x3e, 0xe7, 0x3d, 0x75, 0x44, 0xde, 0xcc, 0xfb, 0xb4, 0x9a, 0x46, 0x12, - 0xa7, 0x73, 0x42, 0x2f, 0x43, 0xa9, 0xed, 0x7b, 0xfb, 0x76, 0x83, 0xf8, 0x22, 0xde, 0x69, 0x23, - 0x8b, 0xf7, 0xbf, 0x5b, 0x82, 0x66, 0x24, 0x7a, 0x64, 0x09, 0x56, 0xfc, 0xcc, 0xdf, 0x2f, 0xc1, - 0x5c, 0x1c, 0x1d, 0x7d, 0x0a, 0xa0, 0xed, 0x7b, 0x2d, 0x12, 0xee, 0x11, 0x15, 0xe2, 0x7d, 0x65, - 0xdc, 0x67, 0xa6, 0x92, 0x9e, 0x8c, 0x73, 0xa0, 0xe2, 0x22, 0x2a, 0xc5, 0x1a, 0x47, 0xe4, 0xc3, - 0xe4, 0x2d, 0x7e, 0x88, 0x0a, 0x9d, 0xe2, 0xf9, 0x4c, 0x34, 0x20, 0xc1, 0x99, 0xc5, 0x26, 0x8b, - 0x22, 0x2c, 0x19, 0xa1, 0x1d, 0xc8, 0xdf, 0x26, 0x3b, 0xd9, 0x3c, 0x88, 0xbc, 0x41, 0x84, 0x6d, - 0x52, 0x9d, 0xec, 0x75, 0xcb, 0xf9, 0x1b, 0x64, 0x07, 0x53, 0xe2, 0xb4, 0x5f, 0x0d, 0x7e, 0x63, - 0x2b, 0x44, 0xc5, 0x98, 0xfd, 0x8a, 0x5d, 0xff, 0xf2, 0x7e, 0x89, 0x22, 0x2c, 0x19, 0xa1, 0x97, - 0x61, 0xea, 0xb6, 0xb5, 0x4f, 0x76, 0x7d, 0xcf, 0x0d, 0x45, 0x70, 0xcd, 0x98, 0x51, 0xc4, 0x37, - 0x24, 0x39, 0xc1, 0x97, 0x1d, 0xef, 0xaa, 0x10, 0x47, 0xec, 0xd0, 0x3e, 0x94, 0x5c, 0x72, 0x1b, - 0x13, 0xc7, 0xae, 0x8b, 0x00, 0xce, 0x31, 0x97, 0xf5, 0x15, 0x41, 0x4d, 0x70, 0x66, 0xe7, 0x9e, - 0x2c, 0xc3, 0x8a, 0x17, 0x9d, 0xcb, 0x9b, 0xde, 0x8e, 0x10, 0x54, 0x63, 0xce, 0xa5, 0xb2, 0x33, - 0xf9, 0x5c, 0x5e, 0xf6, 0x76, 0x30, 0x25, 0x4e, 0xf7, 0x48, 0x5d, 0x45, 0x76, 0x08, 0x31, 0x75, - 0x25, 0xdb, 0x88, 0x16, 0xbe, 0x47, 0xa2, 0x52, 0xac, 0x71, 0xa4, 0x63, 0xdb, 0x14, 0x6e, 0x2d, - 0x21, 0xa8, 0xc6, 0x1c, 0xdb, 0xb8, 0x93, 0x8c, 0x8f, 0xad, 0x2c, 0xc3, 0x8a, 0x97, 0xf9, 0xf5, - 0x09, 0x98, 0xd1, 0xf3, 0x9d, 0x0c, 0x71, 0x56, 0x2b, 0xfd, 0x34, 0x37, 0x8a, 0x7e, 0x4a, 0xcd, - 0x0b, 0xcd, 0x2b, 0x2d, 0x3d, 0x0c, 0xeb, 0x99, 0xa9, 0x67, 0x91, 0x79, 0xa1, 0x15, 0x06, 0x38, - 0xc6, 0x74, 0x84, 0x8b, 0x6a, 0xaa, 0xe4, 0x70, 0x35, 0xa0, 0x18, 0x57, 0x72, 0x62, 0x07, 0xfb, - 0x79, 0x80, 0x28, 0xef, 0x87, 0xb8, 0xad, 0x50, 0xda, 0x93, 0x96, 0x8f, 0x44, 0xc3, 0x42, 0x8f, - 0xc1, 0x04, 0x3d, 0x28, 0x49, 0x43, 0xbc, 0xbf, 0x53, 0x36, 0xdc, 0x45, 0x56, 0x8a, 0x05, 0x14, - 0x3d, 0x4d, 0x75, 0x9a, 0xe8, 0x78, 0x13, 0xcf, 0xea, 0x96, 0x22, 0x9d, 0x26, 0x82, 0xe1, 0x18, - 0x26, 0x6d, 0x3a, 0xa1, 0xa7, 0x11, 0x5b, 0x49, 0x5a, 0xd3, 0xd9, 0x11, 0x85, 0x39, 0x8c, 0xf9, - 0x14, 0x12, 0xa7, 0x17, 0x3b, 0xac, 0x8a, 0x9a, 0x4f, 0x21, 0x01, 0xc7, 0x7d, 0x35, 0x68, 0x67, - 0xc4, 0x45, 0xcb, 0x34, 0x8f, 0xc7, 0x1b, 0x70, 0x45, 0xf2, 0xba, 0xae, 0x99, 0xcf, 0xb0, 0xa9, - 0xff, 0x60, 0x76, 0xb9, 0x7b, 0x86, 0x57, 0xcd, 0xc7, 0x53, 0xa2, 0x3f, 0x06, 0x73, 0x71, 0x99, - 0x45, 0x17, 0x54, 0xdb, 0xf7, 0x76, 0x6d, 0x87, 0x24, 0x7d, 0x3f, 0x5b, 0xbc, 0x18, 0x4b, 0xf8, - 0x70, 0xce, 0xe7, 0xbf, 0xcc, 0xc3, 0x89, 0x2b, 0x4d, 0xdb, 0xbd, 0x93, 0xf0, 0xda, 0xa6, 0xe5, - 0xd4, 0x33, 0x46, 0xcd, 0xa9, 0x17, 0x3d, 0x97, 0x10, 0x49, 0x0b, 0xd3, 0x9f, 0x4b, 0xc8, 0x8c, - 0x86, 0x71, 0x5c, 0xf4, 0x23, 0x03, 0x1e, 0xb6, 0x1a, 0x5c, 0x8b, 0xb4, 0x1c, 0x51, 0x1a, 0x31, - 0x95, 0x3b, 0x3a, 0x18, 0xf3, 0x4c, 0xe8, 0xef, 0xfc, 0x4a, 0xe5, 0x10, 0xae, 0x7c, 0xc6, 0xdf, - 0x21, 0x7a, 0xf0, 0xf0, 0x61, 0xa8, 0xf8, 0xd0, 0xe6, 0x9f, 0xbe, 0x0a, 0x6f, 0xbf, 0x27, 0xa3, - 0x91, 0x56, 0xcb, 0x67, 0x0c, 0x98, 0xe2, 0x4e, 0x49, 0x4c, 0x76, 0xa9, 0xa8, 0xb0, 0xda, 0xf6, - 0x0b, 0xc4, 0x0f, 0x64, 0xb2, 0x0f, 0xcd, 0xd0, 0xaa, 0x6c, 0xad, 0x0b, 0x08, 0xd6, 0xb0, 0xa8, - 0x30, 0xbe, 0x65, 0xbb, 0x0d, 0x31, 0x4d, 0x4a, 0x18, 0x3f, 0x6f, 0xbb, 0x0d, 0xcc, 0x20, 0x4a, - 0x5c, 0xe7, 0x07, 0x89, 0x6b, 0xf3, 0x6b, 0x06, 0xcc, 0xb1, 0xd7, 0x50, 0x91, 0x09, 0xf0, 0x94, - 0x8a, 0x42, 0xe0, 0xcd, 0x38, 0x13, 0x8f, 0x42, 0xb8, 0xdb, 0x2d, 0x4f, 0xf3, 0xf7, 0x53, 0xf1, - 0xa0, 0x84, 0x0f, 0x0b, 0xbf, 0x01, 0x8b, 0x95, 0xc8, 0x8d, 0x6c, 0xd6, 0x2a, 0x2f, 0x59, 0x4d, - 0x12, 0xc1, 0x11, 0x3d, 0xf3, 0x0f, 0xf3, 0x70, 0x22, 0x25, 0xac, 0x9f, 0x9a, 0xf4, 0x13, 0x2c, - 0xb2, 0x59, 0xde, 0xf4, 0xbf, 0x94, 0xf9, 0xd3, 0x81, 0x15, 0x16, 0x40, 0x2d, 0x56, 0x92, 0x12, - 0x60, 0xbc, 0x10, 0x0b, 0xe6, 0xe8, 0x37, 0x0d, 0x98, 0xb6, 0xb4, 0xc5, 0xce, 0x83, 0x1f, 0x76, - 0xb2, 0x6f, 0x4c, 0xdf, 0xda, 0xd6, 0x82, 0xb6, 0xa2, 0xa5, 0xac, 0xb7, 0xe5, 0xf4, 0xfb, 0x60, - 0x5a, 0xeb, 0xc2, 0x28, 0x6b, 0xf4, 0xf4, 0xb3, 0xb0, 0x30, 0xd6, 0x1a, 0xff, 0x10, 0x8c, 0x9a, - 0x3d, 0x86, 0x1e, 0x19, 0xb7, 0xf5, 0x47, 0x82, 0x6a, 0xc4, 0xc5, 0x2b, 0x41, 0x01, 0x35, 0x77, - 0x60, 0x21, 0x69, 0x66, 0x64, 0x7e, 0xd7, 0xf7, 0x1e, 0x18, 0x31, 0xdf, 0x8b, 0xf9, 0x57, 0x39, - 0x98, 0x14, 0x6f, 0x83, 0xee, 0x43, 0xbc, 0xe3, 0xad, 0xd8, 0x65, 0xc5, 0x7a, 0x26, 0x4f, 0x9a, - 0x06, 0x06, 0x3b, 0x06, 0x89, 0x60, 0xc7, 0xe7, 0xb3, 0x61, 0x77, 0x78, 0xa4, 0xe3, 0xd7, 0x0a, - 0x30, 0x9f, 0x78, 0x6b, 0x45, 0x95, 0x85, 0xbe, 0x00, 0x9f, 0xeb, 0x99, 0x3e, 0xe7, 0x52, 0xb1, - 0xb8, 0x87, 0xc7, 0xfa, 0x04, 0xb1, 0xb4, 0x5a, 0xd7, 0x32, 0xcb, 0xc8, 0xf9, 0x8b, 0x0c, 0x5b, - 0xa3, 0xc6, 0xae, 0xfc, 0x93, 0x01, 0x0f, 0x0e, 0x7c, 0x92, 0xc7, 0x72, 0x0d, 0xf8, 0x71, 0xa8, - 0xd8, 0x90, 0x19, 0x3f, 0xb1, 0x55, 0x37, 0x07, 0xc9, 0xe7, 0xe1, 0x49, 0xf6, 0xe8, 0x49, 0x98, - 0x61, 0x87, 0x1b, 0x95, 0x29, 0x21, 0x69, 0x0b, 0x57, 0x29, 0x73, 0x9a, 0xd5, 0xb4, 0x72, 0x1c, - 0xc3, 0x32, 0xbf, 0x6a, 0xc0, 0xf2, 0xa0, 0x97, 0xe7, 0x43, 0x98, 0x66, 0xff, 0x2f, 0x11, 0x90, - 0x59, 0xee, 0x0b, 0xc8, 0x4c, 0x18, 0x67, 0x32, 0xf6, 0x52, 0xb3, 0x8b, 0xf2, 0xf7, 0x88, 0x37, - 0xfc, 0xbc, 0x01, 0xa7, 0x06, 0xec, 0xa6, 0xbe, 0xc0, 0x5c, 0xe3, 0xc8, 0x81, 0xb9, 0xb9, 0x61, - 0x03, 0x73, 0xcd, 0xbf, 0xc9, 0xc3, 0x82, 0x68, 0x4f, 0xa4, 0xe1, 0x3c, 0x1d, 0x0b, 0x6b, 0x7d, - 0x47, 0x22, 0xac, 0x75, 0x29, 0x89, 0xff, 0x8b, 0x98, 0xd6, 0xb7, 0x56, 0x4c, 0xeb, 0xcf, 0x72, - 0x70, 0x32, 0xf5, 0x81, 0x3d, 0xfa, 0x6c, 0xca, 0xd1, 0x70, 0x23, 0xe3, 0x97, 0xfc, 0x43, 0x1e, - 0x0e, 0xe3, 0x06, 0x82, 0x7e, 0x49, 0x0f, 0xc0, 0xe4, 0xa2, 0x7e, 0xf7, 0x18, 0x72, 0x12, 0x8c, - 0x18, 0x8b, 0x69, 0xfe, 0x5a, 0x1e, 0x1e, 0x1f, 0x96, 0xd0, 0x5b, 0x34, 0x56, 0x3f, 0x88, 0xc5, - 0xea, 0xdf, 0xa7, 0x63, 0xfb, 0x58, 0xc2, 0xf6, 0xbf, 0x9e, 0x57, 0xc7, 0x5e, 0xff, 0xfa, 0x1c, - 0xea, 0x5e, 0x6d, 0x92, 0xaa, 0x76, 0x32, 0x4d, 0x5e, 0x24, 0x0a, 0x27, 0x6b, 0xbc, 0xf8, 0x6e, - 0xb7, 0xbc, 0x28, 0x52, 0x67, 0xd5, 0x48, 0x28, 0x0a, 0xb1, 0xac, 0x84, 0x1e, 0x87, 0x92, 0xcf, - 0xa1, 0x32, 0x3a, 0x59, 0x5c, 0x4e, 0xf2, 0x32, 0xac, 0xa0, 0xe8, 0xd3, 0x9a, 0x2e, 0x5c, 0x38, - 0xae, 0x37, 0xde, 0x87, 0xdd, 0xb9, 0xbe, 0x04, 0xa5, 0x40, 0x26, 0xbc, 0xe3, 0x8e, 0xf1, 0x27, - 0x86, 0x0c, 0x7a, 0xa7, 0xa6, 0x93, 0xcc, 0x7e, 0xc7, 0xfb, 0xa7, 0x72, 0xe3, 0x29, 0x92, 0xc8, - 0x54, 0x56, 0x0b, 0xf7, 0xf2, 0x41, 0x8a, 0xc5, 0xf2, 0x3d, 0x03, 0xa6, 0xc5, 0x6c, 0xdd, 0x87, - 0x38, 0xfc, 0x9b, 0xf1, 0x38, 0xfc, 0x0b, 0x99, 0xc8, 0x8e, 0x01, 0x41, 0xf8, 0x37, 0x61, 0x46, - 0xcf, 0xb1, 0x82, 0x5e, 0xd4, 0x64, 0x9f, 0x31, 0x4e, 0x2e, 0x07, 0x29, 0x1d, 0x23, 0xb9, 0x68, - 0x7e, 0xa5, 0xa4, 0x46, 0x91, 0x45, 0xfb, 0xeb, 0x6b, 0xd0, 0x38, 0x74, 0x0d, 0xea, 0x4b, 0x20, - 0x97, 0xfd, 0x12, 0xb8, 0x06, 0x25, 0x29, 0xa0, 0xc4, 0x31, 0xfe, 0xa8, 0x1e, 0x3d, 0x46, 0x75, - 0x01, 0x4a, 0x4c, 0x5b, 0xb8, 0xcc, 0xd4, 0x52, 0x73, 0xa8, 0x04, 0xa7, 0x22, 0x83, 0x5e, 0x86, - 0xe9, 0xdb, 0x9e, 0x7f, 0xcb, 0xf1, 0x2c, 0x96, 0xca, 0x12, 0xb2, 0xb8, 0xe2, 0x50, 0x2e, 0x27, - 0x1e, 0xa4, 0x7c, 0x23, 0xa2, 0x8f, 0x75, 0x66, 0xa8, 0x02, 0xf3, 0x2d, 0xdb, 0xc5, 0xc4, 0x6a, - 0xa8, 0x70, 0xfb, 0x02, 0xcf, 0xb5, 0x27, 0x95, 0xdc, 0xcd, 0x38, 0x18, 0x27, 0xf1, 0xd1, 0x27, - 0xa0, 0x14, 0x88, 0x3c, 0x2e, 0xd9, 0x5c, 0x46, 0x29, 0x9b, 0x91, 0x13, 0x8d, 0xc6, 0x4e, 0x96, - 0x60, 0xc5, 0x10, 0x6d, 0xc0, 0x92, 0x2f, 0x32, 0x25, 0xc4, 0x52, 0x76, 0xf3, 0xfd, 0xc9, 0x52, - 0xba, 0xe1, 0x14, 0x38, 0x4e, 0xad, 0x45, 0xb5, 0x18, 0x96, 0x2c, 0x88, 0x7b, 0xe5, 0x35, 0x47, - 0x36, 0x5b, 0xf0, 0x0d, 0x2c, 0xa0, 0x87, 0x3d, 0xdf, 0x28, 0x8d, 0xf1, 0x7c, 0xa3, 0x06, 0x27, - 0x93, 0x20, 0x96, 0xcf, 0x81, 0xa5, 0x90, 0xd0, 0x4e, 0x8f, 0xad, 0x34, 0x24, 0x9c, 0x5e, 0x17, - 0xdd, 0x80, 0x29, 0x9f, 0x30, 0xfb, 0xa2, 0x22, 0xaf, 0xbf, 0x47, 0x0e, 0xf4, 0xc1, 0x92, 0x00, - 0x8e, 0x68, 0xd1, 0x79, 0xb7, 0xe2, 0xe9, 0xe6, 0xae, 0x65, 0xf8, 0xd1, 0x11, 0x31, 0xf7, 0x03, - 0xf2, 0xac, 0x98, 0x6f, 0xce, 0xc1, 0x6c, 0xcc, 0xb7, 0x80, 0x1e, 0x85, 0x22, 0x4b, 0x70, 0xc1, - 0xc4, 0x43, 0x29, 0x12, 0x61, 0x7c, 0x70, 0x38, 0x0c, 0x7d, 0xc1, 0x80, 0xf9, 0x76, 0xcc, 0x0f, - 0x2a, 0x25, 0xe7, 0x98, 0x37, 0x6d, 0x71, 0xe7, 0xaa, 0x96, 0xa8, 0x35, 0xce, 0x0c, 0x27, 0xb9, - 0xd3, 0x0d, 0x28, 0x62, 0xdf, 0x1c, 0xe2, 0x33, 0x6c, 0xa1, 0xe3, 0x28, 0x12, 0xab, 0x71, 0x30, - 0x4e, 0xe2, 0xd3, 0x19, 0x66, 0xbd, 0x1b, 0xe7, 0x6b, 0x04, 0x15, 0x49, 0x00, 0x47, 0xb4, 0xd0, - 0xb3, 0x30, 0x27, 0xb2, 0x8c, 0x6d, 0x79, 0x8d, 0x4b, 0x56, 0xb0, 0x27, 0x94, 0x7b, 0x65, 0x8c, - 0xac, 0xc6, 0xa0, 0x38, 0x81, 0xcd, 0xfa, 0x16, 0xa5, 0x72, 0x63, 0x04, 0x26, 0xe2, 0x79, 0x6c, - 0x57, 0xe3, 0x60, 0x9c, 0xc4, 0x47, 0xef, 0xd2, 0xe4, 0x3e, 0xbf, 0x29, 0x53, 0xd2, 0x20, 0x45, - 0xf6, 0x57, 0x60, 0xbe, 0xc3, 0x6c, 0xa1, 0x86, 0x04, 0x8a, 0xfd, 0xa8, 0x18, 0x5e, 0x8f, 0x83, - 0x71, 0x12, 0x1f, 0x3d, 0x03, 0xb3, 0x3e, 0x95, 0x6e, 0x8a, 0x00, 0xbf, 0x3e, 0x53, 0xb7, 0x23, - 0x58, 0x07, 0xe2, 0x38, 0x2e, 0x7a, 0x0e, 0x16, 0xa3, 0xd4, 0x47, 0x92, 0x00, 0xbf, 0x4f, 0x53, - 0xb9, 0x44, 0x2a, 0x49, 0x04, 0xdc, 0x5f, 0x07, 0xfd, 0x7f, 0x58, 0xd0, 0x46, 0x62, 0xdd, 0x6d, - 0x90, 0x3b, 0x22, 0x3d, 0x0d, 0xfb, 0xfe, 0xd2, 0x6a, 0x02, 0x86, 0xfb, 0xb0, 0xd1, 0xfb, 0x61, - 0xae, 0xee, 0x39, 0x0e, 0x93, 0x71, 0x3c, 0x87, 0x2a, 0xcf, 0x43, 0xc3, 0x33, 0xf6, 0xc4, 0x20, - 0x38, 0x81, 0x89, 0x2e, 0x03, 0xf2, 0x76, 0x02, 0xe2, 0xef, 0x93, 0xc6, 0x73, 0xfc, 0xfb, 0x66, - 0xf4, 0x88, 0x9f, 0x8d, 0x47, 0xde, 0x5e, 0xed, 0xc3, 0xc0, 0x29, 0xb5, 0x58, 0x2a, 0x12, 0xed, - 0x15, 0xcc, 0x5c, 0x16, 0x99, 0xf9, 0x93, 0x96, 0xfb, 0x3d, 0x9f, 0xc0, 0xf8, 0x30, 0xc1, 0x03, - 0xa1, 0x97, 0xe7, 0xb3, 0x48, 0xc7, 0xa4, 0xa7, 0x53, 0x8c, 0xce, 0x08, 0x5e, 0x8a, 0x05, 0x27, - 0xf4, 0x29, 0x98, 0xda, 0x91, 0xb9, 0x75, 0x97, 0x17, 0xb2, 0x38, 0x17, 0x13, 0x69, 0xa2, 0x23, - 0xcb, 0x54, 0x01, 0x70, 0xc4, 0x12, 0x3d, 0x06, 0xd3, 0x97, 0xb6, 0x2a, 0x6a, 0x15, 0x2e, 0xb2, - 0xd9, 0x2f, 0xd0, 0x2a, 0x58, 0x07, 0xd0, 0x1d, 0xa6, 0xf4, 0x25, 0xc4, 0xa6, 0x38, 0x3a, 0x6f, - 0xfb, 0xd5, 0x1f, 0x8a, 0xcd, 0x2e, 0x04, 0x71, 0x6d, 0xf9, 0x44, 0x02, 0x5b, 0x94, 0x63, 0x85, - 0x81, 0x5e, 0x82, 0x69, 0x71, 0x5e, 0x30, 0xd9, 0xb4, 0x74, 0xb4, 0x17, 0x56, 0x38, 0x22, 0x81, - 0x75, 0x7a, 0xe8, 0x29, 0x98, 0x6e, 0xb3, 0x94, 0xa3, 0xe4, 0x62, 0xc7, 0x71, 0x96, 0x4f, 0x32, - 0xb9, 0xa9, 0x6e, 0x4a, 0xb6, 0x22, 0x10, 0xd6, 0xf1, 0xd0, 0x13, 0x32, 0x76, 0xe1, 0x6d, 0xb1, - 0x8b, 0x2f, 0x15, 0xbb, 0xa0, 0xb4, 0xdc, 0x01, 0xa1, 0xb5, 0xa7, 0xee, 0x11, 0x34, 0xb0, 0x03, - 0xa7, 0xa5, 0x8a, 0xd5, 0xbf, 0x49, 0x96, 0x97, 0x63, 0x5e, 0x82, 0xd3, 0x37, 0x06, 0x62, 0xe2, - 0x43, 0xa8, 0xa0, 0x1d, 0xc8, 0x5b, 0xce, 0xce, 0xf2, 0x83, 0x59, 0xe8, 0x8a, 0xea, 0x7b, 0x85, - 0x3c, 0x1c, 0xa6, 0xb2, 0x51, 0xc5, 0x94, 0xb8, 0xf9, 0x6a, 0x4e, 0x79, 0xe5, 0x55, 0xa2, 0xbe, - 0x4f, 0xea, 0xab, 0xda, 0xc8, 0xe2, 0x7b, 0x5c, 0x7d, 0x09, 0xa8, 0xf9, 0x81, 0x94, 0xba, 0xa6, - 0xdb, 0x6a, 0x1f, 0x67, 0x92, 0xfb, 0x21, 0x9e, 0x84, 0x90, 0x5b, 0x73, 0xf1, 0x5d, 0x6c, 0xfe, - 0xb8, 0xa0, 0x9c, 0x50, 0x89, 0xcb, 0x78, 0x1f, 0x8a, 0x76, 0x10, 0xda, 0x5e, 0x86, 0x0f, 0xa7, - 0x12, 0xd9, 0xfb, 0x58, 0x08, 0x29, 0x03, 0x60, 0xce, 0x8a, 0xf2, 0x74, 0x9b, 0xb6, 0x7b, 0x47, - 0x74, 0xff, 0x5a, 0xe6, 0xb7, 0xec, 0x9c, 0x27, 0x03, 0x60, 0xce, 0x0a, 0xdd, 0xe4, 0x2b, 0x2d, - 0x9b, 0x6f, 0xaf, 0x25, 0x3f, 0xa9, 0x18, 0x5f, 0x71, 0x94, 0x57, 0xd0, 0xb2, 0x85, 0x0e, 0x33, - 0x26, 0xaf, 0xda, 0xe6, 0x7a, 0x1a, 0xaf, 0xda, 0xe6, 0x3a, 0xa6, 0x4c, 0xd0, 0xeb, 0x06, 0x80, - 0xa5, 0xbe, 0x2d, 0x98, 0x4d, 0xb6, 0xf6, 0x41, 0xdf, 0x2a, 0xe4, 0x51, 0x5f, 0x11, 0x14, 0x6b, - 0x9c, 0xcd, 0x7f, 0x35, 0x40, 0xfb, 0x20, 0x53, 0x14, 0x72, 0x64, 0x0c, 0x1d, 0x72, 0x94, 0x1b, - 0x31, 0xe4, 0x28, 0x3f, 0x52, 0xc8, 0x51, 0x61, 0xf4, 0x90, 0xa3, 0xe2, 0xe0, 0x90, 0x23, 0xf3, - 0x0d, 0x03, 0x16, 0xfb, 0xe6, 0x26, 0xf9, 0xe1, 0x4b, 0x63, 0xc8, 0x0f, 0x5f, 0xae, 0xc1, 0x82, - 0x48, 0x67, 0x59, 0x6b, 0x3b, 0x76, 0xea, 0x5b, 0xcb, 0xed, 0x04, 0x1c, 0xf7, 0xd5, 0x30, 0xff, - 0xd4, 0x80, 0x69, 0xed, 0x69, 0x08, 0xed, 0x07, 0x7b, 0x42, 0x23, 0x9a, 0x11, 0x65, 0xf2, 0x64, - 0x6e, 0x46, 0x0e, 0xe3, 0x1e, 0xef, 0xa6, 0x96, 0xb0, 0x2d, 0xf2, 0x78, 0xd3, 0x52, 0x2c, 0xa0, - 0x3c, 0x15, 0x17, 0xe1, 0x1f, 0x35, 0xcd, 0xeb, 0xa9, 0xb8, 0x48, 0x1b, 0x33, 0x08, 0x63, 0x47, - 0xcf, 0x34, 0x11, 0x8d, 0xa6, 0x25, 0x0e, 0xb5, 0xa8, 0xe5, 0xc2, 0x60, 0xe8, 0x0c, 0xe4, 0x89, - 0xdb, 0x10, 0x0a, 0xb8, 0xfa, 0x8c, 0xc4, 0x05, 0xb7, 0x81, 0x69, 0xb9, 0x79, 0x15, 0x66, 0x6a, - 0xa4, 0xee, 0x93, 0xf0, 0x79, 0x72, 0x30, 0xf4, 0x77, 0x29, 0x6e, 0x91, 0x83, 0xe4, 0x77, 0x29, - 0x68, 0x75, 0x5a, 0x6e, 0xfe, 0x9e, 0x01, 0x89, 0x3c, 0xae, 0x9a, 0xf7, 0xcb, 0x18, 0xe4, 0xfd, - 0x8a, 0xf9, 0x69, 0x72, 0x87, 0xfa, 0x69, 0x2e, 0x03, 0x6a, 0x59, 0x61, 0x7d, 0x2f, 0x96, 0x65, - 0x58, 0xd8, 0x3e, 0xd1, 0x43, 0xb4, 0x3e, 0x0c, 0x9c, 0x52, 0xcb, 0x7c, 0xc5, 0x80, 0xbe, 0x6f, - 0x92, 0xd2, 0x13, 0x9b, 0x88, 0x94, 0xff, 0xdc, 0x24, 0x54, 0x27, 0xb6, 0xcc, 0xf4, 0x2f, 0xe1, - 0xd4, 0x6e, 0x90, 0x9e, 0x27, 0x69, 0xc7, 0xf3, 0x27, 0x3b, 0xca, 0x6e, 0x58, 0x8b, 0x83, 0x71, - 0x12, 0xdf, 0x7c, 0x01, 0x4a, 0xf2, 0x5d, 0x23, 0x7b, 0x1c, 0x24, 0x2d, 0x51, 0xfd, 0x71, 0x10, - 0x35, 0x44, 0x19, 0x84, 0x0e, 0x53, 0xe0, 0xda, 0x97, 0xbc, 0x20, 0x94, 0x8f, 0x31, 0xb9, 0xbf, - 0xe9, 0xca, 0x3a, 0x2b, 0xc3, 0x0a, 0x6a, 0x2e, 0xc2, 0xbc, 0x72, 0x24, 0xf1, 0x45, 0x6f, 0x7e, - 0x3b, 0x0f, 0x33, 0xb1, 0x2f, 0x4d, 0xdd, 0x7b, 0xb2, 0x87, 0x9f, 0x96, 0x14, 0x87, 0x50, 0x7e, - 0x44, 0x87, 0x90, 0xee, 0x81, 0x2b, 0x1c, 0xaf, 0x07, 0xae, 0x98, 0x8d, 0x07, 0x2e, 0x84, 0x49, - 0xf1, 0x15, 0x5e, 0x11, 0xd3, 0xbc, 0x99, 0x51, 0x52, 0x02, 0xf1, 0xba, 0x97, 0x85, 0x71, 0x4b, - 0x01, 0x26, 0x59, 0x99, 0xdf, 0x2c, 0xc2, 0x5c, 0x3c, 0x4d, 0xc1, 0x10, 0x33, 0xf9, 0xae, 0xbe, - 0x99, 0x1c, 0xd1, 0x20, 0xce, 0x8f, 0x6b, 0x10, 0x17, 0xc6, 0x35, 0x88, 0x8b, 0x47, 0x30, 0x88, - 0xfb, 0xcd, 0xd9, 0x89, 0xa1, 0xcd, 0xd9, 0x0f, 0xa8, 0xdb, 0xdc, 0xc9, 0xd8, 0xf5, 0x47, 0x74, - 0x9b, 0x8b, 0xe2, 0xd3, 0xb0, 0xea, 0x35, 0x52, 0x6f, 0xc5, 0x4b, 0xf7, 0x50, 0xfc, 0xfd, 0xd4, - 0xcb, 0xd7, 0xd1, 0x7d, 0x6e, 0x6f, 0x1b, 0xe1, 0xe2, 0x35, 0xfa, 0xd0, 0x34, 0x3b, 0xfc, 0x20, - 0x7e, 0x70, 0xd6, 0x22, 0x10, 0xd6, 0xf1, 0xd8, 0x27, 0x86, 0xe2, 0xdf, 0x54, 0x62, 0xfe, 0x05, - 0xfd, 0x13, 0x43, 0x89, 0x6f, 0x30, 0x25, 0xf1, 0xcd, 0x6f, 0xe4, 0x61, 0x2e, 0x9e, 0x22, 0x1e, - 0xdd, 0x56, 0xfa, 0x79, 0x26, 0xa6, 0x01, 0x27, 0xab, 0x3d, 0xd4, 0x1f, 0x68, 0x6c, 0xf3, 0xcf, - 0x1f, 0xef, 0xa8, 0xac, 0x01, 0xc7, 0xc7, 0x58, 0x58, 0xb9, 0x82, 0x1d, 0xcb, 0x2a, 0x1f, 0x05, - 0x94, 0x8a, 0x1b, 0xdc, 0xcc, 0xb9, 0x47, 0x21, 0xa2, 0x8a, 0x15, 0xd6, 0xd8, 0x52, 0xf1, 0xbe, - 0x4f, 0x7c, 0x7b, 0xd7, 0x56, 0x9f, 0xb7, 0x61, 0xc2, 0xf3, 0x05, 0x51, 0x86, 0x15, 0xd4, 0x7c, - 0x25, 0x07, 0xd1, 0xc7, 0xbc, 0x58, 0xb6, 0xea, 0x40, 0x53, 0x1b, 0xc4, 0xb4, 0x5d, 0x1e, 0x37, - 0x25, 0x7c, 0x44, 0x51, 0x04, 0xbb, 0x68, 0x25, 0x38, 0xc6, 0xf1, 0xe7, 0xf0, 0x11, 0x2f, 0x0b, - 0xe6, 0x13, 0xcf, 0x5d, 0x32, 0x8f, 0x28, 0xfc, 0x4a, 0x1e, 0xa6, 0xd4, 0x83, 0x21, 0xf4, 0x3e, - 0x96, 0x68, 0x76, 0xcf, 0x93, 0xe9, 0x7f, 0xdf, 0xae, 0xa5, 0x83, 0xdd, 0xf3, 0x1a, 0x77, 0xbb, - 0xe5, 0x79, 0x85, 0xcc, 0x8b, 0xb0, 0xa8, 0x40, 0x95, 0xb4, 0x8e, 0xef, 0x24, 0x95, 0xb4, 0xeb, - 0x78, 0x03, 0xd3, 0x72, 0x74, 0x07, 0x26, 0xf7, 0x88, 0xd5, 0x20, 0xbe, 0x8c, 0x1d, 0xd8, 0xcc, - 0xe8, 0x91, 0xd3, 0x25, 0x46, 0x35, 0x1a, 0x06, 0xfe, 0x3f, 0xc0, 0x92, 0x1d, 0x3d, 0xa8, 0x76, - 0xbc, 0xc6, 0x41, 0x32, 0x7d, 0x6c, 0xd5, 0x6b, 0x1c, 0x60, 0x06, 0x41, 0xcf, 0xc2, 0x5c, 0x68, - 0xb7, 0x88, 0xd7, 0x09, 0xf5, 0x4f, 0x25, 0xe5, 0x23, 0xe7, 0xf1, 0x76, 0x0c, 0x8a, 0x13, 0xd8, - 0xf4, 0xa0, 0xbb, 0x19, 0x78, 0x2e, 0xcb, 0x09, 0x33, 0x11, 0xf7, 0x34, 0x5d, 0xae, 0x5d, 0xbd, - 0xc2, 0x52, 0xc2, 0x28, 0x0c, 0x8a, 0x6d, 0xb3, 0x57, 0x09, 0x3e, 0x11, 0x77, 0x37, 0x0b, 0xd1, - 0xdb, 0x51, 0x5e, 0x8e, 0x15, 0x86, 0x79, 0x1d, 0xe6, 0x13, 0x5d, 0x95, 0xea, 0xb0, 0x91, 0xae, - 0x0e, 0x0f, 0x97, 0xab, 0xf5, 0x8f, 0x0c, 0x58, 0xec, 0xdb, 0xbc, 0xc3, 0x86, 0xba, 0x26, 0x25, - 0x79, 0xee, 0xe8, 0x92, 0x3c, 0x3f, 0x9a, 0x24, 0xaf, 0xae, 0x7c, 0xe7, 0xcd, 0xb3, 0x0f, 0x7c, - 0xf7, 0xcd, 0xb3, 0x0f, 0x7c, 0xff, 0xcd, 0xb3, 0x0f, 0xbc, 0xd2, 0x3b, 0x6b, 0x7c, 0xa7, 0x77, - 0xd6, 0xf8, 0x6e, 0xef, 0xac, 0xf1, 0xfd, 0xde, 0x59, 0xe3, 0xc7, 0xbd, 0xb3, 0xc6, 0x1b, 0x3f, - 0x39, 0xfb, 0xc0, 0x8b, 0x25, 0xb9, 0x4c, 0xfe, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x98, 0xf2, 0x6f, - 0x46, 0xbd, 0x84, 0x00, 0x00, + 0x75, 0xb0, 0xab, 0x7b, 0x7a, 0xa6, 0xe7, 0xcc, 0xff, 0xdd, 0x59, 0x76, 0xbc, 0xf6, 0x6e, 0x9b, + 0x32, 0xf2, 0x67, 0xbe, 0x0f, 0x66, 0xc1, 0x3f, 0xdf, 0x67, 0x30, 0xf2, 0x97, 0xee, 0x99, 0x5d, + 0xef, 0xac, 0x67, 0x76, 0x67, 0x4f, 0xcf, 0x7a, 0xc1, 0x60, 0x42, 0x4d, 0xf7, 0x9d, 0x9e, 0xda, + 0xed, 0xae, 0x6a, 0xaa, 0xaa, 0x67, 0x77, 0x0c, 0x02, 0x3b, 0xc8, 0x0e, 0x89, 0x40, 0x38, 0x01, + 0x14, 0x45, 0x11, 0x11, 0x8a, 0x90, 0x12, 0x85, 0x3c, 0x44, 0x28, 0x51, 0x5e, 0x90, 0x12, 0x05, + 0x50, 0xc8, 0x43, 0x22, 0x22, 0x25, 0x01, 0x22, 0xe8, 0xc4, 0x43, 0x5e, 0x12, 0x25, 0x8a, 0x22, + 0x11, 0x45, 0xec, 0x53, 0x74, 0x7f, 0xea, 0xd6, 0xad, 0xea, 0xea, 0xd9, 0xee, 0xe9, 0x9a, 0xc5, + 0x4a, 0x78, 0xeb, 0xbe, 0xe7, 0xdc, 0x73, 0xee, 0xef, 0x39, 0xe7, 0x9e, 0x7b, 0xee, 0x29, 0x58, + 0x6f, 0xd8, 0xc1, 0x6e, 0x67, 0x7b, 0xb9, 0xe6, 0xb6, 0xce, 0x59, 0x5e, 0xc3, 0x6d, 0x7b, 0xee, + 0x0d, 0xfe, 0xe3, 0x9d, 0x9e, 0xdb, 0x6c, 0xba, 0x9d, 0xc0, 0x3f, 0xd7, 0xbe, 0xd9, 0x38, 0x67, + 0xb5, 0x6d, 0xff, 0x9c, 0x2a, 0xd9, 0x7b, 0xb7, 0xd5, 0x6c, 0xef, 0x5a, 0xef, 0x3e, 0xd7, 0xa0, + 0x0e, 0xf5, 0xac, 0x80, 0xd6, 0x97, 0xdb, 0x9e, 0x1b, 0xb8, 0xe4, 0x7d, 0x11, 0xb5, 0xe5, 0x90, + 0x1a, 0xff, 0xf1, 0xf3, 0x61, 0xdd, 0xe5, 0xf6, 0xcd, 0xc6, 0x32, 0xa3, 0xb6, 0xac, 0x4a, 0x42, + 0x6a, 0xa7, 0xdf, 0xa9, 0xb5, 0xa5, 0xe1, 0x36, 0xdc, 0x73, 0x9c, 0xe8, 0x76, 0x67, 0x87, 0xff, + 0xe3, 0x7f, 0xf8, 0x2f, 0xc1, 0xec, 0xf4, 0xc3, 0x37, 0x9f, 0xf2, 0x97, 0x6d, 0x97, 0xb5, 0xed, + 0xdc, 0xb6, 0x15, 0xd4, 0x76, 0xcf, 0xed, 0xf5, 0xb4, 0xe8, 0xb4, 0xa9, 0x21, 0xd5, 0x5c, 0x8f, + 0xa6, 0xe1, 0x3c, 0x11, 0xe1, 0xb4, 0xac, 0xda, 0xae, 0xed, 0x50, 0x6f, 0x3f, 0xea, 0x75, 0x8b, + 0x06, 0x56, 0x5a, 0xad, 0x73, 0xfd, 0x6a, 0x79, 0x1d, 0x27, 0xb0, 0x5b, 0xb4, 0xa7, 0xc2, 0xff, + 0xbd, 0x5b, 0x05, 0xbf, 0xb6, 0x4b, 0x5b, 0x56, 0x4f, 0xbd, 0xc7, 0xfb, 0xd5, 0xeb, 0x04, 0x76, + 0xf3, 0x9c, 0xed, 0x04, 0x7e, 0xe0, 0x25, 0x2b, 0x99, 0xdf, 0xcc, 0xc3, 0x64, 0x79, 0xbd, 0x52, + 0x0d, 0xac, 0xa0, 0xe3, 0x93, 0xd7, 0x0c, 0x98, 0x6e, 0xba, 0x56, 0xbd, 0x62, 0x35, 0x2d, 0xa7, + 0x46, 0xbd, 0x25, 0xe3, 0x21, 0xe3, 0xd1, 0xa9, 0xc7, 0xd6, 0x97, 0x47, 0x99, 0xaf, 0xe5, 0xf2, + 0x2d, 0x1f, 0xa9, 0xef, 0x76, 0xbc, 0x1a, 0x45, 0xba, 0x53, 0x59, 0xfc, 0x76, 0xb7, 0x74, 0xdf, + 0x41, 0xb7, 0x34, 0xbd, 0xae, 0x71, 0xc2, 0x18, 0x5f, 0xf2, 0x45, 0x03, 0x16, 0x6a, 0x96, 0x63, + 0x79, 0xfb, 0x5b, 0x96, 0xd7, 0xa0, 0xc1, 0xb3, 0x9e, 0xdb, 0x69, 0x2f, 0xe5, 0x8e, 0xa1, 0x35, + 0xf7, 0xcb, 0xd6, 0x2c, 0xac, 0x24, 0xd9, 0x61, 0x6f, 0x0b, 0x78, 0xbb, 0xfc, 0xc0, 0xda, 0x6e, + 0x52, 0xbd, 0x5d, 0xf9, 0xe3, 0x6c, 0x57, 0x35, 0xc9, 0x0e, 0x7b, 0x5b, 0x60, 0xbe, 0x9a, 0x87, + 0x85, 0xf2, 0x7a, 0x65, 0xcb, 0xb3, 0x76, 0x76, 0xec, 0x1a, 0xba, 0x9d, 0xc0, 0x76, 0x1a, 0xe4, + 0xed, 0x30, 0x61, 0x3b, 0x0d, 0x8f, 0xfa, 0x3e, 0x9f, 0xc8, 0xc9, 0xca, 0x9c, 0x24, 0x3a, 0xb1, + 0x26, 0x8a, 0x31, 0x84, 0x93, 0x27, 0x61, 0xca, 0xa7, 0xde, 0x9e, 0x5d, 0xa3, 0x9b, 0xae, 0x17, + 0xf0, 0x91, 0x2e, 0x54, 0x4e, 0x48, 0xf4, 0xa9, 0x6a, 0x04, 0x42, 0x1d, 0x8f, 0x55, 0xf3, 0x5c, + 0x37, 0x90, 0x70, 0x3e, 0x10, 0x93, 0x51, 0x35, 0x8c, 0x40, 0xa8, 0xe3, 0x91, 0xd7, 0x0d, 0x98, + 0xf7, 0x03, 0xbb, 0x76, 0xd3, 0x76, 0xa8, 0xef, 0xaf, 0xb8, 0xce, 0x8e, 0xdd, 0x58, 0x2a, 0xf0, + 0x51, 0xbc, 0x3c, 0xda, 0x28, 0x56, 0x13, 0x54, 0x2b, 0x8b, 0x07, 0xdd, 0xd2, 0x7c, 0xb2, 0x14, + 0x7b, 0xb8, 0x93, 0x55, 0x98, 0xb7, 0x1c, 0xc7, 0x0d, 0xac, 0xc0, 0x76, 0x9d, 0x4d, 0x8f, 0xee, + 0xd8, 0xb7, 0x97, 0xc6, 0x78, 0x77, 0x96, 0x64, 0x77, 0xe6, 0xcb, 0x09, 0x38, 0xf6, 0xd4, 0x30, + 0x57, 0x61, 0xa9, 0xdc, 0xda, 0xb6, 0x7c, 0xdf, 0xaa, 0xbb, 0x5e, 0x62, 0x36, 0x1e, 0x85, 0x62, + 0xcb, 0x6a, 0xb7, 0x6d, 0xa7, 0xc1, 0xa6, 0x23, 0xff, 0xe8, 0x64, 0x65, 0xfa, 0xa0, 0x5b, 0x2a, + 0x6e, 0xc8, 0x32, 0x54, 0x50, 0xf3, 0xfb, 0x39, 0x98, 0x2a, 0x3b, 0x56, 0x73, 0xdf, 0xb7, 0x7d, + 0xec, 0x38, 0xe4, 0x23, 0x50, 0x64, 0xd2, 0xa5, 0x6e, 0x05, 0x96, 0xdc, 0x91, 0xef, 0x5a, 0x16, + 0x9b, 0x7d, 0x59, 0xdf, 0xec, 0xd1, 0xb8, 0x30, 0xec, 0xe5, 0xbd, 0x77, 0x2f, 0x5f, 0xd9, 0xbe, + 0x41, 0x6b, 0xc1, 0x06, 0x0d, 0xac, 0x0a, 0x91, 0xbd, 0x80, 0xa8, 0x0c, 0x15, 0x55, 0xe2, 0xc2, + 0x98, 0xdf, 0xa6, 0x35, 0xb9, 0xc3, 0x36, 0x46, 0x5c, 0xc9, 0x51, 0xd3, 0xab, 0x6d, 0x5a, 0xab, + 0x4c, 0x4b, 0xd6, 0x63, 0xec, 0x1f, 0x72, 0x46, 0xe4, 0x16, 0x8c, 0xfb, 0x5c, 0xe6, 0xc8, 0xcd, + 0x73, 0x25, 0x3b, 0x96, 0x9c, 0x6c, 0x65, 0x56, 0x32, 0x1d, 0x17, 0xff, 0x51, 0xb2, 0x33, 0xff, + 0xce, 0x80, 0x13, 0x1a, 0x76, 0xd9, 0x6b, 0x74, 0x5a, 0xd4, 0x09, 0xc8, 0x43, 0x30, 0xe6, 0x58, + 0x2d, 0x2a, 0x37, 0x8a, 0x6a, 0xf2, 0x65, 0xab, 0x45, 0x91, 0x43, 0xc8, 0xc3, 0x50, 0xd8, 0xb3, + 0x9a, 0x1d, 0xca, 0x07, 0x69, 0xb2, 0x32, 0x23, 0x51, 0x0a, 0xcf, 0xb3, 0x42, 0x14, 0x30, 0xf2, + 0x71, 0x98, 0xe4, 0x3f, 0x2e, 0x78, 0x6e, 0x2b, 0xa3, 0xae, 0xc9, 0x16, 0x3e, 0x1f, 0x92, 0xad, + 0xcc, 0x1c, 0x74, 0x4b, 0x93, 0xea, 0x2f, 0x46, 0x0c, 0xcd, 0xbf, 0x37, 0x60, 0x4e, 0xeb, 0xdc, + 0xba, 0xed, 0x07, 0xe4, 0x43, 0x3d, 0x8b, 0x67, 0x79, 0xb0, 0xc5, 0xc3, 0x6a, 0xf3, 0xa5, 0x33, + 0x2f, 0x7b, 0x5a, 0x0c, 0x4b, 0xb4, 0x85, 0xe3, 0x40, 0xc1, 0x0e, 0x68, 0xcb, 0x5f, 0xca, 0x3d, + 0x94, 0x7f, 0x74, 0xea, 0xb1, 0xb5, 0xcc, 0xa6, 0x31, 0x1a, 0xdf, 0x35, 0x46, 0x1f, 0x05, 0x1b, + 0xf3, 0x6b, 0x63, 0xb1, 0x1e, 0xb2, 0x15, 0x45, 0x5c, 0x98, 0x68, 0xd1, 0xc0, 0xb3, 0x6b, 0x62, + 0x5f, 0x4d, 0x3d, 0xb6, 0x3a, 0x5a, 0x2b, 0x36, 0x38, 0xb1, 0x48, 0x58, 0x8a, 0xff, 0x3e, 0x86, + 0x5c, 0xc8, 0x2e, 0x8c, 0x59, 0x5e, 0x23, 0xec, 0xf3, 0x85, 0x6c, 0xe6, 0x37, 0x5a, 0x73, 0x65, + 0xaf, 0xe1, 0x23, 0xe7, 0x40, 0xce, 0xc1, 0x64, 0x40, 0xbd, 0x96, 0xed, 0x58, 0x81, 0x90, 0xae, + 0xc5, 0xca, 0x82, 0x44, 0x9b, 0xdc, 0x0a, 0x01, 0x18, 0xe1, 0x90, 0x26, 0x8c, 0xd7, 0xbd, 0x7d, + 0xec, 0x38, 0x4b, 0x63, 0x59, 0x0c, 0xc5, 0x2a, 0xa7, 0x15, 0x6d, 0x26, 0xf1, 0x1f, 0x25, 0x0f, + 0xf2, 0x15, 0x03, 0x16, 0x5b, 0xd4, 0xf2, 0x3b, 0x1e, 0x65, 0x5d, 0x40, 0x1a, 0x50, 0x87, 0x49, + 0xc3, 0xa5, 0x02, 0x67, 0x8e, 0xa3, 0xce, 0x43, 0x2f, 0xe5, 0xca, 0x83, 0xb2, 0x29, 0x8b, 0x69, + 0x50, 0x4c, 0x6d, 0x8d, 0xf9, 0xfd, 0x31, 0x58, 0xe8, 0x91, 0x10, 0xe4, 0x09, 0x28, 0xb4, 0x77, + 0x2d, 0x3f, 0xdc, 0xf2, 0x67, 0xc3, 0xf5, 0xb6, 0xc9, 0x0a, 0xef, 0x74, 0x4b, 0x33, 0x61, 0x15, + 0x5e, 0x80, 0x02, 0x99, 0xe9, 0xd4, 0x16, 0xf5, 0x7d, 0xab, 0x11, 0xca, 0x01, 0x6d, 0x99, 0xf0, + 0x62, 0x0c, 0xe1, 0xe4, 0x17, 0x0d, 0x98, 0x11, 0x4b, 0x06, 0xa9, 0xdf, 0x69, 0x06, 0x4c, 0xd6, + 0xb1, 0x61, 0xb9, 0x94, 0xc5, 0xf2, 0x14, 0x24, 0x2b, 0x27, 0x25, 0xf7, 0x19, 0xbd, 0xd4, 0xc7, + 0x38, 0x5f, 0x72, 0x1d, 0x26, 0xfd, 0xc0, 0xf2, 0x02, 0x5a, 0x2f, 0x07, 0x5c, 0xab, 0x4d, 0x3d, + 0xf6, 0xbf, 0x07, 0x13, 0x02, 0x5b, 0x76, 0x8b, 0x0a, 0x81, 0x53, 0x0d, 0x09, 0x60, 0x44, 0x8b, + 0x7c, 0x1c, 0xc0, 0xeb, 0x38, 0xd5, 0x4e, 0xab, 0x65, 0x79, 0xfb, 0x52, 0x83, 0x5f, 0x1c, 0xad, + 0x7b, 0xa8, 0xe8, 0x45, 0x3a, 0x2b, 0x2a, 0x43, 0x8d, 0x1f, 0x79, 0xc5, 0x80, 0x19, 0xb1, 0x12, + 0xc3, 0x16, 0x8c, 0x67, 0xdc, 0x82, 0x05, 0x36, 0xb4, 0xab, 0x3a, 0x0b, 0x8c, 0x73, 0x34, 0xff, + 0x26, 0xae, 0x4f, 0xaa, 0x01, 0xb3, 0xae, 0x1b, 0xfb, 0xe4, 0x83, 0x70, 0xbf, 0xdf, 0xa9, 0xd5, + 0xa8, 0xef, 0xef, 0x74, 0x9a, 0xd8, 0x71, 0x2e, 0xda, 0x7e, 0xe0, 0x7a, 0xfb, 0xeb, 0x76, 0xcb, + 0x0e, 0xf8, 0x8a, 0x2b, 0x54, 0xce, 0x1c, 0x74, 0x4b, 0xf7, 0x57, 0xfb, 0x21, 0x61, 0xff, 0xfa, + 0xc4, 0x82, 0x07, 0x3a, 0x4e, 0x7f, 0xf2, 0xc2, 0x7a, 0x2b, 0x1d, 0x74, 0x4b, 0x0f, 0x5c, 0xeb, + 0x8f, 0x86, 0x87, 0xd1, 0x30, 0xff, 0xd9, 0x80, 0xf9, 0xb0, 0x5f, 0x5b, 0xb4, 0xd5, 0x6e, 0x32, + 0xe9, 0x72, 0xfc, 0x86, 0x48, 0x10, 0x33, 0x44, 0x30, 0x1b, 0x75, 0x12, 0xb6, 0xbf, 0x9f, 0x35, + 0x62, 0xfe, 0x93, 0x01, 0x8b, 0x49, 0xe4, 0x7b, 0xa0, 0x3c, 0xfd, 0xb8, 0xf2, 0xbc, 0x9c, 0x6d, + 0x6f, 0xfb, 0x68, 0xd0, 0xd7, 0xc6, 0x7a, 0xfb, 0xfa, 0xdf, 0x5d, 0x8d, 0x46, 0x5a, 0x31, 0xff, + 0xd3, 0xd4, 0x8a, 0x63, 0x6f, 0x2a, 0xad, 0xf8, 0x3b, 0x63, 0x30, 0x5d, 0x76, 0x02, 0xbb, 0xbc, + 0xb3, 0x63, 0x3b, 0x76, 0xb0, 0x4f, 0x3e, 0x93, 0x83, 0x73, 0x6d, 0x8f, 0xee, 0x50, 0xcf, 0xa3, + 0xf5, 0xd5, 0x8e, 0x67, 0x3b, 0x8d, 0x6a, 0x6d, 0x97, 0xd6, 0x3b, 0x4d, 0xdb, 0x69, 0xac, 0x35, + 0x1c, 0x57, 0x15, 0x9f, 0xbf, 0x4d, 0x6b, 0x1d, 0xde, 0x25, 0xb1, 0x29, 0x5a, 0xa3, 0x75, 0x69, + 0x73, 0x38, 0xa6, 0x95, 0xc7, 0x0f, 0xba, 0xa5, 0x73, 0x43, 0x56, 0xc2, 0x61, 0xbb, 0x46, 0x3e, + 0x9d, 0x83, 0x65, 0x8f, 0x7e, 0xb4, 0x63, 0x0f, 0x3e, 0x1a, 0x42, 0x6a, 0x35, 0x47, 0x54, 0x3f, + 0x43, 0xf1, 0xac, 0x3c, 0x76, 0xd0, 0x2d, 0x0d, 0x59, 0x07, 0x87, 0xec, 0x97, 0xf9, 0x8d, 0x1c, + 0x9c, 0x2c, 0xb7, 0xdb, 0x1b, 0xd4, 0xdf, 0x4d, 0x1c, 0x6a, 0x3f, 0x67, 0xc0, 0xec, 0x9e, 0xed, + 0x05, 0x1d, 0xab, 0x19, 0x3a, 0x01, 0xc4, 0x92, 0xa8, 0x8e, 0xb8, 0x9d, 0x05, 0xb7, 0xe7, 0x63, + 0xa4, 0x2b, 0xe4, 0xa0, 0x5b, 0x9a, 0x8d, 0x97, 0x61, 0x82, 0x3d, 0xf9, 0x35, 0x03, 0xe6, 0x65, + 0xd1, 0x65, 0xb7, 0x4e, 0x75, 0xcf, 0xd1, 0xb5, 0x2c, 0xdb, 0xa4, 0x88, 0x0b, 0x17, 0x43, 0xb2, + 0x14, 0x7b, 0x1a, 0x61, 0xfe, 0x6b, 0x0e, 0x4e, 0xf5, 0xa1, 0x41, 0x7e, 0xdb, 0x80, 0x45, 0xe1, + 0x6e, 0xd2, 0x40, 0x48, 0x77, 0xe4, 0x68, 0x7e, 0x20, 0xeb, 0x96, 0x23, 0xdb, 0x0b, 0xd4, 0xa9, + 0xd1, 0xca, 0x12, 0x13, 0x1b, 0x2b, 0x29, 0xac, 0x31, 0xb5, 0x41, 0xbc, 0xa5, 0xc2, 0x01, 0x95, + 0x68, 0x69, 0xee, 0x9e, 0xb4, 0xb4, 0x9a, 0xc2, 0x1a, 0x53, 0x1b, 0x64, 0xfe, 0x7f, 0x78, 0xe0, + 0x10, 0x72, 0x77, 0x3f, 0xf1, 0x9b, 0x2f, 0xaa, 0x55, 0x1f, 0x5f, 0x73, 0x03, 0x38, 0x0b, 0x4c, + 0x18, 0xf7, 0xdc, 0x4e, 0x40, 0x85, 0x76, 0x9b, 0xac, 0x00, 0xd3, 0x13, 0xc8, 0x4b, 0x50, 0x42, + 0xcc, 0x6f, 0x18, 0x50, 0x1c, 0xc2, 0xff, 0x50, 0x8a, 0xfb, 0x1f, 0x26, 0x7b, 0x7c, 0x0f, 0x41, + 0xaf, 0xef, 0xe1, 0xd9, 0xd1, 0x66, 0x63, 0x10, 0x9f, 0xc3, 0xbf, 0x19, 0xb0, 0xd0, 0xe3, 0xa3, + 0x20, 0xbb, 0xb0, 0xd8, 0x76, 0xeb, 0xa1, 0x7d, 0x71, 0xd1, 0xf2, 0x77, 0x39, 0x4c, 0x76, 0xef, + 0x09, 0x36, 0x93, 0x9b, 0x29, 0xf0, 0x3b, 0xdd, 0xd2, 0x92, 0x22, 0x92, 0x40, 0xc0, 0x54, 0x8a, + 0xa4, 0x0d, 0xc5, 0x1d, 0x9b, 0x36, 0xeb, 0xd1, 0x12, 0x1c, 0xd1, 0x92, 0xb8, 0x20, 0xa9, 0x09, + 0xf7, 0x5c, 0xf8, 0x0f, 0x15, 0x17, 0xf3, 0x2a, 0xcc, 0xc6, 0x9d, 0xb5, 0x03, 0x4c, 0xde, 0x19, + 0xc8, 0x5b, 0x9e, 0x23, 0xa7, 0x6e, 0x4a, 0x22, 0xe4, 0xcb, 0x78, 0x19, 0x59, 0xb9, 0xf9, 0x93, + 0x31, 0x98, 0xab, 0x34, 0x3b, 0xf4, 0x59, 0x8f, 0xd2, 0xf0, 0x7c, 0x5a, 0x86, 0xb9, 0xb6, 0x47, + 0xf7, 0x6c, 0x7a, 0xab, 0x4a, 0x9b, 0xb4, 0x16, 0xb8, 0x9e, 0xa4, 0x7f, 0x4a, 0x56, 0x9f, 0xdb, + 0x8c, 0x83, 0x31, 0x89, 0x4f, 0x9e, 0x81, 0x59, 0xab, 0x16, 0xd8, 0x7b, 0x54, 0x51, 0x10, 0x0d, + 0x78, 0x8b, 0xa4, 0x30, 0x5b, 0x8e, 0x41, 0x31, 0x81, 0x4d, 0x3e, 0x04, 0x4b, 0x7e, 0xcd, 0x6a, + 0xd2, 0x6b, 0x6d, 0xc9, 0x6a, 0x65, 0x97, 0xd6, 0x6e, 0x6e, 0xba, 0xb6, 0x13, 0x48, 0x6f, 0xc4, + 0x43, 0x92, 0xd2, 0x52, 0xb5, 0x0f, 0x1e, 0xf6, 0xa5, 0x40, 0xfe, 0xd8, 0x80, 0x33, 0x6d, 0x8f, + 0x6e, 0x7a, 0x6e, 0xcb, 0x65, 0x6a, 0xa6, 0xe7, 0x88, 0x2e, 0x8f, 0xaa, 0xcf, 0x8f, 0xa8, 0x4f, + 0x45, 0x49, 0xaf, 0x8b, 0xf0, 0xad, 0x07, 0xdd, 0xd2, 0x99, 0xcd, 0xc3, 0x1a, 0x80, 0x87, 0xb7, + 0x8f, 0xfc, 0xa9, 0x01, 0x67, 0xdb, 0xae, 0x1f, 0x1c, 0xd2, 0x85, 0xc2, 0xb1, 0x76, 0xc1, 0x3c, + 0xe8, 0x96, 0xce, 0x6e, 0x1e, 0xda, 0x02, 0xbc, 0x4b, 0x0b, 0xcd, 0x83, 0x29, 0x58, 0xd0, 0xd6, + 0x9e, 0x3c, 0xbf, 0x3e, 0x0d, 0x33, 0xe1, 0x62, 0x88, 0xd4, 0xfa, 0x64, 0xe4, 0x6f, 0x28, 0xeb, + 0x40, 0x8c, 0xe3, 0xb2, 0x75, 0xa7, 0x96, 0xa2, 0xa8, 0x9d, 0x58, 0x77, 0x9b, 0x31, 0x28, 0x26, + 0xb0, 0xc9, 0x1a, 0x9c, 0x90, 0x25, 0x48, 0xdb, 0x4d, 0xbb, 0x66, 0xad, 0xb8, 0x1d, 0xb9, 0xe4, + 0x0a, 0x95, 0x53, 0x07, 0xdd, 0xd2, 0x89, 0xcd, 0x5e, 0x30, 0xa6, 0xd5, 0x21, 0xeb, 0xb0, 0x68, + 0x75, 0x02, 0x57, 0xf5, 0xff, 0xbc, 0xc3, 0x34, 0x45, 0x9d, 0x2f, 0xad, 0xa2, 0x50, 0x29, 0xe5, + 0x14, 0x38, 0xa6, 0xd6, 0x22, 0x9b, 0x09, 0x6a, 0x55, 0x5a, 0x73, 0x9d, 0xba, 0x98, 0xe5, 0x42, + 0x64, 0x85, 0x97, 0x53, 0x70, 0x30, 0xb5, 0x26, 0x69, 0xc2, 0x6c, 0xcb, 0xba, 0x7d, 0xcd, 0xb1, + 0xf6, 0x2c, 0xbb, 0xc9, 0x98, 0x48, 0x1f, 0x46, 0xff, 0x83, 0x75, 0x27, 0xb0, 0x9b, 0xcb, 0xe2, + 0x3a, 0x6f, 0x79, 0xcd, 0x09, 0xae, 0x78, 0xd5, 0x80, 0x59, 0x6b, 0xc2, 0x38, 0xda, 0x88, 0xd1, + 0xc2, 0x04, 0x6d, 0x72, 0x05, 0x4e, 0xf2, 0xed, 0xb8, 0xea, 0xde, 0x72, 0x56, 0x69, 0xd3, 0xda, + 0x0f, 0x3b, 0x30, 0xc1, 0x3b, 0x70, 0xff, 0x41, 0xb7, 0x74, 0xb2, 0x9a, 0x86, 0x80, 0xe9, 0xf5, + 0x88, 0x05, 0x0f, 0xc4, 0x01, 0x48, 0xf7, 0x6c, 0xdf, 0x76, 0x1d, 0xe1, 0x89, 0x28, 0x46, 0x9e, + 0x88, 0x6a, 0x7f, 0x34, 0x3c, 0x8c, 0x06, 0xf9, 0x0d, 0x03, 0x16, 0xd3, 0xb6, 0xe1, 0xd2, 0x64, + 0x16, 0x97, 0x15, 0x89, 0xad, 0x25, 0x56, 0x44, 0xaa, 0x50, 0x48, 0x6d, 0x04, 0x79, 0xd9, 0x80, + 0x69, 0x4b, 0x3b, 0x45, 0x2d, 0x01, 0x6f, 0xd5, 0xa5, 0x51, 0xcf, 0xf2, 0x11, 0xc5, 0xca, 0xfc, + 0x41, 0xb7, 0x14, 0x3b, 0xa9, 0x61, 0x8c, 0x23, 0xf9, 0x4d, 0x03, 0x4e, 0xa6, 0xee, 0xf1, 0xa5, + 0xa9, 0xe3, 0x18, 0x21, 0xbe, 0x48, 0xd2, 0x65, 0x4e, 0x7a, 0x33, 0xc8, 0xeb, 0x86, 0x52, 0x65, + 0x1b, 0xa1, 0x37, 0x65, 0x9a, 0x37, 0xed, 0xea, 0x88, 0x07, 0xc7, 0xc8, 0x20, 0x08, 0x09, 0x57, + 0x4e, 0x68, 0x9a, 0x31, 0x2c, 0xc4, 0x24, 0x7b, 0xf2, 0x59, 0x23, 0x54, 0x8d, 0xaa, 0x45, 0x33, + 0xc7, 0xd5, 0x22, 0x12, 0x69, 0x5a, 0xd5, 0xa0, 0x04, 0x73, 0xf2, 0x61, 0x38, 0x6d, 0x6d, 0xbb, + 0x5e, 0x90, 0xba, 0xf9, 0x96, 0x66, 0xf9, 0x36, 0x3a, 0x7b, 0xd0, 0x2d, 0x9d, 0x2e, 0xf7, 0xc5, + 0xc2, 0x43, 0x28, 0x98, 0x3f, 0x18, 0x83, 0x69, 0x61, 0xe4, 0x4b, 0xd5, 0xf5, 0x75, 0x03, 0x1e, + 0xac, 0x75, 0x3c, 0x8f, 0x3a, 0x41, 0x35, 0xa0, 0xed, 0x5e, 0xc5, 0x65, 0x1c, 0xab, 0xe2, 0x7a, + 0xe8, 0xa0, 0x5b, 0x7a, 0x70, 0xe5, 0x10, 0xfe, 0x78, 0x68, 0xeb, 0xc8, 0x5f, 0x1a, 0x60, 0x4a, + 0x84, 0x8a, 0x55, 0xbb, 0xd9, 0xf0, 0xdc, 0x8e, 0x53, 0xef, 0xed, 0x44, 0xee, 0x58, 0x3b, 0xf1, + 0xc8, 0x41, 0xb7, 0x64, 0xae, 0xdc, 0xb5, 0x15, 0x38, 0x40, 0x4b, 0xc9, 0xb3, 0xb0, 0x20, 0xb1, + 0xce, 0xdf, 0x6e, 0x53, 0xcf, 0x66, 0xe6, 0xb4, 0xbc, 0x4f, 0x8f, 0x42, 0x14, 0x92, 0x08, 0xd8, + 0x5b, 0x87, 0xf8, 0x30, 0x71, 0x8b, 0xda, 0x8d, 0xdd, 0x20, 0x34, 0x9f, 0x46, 0x8c, 0x4b, 0x90, + 0x07, 0xfe, 0xeb, 0x82, 0x66, 0x65, 0xea, 0xa0, 0x5b, 0x9a, 0x90, 0x7f, 0x30, 0xe4, 0x64, 0xfe, + 0xfe, 0x18, 0x40, 0xb8, 0xbc, 0x68, 0x9b, 0xfc, 0x1f, 0x98, 0xf4, 0x69, 0x20, 0xb0, 0xa4, 0xb3, + 0x5b, 0xdc, 0x21, 0x84, 0x85, 0x18, 0xc1, 0xc9, 0x4d, 0x28, 0xb4, 0xad, 0x8e, 0x4f, 0xe5, 0x64, + 0x5d, 0xca, 0x64, 0xb2, 0x36, 0x19, 0x45, 0x71, 0x46, 0xe2, 0x3f, 0x51, 0xf0, 0x20, 0x9f, 0x32, + 0x00, 0x68, 0x7c, 0x80, 0x47, 0xf6, 0x55, 0x48, 0x96, 0xd1, 0x1c, 0xb0, 0x31, 0xa8, 0xcc, 0x1e, + 0x74, 0x4b, 0xa0, 0x4d, 0x95, 0xc6, 0x96, 0xdc, 0x82, 0xa2, 0x15, 0xca, 0xe8, 0xb1, 0xe3, 0x90, + 0xd1, 0xfc, 0xe8, 0xa2, 0x16, 0x99, 0x62, 0x46, 0x3e, 0x6d, 0xc0, 0xac, 0x4f, 0x03, 0x39, 0x55, + 0x4c, 0x52, 0x48, 0x03, 0x75, 0xc4, 0x45, 0x52, 0x8d, 0xd1, 0x14, 0x12, 0x2f, 0x5e, 0x86, 0x09, + 0xbe, 0xe6, 0x0f, 0xa6, 0x60, 0x36, 0x5c, 0x32, 0x91, 0xcd, 0x29, 0x5c, 0x0e, 0x7d, 0x6c, 0xce, + 0x15, 0x1d, 0x88, 0x71, 0x5c, 0x56, 0x59, 0x78, 0x01, 0xe2, 0x26, 0xa7, 0xaa, 0x5c, 0xd5, 0x81, + 0x18, 0xc7, 0x25, 0x2d, 0x28, 0xf8, 0x01, 0x6d, 0x87, 0x37, 0x74, 0x23, 0x5e, 0x20, 0x45, 0x3b, + 0x21, 0xf2, 0xc1, 0xb3, 0x7f, 0x3e, 0x0a, 0x2e, 0xdc, 0x6b, 0x16, 0xc4, 0x1c, 0x69, 0x72, 0x19, + 0x64, 0xb3, 0x12, 0xe3, 0x3e, 0x3a, 0x31, 0x1b, 0xf1, 0x32, 0x4c, 0xb0, 0x4f, 0x31, 0x43, 0x0b, + 0xc7, 0x68, 0x86, 0xbe, 0x00, 0xc5, 0x96, 0x75, 0xbb, 0xda, 0xf1, 0x1a, 0x47, 0x37, 0x77, 0x65, + 0xf0, 0x8c, 0xa0, 0x82, 0x8a, 0x1e, 0x79, 0xc5, 0xd0, 0x36, 0xd7, 0x04, 0x27, 0x7e, 0x3d, 0xdb, + 0xcd, 0xa5, 0xa4, 0x78, 0xdf, 0x6d, 0xd6, 0x63, 0x14, 0x16, 0xef, 0xb9, 0x51, 0xc8, 0x0c, 0x1c, + 0xb1, 0x41, 0x94, 0x81, 0x33, 0x79, 0xac, 0x06, 0xce, 0x4a, 0x8c, 0x19, 0x26, 0x98, 0xf3, 0xf6, + 0x88, 0x3d, 0xa7, 0xda, 0x03, 0xc7, 0xda, 0x9e, 0x6a, 0x8c, 0x19, 0x26, 0x98, 0xf7, 0x3f, 0x09, + 0x4d, 0x1d, 0xcf, 0x49, 0x68, 0x3a, 0x83, 0x93, 0xd0, 0xe1, 0x46, 0xe2, 0xcc, 0xa8, 0x46, 0x22, + 0xb9, 0x04, 0xa4, 0xbe, 0xef, 0x58, 0x2d, 0xbb, 0x26, 0x85, 0x25, 0x57, 0x10, 0xb3, 0xfc, 0xa4, + 0x7c, 0x5a, 0x0a, 0x32, 0xb2, 0xda, 0x83, 0x81, 0x29, 0xb5, 0xcc, 0xff, 0x30, 0x60, 0x7e, 0xa5, + 0xe9, 0x76, 0xea, 0xd7, 0xad, 0xa0, 0xb6, 0x2b, 0xee, 0xfe, 0xc8, 0x33, 0x50, 0xb4, 0x9d, 0x80, + 0x7a, 0x7b, 0x56, 0x53, 0xca, 0x76, 0x33, 0xbc, 0x1e, 0x5d, 0x93, 0xe5, 0x77, 0xba, 0xa5, 0xd9, + 0xd5, 0x8e, 0xc7, 0x83, 0xea, 0xc4, 0x4e, 0x47, 0x55, 0x87, 0x7c, 0xd9, 0x80, 0x05, 0x71, 0x7b, + 0xb8, 0x6a, 0x05, 0xd6, 0xd5, 0x0e, 0xf5, 0x6c, 0x1a, 0xde, 0x1f, 0x8e, 0xb8, 0xc9, 0x93, 0x6d, + 0x0d, 0x19, 0xec, 0x47, 0xe6, 0xd7, 0x46, 0x92, 0x33, 0xf6, 0x36, 0xc6, 0xfc, 0x7c, 0x1e, 0xee, + 0xef, 0x4b, 0x8b, 0x9c, 0x86, 0x9c, 0x5d, 0x97, 0x5d, 0x07, 0x49, 0x37, 0xb7, 0x56, 0xc7, 0x9c, + 0x5d, 0x27, 0xcb, 0xdc, 0x32, 0xf1, 0xa8, 0xef, 0x87, 0x57, 0x49, 0x93, 0xca, 0x88, 0x90, 0xa5, + 0xa8, 0x61, 0x90, 0x12, 0x14, 0x9a, 0xd6, 0x36, 0x6d, 0x4a, 0x2b, 0x91, 0xdb, 0x3a, 0xeb, 0xac, + 0x00, 0x45, 0x39, 0xf9, 0x05, 0x03, 0x40, 0x34, 0x90, 0xd9, 0x98, 0x52, 0xc3, 0x60, 0xb6, 0xc3, + 0xc4, 0x28, 0x8b, 0x56, 0x46, 0xff, 0x51, 0xe3, 0x4a, 0xb6, 0x60, 0x9c, 0x99, 0x3d, 0x6e, 0xfd, + 0xc8, 0x0a, 0x85, 0xbb, 0xce, 0x37, 0x39, 0x0d, 0x94, 0xb4, 0xd8, 0x58, 0x79, 0x34, 0xe8, 0x78, + 0x0e, 0x1b, 0x5a, 0xae, 0x42, 0x8a, 0xa2, 0x15, 0xa8, 0x4a, 0x51, 0xc3, 0x30, 0xff, 0x28, 0x07, + 0x8b, 0x69, 0x4d, 0x67, 0x92, 0x7a, 0x5c, 0xb4, 0x56, 0x1e, 0x78, 0xde, 0x9f, 0xfd, 0xf8, 0xc8, + 0x8b, 0x70, 0x75, 0x5d, 0x2c, 0x43, 0x75, 0x24, 0x5f, 0xf2, 0x7e, 0x35, 0x42, 0xb9, 0x23, 0x8e, + 0x90, 0xa2, 0x9c, 0x18, 0xa5, 0x87, 0x60, 0xcc, 0x67, 0x33, 0x9f, 0x8f, 0xbb, 0xa5, 0xf9, 0x1c, + 0x71, 0x08, 0xc3, 0xe8, 0x38, 0x76, 0x20, 0x23, 0x5d, 0x15, 0xc6, 0x35, 0xc7, 0x0e, 0x90, 0x43, + 0xcc, 0x2f, 0xe6, 0xe0, 0x74, 0xff, 0x4e, 0x91, 0x2f, 0x1a, 0x00, 0x75, 0x66, 0xd4, 0xb2, 0x25, + 0x19, 0x06, 0x0e, 0x58, 0xc7, 0x35, 0x86, 0xab, 0x21, 0xa7, 0x28, 0x8a, 0x44, 0x15, 0xf9, 0xa8, + 0x35, 0x84, 0x3c, 0x16, 0x2e, 0xfd, 0xcb, 0x56, 0x2b, 0x34, 0x05, 0x55, 0x9d, 0x0d, 0x05, 0x41, + 0x0d, 0x8b, 0x9d, 0x5a, 0x1c, 0xab, 0x45, 0xfd, 0xb6, 0xa5, 0x42, 0x99, 0xf9, 0xa9, 0xe5, 0x72, + 0x58, 0x88, 0x11, 0xdc, 0x6c, 0xc2, 0xc3, 0x03, 0xb4, 0x33, 0xa3, 0xb0, 0x52, 0xf3, 0xdf, 0x0d, + 0x38, 0xb5, 0xd2, 0xec, 0xf8, 0x01, 0xf5, 0xfe, 0xc7, 0x04, 0xe5, 0xfc, 0xa7, 0x01, 0x0f, 0xf4, + 0xe9, 0xf3, 0x3d, 0x88, 0xcd, 0x79, 0x29, 0x1e, 0x9b, 0x73, 0x6d, 0xd4, 0x25, 0x9d, 0xda, 0x8f, + 0x3e, 0x21, 0x3a, 0x01, 0xcc, 0x30, 0xa9, 0x55, 0x77, 0x1b, 0x19, 0xe9, 0xcd, 0x87, 0xa1, 0xf0, + 0x51, 0xa6, 0x7f, 0x92, 0x6b, 0x8c, 0x2b, 0x25, 0x14, 0x30, 0xf3, 0x7d, 0x20, 0x03, 0x59, 0x12, + 0x9b, 0xc7, 0x18, 0x64, 0xf3, 0x98, 0x7f, 0x9b, 0x03, 0xed, 0xb4, 0x7b, 0x0f, 0x16, 0xa5, 0x13, + 0x5b, 0x94, 0x23, 0x9e, 0x5f, 0xb5, 0xb3, 0x7b, 0xbf, 0x88, 0xf5, 0xbd, 0x44, 0xc4, 0xfa, 0xe5, + 0xcc, 0x38, 0x1e, 0x1e, 0xb0, 0xfe, 0x5d, 0x03, 0x1e, 0x88, 0x90, 0x7b, 0x1d, 0x47, 0x77, 0x97, + 0x30, 0x4f, 0xc2, 0x94, 0x15, 0x55, 0x93, 0x6b, 0x40, 0x3d, 0xd2, 0xd0, 0x28, 0xa2, 0x8e, 0x17, + 0xc5, 0xc7, 0xe6, 0x8f, 0x18, 0x1f, 0x3b, 0x76, 0x78, 0x7c, 0xac, 0xf9, 0xe3, 0x1c, 0x9c, 0xe9, + 0xed, 0x59, 0xb8, 0x37, 0x06, 0xbb, 0x57, 0x7d, 0x0a, 0xa6, 0x03, 0x59, 0x41, 0x93, 0xf4, 0xea, + 0x89, 0xd1, 0x96, 0x06, 0xc3, 0x18, 0x26, 0xab, 0x59, 0x13, 0xbb, 0xb2, 0x5a, 0x73, 0xdb, 0x61, + 0x74, 0xb5, 0xaa, 0xb9, 0xa2, 0xc1, 0x30, 0x86, 0xa9, 0xe2, 0xd6, 0xc6, 0x8e, 0x3d, 0x6e, 0xad, + 0x0a, 0x27, 0xc3, 0x48, 0x9d, 0x0b, 0xae, 0xb7, 0xe2, 0xb6, 0xda, 0x4d, 0x2a, 0xe3, 0xab, 0x59, + 0x63, 0xcf, 0xc8, 0x2a, 0x27, 0x31, 0x0d, 0x09, 0xd3, 0xeb, 0x9a, 0xdf, 0xcd, 0xc3, 0x89, 0x68, + 0xd8, 0x57, 0x5c, 0xa7, 0x6e, 0xf3, 0x78, 0xa7, 0xa7, 0x61, 0x2c, 0xd8, 0x6f, 0x87, 0x83, 0xfd, + 0xbf, 0xc2, 0xe6, 0x6c, 0xed, 0xb7, 0xd9, 0x6c, 0x9f, 0x4a, 0xa9, 0xc2, 0x40, 0xc8, 0x2b, 0x91, + 0x75, 0xb5, 0x3b, 0xc4, 0x0c, 0x3c, 0x11, 0x5f, 0xcd, 0x77, 0xba, 0xa5, 0x94, 0x17, 0x76, 0xcb, + 0x8a, 0x52, 0x7c, 0xcd, 0x93, 0x1b, 0x30, 0xdb, 0xb4, 0xfc, 0xe0, 0x5a, 0xbb, 0x6e, 0x05, 0x74, + 0xcb, 0x6e, 0x51, 0xb9, 0xe7, 0x86, 0x09, 0x5a, 0x56, 0x77, 0x8d, 0xeb, 0x31, 0x4a, 0x98, 0xa0, + 0x4c, 0xf6, 0x80, 0xb0, 0x92, 0x2d, 0xcf, 0x72, 0x7c, 0xd1, 0x2b, 0xc6, 0x6f, 0xf8, 0x20, 0x69, + 0x75, 0x40, 0x5a, 0xef, 0xa1, 0x86, 0x29, 0x1c, 0xc8, 0x23, 0x30, 0xee, 0x51, 0xcb, 0x97, 0x93, + 0x39, 0x19, 0xed, 0x7f, 0xe4, 0xa5, 0x28, 0xa1, 0xfa, 0x86, 0x1a, 0xbf, 0xcb, 0x86, 0xfa, 0xa1, + 0x01, 0xb3, 0xd1, 0x34, 0xdd, 0x03, 0x25, 0xd9, 0x8a, 0x2b, 0xc9, 0x8b, 0x59, 0x89, 0xc4, 0x3e, + 0x7a, 0xf1, 0xcf, 0xc6, 0xf5, 0xfe, 0xf1, 0xa0, 0xd5, 0x8f, 0xc1, 0x64, 0xb8, 0xab, 0x43, 0xeb, + 0x73, 0x44, 0x2f, 0x4b, 0xcc, 0x2e, 0xd1, 0x1e, 0x5b, 0x48, 0x26, 0x18, 0xf1, 0x63, 0x6a, 0xb9, + 0x2e, 0x55, 0xae, 0x5c, 0xf6, 0x4a, 0x2d, 0x87, 0xaa, 0x38, 0x4d, 0x2d, 0x87, 0x75, 0xc8, 0x35, + 0x38, 0xd5, 0xf6, 0x5c, 0xfe, 0x00, 0x6f, 0x95, 0x5a, 0xf5, 0xa6, 0xed, 0xd0, 0xf0, 0x30, 0x2f, + 0xae, 0xba, 0x1f, 0x38, 0xe8, 0x96, 0x4e, 0x6d, 0xa6, 0xa3, 0x60, 0xbf, 0xba, 0xf1, 0x47, 0x23, + 0x63, 0x03, 0x3c, 0x1a, 0xf9, 0x25, 0xe5, 0x32, 0xa3, 0xbe, 0x7c, 0xba, 0xf1, 0xc1, 0xac, 0xa6, + 0x32, 0x45, 0xac, 0x47, 0x4b, 0xaa, 0x2c, 0x99, 0xa2, 0x62, 0xdf, 0xdf, 0x2f, 0x33, 0x7e, 0x44, + 0xbf, 0x4c, 0x14, 0xfb, 0x3b, 0xf1, 0xd3, 0x8c, 0xfd, 0x2d, 0xbe, 0xa9, 0x62, 0x7f, 0x5f, 0x2d, + 0xc0, 0x7c, 0xd2, 0x02, 0x39, 0xfe, 0x07, 0x31, 0xbf, 0x6a, 0xc0, 0x7c, 0xb8, 0x7b, 0x04, 0x4f, + 0x1a, 0x7a, 0xdc, 0xd7, 0x33, 0xda, 0xb4, 0xc2, 0x96, 0x52, 0x4f, 0x36, 0xb7, 0x12, 0xdc, 0xb0, + 0x87, 0x3f, 0x79, 0x11, 0xa6, 0x94, 0x63, 0xfa, 0x48, 0xaf, 0x63, 0xe6, 0xb8, 0x15, 0x15, 0x91, + 0x40, 0x9d, 0x1e, 0x79, 0xd5, 0x00, 0xa8, 0x85, 0x6a, 0x2e, 0xdc, 0x5d, 0x57, 0xb3, 0xda, 0x5d, + 0x4a, 0x81, 0x46, 0xc6, 0xb2, 0x2a, 0xf2, 0x51, 0x63, 0x4c, 0x3e, 0xcf, 0x5d, 0xd2, 0xca, 0xba, + 0x63, 0xfb, 0x29, 0x3f, 0x7a, 0xb8, 0xe6, 0x21, 0x86, 0x69, 0x64, 0x4a, 0x69, 0x20, 0x1f, 0x63, + 0x8d, 0x30, 0x9f, 0x06, 0x15, 0x60, 0xc7, 0xc4, 0x16, 0x0f, 0xb1, 0xdb, 0xb4, 0x82, 0x5d, 0xb9, + 0x04, 0x95, 0xd8, 0xba, 0x10, 0x02, 0x30, 0xc2, 0x31, 0x3f, 0x02, 0xb3, 0xcf, 0x7a, 0x56, 0x7b, + 0xd7, 0xe6, 0xae, 0x5f, 0x76, 0x4e, 0x7a, 0x3b, 0x4c, 0x58, 0xf5, 0x7a, 0xda, 0x83, 0xe7, 0xb2, + 0x28, 0xc6, 0x10, 0x3e, 0xd8, 0x91, 0xe8, 0x9b, 0x06, 0x2c, 0xae, 0xf9, 0x81, 0xed, 0xae, 0x52, + 0x3f, 0x60, 0xb2, 0x92, 0xed, 0xa8, 0x4e, 0x73, 0x90, 0x00, 0xd0, 0x55, 0x98, 0x97, 0xf7, 0x53, + 0x9d, 0x6d, 0x9f, 0x06, 0x9a, 0x71, 0xaa, 0x16, 0xe7, 0x4a, 0x02, 0x8e, 0x3d, 0x35, 0x18, 0x15, + 0x79, 0x51, 0x15, 0x51, 0xc9, 0xc7, 0xa9, 0x54, 0x13, 0x70, 0xec, 0xa9, 0x61, 0x7e, 0x27, 0x0f, + 0x27, 0x78, 0x37, 0x12, 0xc1, 0xdb, 0x9f, 0xed, 0x17, 0xbc, 0x3d, 0xe2, 0xfa, 0xe4, 0xbc, 0x8e, + 0x10, 0xba, 0xfd, 0x2b, 0x06, 0xcc, 0xd5, 0xe3, 0x23, 0x9d, 0x8d, 0xcf, 0x21, 0x6d, 0x0e, 0x45, + 0xa0, 0x48, 0xa2, 0x10, 0x93, 0xfc, 0xc9, 0x17, 0x0c, 0x98, 0x8b, 0x37, 0x33, 0x14, 0x59, 0xc7, + 0x30, 0x48, 0x2a, 0xb2, 0x33, 0x5e, 0xee, 0x63, 0xb2, 0x09, 0xe6, 0x5f, 0x1b, 0x72, 0x4a, 0x8f, + 0x23, 0x32, 0x99, 0xdc, 0x82, 0xc9, 0xa0, 0xe9, 0x8b, 0x42, 0xd9, 0xdb, 0x11, 0x8f, 0x39, 0x5b, + 0xeb, 0x55, 0x4e, 0x4e, 0xb3, 0x44, 0x64, 0x09, 0xb3, 0xa8, 0x42, 0x5e, 0xe6, 0x57, 0x0d, 0x98, + 0xbc, 0xe4, 0x6e, 0xcb, 0xed, 0xfc, 0xe1, 0x0c, 0x9c, 0x08, 0xca, 0xd6, 0x50, 0x37, 0x41, 0x91, + 0xf9, 0xfa, 0x4c, 0xcc, 0x85, 0xf0, 0xa0, 0x46, 0x7b, 0x99, 0x27, 0x0a, 0x61, 0xa4, 0x2e, 0xb9, + 0xdb, 0x7d, 0x3d, 0x54, 0xbf, 0x55, 0x80, 0x99, 0xe7, 0xac, 0x7d, 0xea, 0x04, 0xd6, 0xf0, 0x02, + 0x88, 0x9d, 0xca, 0xdb, 0x3c, 0x50, 0x51, 0xb3, 0x1f, 0xa3, 0x53, 0x79, 0x04, 0x42, 0x1d, 0x2f, + 0x92, 0x2b, 0x22, 0x6f, 0x41, 0x9a, 0x44, 0x58, 0x49, 0xc0, 0xb1, 0xa7, 0x06, 0xb9, 0x04, 0x44, + 0xbe, 0xc2, 0x2a, 0xd7, 0x6a, 0x6e, 0xc7, 0x11, 0x92, 0x45, 0x1c, 0xd8, 0xd5, 0x41, 0x66, 0xa3, + 0x07, 0x03, 0x53, 0x6a, 0x91, 0x0f, 0xc1, 0x52, 0x8d, 0x53, 0x96, 0x66, 0xad, 0x4e, 0x51, 0x1c, + 0x6d, 0x54, 0x90, 0xf0, 0x4a, 0x1f, 0x3c, 0xec, 0x4b, 0x81, 0xb5, 0xd4, 0x0f, 0x5c, 0xcf, 0x6a, + 0x50, 0x9d, 0xee, 0x78, 0xbc, 0xa5, 0xd5, 0x1e, 0x0c, 0x4c, 0xa9, 0x45, 0x3e, 0x09, 0x93, 0xc1, + 0xae, 0x47, 0xfd, 0x5d, 0xb7, 0x59, 0x97, 0x57, 0xc3, 0x23, 0x7a, 0x71, 0xe4, 0xec, 0x6f, 0x85, + 0x54, 0xb5, 0xe5, 0x1d, 0x16, 0x61, 0xc4, 0x93, 0x78, 0x30, 0xee, 0xd7, 0xdc, 0x36, 0xf5, 0xa5, + 0x39, 0x78, 0x29, 0x13, 0xee, 0xdc, 0x2b, 0xa1, 0xf9, 0x8f, 0x38, 0x07, 0x94, 0x9c, 0xcc, 0x6f, + 0xe5, 0x60, 0x5a, 0x47, 0x1c, 0x40, 0x44, 0x7c, 0xca, 0x80, 0xe9, 0x9a, 0xeb, 0x04, 0x9e, 0xdb, + 0x14, 0xbe, 0x11, 0xb1, 0x41, 0x46, 0x7c, 0xdc, 0xcf, 0x49, 0xad, 0xd2, 0xc0, 0xb2, 0x9b, 0x9a, + 0x9b, 0x45, 0x63, 0x83, 0x31, 0xa6, 0xe4, 0x33, 0x06, 0xcc, 0x45, 0x31, 0x33, 0x91, 0x93, 0x26, + 0xd3, 0x86, 0x28, 0x89, 0x7b, 0x3e, 0xce, 0x09, 0x93, 0xac, 0xcd, 0x6d, 0x98, 0x4f, 0xce, 0x36, + 0x1b, 0xca, 0xb6, 0x25, 0xf7, 0x7a, 0x3e, 0x1a, 0xca, 0x4d, 0xcb, 0xf7, 0x91, 0x43, 0xc8, 0x3b, + 0xa0, 0xd8, 0xb2, 0xbc, 0x86, 0xed, 0x58, 0x4d, 0x3e, 0x8a, 0x79, 0x4d, 0x20, 0xc9, 0x72, 0x54, + 0x18, 0xe6, 0x8f, 0xc6, 0x60, 0x4a, 0xb3, 0xe2, 0x8f, 0xdf, 0x22, 0x8f, 0x3d, 0x0c, 0xcf, 0x67, + 0xf8, 0x30, 0xfc, 0x05, 0x80, 0x1d, 0xdb, 0xb1, 0xfd, 0xdd, 0x23, 0x3e, 0x39, 0xe7, 0x97, 0x79, + 0x17, 0x14, 0x05, 0xd4, 0xa8, 0x45, 0x37, 0x26, 0x85, 0x43, 0x12, 0x71, 0xbc, 0x6a, 0x68, 0xca, + 0x63, 0x3c, 0x8b, 0x1b, 0x62, 0x6d, 0x62, 0x96, 0x43, 0x65, 0x72, 0xde, 0x09, 0xbc, 0xfd, 0x43, + 0x75, 0xcc, 0x16, 0x14, 0x3d, 0xea, 0x77, 0x5a, 0xec, 0x6c, 0x31, 0x31, 0xf4, 0x30, 0xf0, 0x00, + 0x13, 0x94, 0xf5, 0x51, 0x51, 0x3a, 0xfd, 0x34, 0xcc, 0xc4, 0x9a, 0x40, 0xe6, 0x21, 0x7f, 0x93, + 0xee, 0x8b, 0x75, 0x82, 0xec, 0x27, 0x59, 0x8c, 0xdd, 0x2b, 0xc9, 0x61, 0x79, 0x6f, 0xee, 0x29, + 0xc3, 0x74, 0x21, 0xf5, 0xa8, 0x78, 0x14, 0xb7, 0x3f, 0x9b, 0x8b, 0xa6, 0xf6, 0xe6, 0x5c, 0xcd, + 0x85, 0x88, 0x66, 0x10, 0x30, 0xf3, 0xc7, 0xe3, 0x20, 0x2f, 0x3d, 0x07, 0x10, 0x3e, 0xfa, 0x5d, + 0x47, 0xee, 0x08, 0x77, 0x1d, 0x97, 0x60, 0xda, 0x76, 0xec, 0xc0, 0xb6, 0x9a, 0xdc, 0x0d, 0x20, + 0x95, 0xe3, 0x23, 0xa1, 0xc0, 0x59, 0xd3, 0x60, 0x29, 0x74, 0x62, 0x75, 0xc9, 0x55, 0x28, 0x70, + 0xed, 0x21, 0x17, 0xf0, 0xf0, 0x37, 0xb3, 0xfc, 0x52, 0x5e, 0xbc, 0x4e, 0x10, 0x94, 0xb8, 0x45, + 0x2f, 0x1e, 0xdd, 0xab, 0x83, 0x9a, 0x5c, 0xc7, 0x91, 0x45, 0x9f, 0x80, 0x63, 0x4f, 0x0d, 0x46, + 0x65, 0xc7, 0xb2, 0x9b, 0x1d, 0x8f, 0x46, 0x54, 0xc6, 0xe3, 0x54, 0x2e, 0x24, 0xe0, 0xd8, 0x53, + 0x83, 0xec, 0xc0, 0xb4, 0x2c, 0x13, 0x31, 0x2a, 0x13, 0x47, 0xec, 0x25, 0x8f, 0x45, 0xba, 0xa0, + 0x51, 0xc2, 0x18, 0x5d, 0xd2, 0x81, 0x05, 0xdb, 0xa9, 0xb9, 0x4e, 0xad, 0xd9, 0xf1, 0xed, 0x3d, + 0x1a, 0x3d, 0x0d, 0x38, 0x0a, 0xb3, 0x93, 0x07, 0xdd, 0xd2, 0xc2, 0x5a, 0x92, 0x1c, 0xf6, 0x72, + 0x20, 0xaf, 0x18, 0x70, 0xb2, 0xe6, 0x3a, 0x3e, 0x7f, 0xc5, 0xba, 0x47, 0xcf, 0x7b, 0x9e, 0xeb, + 0x09, 0xde, 0x93, 0x47, 0xe4, 0xcd, 0xbd, 0x4f, 0x2b, 0x69, 0x24, 0x31, 0x9d, 0x13, 0x79, 0x09, + 0x8a, 0x6d, 0xcf, 0xdd, 0xb3, 0xeb, 0xd4, 0x93, 0xf1, 0x4e, 0xeb, 0x59, 0xbc, 0xaa, 0xdf, 0x94, + 0x34, 0x23, 0xd1, 0x13, 0x96, 0xa0, 0xe2, 0x67, 0xfe, 0x5e, 0x11, 0x66, 0xe3, 0xe8, 0xe4, 0x13, + 0x00, 0x6d, 0xcf, 0x6d, 0xd1, 0x60, 0x97, 0xaa, 0x10, 0xef, 0xcb, 0xa3, 0x3e, 0xde, 0x0e, 0xe9, + 0x85, 0x71, 0x0e, 0x4c, 0x5c, 0x44, 0xa5, 0xa8, 0x71, 0x24, 0x1e, 0x4c, 0xdc, 0x14, 0x4a, 0x54, + 0xda, 0x14, 0xcf, 0x65, 0x62, 0x01, 0x49, 0xce, 0x3c, 0x36, 0x59, 0x16, 0x61, 0xc8, 0x88, 0x6c, + 0x43, 0xfe, 0x16, 0xdd, 0xce, 0xe6, 0x41, 0xe4, 0x75, 0x2a, 0xcf, 0x26, 0x95, 0x89, 0x83, 0x6e, + 0x29, 0x7f, 0x9d, 0x6e, 0x23, 0x23, 0xce, 0xfa, 0x55, 0x17, 0x37, 0xb6, 0x52, 0x54, 0x8c, 0xd8, + 0xaf, 0xd8, 0xf5, 0xaf, 0xe8, 0x97, 0x2c, 0xc2, 0x90, 0x11, 0x79, 0x09, 0x26, 0x6f, 0x59, 0x7b, + 0x74, 0xc7, 0x73, 0x9d, 0x40, 0x06, 0xd7, 0x8c, 0x18, 0x45, 0x7c, 0x3d, 0x24, 0x27, 0xf9, 0x72, + 0xf5, 0xae, 0x0a, 0x31, 0x62, 0x47, 0xf6, 0xa0, 0xe8, 0xd0, 0x5b, 0x48, 0x9b, 0x76, 0x4d, 0x06, + 0x70, 0x8e, 0xb8, 0xac, 0x2f, 0x4b, 0x6a, 0x92, 0x33, 0xd7, 0x7b, 0x61, 0x19, 0x2a, 0x5e, 0x6c, + 0x2e, 0x6f, 0xb8, 0xdb, 0x52, 0x50, 0x8d, 0x38, 0x97, 0xea, 0x9c, 0x29, 0xe6, 0xf2, 0x92, 0xbb, + 0x8d, 0x8c, 0x38, 0xdb, 0x23, 0x35, 0x15, 0xd9, 0x21, 0xc5, 0xd4, 0xe5, 0x6c, 0x23, 0x5a, 0xc4, + 0x1e, 0x89, 0x4a, 0x51, 0xe3, 0xc8, 0xc6, 0xb6, 0x21, 0xdd, 0x5a, 0x52, 0x50, 0x8d, 0x38, 0xb6, + 0x71, 0x27, 0x99, 0x18, 0xdb, 0xb0, 0x0c, 0x15, 0x2f, 0xf3, 0xab, 0xe3, 0x30, 0xad, 0x67, 0x11, + 0x1a, 0x40, 0x57, 0x2b, 0xfb, 0x34, 0x37, 0x8c, 0x7d, 0xca, 0x8e, 0x17, 0x9a, 0x57, 0x3a, 0xf4, + 0x30, 0xac, 0x65, 0x66, 0x9e, 0x45, 0xc7, 0x0b, 0xad, 0xd0, 0xc7, 0x18, 0xd3, 0x21, 0x2e, 0xaa, + 0x99, 0x91, 0x23, 0xcc, 0x80, 0x42, 0xdc, 0xc8, 0x89, 0x29, 0xf6, 0xc7, 0x00, 0xa2, 0x6c, 0x3a, + 0xf2, 0xb6, 0x42, 0x59, 0x4f, 0x5a, 0x96, 0x1f, 0x0d, 0x8b, 0x3c, 0x02, 0xe3, 0x4c, 0x51, 0xd2, + 0xba, 0x7c, 0x7f, 0xa7, 0xce, 0x70, 0x17, 0x78, 0x29, 0x4a, 0x28, 0x79, 0x8a, 0xd9, 0x34, 0x91, + 0x7a, 0x93, 0xcf, 0xea, 0x16, 0x23, 0x9b, 0x26, 0x82, 0x61, 0x0c, 0x93, 0x35, 0x9d, 0x32, 0x6d, + 0xc4, 0x57, 0x92, 0xd6, 0x74, 0xae, 0xa2, 0x50, 0xc0, 0xb8, 0x4f, 0x21, 0xa1, 0xbd, 0xb8, 0xb2, + 0x2a, 0x68, 0x3e, 0x85, 0x04, 0x1c, 0x7b, 0x6a, 0xb0, 0xce, 0xc8, 0x8b, 0x96, 0x29, 0x11, 0x8f, + 0xd7, 0xe7, 0x8a, 0xe4, 0x35, 0xdd, 0x32, 0x9f, 0xe6, 0x53, 0xff, 0xfe, 0xec, 0x32, 0x62, 0x0d, + 0x6e, 0x9a, 0x8f, 0x66, 0x44, 0x7f, 0x04, 0x66, 0xe3, 0x32, 0x8b, 0x2d, 0xa8, 0xb6, 0xe7, 0xee, + 0xd8, 0x4d, 0x9a, 0xf4, 0xfd, 0x6c, 0x8a, 0x62, 0x0c, 0xe1, 0x83, 0x39, 0x9f, 0xff, 0x3c, 0x0f, + 0x27, 0x2e, 0x37, 0x6c, 0xe7, 0x76, 0xc2, 0x6b, 0x9b, 0x96, 0xa9, 0xd2, 0x18, 0x36, 0x53, 0x65, + 0xf4, 0x5c, 0x42, 0xa6, 0x02, 0x4d, 0x7f, 0x2e, 0x11, 0xe6, 0x09, 0x8d, 0xe3, 0x92, 0x1f, 0x1a, + 0xf0, 0xa0, 0x55, 0x17, 0x56, 0xa4, 0xd5, 0x94, 0xa5, 0x11, 0xd3, 0x70, 0x47, 0xfb, 0x23, 0xea, + 0x84, 0xde, 0xce, 0x2f, 0x97, 0x0f, 0xe1, 0x2a, 0x66, 0xfc, 0x6d, 0xb2, 0x07, 0x0f, 0x1e, 0x86, + 0x8a, 0x87, 0x36, 0xff, 0xf4, 0x15, 0x78, 0xeb, 0x5d, 0x19, 0x0d, 0xb5, 0x5a, 0x3e, 0x65, 0xc0, + 0xa4, 0x70, 0x4a, 0x22, 0xdd, 0x61, 0xa2, 0xc2, 0x6a, 0xdb, 0xcf, 0x53, 0xcf, 0x0f, 0x53, 0xe8, + 0x68, 0x07, 0xad, 0xf2, 0xe6, 0x9a, 0x84, 0xa0, 0x86, 0xc5, 0x84, 0xf1, 0x4d, 0xdb, 0xa9, 0xcb, + 0x69, 0x52, 0xc2, 0xf8, 0x39, 0xdb, 0xa9, 0x23, 0x87, 0x28, 0x71, 0x9d, 0xef, 0x9b, 0xcf, 0xe2, + 0x2b, 0x06, 0xcc, 0xf2, 0xd7, 0x50, 0xd1, 0x11, 0xe0, 0x49, 0x15, 0x85, 0x20, 0x9a, 0x71, 0x26, + 0x1e, 0x85, 0x70, 0xa7, 0x5b, 0x9a, 0x12, 0xef, 0xa7, 0xe2, 0x41, 0x09, 0x1f, 0x94, 0x7e, 0x03, + 0x1e, 0x2b, 0x91, 0x1b, 0xfa, 0x58, 0xab, 0xbc, 0x64, 0xd5, 0x90, 0x08, 0x46, 0xf4, 0xcc, 0x3f, + 0xc8, 0xc3, 0x89, 0x94, 0xb0, 0x7e, 0x76, 0xa4, 0x1f, 0xe7, 0x91, 0xcd, 0xe1, 0x4d, 0xff, 0x8b, + 0x99, 0x3f, 0x1d, 0x58, 0xe6, 0x01, 0xd4, 0x72, 0x25, 0x29, 0x01, 0x26, 0x0a, 0x51, 0x32, 0x27, + 0xbf, 0x6e, 0xc0, 0x94, 0xa5, 0x2d, 0x76, 0x11, 0xfc, 0xb0, 0x9d, 0x7d, 0x63, 0x7a, 0xd6, 0xb6, + 0x16, 0xb4, 0x15, 0x2d, 0x65, 0xbd, 0x2d, 0xa7, 0xdf, 0x03, 0x53, 0x5a, 0x17, 0x86, 0x59, 0xa3, + 0xa7, 0x9f, 0x81, 0xf9, 0x91, 0xd6, 0xf8, 0x07, 0x60, 0xd8, 0x9c, 0x4c, 0x4c, 0x65, 0xdc, 0xd2, + 0x1f, 0x09, 0xaa, 0x11, 0x97, 0xaf, 0x04, 0x25, 0xd4, 0xdc, 0x86, 0xf9, 0xe4, 0x31, 0x23, 0xf3, + 0xbb, 0xbe, 0x77, 0xc1, 0x90, 0x59, 0x94, 0xcc, 0xbf, 0xc8, 0xc1, 0x84, 0x7c, 0x1b, 0x74, 0x0f, + 0xe2, 0x1d, 0x6f, 0xc6, 0x2e, 0x2b, 0xd6, 0x32, 0x79, 0xd2, 0xd4, 0x37, 0xd8, 0xd1, 0x4f, 0x04, + 0x3b, 0x3e, 0x97, 0x0d, 0xbb, 0xc3, 0x23, 0x1d, 0xbf, 0x32, 0x06, 0x73, 0x89, 0xb7, 0x56, 0xcc, + 0x58, 0xe8, 0x09, 0xf0, 0xb9, 0x96, 0xe9, 0x73, 0x2e, 0x15, 0x8b, 0x7b, 0x78, 0xac, 0x8f, 0x1f, + 0x4b, 0x56, 0x77, 0x35, 0xb3, 0x3c, 0xb7, 0x3f, 0xcb, 0x5b, 0x37, 0x6c, 0xec, 0xca, 0x3f, 0x1a, + 0x70, 0x7f, 0xdf, 0x27, 0x79, 0x3c, 0xd7, 0x80, 0x17, 0x87, 0xca, 0x0d, 0x99, 0xf1, 0x13, 0x5b, + 0x75, 0x73, 0x90, 0x7c, 0x1e, 0x9e, 0x64, 0x4f, 0x9e, 0x80, 0x69, 0xae, 0xdc, 0x98, 0x4c, 0x09, + 0x68, 0x5b, 0xba, 0x4a, 0xb9, 0xd3, 0xac, 0xaa, 0x95, 0x63, 0x0c, 0xcb, 0xfc, 0xb2, 0x01, 0x4b, + 0xfd, 0x5e, 0x9e, 0x0f, 0x70, 0x34, 0xfb, 0x7f, 0x89, 0x80, 0xcc, 0x52, 0x4f, 0x40, 0x66, 0xe2, + 0x70, 0x16, 0xc6, 0x5e, 0x6a, 0xe7, 0xa2, 0xfc, 0x5d, 0xe2, 0x0d, 0x3f, 0x6b, 0xc0, 0xa9, 0x3e, + 0xbb, 0xa9, 0x27, 0x30, 0xd7, 0x38, 0x72, 0x60, 0x6e, 0x6e, 0xd0, 0xc0, 0x5c, 0xf3, 0xaf, 0xf2, + 0x30, 0x2f, 0xdb, 0x13, 0x59, 0x38, 0x4f, 0xc5, 0xc2, 0x5a, 0xdf, 0x96, 0x08, 0x6b, 0x5d, 0x4c, + 0xe2, 0xff, 0x2c, 0xa6, 0xf5, 0xcd, 0x15, 0xd3, 0xfa, 0x93, 0x1c, 0x9c, 0x4c, 0x7d, 0x60, 0x4f, + 0x3e, 0x9d, 0xa2, 0x1a, 0xae, 0x67, 0xfc, 0x92, 0x7f, 0x40, 0xe5, 0x30, 0x6a, 0x20, 0xe8, 0x17, + 0xf4, 0x00, 0x4c, 0x21, 0xea, 0x77, 0x8e, 0x21, 0x27, 0xc1, 0x90, 0xb1, 0x98, 0xe6, 0x2f, 0xe7, + 0xe1, 0xd1, 0x41, 0x09, 0xbd, 0x49, 0x63, 0xf5, 0xfd, 0x58, 0xac, 0xfe, 0x3d, 0x52, 0xdb, 0xc7, + 0x12, 0xb6, 0xff, 0xd5, 0xbc, 0x52, 0x7b, 0xbd, 0xeb, 0x73, 0xa0, 0x7b, 0xb5, 0x09, 0x66, 0xda, + 0x85, 0x69, 0xf2, 0x22, 0x51, 0x38, 0x51, 0x15, 0xc5, 0x77, 0xba, 0xa5, 0x05, 0x99, 0x3a, 0xab, + 0x4a, 0x03, 0x59, 0x88, 0x61, 0x25, 0xf2, 0x28, 0x14, 0x3d, 0x01, 0x0d, 0xa3, 0x93, 0xe5, 0xe5, + 0xa4, 0x28, 0x43, 0x05, 0x25, 0x9f, 0xd4, 0x6c, 0xe1, 0xb1, 0xe3, 0x7a, 0xe3, 0x7d, 0xd8, 0x9d, + 0xeb, 0x8b, 0x50, 0xf4, 0xc3, 0x84, 0x77, 0xc2, 0x31, 0xfe, 0xf8, 0x80, 0x41, 0xef, 0xec, 0xe8, + 0x14, 0x66, 0xbf, 0x13, 0xfd, 0x53, 0xb9, 0xf1, 0x14, 0x49, 0x62, 0xaa, 0x53, 0x8b, 0xf0, 0xf2, + 0x41, 0xca, 0x89, 0xe5, 0xbb, 0x06, 0x4c, 0xc9, 0xd9, 0xba, 0x07, 0x71, 0xf8, 0x37, 0xe2, 0x71, + 0xf8, 0xe7, 0x33, 0x91, 0x1d, 0x7d, 0x82, 0xf0, 0x6f, 0xc0, 0xb4, 0x9e, 0x63, 0x85, 0xbc, 0xa0, + 0xc9, 0x3e, 0x63, 0x94, 0x5c, 0x0e, 0xa1, 0x74, 0x8c, 0xe4, 0xa2, 0xf9, 0xa5, 0xa2, 0x1a, 0x45, + 0x1e, 0xed, 0xaf, 0xaf, 0x41, 0xe3, 0xd0, 0x35, 0xa8, 0x2f, 0x81, 0x5c, 0xf6, 0x4b, 0xe0, 0x2a, + 0x14, 0x43, 0x01, 0x25, 0xd5, 0xf8, 0xc3, 0x7a, 0xf4, 0x18, 0xb3, 0x05, 0x18, 0x31, 0x6d, 0xe1, + 0xf2, 0xa3, 0x96, 0x9a, 0x43, 0x25, 0x38, 0x15, 0x19, 0xf2, 0x12, 0x4c, 0xdd, 0x72, 0xbd, 0x9b, + 0x4d, 0xd7, 0xe2, 0xa9, 0x2c, 0x21, 0x8b, 0x2b, 0x0e, 0xe5, 0x72, 0x12, 0x41, 0xca, 0xd7, 0x23, + 0xfa, 0xa8, 0x33, 0x23, 0x65, 0x98, 0x6b, 0xd9, 0x0e, 0x52, 0xab, 0xae, 0xc2, 0xed, 0xc7, 0x44, + 0xae, 0xbd, 0xd0, 0xc8, 0xdd, 0x88, 0x83, 0x31, 0x89, 0x4f, 0x3e, 0x06, 0x45, 0x5f, 0xe6, 0x71, + 0xc9, 0xe6, 0x32, 0x4a, 0x9d, 0x19, 0x05, 0xd1, 0x68, 0xec, 0xc2, 0x12, 0x54, 0x0c, 0xc9, 0x3a, + 0x2c, 0x7a, 0x32, 0x53, 0x42, 0x2c, 0x11, 0xbe, 0xd8, 0x9f, 0x3c, 0xa5, 0x1b, 0xa6, 0xc0, 0x31, + 0xb5, 0x16, 0xb3, 0x62, 0x78, 0xb2, 0x20, 0xe1, 0x95, 0xd7, 0x1c, 0xd9, 0x7c, 0xc1, 0xd7, 0x51, + 0x42, 0x0f, 0x7b, 0xbe, 0x51, 0x1c, 0xe1, 0xf9, 0x46, 0x15, 0x4e, 0x26, 0x41, 0x3c, 0x9f, 0x03, + 0x4f, 0x21, 0xa1, 0x69, 0x8f, 0xcd, 0x34, 0x24, 0x4c, 0xaf, 0x4b, 0xae, 0xc3, 0xa4, 0x47, 0xf9, + 0xf9, 0xa2, 0x1c, 0x5e, 0x7f, 0x0f, 0x1d, 0xe8, 0x83, 0x21, 0x01, 0x8c, 0x68, 0xb1, 0x79, 0xb7, + 0xe2, 0xe9, 0xe6, 0xae, 0x66, 0xf8, 0x29, 0x1f, 0x39, 0xf7, 0x7d, 0xf2, 0xac, 0x98, 0x6f, 0xcc, + 0xc2, 0x4c, 0xcc, 0xb7, 0x40, 0x1e, 0x86, 0x02, 0x4f, 0x70, 0xc1, 0xc5, 0x43, 0x31, 0x12, 0x61, + 0x62, 0x70, 0x04, 0x8c, 0x7c, 0xce, 0x80, 0xb9, 0x76, 0xcc, 0x0f, 0x1a, 0x4a, 0xce, 0x11, 0x6f, + 0xda, 0xe2, 0xce, 0x55, 0x2d, 0x51, 0x6b, 0x9c, 0x19, 0x26, 0xb9, 0xb3, 0x0d, 0x28, 0x63, 0xdf, + 0x9a, 0xd4, 0xe3, 0xd8, 0xd2, 0xc6, 0x51, 0x24, 0x56, 0xe2, 0x60, 0x4c, 0xe2, 0xb3, 0x19, 0xe6, + 0xbd, 0x1b, 0xe5, 0x1b, 0x1f, 0xe5, 0x90, 0x00, 0x46, 0xb4, 0xc8, 0x33, 0x30, 0x2b, 0xb3, 0x8c, + 0x6d, 0xba, 0xf5, 0x8b, 0x96, 0xbf, 0x2b, 0x8d, 0x7b, 0x75, 0x18, 0x59, 0x89, 0x41, 0x31, 0x81, + 0xcd, 0xfb, 0x16, 0xa5, 0x72, 0xe3, 0x04, 0xc6, 0xe3, 0x79, 0x6c, 0x57, 0xe2, 0x60, 0x4c, 0xe2, + 0x93, 0x77, 0x68, 0x72, 0x5f, 0xdc, 0x94, 0x29, 0x69, 0x90, 0x22, 0xfb, 0xcb, 0x30, 0xd7, 0xe1, + 0x67, 0xa1, 0x7a, 0x08, 0x94, 0xfb, 0x51, 0x31, 0xbc, 0x16, 0x07, 0x63, 0x12, 0x9f, 0x3c, 0x0d, + 0x33, 0x1e, 0x93, 0x6e, 0x8a, 0x80, 0xb8, 0x3e, 0x53, 0xb7, 0x23, 0xa8, 0x03, 0x31, 0x8e, 0x4b, + 0x9e, 0x85, 0x85, 0x28, 0xf5, 0x51, 0x48, 0x40, 0xdc, 0xa7, 0xa9, 0x5c, 0x22, 0xe5, 0x24, 0x02, + 0xf6, 0xd6, 0x21, 0x3f, 0x07, 0xf3, 0xda, 0x48, 0xac, 0x39, 0x75, 0x7a, 0x5b, 0xa6, 0xa7, 0xe1, + 0x29, 0xc7, 0x57, 0x12, 0x30, 0xec, 0xc1, 0x26, 0xef, 0x85, 0xd9, 0x9a, 0xdb, 0x6c, 0x72, 0x19, + 0x27, 0x72, 0xa8, 0x8a, 0x3c, 0x34, 0x22, 0x63, 0x4f, 0x0c, 0x82, 0x09, 0x4c, 0x72, 0x09, 0x88, + 0xbb, 0xed, 0x53, 0x6f, 0x8f, 0xd6, 0x9f, 0x15, 0x5f, 0x0d, 0x64, 0x2a, 0x7e, 0x26, 0x1e, 0x79, + 0x7b, 0xa5, 0x07, 0x03, 0x53, 0x6a, 0xf1, 0x54, 0x24, 0xda, 0x2b, 0x98, 0xd9, 0x2c, 0xbe, 0x77, + 0x91, 0x3c, 0xb9, 0xdf, 0xf5, 0x09, 0x8c, 0x07, 0xe3, 0x22, 0x10, 0x7a, 0x69, 0x2e, 0x8b, 0x74, + 0x4c, 0x7a, 0x3a, 0xc5, 0x48, 0x47, 0x88, 0x52, 0x94, 0x9c, 0xc8, 0x27, 0x60, 0x72, 0x3b, 0xcc, + 0xad, 0xbb, 0x34, 0x9f, 0x85, 0x5e, 0x4c, 0xa4, 0x89, 0x8e, 0x4e, 0xa6, 0x0a, 0x80, 0x11, 0x4b, + 0xf2, 0x08, 0x4c, 0x5d, 0xdc, 0x2c, 0xab, 0x55, 0xb8, 0xc0, 0x67, 0x7f, 0x8c, 0x55, 0x41, 0x1d, + 0xc0, 0x76, 0x98, 0xb2, 0x97, 0x08, 0x9f, 0xe2, 0x48, 0xdf, 0xf6, 0x9a, 0x3f, 0x0c, 0x9b, 0x5f, + 0x08, 0x62, 0x75, 0xe9, 0x44, 0x02, 0x5b, 0x96, 0xa3, 0xc2, 0x20, 0x2f, 0xc2, 0x94, 0xd4, 0x17, + 0x5c, 0x36, 0x2d, 0x1e, 0xed, 0x85, 0x15, 0x46, 0x24, 0x50, 0xa7, 0x47, 0x9e, 0x84, 0xa9, 0x36, + 0x4f, 0x39, 0x4a, 0x2f, 0x74, 0x9a, 0xcd, 0xa5, 0x93, 0x5c, 0x6e, 0xaa, 0x9b, 0x92, 0xcd, 0x08, + 0x84, 0x3a, 0x1e, 0x79, 0x3c, 0x8c, 0x5d, 0x78, 0x4b, 0xec, 0xe2, 0x4b, 0xc5, 0x2e, 0x28, 0x2b, + 0xb7, 0x4f, 0x68, 0xed, 0xa9, 0xbb, 0x04, 0x0d, 0x6c, 0xc3, 0xe9, 0xd0, 0xc4, 0xea, 0xdd, 0x24, + 0x4b, 0x4b, 0x31, 0x2f, 0xc1, 0xe9, 0xeb, 0x7d, 0x31, 0xf1, 0x10, 0x2a, 0x64, 0x1b, 0xf2, 0x56, + 0x73, 0x7b, 0xe9, 0xfe, 0x2c, 0x6c, 0x45, 0xf5, 0x15, 0x50, 0x11, 0x0e, 0x53, 0x5e, 0xaf, 0x20, + 0x23, 0x6e, 0xbe, 0x92, 0x53, 0x5e, 0x79, 0x95, 0xa8, 0xef, 0xe3, 0xfa, 0xaa, 0x36, 0xb2, 0xf8, + 0xca, 0x5d, 0x4f, 0x02, 0x6a, 0xa1, 0x90, 0x52, 0xd7, 0x74, 0x5b, 0xed, 0xe3, 0x4c, 0x72, 0x3f, + 0xc4, 0x93, 0x10, 0x8a, 0xd3, 0x5c, 0x7c, 0x17, 0x9b, 0x3f, 0x28, 0x28, 0x27, 0x54, 0xe2, 0x32, + 0xde, 0x83, 0x82, 0xed, 0x07, 0xb6, 0x9b, 0xe1, 0xc3, 0xa9, 0x44, 0xf6, 0x3e, 0x1e, 0x42, 0xca, + 0x01, 0x28, 0x58, 0x31, 0x9e, 0x4e, 0xc3, 0x76, 0x6e, 0xcb, 0xee, 0x5f, 0xcd, 0xfc, 0x96, 0x5d, + 0xf0, 0xe4, 0x00, 0x14, 0xac, 0xc8, 0x0d, 0xb1, 0xd2, 0xb2, 0xf9, 0xa2, 0x61, 0xf2, 0x43, 0xa5, + 0xf1, 0x15, 0xc7, 0x78, 0xf9, 0x2d, 0x5b, 0xda, 0x30, 0x23, 0xf2, 0xaa, 0x6e, 0xac, 0xa5, 0xf1, + 0xaa, 0x6e, 0xac, 0x21, 0x63, 0x42, 0x5e, 0x33, 0x00, 0x2c, 0xf5, 0xc5, 0xce, 0x6c, 0xb2, 0xb5, + 0xf7, 0xfb, 0x02, 0xa8, 0x88, 0xfa, 0x8a, 0xa0, 0xa8, 0x71, 0x26, 0x2f, 0xc1, 0x84, 0x25, 0xbe, + 0x35, 0x21, 0x03, 0xea, 0xb2, 0xf9, 0x80, 0x4a, 0xa2, 0x05, 0x3c, 0x92, 0x50, 0x82, 0x30, 0x64, + 0x68, 0xfe, 0x8b, 0x01, 0xda, 0x27, 0xd6, 0xa2, 0x70, 0x27, 0x63, 0xe0, 0x70, 0xa7, 0xdc, 0x90, + 0xe1, 0x4e, 0xf9, 0xa1, 0xc2, 0x9d, 0xc6, 0x86, 0x0f, 0x77, 0x2a, 0xf4, 0x0f, 0x77, 0x32, 0x5f, + 0x37, 0x60, 0xa1, 0x67, 0x5d, 0x24, 0x3f, 0x65, 0x6b, 0x0c, 0xf8, 0x29, 0xdb, 0x55, 0x98, 0x97, + 0xa9, 0x34, 0xab, 0xed, 0xa6, 0x9d, 0xfa, 0xce, 0x73, 0x2b, 0x01, 0xc7, 0x9e, 0x1a, 0xe6, 0x9f, + 0x18, 0x30, 0xa5, 0x3d, 0x4b, 0x61, 0xfd, 0xe0, 0xcf, 0x77, 0x64, 0x33, 0xa2, 0x2c, 0xa2, 0xdc, + 0xc5, 0x29, 0x60, 0xc2, 0xdb, 0xde, 0xd0, 0x92, 0xc5, 0x45, 0xde, 0x76, 0x56, 0x8a, 0x12, 0x2a, + 0xd2, 0x80, 0x51, 0xf1, 0x99, 0xe2, 0xbc, 0x9e, 0x06, 0x8c, 0xb6, 0x91, 0x43, 0x38, 0x3b, 0xa6, + 0x4f, 0x65, 0x24, 0x9c, 0x96, 0xb4, 0xd4, 0x62, 0xa7, 0x26, 0x0e, 0x23, 0x67, 0x20, 0x4f, 0x9d, + 0xba, 0x34, 0xfe, 0xd5, 0x27, 0x2c, 0xce, 0x3b, 0x75, 0x64, 0xe5, 0xe6, 0x15, 0x98, 0xae, 0xd2, + 0x9a, 0x47, 0x83, 0xe7, 0xe8, 0xfe, 0xc0, 0xdf, 0xc4, 0xb8, 0x49, 0xf7, 0x93, 0xdf, 0xc4, 0x60, + 0xd5, 0x59, 0xb9, 0xf9, 0xbb, 0x06, 0x24, 0x72, 0xc8, 0x6a, 0x9e, 0x37, 0xa3, 0x9f, 0xe7, 0x2d, + 0xe6, 0x23, 0xca, 0x1d, 0xea, 0x23, 0xba, 0x04, 0xa4, 0x65, 0x05, 0xb5, 0xdd, 0x58, 0x86, 0x63, + 0x79, 0xee, 0x8a, 0x1e, 0xc1, 0xf5, 0x60, 0x60, 0x4a, 0x2d, 0xf3, 0x65, 0x03, 0x7a, 0xbe, 0x32, + 0xcc, 0xac, 0x05, 0x2a, 0x3f, 0x37, 0x20, 0x8e, 0xa3, 0xca, 0x5a, 0x08, 0xbf, 0x32, 0x10, 0xc2, + 0xd9, 0x99, 0x25, 0xf4, 0x7a, 0x85, 0x3e, 0x04, 0xf1, 0x5c, 0x48, 0x9d, 0x59, 0x56, 0xe3, 0x60, + 0x4c, 0xe2, 0x9b, 0xcf, 0x43, 0x31, 0x7c, 0x53, 0xc9, 0x1f, 0x26, 0x85, 0xa7, 0x60, 0xfd, 0x61, + 0x12, 0x3b, 0x04, 0x73, 0x08, 0x1b, 0x26, 0xdf, 0xb1, 0x2f, 0xba, 0x7e, 0x10, 0x3e, 0x04, 0x15, + 0xbe, 0xae, 0xcb, 0x6b, 0xbc, 0x0c, 0x15, 0xd4, 0x5c, 0x80, 0x39, 0xe5, 0xc4, 0x12, 0x8b, 0xde, + 0xfc, 0x56, 0x1e, 0xa6, 0x63, 0xdf, 0x8e, 0xbb, 0xfb, 0x64, 0x0f, 0x3e, 0x2d, 0x29, 0xce, 0xa8, + 0xfc, 0x90, 0xce, 0x28, 0xdd, 0xfb, 0x37, 0x76, 0xbc, 0xde, 0xbf, 0x42, 0x36, 0xde, 0xbf, 0x00, + 0x26, 0xe4, 0x77, 0xb5, 0xa5, 0xf8, 0xdf, 0xc8, 0x28, 0x21, 0x82, 0x7c, 0x59, 0xcc, 0x05, 0x7f, + 0x28, 0xc0, 0x42, 0x56, 0xe6, 0xd7, 0x0b, 0x30, 0x1b, 0x4f, 0x91, 0x30, 0xc0, 0x4c, 0xbe, 0xa3, + 0x67, 0x26, 0x87, 0x3c, 0x8c, 0xe7, 0x47, 0x3d, 0x8c, 0x8f, 0x8d, 0x7a, 0x18, 0x2f, 0x1c, 0xe1, + 0x30, 0xde, 0x7b, 0x94, 0x1e, 0x1f, 0xf8, 0x28, 0xfd, 0x3e, 0x75, 0x93, 0x3c, 0x11, 0xbb, 0x7a, + 0x89, 0x6e, 0x92, 0x49, 0x7c, 0x1a, 0x56, 0xdc, 0x7a, 0xea, 0x8d, 0x7c, 0xf1, 0x2e, 0x87, 0x0e, + 0x2f, 0xf5, 0xe2, 0x77, 0x78, 0x7f, 0xdf, 0x5b, 0x86, 0xb8, 0xf4, 0x8d, 0x3e, 0x1d, 0xcf, 0x95, + 0x1f, 0xc4, 0x15, 0x67, 0x35, 0x02, 0xa1, 0x8e, 0xc7, 0x3f, 0x6f, 0x14, 0xff, 0x9e, 0x13, 0xf7, + 0x6d, 0xe8, 0x9f, 0x37, 0x4a, 0x7c, 0xff, 0x29, 0x89, 0x6f, 0x7e, 0x2d, 0x0f, 0xb3, 0xf1, 0xf4, + 0xf4, 0xe4, 0x96, 0x3a, 0x1b, 0x64, 0x72, 0x2c, 0x11, 0x64, 0xb5, 0x24, 0x01, 0x7d, 0x0f, 0xfa, + 0xe2, 0x83, 0xe6, 0xdb, 0x2a, 0x63, 0xc1, 0xf1, 0x31, 0x96, 0x27, 0x6c, 0xc9, 0x8e, 0x67, 0xb4, + 0x8f, 0x82, 0x59, 0xe5, 0xed, 0x71, 0xe6, 0xdc, 0xa3, 0xf0, 0x54, 0xc5, 0x0a, 0x35, 0xb6, 0x4c, + 0xbc, 0xef, 0x51, 0xcf, 0xde, 0xb1, 0xd5, 0xa7, 0x75, 0xb8, 0xf0, 0x7c, 0x5e, 0x96, 0xa1, 0x82, + 0x9a, 0x2f, 0xe7, 0x20, 0xfa, 0x90, 0x18, 0xcf, 0x94, 0xed, 0x6b, 0x66, 0x83, 0x9c, 0xb6, 0x4b, + 0xa3, 0xa6, 0xa3, 0x8f, 0x28, 0xca, 0x40, 0x1b, 0xad, 0x04, 0x63, 0x1c, 0x7f, 0x0a, 0x1f, 0x10, + 0xb3, 0x60, 0x2e, 0xf1, 0xd4, 0x26, 0xf3, 0x68, 0xc6, 0x2f, 0xe5, 0x61, 0x52, 0x3d, 0x56, 0x22, + 0xef, 0xe1, 0x49, 0x6e, 0x77, 0xdd, 0x30, 0xf5, 0xf0, 0x5b, 0xb5, 0x54, 0xb4, 0xbb, 0x6e, 0xfd, + 0x4e, 0xb7, 0x34, 0xa7, 0x90, 0x45, 0x11, 0xca, 0x0a, 0xcc, 0x48, 0xeb, 0x78, 0xcd, 0xa4, 0x91, + 0x76, 0x0d, 0xd7, 0x91, 0x95, 0x93, 0xdb, 0x30, 0xb1, 0x4b, 0xad, 0x3a, 0xf5, 0xc2, 0xb8, 0x85, + 0x8d, 0x8c, 0x1e, 0x58, 0x5d, 0xe4, 0x54, 0xa3, 0x61, 0x10, 0xff, 0x7d, 0x0c, 0xd9, 0x31, 0x45, + 0xb5, 0xed, 0xd6, 0xf7, 0x93, 0xa9, 0x6b, 0x2b, 0x6e, 0x7d, 0x1f, 0x39, 0x84, 0x3c, 0x03, 0xb3, + 0x81, 0xdd, 0xa2, 0x6e, 0x27, 0xd0, 0x3f, 0xd3, 0x94, 0x8f, 0x1c, 0xd7, 0x5b, 0x31, 0x28, 0x26, + 0xb0, 0x99, 0xa2, 0xbb, 0xe1, 0xbb, 0x0e, 0xcf, 0x47, 0x33, 0x1e, 0xf7, 0x72, 0x5d, 0xaa, 0x5e, + 0xb9, 0xcc, 0xd3, 0xd1, 0x28, 0x0c, 0x86, 0x6d, 0xf3, 0x17, 0x11, 0x1e, 0x95, 0xf7, 0x46, 0xf3, + 0xd1, 0xbb, 0x55, 0x51, 0x8e, 0x0a, 0xc3, 0xbc, 0x06, 0x73, 0x89, 0xae, 0x86, 0xe6, 0xb0, 0x91, + 0x6e, 0x0e, 0x0f, 0x96, 0x27, 0xf6, 0x0f, 0x0d, 0x58, 0xe8, 0xd9, 0xbc, 0x83, 0x86, 0xd9, 0x26, + 0x25, 0x79, 0xee, 0xe8, 0x92, 0x3c, 0x3f, 0x9c, 0x24, 0xaf, 0x2c, 0x7f, 0xfb, 0x8d, 0xb3, 0xf7, + 0x7d, 0xe7, 0x8d, 0xb3, 0xf7, 0x7d, 0xef, 0x8d, 0xb3, 0xf7, 0xbd, 0x7c, 0x70, 0xd6, 0xf8, 0xf6, + 0xc1, 0x59, 0xe3, 0x3b, 0x07, 0x67, 0x8d, 0xef, 0x1d, 0x9c, 0x35, 0xfe, 0xe1, 0xe0, 0xac, 0xf1, + 0xfa, 0x8f, 0xce, 0xde, 0xf7, 0x42, 0x31, 0x5c, 0x26, 0xff, 0x15, 0x00, 0x00, 0xff, 0xff, 0xbe, + 0x64, 0xb8, 0x28, 0x8f, 0x88, 0x00, 0x00, } func (m *ALBStatus) Marshal() (dAtA []byte, err error) { @@ -3811,7 +3936,7 @@ func (m *AntiAffinity) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *Argument) Marshal() (dAtA []byte, err error) { +func (m *AppMeshTrafficRouting) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -3821,19 +3946,19 @@ func (m *Argument) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *Argument) MarshalTo(dAtA []byte) (int, error) { +func (m *AppMeshTrafficRouting) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Argument) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *AppMeshTrafficRouting) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if m.ValueFrom != nil { + if m.VirtualNodeGroup != nil { { - size, err := m.ValueFrom.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.VirtualNodeGroup.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -3841,24 +3966,24 @@ func (m *Argument) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintGenerated(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x1a + dAtA[i] = 0x12 } - if m.Value != nil { - i -= len(*m.Value) - copy(dAtA[i:], *m.Value) - i = encodeVarintGenerated(dAtA, i, uint64(len(*m.Value))) + if m.VirtualService != nil { + { + size, err := m.VirtualService.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } i-- - dAtA[i] = 0x12 + dAtA[i] = 0xa } - i -= len(m.Name) - copy(dAtA[i:], m.Name) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) - i-- - dAtA[i] = 0xa return len(dAtA) - i, nil } -func (m *ArgumentValueFrom) Marshal() (dAtA []byte, err error) { +func (m *AppMeshVirtualNodeGroup) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -3868,19 +3993,19 @@ func (m *ArgumentValueFrom) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *ArgumentValueFrom) MarshalTo(dAtA []byte) (int, error) { +func (m *AppMeshVirtualNodeGroup) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *ArgumentValueFrom) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *AppMeshVirtualNodeGroup) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if m.FieldRef != nil { + if m.StableVirtualNodeRef != nil { { - size, err := m.FieldRef.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.StableVirtualNodeRef.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -3890,12 +4015,171 @@ func (m *ArgumentValueFrom) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x12 } - if m.PodTemplateHashValue != nil { - i -= len(*m.PodTemplateHashValue) - copy(dAtA[i:], *m.PodTemplateHashValue) - i = encodeVarintGenerated(dAtA, i, uint64(len(*m.PodTemplateHashValue))) - i-- - dAtA[i] = 0xa + if m.CanaryVirtualNodeRef != nil { + { + size, err := m.CanaryVirtualNodeRef.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AppMeshVirtualNodeReference) 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 *AppMeshVirtualNodeReference) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AppMeshVirtualNodeReference) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *AppMeshVirtualService) 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 *AppMeshVirtualService) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AppMeshVirtualService) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Routes) > 0 { + for iNdEx := len(m.Routes) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Routes[iNdEx]) + copy(dAtA[i:], m.Routes[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Routes[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *Argument) 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 *Argument) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Argument) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ValueFrom != nil { + { + size, err := m.ValueFrom.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.Value != nil { + i -= len(*m.Value) + copy(dAtA[i:], *m.Value) + i = encodeVarintGenerated(dAtA, i, uint64(len(*m.Value))) + i-- + dAtA[i] = 0x12 + } + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *ArgumentValueFrom) 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 *ArgumentValueFrom) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ArgumentValueFrom) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.FieldRef != nil { + { + size, err := m.FieldRef.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.PodTemplateHashValue != nil { + i -= len(*m.PodTemplateHashValue) + copy(dAtA[i:], *m.PodTemplateHashValue) + i = encodeVarintGenerated(dAtA, i, uint64(len(*m.PodTemplateHashValue))) + i-- + dAtA[i] = 0xa } return len(dAtA) - i, nil } @@ -7468,6 +7752,18 @@ func (m *RolloutTrafficRouting) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.AppMesh != nil { + { + size, err := m.AppMesh.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } if m.Ambassador != nil { { size, err := m.Ambassador.MarshalToSizedBuffer(dAtA[:i]) @@ -8513,6 +8809,68 @@ func (m *AntiAffinity) Size() (n int) { return n } +func (m *AppMeshTrafficRouting) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.VirtualService != nil { + l = m.VirtualService.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + if m.VirtualNodeGroup != nil { + l = m.VirtualNodeGroup.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + return n +} + +func (m *AppMeshVirtualNodeGroup) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CanaryVirtualNodeRef != nil { + l = m.CanaryVirtualNodeRef.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + if m.StableVirtualNodeRef != nil { + l = m.StableVirtualNodeRef.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + return n +} + +func (m *AppMeshVirtualNodeReference) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + +func (m *AppMeshVirtualService) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + if len(m.Routes) > 0 { + for _, s := range m.Routes { + l = len(s) + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + func (m *Argument) Size() (n int) { if m == nil { return 0 @@ -9862,6 +10220,10 @@ func (m *RolloutTrafficRouting) Size() (n int) { l = m.Ambassador.Size() n += 1 + l + sovGenerated(uint64(l)) } + if m.AppMesh != nil { + l = m.AppMesh.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -10352,6 +10714,49 @@ func (this *AntiAffinity) String() string { }, "") return s } +func (this *AppMeshTrafficRouting) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&AppMeshTrafficRouting{`, + `VirtualService:` + strings.Replace(this.VirtualService.String(), "AppMeshVirtualService", "AppMeshVirtualService", 1) + `,`, + `VirtualNodeGroup:` + strings.Replace(this.VirtualNodeGroup.String(), "AppMeshVirtualNodeGroup", "AppMeshVirtualNodeGroup", 1) + `,`, + `}`, + }, "") + return s +} +func (this *AppMeshVirtualNodeGroup) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&AppMeshVirtualNodeGroup{`, + `CanaryVirtualNodeRef:` + strings.Replace(this.CanaryVirtualNodeRef.String(), "AppMeshVirtualNodeReference", "AppMeshVirtualNodeReference", 1) + `,`, + `StableVirtualNodeRef:` + strings.Replace(this.StableVirtualNodeRef.String(), "AppMeshVirtualNodeReference", "AppMeshVirtualNodeReference", 1) + `,`, + `}`, + }, "") + return s +} +func (this *AppMeshVirtualNodeReference) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&AppMeshVirtualNodeReference{`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `}`, + }, "") + return s +} +func (this *AppMeshVirtualService) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&AppMeshVirtualService{`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `Routes:` + fmt.Sprintf("%v", this.Routes) + `,`, + `}`, + }, "") + return s +} func (this *Argument) String() string { if this == nil { return "nil" @@ -11352,6 +11757,7 @@ func (this *RolloutTrafficRouting) String() string { `ALB:` + strings.Replace(this.ALB.String(), "ALBTrafficRouting", "ALBTrafficRouting", 1) + `,`, `SMI:` + strings.Replace(this.SMI.String(), "SMITrafficRouting", "SMITrafficRouting", 1) + `,`, `Ambassador:` + strings.Replace(this.Ambassador.String(), "AmbassadorTrafficRouting", "AmbassadorTrafficRouting", 1) + `,`, + `AppMesh:` + strings.Replace(this.AppMesh.String(), "AppMeshTrafficRouting", "AppMeshTrafficRouting", 1) + `,`, `}`, }, "") return s @@ -12916,7 +13322,398 @@ func (m *AnalysisRunStrategy) Unmarshal(dAtA []byte) error { if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field SuccessfulRunHistoryLimit", wireType) } - var v int32 + 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.SuccessfulRunHistoryLimit = &v + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UnsuccessfulRunHistoryLimit", 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.UnsuccessfulRunHistoryLimit = &v + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AnalysisTemplate) 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: AnalysisTemplate: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AnalysisTemplate: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ObjectMeta", 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 err := m.ObjectMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Spec", 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 err := m.Spec.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AnalysisTemplateList) 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: AnalysisTemplateList: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AnalysisTemplateList: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ListMeta", 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 err := m.ListMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Items", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Items = append(m.Items, AnalysisTemplate{}) + if err := m.Items[len(m.Items)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AnalysisTemplateSpec) 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: AnalysisTemplateSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AnalysisTemplateSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Metrics", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Metrics = append(m.Metrics, Metric{}) + if err := m.Metrics[len(m.Metrics)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Args", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Args = append(m.Args, Argument{}) + if err := m.Args[len(m.Args)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DryRun", wireType) + } + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -12926,17 +13723,31 @@ func (m *AnalysisRunStrategy) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - v |= int32(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - m.SuccessfulRunHistoryLimit = &v - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field UnsuccessfulRunHistoryLimit", wireType) + if msglen < 0 { + return ErrInvalidLengthGenerated } - var v int32 + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DryRun = append(m.DryRun, DryRun{}) + if err := m.DryRun[len(m.DryRun)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MeasurementRetention", wireType) + } + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -12946,12 +13757,26 @@ func (m *AnalysisRunStrategy) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - v |= int32(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - m.UnsuccessfulRunHistoryLimit = &v + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MeasurementRetention = append(m.MeasurementRetention, MeasurementRetention{}) + if err := m.MeasurementRetention[len(m.MeasurementRetention)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -12973,7 +13798,7 @@ func (m *AnalysisRunStrategy) Unmarshal(dAtA []byte) error { } return nil } -func (m *AnalysisTemplate) Unmarshal(dAtA []byte) error { +func (m *AntiAffinity) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -12996,15 +13821,15 @@ func (m *AnalysisTemplate) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: AnalysisTemplate: wiretype end group for non-group") + return fmt.Errorf("proto: AntiAffinity: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: AnalysisTemplate: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: AntiAffinity: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ObjectMeta", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field PreferredDuringSchedulingIgnoredDuringExecution", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -13031,13 +13856,16 @@ func (m *AnalysisTemplate) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.ObjectMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if m.PreferredDuringSchedulingIgnoredDuringExecution == nil { + m.PreferredDuringSchedulingIgnoredDuringExecution = &PreferredDuringSchedulingIgnoredDuringExecution{} + } + if err := m.PreferredDuringSchedulingIgnoredDuringExecution.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Spec", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field RequiredDuringSchedulingIgnoredDuringExecution", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -13064,7 +13892,10 @@ func (m *AnalysisTemplate) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Spec.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if m.RequiredDuringSchedulingIgnoredDuringExecution == nil { + m.RequiredDuringSchedulingIgnoredDuringExecution = &RequiredDuringSchedulingIgnoredDuringExecution{} + } + if err := m.RequiredDuringSchedulingIgnoredDuringExecution.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -13089,7 +13920,7 @@ func (m *AnalysisTemplate) Unmarshal(dAtA []byte) error { } return nil } -func (m *AnalysisTemplateList) Unmarshal(dAtA []byte) error { +func (m *AppMeshTrafficRouting) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -13112,15 +13943,15 @@ func (m *AnalysisTemplateList) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: AnalysisTemplateList: wiretype end group for non-group") + return fmt.Errorf("proto: AppMeshTrafficRouting: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: AnalysisTemplateList: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: AppMeshTrafficRouting: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ListMeta", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field VirtualService", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -13147,13 +13978,16 @@ func (m *AnalysisTemplateList) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.ListMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if m.VirtualService == nil { + m.VirtualService = &AppMeshVirtualService{} + } + if err := m.VirtualService.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Items", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field VirtualNodeGroup", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -13180,8 +14014,10 @@ func (m *AnalysisTemplateList) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Items = append(m.Items, AnalysisTemplate{}) - if err := m.Items[len(m.Items)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if m.VirtualNodeGroup == nil { + m.VirtualNodeGroup = &AppMeshVirtualNodeGroup{} + } + if err := m.VirtualNodeGroup.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -13206,7 +14042,7 @@ func (m *AnalysisTemplateList) Unmarshal(dAtA []byte) error { } return nil } -func (m *AnalysisTemplateSpec) Unmarshal(dAtA []byte) error { +func (m *AppMeshVirtualNodeGroup) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -13229,15 +14065,15 @@ func (m *AnalysisTemplateSpec) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: AnalysisTemplateSpec: wiretype end group for non-group") + return fmt.Errorf("proto: AppMeshVirtualNodeGroup: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: AnalysisTemplateSpec: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: AppMeshVirtualNodeGroup: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Metrics", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field CanaryVirtualNodeRef", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -13264,14 +14100,16 @@ func (m *AnalysisTemplateSpec) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Metrics = append(m.Metrics, Metric{}) - if err := m.Metrics[len(m.Metrics)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if m.CanaryVirtualNodeRef == nil { + m.CanaryVirtualNodeRef = &AppMeshVirtualNodeReference{} + } + if err := m.CanaryVirtualNodeRef.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Args", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field StableVirtualNodeRef", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -13298,50 +14136,68 @@ func (m *AnalysisTemplateSpec) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Args = append(m.Args, Argument{}) - if err := m.Args[len(m.Args)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if m.StableVirtualNodeRef == nil { + m.StableVirtualNodeRef = &AppMeshVirtualNodeReference{} + } + if err := m.StableVirtualNodeRef.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DryRun", 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 - } + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err } - if msglen < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF } - if postIndex > l { + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AppMeshVirtualNodeReference) 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 } - m.DryRun = append(m.DryRun, DryRun{}) - if err := m.DryRun[len(m.DryRun)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break } - iNdEx = postIndex - case 4: + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AppMeshVirtualNodeReference: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AppMeshVirtualNodeReference: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field MeasurementRetention", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -13351,25 +14207,23 @@ func (m *AnalysisTemplateSpec) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - m.MeasurementRetention = append(m.MeasurementRetention, MeasurementRetention{}) - if err := m.MeasurementRetention[len(m.MeasurementRetention)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.Name = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -13392,7 +14246,7 @@ func (m *AnalysisTemplateSpec) Unmarshal(dAtA []byte) error { } return nil } -func (m *AntiAffinity) Unmarshal(dAtA []byte) error { +func (m *AppMeshVirtualService) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -13415,17 +14269,17 @@ func (m *AntiAffinity) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: AntiAffinity: wiretype end group for non-group") + return fmt.Errorf("proto: AppMeshVirtualService: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: AntiAffinity: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: AppMeshVirtualService: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PreferredDuringSchedulingIgnoredDuringExecution", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -13435,33 +14289,29 @@ func (m *AntiAffinity) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - if m.PreferredDuringSchedulingIgnoredDuringExecution == nil { - m.PreferredDuringSchedulingIgnoredDuringExecution = &PreferredDuringSchedulingIgnoredDuringExecution{} - } - if err := m.PreferredDuringSchedulingIgnoredDuringExecution.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.Name = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RequiredDuringSchedulingIgnoredDuringExecution", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Routes", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -13471,27 +14321,23 @@ func (m *AntiAffinity) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - if m.RequiredDuringSchedulingIgnoredDuringExecution == nil { - m.RequiredDuringSchedulingIgnoredDuringExecution = &RequiredDuringSchedulingIgnoredDuringExecution{} - } - if err := m.RequiredDuringSchedulingIgnoredDuringExecution.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.Routes = append(m.Routes, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex default: iNdEx = preIndex @@ -25364,6 +26210,42 @@ func (m *RolloutTrafficRouting) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AppMesh", 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.AppMesh == nil { + m.AppMesh = &AppMeshTrafficRouting{} + } + if err := m.AppMesh.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) diff --git a/pkg/apis/rollouts/v1alpha1/generated.proto b/pkg/apis/rollouts/v1alpha1/generated.proto index e4e18c0d55..4f19568d00 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.proto +++ b/pkg/apis/rollouts/v1alpha1/generated.proto @@ -215,6 +215,39 @@ message AntiAffinity { optional RequiredDuringSchedulingIgnoredDuringExecution requiredDuringSchedulingIgnoredDuringExecution = 2; } +// AppMeshTrafficRouting configuration for AWS AppMesh service mesh to enable fine grain configuration +message AppMeshTrafficRouting { + // VirtualService references an AppMesh VirtualService and VirtualRouter to modify to shape traffic + optional AppMeshVirtualService virtualService = 1; + + // VirtualNodeGroup references an AppMesh Route targets that are formed by a set of VirtualNodes that are used to shape traffic + optional AppMeshVirtualNodeGroup virtualNodeGroup = 2; +} + +// AppMeshVirtualNodeGroup holds information about targets used for routing traffic to a virtual service +message AppMeshVirtualNodeGroup { + // CanaryVirtualNodeRef is the virtual node ref to modify labels with canary ReplicaSet pod template hash value + optional AppMeshVirtualNodeReference canaryVirtualNodeRef = 1; + + // StableVirtualNodeRef is the virtual node name to modify labels with stable ReplicaSet pod template hash value + optional AppMeshVirtualNodeReference stableVirtualNodeRef = 2; +} + +// AppMeshVirtualNodeReference holds a reference to VirtualNode.appmesh.k8s.aws +message AppMeshVirtualNodeReference { + // Name is the name of VirtualNode CR + optional string name = 1; +} + +// AppMeshVirtualService holds information on the virtual service the rollout needs to modify +message AppMeshVirtualService { + // Name is the name of virtual service + optional string name = 1; + + // Routes is list of HTTP routes within virtual router associated with virtual service to edit. If omitted, virtual service must have a single route of this type. + repeated string routes = 2; +} + // Argument is an argument to an AnalysisRun message Argument { // Name is the name of the argument @@ -1347,6 +1380,9 @@ message RolloutTrafficRouting { // Ambassador holds specific configuration to use Ambassador to route traffic optional AmbassadorTrafficRouting ambassador = 5; + + // AppMesh holds specific configuration to use AppMesh to route traffic + optional AppMeshTrafficRouting appMesh = 6; } // RunSummary contains the final results from the metric executions diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index 42164f2606..a0ee737923 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -43,6 +43,10 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisTemplateList": schema_pkg_apis_rollouts_v1alpha1_AnalysisTemplateList(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisTemplateSpec": schema_pkg_apis_rollouts_v1alpha1_AnalysisTemplateSpec(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AntiAffinity": schema_pkg_apis_rollouts_v1alpha1_AntiAffinity(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AppMeshTrafficRouting": schema_pkg_apis_rollouts_v1alpha1_AppMeshTrafficRouting(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AppMeshVirtualNodeGroup": schema_pkg_apis_rollouts_v1alpha1_AppMeshVirtualNodeGroup(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AppMeshVirtualNodeReference": schema_pkg_apis_rollouts_v1alpha1_AppMeshVirtualNodeReference(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AppMeshVirtualService": schema_pkg_apis_rollouts_v1alpha1_AppMeshVirtualService(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Argument": schema_pkg_apis_rollouts_v1alpha1_Argument(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ArgumentValueFrom": schema_pkg_apis_rollouts_v1alpha1_ArgumentValueFrom(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AwsResourceRef": schema_pkg_apis_rollouts_v1alpha1_AwsResourceRef(ref), @@ -776,6 +780,120 @@ func schema_pkg_apis_rollouts_v1alpha1_AntiAffinity(ref common.ReferenceCallback } } +func schema_pkg_apis_rollouts_v1alpha1_AppMeshTrafficRouting(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "AppMeshTrafficRouting configuration for AWS AppMesh service mesh to enable fine grain configuration", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "virtualService": { + SchemaProps: spec.SchemaProps{ + Description: "VirtualService references an AppMesh VirtualService and VirtualRouter to modify to shape traffic", + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AppMeshVirtualService"), + }, + }, + "virtualNodeGroup": { + SchemaProps: spec.SchemaProps{ + Description: "VirtualNodeGroup references an AppMesh Route targets that are formed by a set of VirtualNodes that are used to shape traffic", + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AppMeshVirtualNodeGroup"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AppMeshVirtualNodeGroup", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AppMeshVirtualService"}, + } +} + +func schema_pkg_apis_rollouts_v1alpha1_AppMeshVirtualNodeGroup(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "AppMeshVirtualNodeGroup holds information about targets used for routing traffic to a virtual service", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "canaryVirtualNodeRef": { + SchemaProps: spec.SchemaProps{ + Description: "CanaryVirtualNodeRef is the virtual node ref to modify labels with canary ReplicaSet pod template hash value", + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AppMeshVirtualNodeReference"), + }, + }, + "stableVirtualNodeRef": { + SchemaProps: spec.SchemaProps{ + Description: "StableVirtualNodeRef is the virtual node name to modify labels with stable ReplicaSet pod template hash value", + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AppMeshVirtualNodeReference"), + }, + }, + }, + Required: []string{"canaryVirtualNodeRef", "stableVirtualNodeRef"}, + }, + }, + Dependencies: []string{ + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AppMeshVirtualNodeReference"}, + } +} + +func schema_pkg_apis_rollouts_v1alpha1_AppMeshVirtualNodeReference(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "AppMeshVirtualNodeReference holds a reference to VirtualNode.appmesh.k8s.aws", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "Name is the name of VirtualNode CR", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"name"}, + }, + }, + } +} + +func schema_pkg_apis_rollouts_v1alpha1_AppMeshVirtualService(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "AppMeshVirtualService holds information on the virtual service the rollout needs to modify", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "Name is the name of virtual service", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "routes": { + SchemaProps: spec.SchemaProps{ + Description: "Routes is list of HTTP routes within virtual router associated with virtual service to edit. If omitted, virtual service must have a single route of this type.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + Required: []string{"name"}, + }, + }, + } +} + func schema_pkg_apis_rollouts_v1alpha1_Argument(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -3945,11 +4063,17 @@ func schema_pkg_apis_rollouts_v1alpha1_RolloutTrafficRouting(ref common.Referenc Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AmbassadorTrafficRouting"), }, }, + "appMesh": { + SchemaProps: spec.SchemaProps{ + Description: "AppMesh holds specific configuration to use AppMesh to route traffic", + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AppMeshTrafficRouting"), + }, + }, }, }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ALBTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AmbassadorTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.IstioTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.NginxTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SMITrafficRouting"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ALBTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AmbassadorTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AppMeshTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.IstioTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.NginxTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SMITrafficRouting"}, } } diff --git a/pkg/apis/rollouts/v1alpha1/types.go b/pkg/apis/rollouts/v1alpha1/types.go index bc43fd5fb2..6a81900b74 100644 --- a/pkg/apis/rollouts/v1alpha1/types.go +++ b/pkg/apis/rollouts/v1alpha1/types.go @@ -349,6 +349,8 @@ type RolloutTrafficRouting struct { SMI *SMITrafficRouting `json:"smi,omitempty" protobuf:"bytes,4,opt,name=smi"` // Ambassador holds specific configuration to use Ambassador to route traffic Ambassador *AmbassadorTrafficRouting `json:"ambassador,omitempty" protobuf:"bytes,5,opt,name=ambassador"` + // AppMesh holds specific configuration to use AppMesh to route traffic + AppMesh *AppMeshTrafficRouting `json:"appMesh,omitempty" protobuf:"bytes,6,opt,name=appMesh"` } // AmbassadorTrafficRouting defines the configuration required to use Ambassador as traffic @@ -418,6 +420,36 @@ type IstioDestinationRule struct { StableSubsetName string `json:"stableSubsetName" protobuf:"bytes,3,opt,name=stableSubsetName"` } +// AppMeshTrafficRouting configuration for AWS AppMesh service mesh to enable fine grain configuration +type AppMeshTrafficRouting struct { + // VirtualService references an AppMesh VirtualService and VirtualRouter to modify to shape traffic + VirtualService *AppMeshVirtualService `json:"virtualService,omitempty" protobuf:"bytes,1,opt,name=virtualService"` + // VirtualNodeGroup references an AppMesh Route targets that are formed by a set of VirtualNodes that are used to shape traffic + VirtualNodeGroup *AppMeshVirtualNodeGroup `json:"virtualNodeGroup,omitempty" protobuf:"bytes,2,opt,name=virtualNodeGroup"` +} + +// AppMeshVirtualService holds information on the virtual service the rollout needs to modify +type AppMeshVirtualService struct { + // Name is the name of virtual service + Name string `json:"name" protobuf:"bytes,1,opt,name=name"` + // Routes is list of HTTP routes within virtual router associated with virtual service to edit. If omitted, virtual service must have a single route of this type. + Routes []string `json:"routes,omitempty" protobuf:"bytes,2,rep,name=routes"` +} + +// AppMeshVirtualNodeGroup holds information about targets used for routing traffic to a virtual service +type AppMeshVirtualNodeGroup struct { + // CanaryVirtualNodeRef is the virtual node ref to modify labels with canary ReplicaSet pod template hash value + CanaryVirtualNodeRef *AppMeshVirtualNodeReference `json:"canaryVirtualNodeRef" protobuf:"bytes,1,opt,name=canaryVirtualNodeRef"` + // StableVirtualNodeRef is the virtual node name to modify labels with stable ReplicaSet pod template hash value + StableVirtualNodeRef *AppMeshVirtualNodeReference `json:"stableVirtualNodeRef" protobuf:"bytes,2,opt,name=stableVirtualNodeRef"` +} + +// AppMeshVirtualNodeReference holds a reference to VirtualNode.appmesh.k8s.aws +type AppMeshVirtualNodeReference struct { + // Name is the name of VirtualNode CR + Name string `json:"name" protobuf:"bytes,1,opt,name=name"` +} + // RolloutExperimentStep defines a template that is used to create a experiment for a step type RolloutExperimentStep struct { // Templates what templates that should be added to the experiment. Should be non-nil diff --git a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go index f29fe515e3..e18e5ade4b 100644 --- a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go @@ -395,6 +395,95 @@ func (in *AntiAffinity) DeepCopy() *AntiAffinity { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AppMeshTrafficRouting) DeepCopyInto(out *AppMeshTrafficRouting) { + *out = *in + if in.VirtualService != nil { + in, out := &in.VirtualService, &out.VirtualService + *out = new(AppMeshVirtualService) + (*in).DeepCopyInto(*out) + } + if in.VirtualNodeGroup != nil { + in, out := &in.VirtualNodeGroup, &out.VirtualNodeGroup + *out = new(AppMeshVirtualNodeGroup) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AppMeshTrafficRouting. +func (in *AppMeshTrafficRouting) DeepCopy() *AppMeshTrafficRouting { + if in == nil { + return nil + } + out := new(AppMeshTrafficRouting) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AppMeshVirtualNodeGroup) DeepCopyInto(out *AppMeshVirtualNodeGroup) { + *out = *in + if in.CanaryVirtualNodeRef != nil { + in, out := &in.CanaryVirtualNodeRef, &out.CanaryVirtualNodeRef + *out = new(AppMeshVirtualNodeReference) + **out = **in + } + if in.StableVirtualNodeRef != nil { + in, out := &in.StableVirtualNodeRef, &out.StableVirtualNodeRef + *out = new(AppMeshVirtualNodeReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AppMeshVirtualNodeGroup. +func (in *AppMeshVirtualNodeGroup) DeepCopy() *AppMeshVirtualNodeGroup { + if in == nil { + return nil + } + out := new(AppMeshVirtualNodeGroup) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AppMeshVirtualNodeReference) DeepCopyInto(out *AppMeshVirtualNodeReference) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AppMeshVirtualNodeReference. +func (in *AppMeshVirtualNodeReference) DeepCopy() *AppMeshVirtualNodeReference { + if in == nil { + return nil + } + out := new(AppMeshVirtualNodeReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AppMeshVirtualService) DeepCopyInto(out *AppMeshVirtualService) { + *out = *in + if in.Routes != nil { + in, out := &in.Routes, &out.Routes + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AppMeshVirtualService. +func (in *AppMeshVirtualService) DeepCopy() *AppMeshVirtualService { + if in == nil { + return nil + } + out := new(AppMeshVirtualService) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Argument) DeepCopyInto(out *Argument) { *out = *in @@ -2078,6 +2167,11 @@ func (in *RolloutTrafficRouting) DeepCopyInto(out *RolloutTrafficRouting) { *out = new(AmbassadorTrafficRouting) (*in).DeepCopyInto(*out) } + if in.AppMesh != nil { + in, out := &in.AppMesh, &out.AppMesh + *out = new(AppMeshTrafficRouting) + (*in).DeepCopyInto(*out) + } return } diff --git a/pkg/apis/rollouts/validation/validation_references.go b/pkg/apis/rollouts/validation/validation_references.go index de180e98d7..6a223b2fe5 100644 --- a/pkg/apis/rollouts/validation/validation_references.go +++ b/pkg/apis/rollouts/validation/validation_references.go @@ -17,6 +17,7 @@ import ( "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/rollout/trafficrouting/ambassador" + "github.com/argoproj/argo-rollouts/rollout/trafficrouting/appmesh" "github.com/argoproj/argo-rollouts/rollout/trafficrouting/istio" ) @@ -61,6 +62,7 @@ type ReferencedResources struct { ServiceWithType []ServiceWithType VirtualServices []unstructured.Unstructured AmbassadorMappings []unstructured.Unstructured + AppMeshResources []unstructured.Unstructured } func ValidateRolloutReferencedResources(rollout *v1alpha1.Rollout, referencedResources ReferencedResources) field.ErrorList { @@ -80,6 +82,9 @@ func ValidateRolloutReferencedResources(rollout *v1alpha1.Rollout, referencedRes for _, mapping := range referencedResources.AmbassadorMappings { allErrs = append(allErrs, ValidateAmbassadorMapping(mapping)...) } + for _, appmeshRes := range referencedResources.AppMeshResources { + allErrs = append(allErrs, ValidateAppMeshResource(appmeshRes)...) + } return allErrs } @@ -321,6 +326,57 @@ func ValidateAmbassadorMapping(obj unstructured.Unstructured) field.ErrorList { return allErrs } +func ValidateAppMeshResource(obj unstructured.Unstructured) field.ErrorList { + if obj.GetKind() != "VirtualRouter" { + fldPath := field.NewPath("kind") + msg := fmt.Sprintf("Expected object kind to be VirtualRouter but is %s", obj.GetKind()) + return field.ErrorList{field.Invalid(fldPath, obj.GetKind(), msg)} + } + + err := ValidateAppMeshVirtualRouter(&obj) + if err != nil { + return field.ErrorList{err} + } + return field.ErrorList{} +} + +func ValidateAppMeshVirtualRouter(vrouter *unstructured.Unstructured) *field.Error { + routesFldPath := field.NewPath("spec", "routes") + allRoutesI, found, err := unstructured.NestedSlice(vrouter.Object, "spec", "routes") + if !found || err != nil || len(allRoutesI) == 0 { + msg := fmt.Sprintf("No routes defined for AppMesh virtual-router %s", vrouter.GetName()) + return field.Invalid(routesFldPath, vrouter.GetName(), msg) + } + for idx, routeI := range allRoutesI { + routeFldPath := routesFldPath.Index(idx) + route, ok := routeI.(map[string]interface{}) + if !ok { + msg := fmt.Sprintf("Invalid route was found for AppMesh virtual-router %s at index %d", vrouter.GetName(), idx) + return field.Invalid(routeFldPath, vrouter.GetName(), msg) + } + + routeName := route["name"] + routeRule, routeType, err := appmesh.GetRouteRule(route) + if err != nil { + msg := fmt.Sprintf("Error getting route details for AppMesh virtual-router %s and route %s. Error: %s", vrouter.GetName(), routeName, err.Error()) + return field.Invalid(routeFldPath, vrouter.GetName(), msg) + } + + weightedTargetsFldPath := routeFldPath.Child(routeType).Child("action").Child("weightedTargets") + weightedTargets, found, err := unstructured.NestedSlice(routeRule, "action", "weightedTargets") + if !found || err != nil { + msg := fmt.Sprintf("Invalid route action found for AppMesh virtual-router %s and route %s", vrouter.GetName(), routeName) + return field.Invalid(weightedTargetsFldPath, vrouter.GetName(), msg) + } + + if len(weightedTargets) != 2 { + msg := fmt.Sprintf("Invalid number of weightedTargets (%d) for AppMesh virtual-router %s and route %s, expected 2", len(weightedTargets), vrouter.GetName(), routeName) + return field.Invalid(weightedTargetsFldPath, vrouter.GetName(), msg) + } + } + return nil +} + func GetServiceWithTypeFieldPath(serviceType ServiceType) *field.Path { fldPath := field.NewPath("spec", "strategy") switch serviceType { diff --git a/pkg/apis/rollouts/validation/validation_references_test.go b/pkg/apis/rollouts/validation/validation_references_test.go index fae183544c..104844b4b0 100644 --- a/pkg/apis/rollouts/validation/validation_references_test.go +++ b/pkg/apis/rollouts/validation/validation_references_test.go @@ -672,6 +672,203 @@ spec: }) } +func TestValidateAppMeshResource(t *testing.T) { + t.Run("will return error with appmesh virtual-service", func(t *testing.T) { + t.Parallel() + manifest := ` +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualService +metadata: + namespace: myns + name: mysvc +spec: + awsName: mysvc.myns.svc.cluster.local + provider: + virtualRouter: + virtualRouterRef: + name: mysvc-vrouter +` + obj := toUnstructured(t, manifest) + refResources := ReferencedResources{ + AppMeshResources: []k8sunstructured.Unstructured{*obj}, + } + errList := ValidateRolloutReferencedResources(getRollout(), refResources) + assert.NotNil(t, errList) + assert.Len(t, errList, 1) + assert.Equal(t, errList[0].Detail, "Expected object kind to be VirtualRouter but is VirtualService") + }) + + t.Run("will return error when appmesh virtual-router has no routes", func(t *testing.T) { + t.Parallel() + manifest := ` +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualRouter +metadata: + namespace: myns + name: mysvc-vrouter +spec: + routes: +` + obj := toUnstructured(t, manifest) + errList := ValidateAppMeshResource(*obj) + assert.NotNil(t, errList) + assert.Len(t, errList, 1) + assert.Equal(t, errList[0].Field, field.NewPath("spec", "routes").String()) + }) + + routeTypes := []string{"httpRoute", "tcpRoute", "grpcRoute", "http2Route"} + for _, routeType := range routeTypes { + t.Run(fmt.Sprintf("will succeed with valid appmesh virtual-router with %s", routeType), func(t *testing.T) { + t.Parallel() + manifest := fmt.Sprintf(` +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualRouter +metadata: + namespace: myns + name: mysvc-vrouter +spec: + routes: + - name: primary + %s: + action: + weightedTargets: + - virtualNodeRef: + name: mysvc-canary-vn + weight: 0 + - virtualNodeRef: + name: mysvc-stable-vn + weight: 100 +`, routeType) + obj := toUnstructured(t, manifest) + errList := ValidateAppMeshResource(*obj) + assert.NotNil(t, errList) + assert.Len(t, errList, 0) + }) + } + + t.Run("will return error with appmesh virtual-router with unsupported route type", func(t *testing.T) { + t.Parallel() + manifest := ` +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualRouter +metadata: + namespace: myns + name: mysvc-vrouter +spec: + routes: + - name: primary + badRouteType: +` + obj := toUnstructured(t, manifest) + errList := ValidateAppMeshResource(*obj) + assert.NotNil(t, errList) + assert.Len(t, errList, 1) + assert.Equal(t, field.NewPath("spec", "routes").Index(0).String(), errList[0].Field) + }) + + t.Run("will return error when appmesh virtual-router has route that is not a struct", func(t *testing.T) { + t.Parallel() + manifest := ` +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualRouter +metadata: + namespace: myns + name: mysvc-vrouter +spec: + routes: + - invalid-spec +` + obj := toUnstructured(t, manifest) + errList := ValidateAppMeshResource(*obj) + assert.NotNil(t, errList) + assert.Len(t, errList, 1) + assert.Equal(t, field.NewPath("spec", "routes").Index(0).String(), errList[0].Field) + }) + + t.Run("will return error when appmesh virtual-router has routes with no targets", func(t *testing.T) { + t.Parallel() + manifest := ` +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualRouter +metadata: + namespace: myns + name: mysvc-vrouter +spec: + routes: + - name: primary + httpRoute: + match: + prefix: / + action: +` + obj := toUnstructured(t, manifest) + errList := ValidateAppMeshResource(*obj) + assert.NotNil(t, errList) + assert.Len(t, errList, 1) + assert.Equal(t, field.NewPath("spec", "routes").Index(0).Child("httpRoute").Child("action").Child("weightedTargets").String(), errList[0].Field) + }) + + t.Run("will return error when appmesh virtual-router has routes with 1 target", func(t *testing.T) { + t.Parallel() + manifest := ` +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualRouter +metadata: + namespace: myns + name: mysvc-vrouter +spec: + routes: + - name: primary + httpRoute: + match: + prefix: / + action: + weightedTargets: + - virtualNodeRef: + name: only-target + weight: 100 +` + obj := toUnstructured(t, manifest) + errList := ValidateAppMeshResource(*obj) + assert.NotNil(t, errList) + assert.Len(t, errList, 1) + assert.Equal(t, field.NewPath("spec", "routes").Index(0).Child("httpRoute").Child("action").Child("weightedTargets").String(), errList[0].Field) + }) + + t.Run("will return error when appmesh virtual-router has routes with 3 targets", func(t *testing.T) { + t.Parallel() + manifest := ` +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualRouter +metadata: + namespace: myns + name: mysvc-vrouter +spec: + routes: + - name: primary + httpRoute: + match: + prefix: / + action: + weightedTargets: + - virtualNodeRef: + name: target-1 + weight: 10 + - virtualNodeRef: + name: target-2 + weight: 10 + - virtualNodeRef: + name: target-3 + weight: 80 +` + obj := toUnstructured(t, manifest) + errList := ValidateAppMeshResource(*obj) + assert.NotNil(t, errList) + assert.Len(t, errList, 1) + assert.Equal(t, field.NewPath("spec", "routes").Index(0).Child("httpRoute").Child("action").Child("weightedTargets").String(), errList[0].Field) + }) +} + func toUnstructured(t *testing.T, manifest string) *k8sunstructured.Unstructured { t.Helper() obj := &k8sunstructured.Unstructured{} diff --git a/pkg/apis/rollouts/validation/validation_test.go b/pkg/apis/rollouts/validation/validation_test.go index 1c9ffb551d..936030a95b 100644 --- a/pkg/apis/rollouts/validation/validation_test.go +++ b/pkg/apis/rollouts/validation/validation_test.go @@ -15,6 +15,10 @@ import ( "github.com/argoproj/argo-rollouts/utils/defaults" ) +const ( + errTrafficRoutingWithExperimentSupport = "Experiment template weight is only available for TrafficRouting with SMI, ALB, and Istio at this time" +) + func TestValidateRollout(t *testing.T) { selector := &metav1.LabelSelector{ MatchLabels: map[string]string{"key": "value"}, @@ -438,7 +442,7 @@ func TestCanaryExperimentStepWithWeight(t *testing.T) { invalidRo.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{} allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) assert.Equal(t, 1, len(allErrs)) - assert.Equal(t, "Experiment template weight is only available for TrafficRouting with SMI, ALB, and Istio at this time", allErrs[0].Detail) + assert.Equal(t, errTrafficRoutingWithExperimentSupport, allErrs[0].Detail) }) t.Run("unsupported - Nginx TrafficRouting", func(t *testing.T) { @@ -450,7 +454,7 @@ func TestCanaryExperimentStepWithWeight(t *testing.T) { } allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) assert.Equal(t, 1, len(allErrs)) - assert.Equal(t, "Experiment template weight is only available for TrafficRouting with SMI, ALB, and Istio at this time", allErrs[0].Detail) + assert.Equal(t, errTrafficRoutingWithExperimentSupport, allErrs[0].Detail) }) t.Run("unsupported - Ambassador TrafficRouting", func(t *testing.T) { @@ -462,7 +466,7 @@ func TestCanaryExperimentStepWithWeight(t *testing.T) { } allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) assert.Equal(t, 1, len(allErrs)) - assert.Equal(t, "Experiment template weight is only available for TrafficRouting with SMI, ALB, and Istio at this time", allErrs[0].Detail) + assert.Equal(t, errTrafficRoutingWithExperimentSupport, allErrs[0].Detail) }) t.Run("unsupported - Istio TrafficRouting", func(t *testing.T) { @@ -495,4 +499,15 @@ func TestCanaryExperimentStepWithWeight(t *testing.T) { allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) assert.Equal(t, 0, len(allErrs)) }) + + t.Run("unsupported - AppMesh TrafficRouting", func(t *testing.T) { + invalidRo := ro.DeepCopy() + invalidRo.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{ + AppMesh: &v1alpha1.AppMeshTrafficRouting{}, + } + allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) + assert.Equal(t, 1, len(allErrs)) + assert.Equal(t, errTrafficRoutingWithExperimentSupport, allErrs[0].Detail) + }) + } diff --git a/rollout/controller.go b/rollout/controller.go index e17fbafc37..6e7f354133 100644 --- a/rollout/controller.go +++ b/rollout/controller.go @@ -40,6 +40,7 @@ import ( listers "github.com/argoproj/argo-rollouts/pkg/client/listers/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/rollout/trafficrouting" "github.com/argoproj/argo-rollouts/rollout/trafficrouting/ambassador" + "github.com/argoproj/argo-rollouts/rollout/trafficrouting/appmesh" "github.com/argoproj/argo-rollouts/rollout/trafficrouting/istio" analysisutil "github.com/argoproj/argo-rollouts/utils/analysis" "github.com/argoproj/argo-rollouts/utils/conditions" @@ -557,9 +558,49 @@ func (c *rolloutContext) getRolloutReferencedResources() (*validation.Referenced } refResources.AmbassadorMappings = ambassadorMappings + appmeshResources, err := c.getReferencedAppMeshResources() + if err != nil { + return nil, err + } + refResources.AppMeshResources = appmeshResources + return &refResources, nil } +func (c *rolloutContext) getReferencedAppMeshResources() ([]unstructured.Unstructured, error) { + ctx := context.TODO() + appmeshClient := appmesh.NewResourceClient(c.dynamicclientset) + rollout := c.rollout + refResources := []unstructured.Unstructured{} + if rollout.Spec.Strategy.Canary != nil { + canary := rollout.Spec.Strategy.Canary + if canary.TrafficRouting != nil && canary.TrafficRouting.AppMesh != nil { + fldPath := field.NewPath("spec", "strategy", "canary", "trafficRouting", "appmesh", "virtualService") + tr := canary.TrafficRouting.AppMesh + if tr.VirtualService == nil { + return nil, field.Invalid(fldPath, nil, "must provide virtual-service") + } + + vsvc, err := appmeshClient.GetVirtualServiceCR(ctx, c.rollout.Namespace, tr.VirtualService.Name) + if err != nil { + if k8serrors.IsNotFound(err) { + return nil, field.Invalid(fldPath, fmt.Sprintf("%s.%s", tr.VirtualService.Name, c.rollout.Namespace), err.Error()) + } + return nil, err + } + vr, err := appmeshClient.GetVirtualRouterCRForVirtualService(ctx, vsvc) + if err != nil { + if k8serrors.IsNotFound(err) { + return nil, field.Invalid(fldPath, fmt.Sprintf("%s.%s", tr.VirtualService.Name, c.rollout.Namespace), err.Error()) + } + return nil, err + } + refResources = append(refResources, *vr) + } + } + return refResources, nil +} + func (c *rolloutContext) getAmbassadorMappings() ([]unstructured.Unstructured, error) { mappings := []unstructured.Unstructured{} if c.rollout.Spec.Strategy.Canary != nil { diff --git a/rollout/controller_test.go b/rollout/controller_test.go index f8e922ee3b..7f324ea10b 100644 --- a/rollout/controller_test.go +++ b/rollout/controller_test.go @@ -54,6 +54,7 @@ import ( replicasetutil "github.com/argoproj/argo-rollouts/utils/replicaset" rolloututil "github.com/argoproj/argo-rollouts/utils/rollout" timeutil "github.com/argoproj/argo-rollouts/utils/time" + unstructuredutil "github.com/argoproj/argo-rollouts/utils/unstructured" ) var ( @@ -1683,6 +1684,135 @@ func TestGetReferencedIngressesNginx(t *testing.T) { }) } +func TestGetReferencedAppMeshResources(t *testing.T) { + r := newCanaryRollout("rollout", 1, nil, nil, nil, intstr.FromInt(0), intstr.FromInt(1)) + r.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{ + AppMesh: &v1alpha1.AppMeshTrafficRouting{ + VirtualService: &v1alpha1.AppMeshVirtualService{ + Name: "mysvc", + Routes: []string{"primary"}, + }, + VirtualNodeGroup: &v1alpha1.AppMeshVirtualNodeGroup{ + CanaryVirtualNodeRef: &v1alpha1.AppMeshVirtualNodeReference{ + Name: "mysvc-canary-vn", + }, + StableVirtualNodeRef: &v1alpha1.AppMeshVirtualNodeReference{ + Name: "mysvc-stable-vn", + }, + }, + }, + } + r.Namespace = "default" + + t.Run("should return error when virtual-service is not defined on rollout", func(t *testing.T) { + f := newFixture(t) + defer f.Close() + + c, _, _ := f.newController(noResyncPeriodFunc) + rCopy := r.DeepCopy() + rCopy.Spec.Strategy.Canary.TrafficRouting.AppMesh.VirtualService = nil + roCtx, err := c.newRolloutContext(rCopy) + assert.NoError(t, err) + _, err = roCtx.getRolloutReferencedResources() + expectedErr := field.Invalid(field.NewPath("spec", "strategy", "canary", "trafficRouting", "appmesh", "virtualService"), "null", "must provide virtual-service") + assert.Equal(t, expectedErr.Error(), err.Error()) + }) + + t.Run("should return error when virtual-service is not-found", func(t *testing.T) { + f := newFixture(t) + defer f.Close() + + c, _, _ := f.newController(noResyncPeriodFunc) + roCtx, err := c.newRolloutContext(r) + assert.NoError(t, err) + _, err = roCtx.getRolloutReferencedResources() + expectedErr := field.Invalid(field.NewPath("spec", "strategy", "canary", "trafficRouting", "appmesh", "virtualService"), "mysvc.default", "virtualservices.appmesh.k8s.aws \"mysvc\" not found") + assert.Equal(t, expectedErr.Error(), err.Error()) + }) + + t.Run("should return error when virtual-router is not-found", func(t *testing.T) { + f := newFixture(t) + defer f.Close() + + vsvc := ` +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualService +metadata: + name: mysvc + namespace: default +spec: + provider: + virtualRouter: + virtualRouterRef: + name: mysvc-vrouter +` + uVsvc := unstructuredutil.StrToUnstructuredUnsafe(vsvc) + f.objects = append(f.objects, uVsvc) + c, _, _ := f.newController(noResyncPeriodFunc) + roCtx, err := c.newRolloutContext(r) + assert.NoError(t, err) + _, err = roCtx.getRolloutReferencedResources() + expectedErr := field.Invalid(field.NewPath("spec", "strategy", "canary", "trafficRouting", "appmesh", "virtualService"), "mysvc.default", "virtualrouters.appmesh.k8s.aws \"mysvc-vrouter\" not found") + assert.Equal(t, expectedErr.Error(), err.Error()) + }) + + t.Run("get referenced App Mesh - success", func(t *testing.T) { + f := newFixture(t) + defer f.Close() + + vsvc := ` +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualService +metadata: + name: mysvc + namespace: default +spec: + provider: + virtualRouter: + virtualRouterRef: + name: mysvc-vrouter +` + + vrouter := ` +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualRouter +metadata: + name: mysvc-vrouter + namespace: default +spec: + listeners: + - portMapping: + port: 8080 + protocol: http + routes: + - name: primary + httpRoute: + match: + prefix: / + action: + weightedTargets: + - virtualNodeRef: + name: mysvc-canary-vn + weight: 0 + - virtualNodeRef: + name: mysvc-stable-vn + weight: 100 +` + + uVsvc := unstructuredutil.StrToUnstructuredUnsafe(vsvc) + uVrouter := unstructuredutil.StrToUnstructuredUnsafe(vrouter) + f.objects = append(f.objects, uVsvc, uVrouter) + c, _, _ := f.newController(noResyncPeriodFunc) + roCtx, err := c.newRolloutContext(r) + assert.NoError(t, err) + refRsources, err := roCtx.getRolloutReferencedResources() + assert.NoError(t, err) + assert.Len(t, refRsources.AppMeshResources, 1) + assert.Equal(t, refRsources.AppMeshResources[0].GetKind(), "VirtualRouter") + }) + +} + func TestGetAmbassadorMappings(t *testing.T) { f := newFixture(t) defer f.Close() diff --git a/rollout/trafficrouting.go b/rollout/trafficrouting.go index 7c018d7ec5..a037f3700d 100644 --- a/rollout/trafficrouting.go +++ b/rollout/trafficrouting.go @@ -9,6 +9,7 @@ import ( "github.com/argoproj/argo-rollouts/rollout/trafficrouting" "github.com/argoproj/argo-rollouts/rollout/trafficrouting/alb" "github.com/argoproj/argo-rollouts/rollout/trafficrouting/ambassador" + "github.com/argoproj/argo-rollouts/rollout/trafficrouting/appmesh" "github.com/argoproj/argo-rollouts/rollout/trafficrouting/istio" "github.com/argoproj/argo-rollouts/rollout/trafficrouting/nginx" "github.com/argoproj/argo-rollouts/rollout/trafficrouting/smi" @@ -75,6 +76,13 @@ func (c *Controller) NewTrafficRoutingReconciler(roCtx *rolloutContext) ([]traff ac := ambassador.NewDynamicClient(c.dynamicclientset, rollout.GetNamespace()) trafficReconcilers = append(trafficReconcilers, ambassador.NewReconciler(rollout, ac, c.recorder)) } + if rollout.Spec.Strategy.Canary.TrafficRouting.AppMesh != nil { + trafficReconcilers = append(trafficReconcilers, appmesh.NewReconciler(appmesh.ReconcilerConfig{ + Rollout: rollout, + Client: c.dynamicclientset, + Recorder: c.recorder, + })) + } // ensure that the trafficReconcilers is a healthy list and its not empty if len(trafficReconcilers) > 0 { diff --git a/rollout/trafficrouting/appmesh/appmesh.go b/rollout/trafficrouting/appmesh/appmesh.go new file mode 100644 index 0000000000..19d2100907 --- /dev/null +++ b/rollout/trafficrouting/appmesh/appmesh.go @@ -0,0 +1,388 @@ +package appmesh + +import ( + "context" + "errors" + "fmt" + + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + logutil "github.com/argoproj/argo-rollouts/utils/log" + "github.com/argoproj/argo-rollouts/utils/record" + "github.com/sirupsen/logrus" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/client-go/dynamic" +) + +const ( + Type = "AppMesh" + ErrVirtualServiceNotUsingVirtualRouter = "Virtual-service is not associated with virtual-router" + ErrVirtualServiceMissing = "Virtual-service is missing" + ErrVirtualRouterMissing = "Virtual-router is missing" + ErrVirtualNodeMissing = "Virtual-node is missing" + ErrNotWellFormed = "not well-formed" + defaultCanaryHash = "canary-hash" + defaultStableHash = "stable-hash" +) + +var ( + // Only following route-types are supported when it comes to traffic splitting + supportedRouteTypes = []string{"httpRoute", "tcpRoute", "http2Route", "grpcRoute"} +) + +// ReconcilerConfig describes static configuration data for the AppMesh reconciler +type ReconcilerConfig struct { + Rollout *v1alpha1.Rollout + Client dynamic.Interface + Recorder record.EventRecorder +} + +// Reconciler holds required fields to reconcile AppMesh resources +type Reconciler struct { + rollout *v1alpha1.Rollout + client *ResourceClient + recorder record.EventRecorder + log *logrus.Entry +} + +// NewReconciler returns a trafficrouting reconciler to work with services using App Mesh custom resources such as +// virtual-services, virtual-routers and virtual-nodes to perform traffic-splitting functionality. This reconciler +// only works with appmesh.k8s.aws/v1beta2 custom resources. This reconciler uses dynamic client to avoid hard dependency +// on App Mesh controller. +func NewReconciler(cfg ReconcilerConfig) *Reconciler { + reconciler := Reconciler{ + rollout: cfg.Rollout, + client: NewResourceClient(cfg.Client), + recorder: cfg.Recorder, + log: logutil.WithRollout(cfg.Rollout), + } + return &reconciler +} + +// UpdateHash informs a traffic routing reconciler about new canary/stable pod hashes. UpdateHash initializes +// virtual-nodes with appropriate match-labels in pod-selector. It will mutate the pod-selector in two ways. +// Firstly it will update a label with name v1alpha1.DefaultRolloutUniqueLabelKey if one exists. Secondly it will add a +// new label with name v1alpha1.DefaultRolloutUniqueLabelKey if one does not exist. +func (r *Reconciler) UpdateHash(canaryHash, stableHash string, additionalDestinations ...v1alpha1.WeightDestination) error { + ctx := context.TODO() + + r.log.Debugf("UpdateHash: canaryHash (%s), stableHash (%s)", canaryHash, stableHash) + + if stableHash == "" { + stableHash = defaultStableHash + } + rStableVnodeRef := r.rollout.Spec.Strategy.Canary.TrafficRouting.AppMesh.VirtualNodeGroup.StableVirtualNodeRef + err := r.updateVirtualNodeWithHash(ctx, rStableVnodeRef, stableHash) + if err != nil { + return err + } + + r.log.Debugf("UpdateHash: updated stable virtual-node (%s) pod-selector to (%s)", rStableVnodeRef.Name, stableHash) + + // If both hashes are same then virtual-nodes will end up with exact same podSelector. This is not allowed by the + // admission hook installed by appmesh controller. For now assuming that both hashes correspond to stable virtual-node + // when this happens and resetting canaryHash + if canaryHash == stableHash || canaryHash == "" { + canaryHash = defaultCanaryHash + } + rCanaryVnodeRef := r.rollout.Spec.Strategy.Canary.TrafficRouting.AppMesh.VirtualNodeGroup.CanaryVirtualNodeRef + err = r.updateVirtualNodeWithHash(ctx, rCanaryVnodeRef, canaryHash) + if err != nil { + return err + } + r.log.Debugf("UpdateHash: updated canary virtual-node (%s) pod-selector to (%s)", rCanaryVnodeRef.Name, canaryHash) + + return nil +} + +// SetWeight sets the canary weight to the desired weight. SetWeight relates to a step in rollout process where +// traffic-routing shifts weight to/from stable and canary (traffic-splitting) based on the configuration. In the +// context of App Mesh, traffic-splitting is performed by adding a virtual-router with route(s) for virtual-service. +// This route includes a match condition and an action. Action is defined as weighted-targets where each target is a +// virtual-node. SetWeight adjusts the weights on this route. +func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { + ctx := context.TODO() + + r.log.Debugf("SetWeight: setting desired-weight to %d", desiredWeight) + + rVirtualService := r.rollout.Spec.Strategy.Canary.TrafficRouting.AppMesh.VirtualService + uVsvc, err := r.client.GetVirtualServiceCR(ctx, r.rollout.Namespace, rVirtualService.Name) + if err != nil { + if k8serrors.IsNotFound(err) { + r.recorder.Warnf(r.rollout, record.EventOptions{EventReason: "VirtualServiceNotFound"}, "VirtualService `%s` not found in namespace `%s`", rVirtualService.Name, r.rollout.Namespace) + return errors.New(ErrVirtualServiceMissing) + } + return err + } + + uVr, err := r.client.GetVirtualRouterCRForVirtualService(ctx, uVsvc) + if err != nil { + if k8serrors.IsNotFound(err) { + r.recorder.Warnf(r.rollout, record.EventOptions{EventReason: "VirtualRouterNotFound"}, "VirtualRouter for `%s` not found in namespace `%s`", rVirtualService.Name, r.rollout.Namespace) + return errors.New(ErrVirtualRouterMissing) + } + return err + } + + err = r.reconcileVirtualRouter(ctx, rVirtualService.Routes, uVr, desiredWeight) + if err != nil { + return err + } + + r.log.Debugf("SetWeight: updated virtual router (%s) with desiredWeight (%d)", uVr.GetName(), desiredWeight) + + return nil +} + +type routeReconcileContext struct { + route map[string]interface{} + routeIndex int + routeFldPath *field.Path + rCanaryVnodeRef *v1alpha1.AppMeshVirtualNodeReference + rStableVnodeRef *v1alpha1.AppMeshVirtualNodeReference + routesFilterMap map[string]bool + desiredWeight int32 +} + +func (r *Reconciler) reconcileVirtualRouter(ctx context.Context, rRoutes []string, uVr *unstructured.Unstructured, desiredWeight int32) error { + uVrCopy := uVr.DeepCopy() + + rCanaryVnodeRef := r.rollout.Spec.Strategy.Canary.TrafficRouting.AppMesh.VirtualNodeGroup.CanaryVirtualNodeRef + rStableVnodeRef := r.rollout.Spec.Strategy.Canary.TrafficRouting.AppMesh.VirtualNodeGroup.StableVirtualNodeRef + requiresUpdate := false + + routesFilterMap := make(map[string]bool) + for _, r := range rRoutes { + routesFilterMap[r] = true + } + + routesFldPath := field.NewPath("spec", "routes") + routesI, found, err := unstructured.NestedSlice(uVrCopy.Object, "spec", "routes") + if !found || err != nil { + return field.Invalid(routesFldPath, uVrCopy.GetName(), fmt.Sprintf("No routes found")) + } + + for idx, routeI := range routesI { + routeFldPath := routesFldPath.Index(idx) + route, ok := routeI.(map[string]interface{}) + if !ok { + return field.Invalid(routeFldPath, uVrCopy.GetName(), ErrNotWellFormed) + } + + reconCtx := &routeReconcileContext{ + route: route, + routeIndex: idx, + routeFldPath: routeFldPath, + rCanaryVnodeRef: rCanaryVnodeRef, + rStableVnodeRef: rStableVnodeRef, + routesFilterMap: routesFilterMap, + desiredWeight: desiredWeight, + } + ru, err := r.reconcileRoute(ctx, uVrCopy, reconCtx) + if err != nil { + return err + } + requiresUpdate = requiresUpdate || ru + } + + //update virtual-router with updated routes + err = unstructured.SetNestedSlice(uVrCopy.Object, routesI, "spec", "routes") + if err != nil { + return err + } + if requiresUpdate { + _, err = r.client.UpdateVirtualRouterCR(ctx, uVrCopy) + if err != nil { + return err + } + } + return nil +} + +func (r *Reconciler) reconcileRoute(ctx context.Context, uVr *unstructured.Unstructured, routeCtx *routeReconcileContext) (bool, error) { + routeName, ok := routeCtx.route["name"].(string) + if !ok { + return false, field.Invalid(routeCtx.routeFldPath.Child("name"), uVr.GetName(), ErrNotWellFormed) + } + + if len(routeCtx.routesFilterMap) > 0 { + // filter out the routes that are not specified in route filter + if _, ok := routeCtx.routesFilterMap[routeName]; !ok { + return false, nil + } + } + + routeRule, routeType, err := GetRouteRule(routeCtx.route) + if err != nil && routeRule == nil { + return false, field.Invalid(routeCtx.routeFldPath, uVr.GetName(), ErrNotWellFormed) + } + + weightedTargetsFldPath := routeCtx.routeFldPath.Child(routeType).Child("action").Child("weightedTargets") + weightedTargets, found, err := unstructured.NestedSlice(routeRule, "action", "weightedTargets") + if !found || err != nil { + return false, field.Invalid(weightedTargetsFldPath, uVr.GetName(), ErrNotWellFormed) + } + + requiresUpdate := false + for idx, wtI := range weightedTargets { + wtFldPath := weightedTargetsFldPath.Index(idx) + wt, ok := wtI.(map[string]interface{}) + if !ok { + return false, field.Invalid(wtFldPath, uVr.GetName(), ErrNotWellFormed) + } + wtVnRefFldPath := wtFldPath.Child("virtualNodeRef") + wtVnRef, ok := wt["virtualNodeRef"].(map[string]interface{}) + if !ok { + return false, field.Invalid(wtVnRefFldPath, uVr.GetName(), ErrNotWellFormed) + } + wtVnName, _ := wtVnRef["name"].(string) + wtVnNamespace := defaultIfEmpty(wtVnRef["namespace"], r.rollout.Namespace) + // weight in AppMesh CRD is int64 + //https://aws.github.io/aws-app-mesh-controller-for-k8s/reference/api_spec/#appmesh.k8s.aws/v1beta2.WeightedTarget + weight, err := toInt64(wt["weight"]) + if err != nil { + return false, field.Invalid(wtFldPath.Child("weight"), uVr.GetName(), ErrNotWellFormed) + } + if wtVnName == routeCtx.rStableVnodeRef.Name && wtVnNamespace == r.rollout.Namespace { + if weight != int64(100-routeCtx.desiredWeight) { + requiresUpdate = true + wt["weight"] = int64(100 - routeCtx.desiredWeight) + } + } else if wtVnName == routeCtx.rCanaryVnodeRef.Name && wtVnNamespace == r.rollout.Namespace { + if weight != int64(routeCtx.desiredWeight) { + requiresUpdate = true + wt["weight"] = int64(routeCtx.desiredWeight) + } + } + r.log.Debugf("SetWeight: updating weight of virtualNode (%s.%s) with existing weight of (%d) to (%d)", wtVnName, wtVnNamespace, weight, wt["weight"]) + } + + if requiresUpdate { + //update route with new weighted targets + err = unstructured.SetNestedSlice(routeCtx.route, weightedTargets, routeType, "action", "weightedTargets") + if err != nil { + return false, err + } + } + + return requiresUpdate, nil +} + +func (r *Reconciler) updateVirtualNodeWithHash(ctx context.Context, vnodeRef *v1alpha1.AppMeshVirtualNodeReference, hash string) error { + uVnode, err := r.client.GetVirtualNodeCR(ctx, r.rollout.Namespace, vnodeRef.Name) + if err != nil { + if k8serrors.IsNotFound(err) { + r.recorder.Warnf(r.rollout, record.EventOptions{EventReason: "VirtualNodeNotFound"}, "VirtualNode `%s` not found in namespace `%s`", vnodeRef.Name, r.rollout.Namespace) + return errors.New(ErrVirtualNodeMissing) + } + return err + } + + newVnode := uVnode.DeepCopy() + annotations := newVnode.GetAnnotations() + if annotations == nil { + annotations = make(map[string]string) + } + annotations[v1alpha1.ManagedByRolloutsKey] = r.rollout.Name + ml, err := getPodSelectorMatchLabels(newVnode) + if err != nil { + return err + } + if hash != "" { + ml[v1alpha1.DefaultRolloutUniqueLabelKey] = hash + } else { + delete(ml, v1alpha1.DefaultRolloutUniqueLabelKey) + } + + err = setPodSelectorMatchLabels(newVnode, ml) + if err != nil { + return err + } + + _, err = r.client.UpdateVirtualNodeCR(ctx, newVnode) + if err != nil { + return err + } + + return nil +} + +// VerifyWeight returns true if the canary is at the desired weight and additonalDestinations are at the weights specified +// Returns nil if weight verification is not supported or not applicable +func (r *Reconciler) VerifyWeight(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) (*bool, error) { + return nil, nil +} + +// Type returns the type of the traffic routing reconciler +func (r *Reconciler) Type() string { + return Type +} + +func getPodSelectorMatchLabels(vnode *unstructured.Unstructured) (map[string]interface{}, error) { + m, found, err := unstructured.NestedMap(vnode.Object, "spec", "podSelector", "matchLabels") + if err != nil { + return nil, err + } + if !found || m == nil { + return make(map[string]interface{}), nil + } + return m, nil +} + +func setPodSelectorMatchLabels(vnode *unstructured.Unstructured, ml map[string]interface{}) error { + return unstructured.SetNestedMap(vnode.Object, ml, "spec", "podSelector", "matchLabels") +} + +func toInt64(obj interface{}) (int64, error) { + switch i := obj.(type) { + case float64: + return int64(i), nil + case float32: + return int64(i), nil + case int64: + return i, nil + case int32: + return int64(i), nil + case int16: + return int64(i), nil + case int8: + return int64(i), nil + case uint64: + return int64(i), nil + case uint32: + return int64(i), nil + case uint16: + return int64(i), nil + case uint8: + return int64(i), nil + case int: + return int64(i), nil + case uint: + return int64(i), nil + default: + return 0, fmt.Errorf("toInt64: unknown value %v that is incompatible with int64", obj) + } +} + +func GetRouteRule(route map[string]interface{}) (map[string]interface{}, string, error) { + var routeRule map[string]interface{} + var routeType string + for _, rType := range supportedRouteTypes { + r, found, err := unstructured.NestedMap(route, rType) + if err != nil { + return nil, "", err + } + if found { + routeRule = r + routeType = rType + break + } + } + + if routeRule == nil { + return nil, "", errors.New("Route has unsupported route type") + } + + return routeRule, routeType, nil +} diff --git a/rollout/trafficrouting/appmesh/appmesh_test.go b/rollout/trafficrouting/appmesh/appmesh_test.go new file mode 100644 index 0000000000..ae37aac64d --- /dev/null +++ b/rollout/trafficrouting/appmesh/appmesh_test.go @@ -0,0 +1,828 @@ +package appmesh + +import ( + "errors" + "fmt" + "strings" + "testing" + + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + testutil "github.com/argoproj/argo-rollouts/test/util" + "github.com/argoproj/argo-rollouts/utils/record" + unstructuredutil "github.com/argoproj/argo-rollouts/utils/unstructured" + "github.com/tj/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation/field" + k8stesting "k8s.io/client-go/testing" +) + +const ( + sampleOldCanaryHash = "canary-old" + sampleNewCanaryHash = "canary-new" + sampleOldStableHash = "stable-old" + sampleNewStableHash = "stable-new" +) + +func fakeRollout() *v1alpha1.Rollout { + return &v1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rollout", + Namespace: "myns", + }, + Spec: v1alpha1.RolloutSpec{ + Strategy: v1alpha1.RolloutStrategy{ + Canary: &v1alpha1.CanaryStrategy{ + TrafficRouting: &v1alpha1.RolloutTrafficRouting{ + AppMesh: &v1alpha1.AppMeshTrafficRouting{ + VirtualService: &v1alpha1.AppMeshVirtualService{ + Name: "mysvc", + }, + VirtualNodeGroup: &v1alpha1.AppMeshVirtualNodeGroup{ + CanaryVirtualNodeRef: &v1alpha1.AppMeshVirtualNodeReference{ + Name: "mysvc-canary-vn", + }, + StableVirtualNodeRef: &v1alpha1.AppMeshVirtualNodeReference{ + Name: "mysvc-stable-vn", + }, + }, + }, + }, + }, + }, + }, + } +} + +func TestSetWeightWithMissingVsvc(t *testing.T) { + client := testutil.NewFakeDynamicClient() + ro := fakeRollout() + cfg := ReconcilerConfig{ + Rollout: ro, + Client: client, + Recorder: record.NewFakeEventRecorder(), + } + r := NewReconciler(cfg) + err := r.SetWeight(0) + assert.EqualError(t, err, ErrVirtualServiceMissing) + actions := client.Actions() + assert.Len(t, actions, 1) + assert.True(t, actions[0].Matches("get", "virtualservices")) +} + +func TestSetWeightVsvcWithVnodeProvider(t *testing.T) { + vsvc := unstructuredutil.StrToUnstructuredUnsafe(vsvcWithVnode) + client := testutil.NewFakeDynamicClient(vsvc) + ro := fakeRollout() + cfg := ReconcilerConfig{ + Rollout: ro, + Client: client, + Recorder: record.NewFakeEventRecorder(), + } + r := NewReconciler(cfg) + err := r.SetWeight(0) + assert.EqualError(t, err, ErrVirtualServiceNotUsingVirtualRouter) + actions := client.Actions() + assert.Len(t, actions, 1) + assert.True(t, actions[0].Matches("get", "virtualservices")) +} + +func TestSetWeightForVsvcWithMissingVrouter(t *testing.T) { + vsvc := unstructuredutil.StrToUnstructuredUnsafe(vsvcWithVrouter) + client := testutil.NewFakeDynamicClient(vsvc) + cfg := ReconcilerConfig{ + Rollout: fakeRollout(), + Client: client, + Recorder: record.NewFakeEventRecorder(), + } + r := NewReconciler(cfg) + err := r.SetWeight(50) + assert.EqualError(t, err, ErrVirtualRouterMissing) + actions := client.Actions() + assert.Len(t, actions, 2) + assert.True(t, actions[0].Matches("get", "virtualservices")) + assert.True(t, actions[1].Matches("get", "virtualrouters")) +} + +func TestSetWeightForVsvcWithVrouter(t *testing.T) { + type args struct { + vsvc *unstructured.Unstructured + vrouter *unstructured.Unstructured + routeType string + rollout *v1alpha1.Rollout + } + + fixtures := []struct { + name string + args args + }{ + { + name: "http", + args: args{ + vsvc: unstructuredutil.StrToUnstructuredUnsafe(vsvcWithVrouter), + vrouter: unstructuredutil.StrToUnstructuredUnsafe(vrouterWithHTTPRoutes), + routeType: "httpRoute", + rollout: fakeRollout(), + }, + }, + { + name: "tcp", + args: args{ + vsvc: unstructuredutil.StrToUnstructuredUnsafe(vsvcWithVrouter), + vrouter: unstructuredutil.StrToUnstructuredUnsafe(vrouterWithTCPRoutes), + routeType: "tcpRoute", + rollout: fakeRollout(), + }, + }, + { + name: "http2", + args: args{ + vsvc: unstructuredutil.StrToUnstructuredUnsafe(vsvcWithVrouter), + vrouter: unstructuredutil.StrToUnstructuredUnsafe(vrouterWithHTTP2Routes), + routeType: "http2Route", + rollout: fakeRollout(), + }, + }, + { + name: "grpc", + args: args{ + vsvc: unstructuredutil.StrToUnstructuredUnsafe(vsvcWithVrouter), + vrouter: unstructuredutil.StrToUnstructuredUnsafe(vrouterWithGRPCRoutes), + routeType: "grpcRoute", + rollout: fakeRollout(), + }, + }, + } + + for _, wantUpdate := range []bool{true, false} { + for _, f := range fixtures { + fixture := f + t.Run(fmt.Sprintf("%s-%t", fixture.name, wantUpdate), func(t *testing.T) { + t.Parallel() + client := testutil.NewFakeDynamicClient(fixture.args.vsvc, fixture.args.vrouter) + cfg := ReconcilerConfig{ + Rollout: fixture.args.rollout, + Client: client, + Recorder: record.NewFakeEventRecorder(), + } + r := NewReconciler(cfg) + desiredWeight := 0 + if wantUpdate { + desiredWeight = 55 + } + err := r.SetWeight(int32(desiredWeight)) + assert.Nil(t, err) + actions := client.Actions() + if wantUpdate { + assert.Len(t, actions, 3) + assert.True(t, actions[0].Matches("get", "virtualservices")) + assert.True(t, actions[1].Matches("get", "virtualrouters")) + assert.True(t, actions[2].Matches("update", "virtualrouters")) + assertSetWeightAction(t, actions[2], int64(desiredWeight), fixture.args.routeType) + } else { + assert.Len(t, actions, 2) + assert.True(t, actions[0].Matches("get", "virtualservices")) + assert.True(t, actions[1].Matches("get", "virtualrouters")) + } + }) + } + } +} + +func TestSetWeightWithUpdateVirtualRouterError(t *testing.T) { + vsvc := unstructuredutil.StrToUnstructuredUnsafe(vsvcWithVrouter) + vrouter := unstructuredutil.StrToUnstructuredUnsafe(vrouterWithHTTPRoutes) + client := testutil.NewFakeDynamicClient(vsvc, vrouter) + updateError := errors.New("Failed to update virtual-router") + client.PrependReactor("update", "virtualrouters", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { + return true, ret, updateError + }) + cfg := ReconcilerConfig{ + Rollout: fakeRollout(), + Client: client, + Recorder: record.NewFakeEventRecorder(), + } + r := NewReconciler(cfg) + desiredWeight := 50 + err := r.SetWeight(int32(desiredWeight)) + assert.Equal(t, updateError.Error(), err.Error()) + actions := client.Actions() + assert.Len(t, actions, 3) + assert.True(t, actions[0].Matches("get", "virtualservices")) + assert.True(t, actions[1].Matches("get", "virtualrouters")) + assert.True(t, actions[2].Matches("update", "virtualrouters")) + assertSetWeightAction(t, actions[2], int64(desiredWeight), "httpRoute") +} + +func TestSetWeightWithInvalidRoutes(t *testing.T) { + type args struct { + routes []interface{} + fieldPathWithError string + } + + fixtures := []struct { + name string + args args + }{ + { + name: "missing routes", + args: args{ + routes: nil, + fieldPathWithError: field.NewPath("spec", "routes").String(), + }, + }, + { + name: "route with malformed content", + args: args{ + routes: []interface{}{ + "malformed-content", + }, + fieldPathWithError: field.NewPath("spec", "routes").Index(0).String(), + }, + }, + { + name: "route with no name", + args: args{ + routes: []interface{}{ + map[string]interface{}{ + "httpRoute": map[string]interface{}{}, + }, + }, + fieldPathWithError: field.NewPath("spec", "routes").Index(0).Child("name").String(), + }, + }, + { + name: "route with bad route-type", + args: args{ + routes: []interface{}{ + map[string]interface{}{ + "name": "primary", + "badRoute": map[string]interface{}{}, + }, + }, + fieldPathWithError: field.NewPath("spec", "routes").Index(0).String(), + }, + }, + { + name: "route with no targets", + args: args{ + routes: []interface{}{ + map[string]interface{}{ + "name": "primary", + "httpRoute": map[string]interface{}{}, + }, + }, + fieldPathWithError: field.NewPath("spec", "routes").Index(0).Child("httpRoute").Child("action").Child("weightedTargets").String(), + }, + }, + } + + for _, f := range fixtures { + fixture := f + t.Run(f.name, func(t *testing.T) { + var err error + vsvc := unstructuredutil.StrToUnstructuredUnsafe(vsvcWithVrouter) + vrouter := unstructuredutil.StrToUnstructuredUnsafe(vrouterWithHTTPRoutes) + if fixture.args.routes == nil { + unstructured.RemoveNestedField(vrouter.Object, "spec", "routes") + } else { + err = unstructured.SetNestedSlice(vrouter.Object, fixture.args.routes, "spec", "routes") + } + assert.Nil(t, err) + client := testutil.NewFakeDynamicClient(vsvc, vrouter) + cfg := ReconcilerConfig{ + Rollout: fakeRollout(), + Client: client, + Recorder: record.NewFakeEventRecorder(), + } + r := NewReconciler(cfg) + desiredWeight := 55 + err = r.SetWeight(int32(desiredWeight)) + assert.NotNil(t, err) + assert.Equal(t, (err.(*field.Error)).Field, fixture.args.fieldPathWithError) + actions := client.Actions() + assert.Len(t, actions, 2) + assert.True(t, actions[0].Matches("get", "virtualservices")) + assert.True(t, actions[1].Matches("get", "virtualrouters")) + }) + } +} + +func TestSetWeightForRolloutWithRouteFilter(t *testing.T) { + type args struct { + vsvc *unstructured.Unstructured + vrouter *unstructured.Unstructured + routeType string + rollout *v1alpha1.Rollout + routeFilters []string + wantUpdate bool + } + + fixtures := []struct { + name string + args args + }{ + { + name: "with matched route-filter", + args: args{ + vsvc: unstructuredutil.StrToUnstructuredUnsafe(vsvcWithVrouter), + vrouter: unstructuredutil.StrToUnstructuredUnsafe(vrouterWithHTTPRoutes), + routeType: "httpRoute", + rollout: fakeRollout(), + routeFilters: []string{"primary"}, + wantUpdate: true, + }, + }, + { + name: "with mismatched route-filter", + args: args{ + vsvc: unstructuredutil.StrToUnstructuredUnsafe(vsvcWithVrouter), + vrouter: unstructuredutil.StrToUnstructuredUnsafe(vrouterWithHTTPRoutes), + routeType: "httpRoute", + rollout: fakeRollout(), + routeFilters: []string{"unknown"}, + wantUpdate: false, + }, + }, + { + name: "with multiple route-filter", + args: args{ + vsvc: unstructuredutil.StrToUnstructuredUnsafe(vsvcWithVrouter), + vrouter: unstructuredutil.StrToUnstructuredUnsafe(vrouterWithHTTPRoutes), + routeType: "httpRoute", + rollout: fakeRollout(), + routeFilters: []string{"unknown", "primary"}, + wantUpdate: true, + }, + }, + } + + for _, f := range fixtures { + fixture := f + t.Run(fixture.name, func(t *testing.T) { + t.Parallel() + client := testutil.NewFakeDynamicClient(fixture.args.vsvc, fixture.args.vrouter) + ro := fixture.args.rollout + ro.Spec.Strategy.Canary.TrafficRouting.AppMesh.VirtualService.Routes = fixture.args.routeFilters + cfg := ReconcilerConfig{ + Rollout: fixture.args.rollout, + Client: client, + Recorder: record.NewFakeEventRecorder(), + } + r := NewReconciler(cfg) + desiredWeight := 55 + err := r.SetWeight(int32(desiredWeight)) + assert.Nil(t, err) + actions := client.Actions() + if fixture.args.wantUpdate { + assert.Len(t, actions, 3) + assert.True(t, actions[0].Matches("get", "virtualservices")) + assert.True(t, actions[1].Matches("get", "virtualrouters")) + assert.True(t, actions[2].Matches("update", "virtualrouters")) + assertSetWeightAction(t, actions[2], int64(desiredWeight), fixture.args.routeType) + } else { + assert.Len(t, actions, 2) + assert.True(t, actions[0].Matches("get", "virtualservices")) + assert.True(t, actions[1].Matches("get", "virtualrouters")) + } + }) + } +} + +func TestUpdateHash(t *testing.T) { + type args struct { + newCanaryHash string + newStableHash string + existingCanaryHash string + existingStableHash string + expectedCanaryHash string + expectedStableHash string + rollout *v1alpha1.Rollout + } + + fixtures := []struct { + name string + args args + }{ + { + name: "with no existing hashes", + args: args{ + newCanaryHash: sampleNewCanaryHash, + expectedCanaryHash: sampleNewCanaryHash, + newStableHash: sampleNewStableHash, + expectedStableHash: sampleNewStableHash, + rollout: fakeRollout(), + }, + }, + { + name: "with different existing hashes", + args: args{ + newCanaryHash: sampleNewCanaryHash, + existingCanaryHash: sampleOldCanaryHash, + expectedCanaryHash: sampleNewCanaryHash, + newStableHash: sampleNewStableHash, + existingStableHash: sampleOldStableHash, + expectedStableHash: sampleNewStableHash, + rollout: fakeRollout(), + }, + }, + { + name: "with existing hashes cleared", + args: args{ + newCanaryHash: "", + existingCanaryHash: sampleOldCanaryHash, + expectedCanaryHash: defaultCanaryHash, + newStableHash: "", + existingStableHash: sampleOldStableHash, + expectedStableHash: defaultStableHash, + rollout: fakeRollout(), + }, + }, + { + name: "with canaryHash == stableHash", + args: args{ + newCanaryHash: "12345", + existingCanaryHash: sampleOldCanaryHash, + expectedCanaryHash: defaultCanaryHash, + existingStableHash: sampleOldStableHash, + newStableHash: "12345", + expectedStableHash: "12345", + rollout: fakeRollout(), + }, + }, + } + + for _, f := range fixtures { + fixture := f + t.Run(fixture.name, func(t *testing.T) { + t.Parallel() + canaryVnode := createVnodeWithHash(baselineCanaryVnode, fixture.args.existingCanaryHash) + stableVnode := createVnodeWithHash(baselineStableVnode, fixture.args.existingStableHash) + client := testutil.NewFakeDynamicClient(canaryVnode, stableVnode) + cfg := ReconcilerConfig{ + Rollout: fixture.args.rollout, + Client: client, + Recorder: record.NewFakeEventRecorder(), + } + r := NewReconciler(cfg) + + err := r.UpdateHash(fixture.args.newCanaryHash, fixture.args.newStableHash) + assert.Nil(t, err) + actions := client.Actions() + assert.Len(t, actions, 4) + assert.True(t, actions[0].Matches("get", "virtualnodes")) + assert.True(t, actions[1].Matches("update", "virtualnodes")) + assertUpdateHashAction(t, actions[1], fixture.args.expectedStableHash) + assert.True(t, actions[2].Matches("get", "virtualnodes")) + assert.True(t, actions[3].Matches("update", "virtualnodes")) + assertUpdateHashAction(t, actions[3], fixture.args.expectedCanaryHash) + }) + } +} + +func TestUpdateHashWhenGetStableVirtualNodeFails(t *testing.T) { + canaryHash := sampleNewCanaryHash + stableHash := sampleNewStableHash + + canaryVnode := unstructuredutil.StrToUnstructuredUnsafe(baselineCanaryVnode) + client := testutil.NewFakeDynamicClient(canaryVnode) + cfg := ReconcilerConfig{ + Rollout: fakeRollout(), + Client: client, + Recorder: record.NewFakeEventRecorder(), + } + r := NewReconciler(cfg) + + err := r.UpdateHash(canaryHash, stableHash) + assert.Equal(t, ErrVirtualNodeMissing, err.Error()) + actions := client.Actions() + assert.Len(t, actions, 1) + assert.True(t, actions[0].Matches("get", "virtualnodes")) +} + +func TestUpdateHashWhenGetCanaryVirtualNodeFails(t *testing.T) { + canaryHash := sampleNewCanaryHash + stableHash := sampleNewStableHash + + stableVnode := unstructuredutil.StrToUnstructuredUnsafe(baselineStableVnode) + client := testutil.NewFakeDynamicClient(stableVnode) + cfg := ReconcilerConfig{ + Rollout: fakeRollout(), + Client: client, + Recorder: record.NewFakeEventRecorder(), + } + r := NewReconciler(cfg) + + err := r.UpdateHash(canaryHash, stableHash) + assert.Equal(t, ErrVirtualNodeMissing, err.Error()) + actions := client.Actions() + assert.Len(t, actions, 3) + assert.True(t, actions[0].Matches("get", "virtualnodes")) + assert.True(t, actions[1].Matches("update", "virtualnodes")) + assertUpdateHashAction(t, actions[1], stableHash) + assert.True(t, actions[2].Matches("get", "virtualnodes")) +} + +func TestUpdateHashWhenUpdateStableVirtualNodeFails(t *testing.T) { + canaryHash := sampleNewCanaryHash + stableHash := sampleNewStableHash + + canaryVnode := unstructuredutil.StrToUnstructuredUnsafe(baselineCanaryVnode) + stableVnode := unstructuredutil.StrToUnstructuredUnsafe(baselineStableVnode) + client := testutil.NewFakeDynamicClient(canaryVnode, stableVnode) + updateError := errors.New("Failed to update virtual-node") + client.PrependReactor("update", "virtualnodes", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { + updateAction := action.(k8stesting.UpdateAction) + uVnode, _ := runtime.DefaultUnstructuredConverter.ToUnstructured(updateAction.GetObject()) + matchLabels, _, _ := unstructured.NestedMap(uVnode, "spec", "podSelector", "matchLabels") + if matchLabels[v1alpha1.DefaultRolloutUniqueLabelKey].(string) == stableHash { + return true, nil, updateError + } + return false, ret, nil + }) + cfg := ReconcilerConfig{ + Rollout: fakeRollout(), + Client: client, + Recorder: record.NewFakeEventRecorder(), + } + r := NewReconciler(cfg) + + err := r.UpdateHash(canaryHash, stableHash) + assert.Equal(t, updateError.Error(), err.Error()) + actions := client.Actions() + assert.Len(t, actions, 2) + assert.True(t, actions[0].Matches("get", "virtualnodes")) + assert.True(t, actions[1].Matches("update", "virtualnodes")) + assertUpdateHashAction(t, actions[1], stableHash) +} + +func TestUpdateHashWhenUpdateCanaryVirtualNodeFails(t *testing.T) { + canaryHash := sampleNewCanaryHash + stableHash := sampleNewStableHash + + canaryVnode := unstructuredutil.StrToUnstructuredUnsafe(baselineCanaryVnode) + stableVnode := unstructuredutil.StrToUnstructuredUnsafe(baselineStableVnode) + client := testutil.NewFakeDynamicClient(canaryVnode, stableVnode) + updateError := errors.New("Failed to update virtual-node") + client.PrependReactor("update", "virtualnodes", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { + updateAction := action.(k8stesting.UpdateAction) + uVnode, _ := runtime.DefaultUnstructuredConverter.ToUnstructured(updateAction.GetObject()) + matchLabels, _, _ := unstructured.NestedMap(uVnode, "spec", "podSelector", "matchLabels") + if matchLabels[v1alpha1.DefaultRolloutUniqueLabelKey].(string) == canaryHash { + return true, nil, updateError + } + return false, ret, nil + }) + cfg := ReconcilerConfig{ + Rollout: fakeRollout(), + Client: client, + Recorder: record.NewFakeEventRecorder(), + } + r := NewReconciler(cfg) + + err := r.UpdateHash(canaryHash, stableHash) + assert.Equal(t, updateError.Error(), err.Error()) + actions := client.Actions() + assert.Len(t, actions, 4) + assert.True(t, actions[0].Matches("get", "virtualnodes")) + assert.True(t, actions[1].Matches("update", "virtualnodes")) + assertUpdateHashAction(t, actions[1], stableHash) + assert.True(t, actions[2].Matches("get", "virtualnodes")) + assert.True(t, actions[3].Matches("update", "virtualnodes")) + assertUpdateHashAction(t, actions[3], canaryHash) + +} + +func TestUpdateHashWithVirtualNodeMissingMatchLabels(t *testing.T) { + canaryVnode := unstructuredutil.StrToUnstructuredUnsafe(baselineCanaryVnode) + unstructured.SetNestedMap(canaryVnode.Object, make(map[string]interface{}), "spec", "podSelector") + stableVnode := unstructuredutil.StrToUnstructuredUnsafe(baselineStableVnode) + unstructured.SetNestedMap(stableVnode.Object, make(map[string]interface{}), "spec", "podSelector") + client := testutil.NewFakeDynamicClient(canaryVnode, stableVnode) + cfg := ReconcilerConfig{ + Rollout: fakeRollout(), + Client: client, + Recorder: record.NewFakeEventRecorder(), + } + r := NewReconciler(cfg) + + canaryHash := sampleNewCanaryHash + stableHash := sampleNewStableHash + err := r.UpdateHash(canaryHash, stableHash) + assert.Nil(t, err) + actions := client.Actions() + assert.Len(t, actions, 4) + assert.True(t, actions[0].Matches("get", "virtualnodes")) + assert.True(t, actions[1].Matches("update", "virtualnodes")) + assertUpdateHashAction(t, actions[1], stableHash) + assert.True(t, actions[2].Matches("get", "virtualnodes")) + assert.True(t, actions[3].Matches("update", "virtualnodes")) + assertUpdateHashAction(t, actions[3], canaryHash) +} + +func createVnodeWithHash(vnodeStr string, hash string) *unstructured.Unstructured { + vnode := unstructuredutil.StrToUnstructuredUnsafe(vnodeStr) + ml, _ := getPodSelectorMatchLabels(vnode) + ml[v1alpha1.DefaultRolloutUniqueLabelKey] = hash + setPodSelectorMatchLabels(vnode, ml) + return vnode +} + +func assertUpdateHashAction(t *testing.T, action k8stesting.Action, hash string) { + updateAction := action.(k8stesting.UpdateAction) + uVnode, err := runtime.DefaultUnstructuredConverter.ToUnstructured(updateAction.GetObject()) + assert.Nil(t, err) + matchLabels, found, err := unstructured.NestedMap(uVnode, "spec", "podSelector", "matchLabels") + assert.True(t, found, "Virtual-node's podSelector is missing matchLabels") + assert.Nil(t, err) + assert.Equal(t, matchLabels[v1alpha1.DefaultRolloutUniqueLabelKey].(string), hash) +} + +func assertSetWeightAction(t *testing.T, action k8stesting.Action, desiredWeight int64, routeType string) { + updateAction := action.(k8stesting.UpdateAction) + uVr, err := runtime.DefaultUnstructuredConverter.ToUnstructured(updateAction.GetObject()) + assert.Nil(t, err) + routesI, _, err := unstructured.NestedSlice(uVr, "spec", "routes") + assert.Nil(t, err) + for _, routeI := range routesI { + route, _ := routeI.(map[string]interface{}) + weightedTargetsI, found, err := unstructured.NestedSlice(route, routeType, "action", "weightedTargets") + assert.Nil(t, err) + assert.True(t, found, "Did not find weightedTargets in route") + assert.Len(t, weightedTargetsI, 2) + for _, wtI := range weightedTargetsI { + wt, _ := wtI.(map[string]interface{}) + vnodeName, _, err := unstructured.NestedString(wt, "virtualNodeRef", "name") + assert.Nil(t, err) + weight, err := toInt64(wt["weight"]) + assert.Nil(t, err) + if strings.Contains(vnodeName, "canary") { + assert.Equal(t, weight, desiredWeight) + } else { + assert.Equal(t, weight, 100-desiredWeight) + } + } + } +} + +const vsvcWithVnode = ` +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualService +metadata: + name: mysvc + namespace: myns +spec: + awsName: mysvc.myns.svc.cluster.local + provider: + virtualNode: + virtualNodeRef: + name: mysvc-vnode` + +const vsvcWithVrouter = ` +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualService +metadata: + namespace: myns + name: mysvc +spec: + awsName: mysvc.myns.svc.cluster.local + provider: + virtualRouter: + virtualRouterRef: + name: mysvc-vrouter` + +const vrouterWithHTTPRoutes = ` +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualRouter +metadata: + namespace: myns + name: mysvc-vrouter +spec: + listeners: + - portMapping: + port: 8080 + protocol: http + routes: + - name: primary + httpRoute: + match: + prefix: / + action: + weightedTargets: + - virtualNodeRef: + name: mysvc-canary-vn + weight: 0 + - virtualNodeRef: + name: mysvc-stable-vn + weight: 100` + +const vrouterWithGRPCRoutes = ` +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualRouter +metadata: + namespace: myns + name: mysvc-vrouter +spec: + listeners: + - portMapping: + port: 8080 + protocol: http + routes: + - name: primary + grpcRoute: + match: + methodName: GetItem + serviceName: MySvc + action: + weightedTargets: + - virtualNodeRef: + name: mysvc-canary-vn + weight: 0 + - virtualNodeRef: + name: mysvc-stable-vn + weight: 100` + +const vrouterWithHTTP2Routes = ` +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualRouter +metadata: + namespace: myns + name: mysvc-vrouter +spec: + listeners: + - portMapping: + port: 8080 + protocol: http + routes: + - name: primary + http2Route: + match: + prefix: / + action: + weightedTargets: + - virtualNodeRef: + name: mysvc-canary-vn + weight: 0 + - virtualNodeRef: + name: mysvc-stable-vn + weight: 100` + +const vrouterWithTCPRoutes = ` +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualRouter +metadata: + namespace: myns + name: mysvc-vrouter +spec: + listeners: + - portMapping: + port: 8080 + protocol: http + routes: + - name: primary + tcpRoute: + action: + weightedTargets: + - virtualNodeRef: + name: mysvc-canary-vn + weight: 0 + - virtualNodeRef: + name: mysvc-stable-vn + weight: 100` + +const baselineCanaryVnode = ` +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualNode +metadata: + namespace: myns + name: mysvc-canary-vn +spec: + podSelector: + matchLabels: + app: mysvc-pod + listeners: + - portMapping: + port: 8080 + protocol: http + serviceDiscovery: + dns: + hostname: mysvc.myns.svc.cluster.local` + +const baselineStableVnode = ` +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualNode +metadata: + namespace: myns + name: mysvc-stable-vn +spec: + podSelector: + matchLabels: + app: mysvc-pod + listeners: + - portMapping: + port: 8080 + protocol: http + serviceDiscovery: + dns: + hostname: mysvc.myns.svc.cluster.local` diff --git a/rollout/trafficrouting/appmesh/resource_client.go b/rollout/trafficrouting/appmesh/resource_client.go new file mode 100644 index 0000000000..4171b9a385 --- /dev/null +++ b/rollout/trafficrouting/appmesh/resource_client.go @@ -0,0 +1,74 @@ +package appmesh + +import ( + "context" + "errors" + + appmeshutil "github.com/argoproj/argo-rollouts/utils/appmesh" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/client-go/dynamic" +) + +type ResourceClient struct { + client dynamic.Interface +} + +func NewResourceClient(client dynamic.Interface) *ResourceClient { + return &ResourceClient{ + client: client, + } +} + +func (rc *ResourceClient) GetVirtualServiceCR(ctx context.Context, namespace string, name string) (*unstructured.Unstructured, error) { + return rc.client.Resource(appmeshutil.GetAppMeshVirtualServiceGVR()). + Namespace(namespace). + Get(ctx, name, metav1.GetOptions{}) +} + +func (rc *ResourceClient) GetVirtualRouterCR(ctx context.Context, namespace string, name string) (*unstructured.Unstructured, error) { + return rc.client.Resource(appmeshutil.GetAppMeshVirtualRouterGVR()). + Namespace(namespace). + Get(ctx, name, metav1.GetOptions{}) +} + +func (rc *ResourceClient) GetVirtualNodeCR(ctx context.Context, namespace string, name string) (*unstructured.Unstructured, error) { + return rc.client.Resource(appmeshutil.GetAppMeshVirtualNodeGVR()). + Namespace(namespace). + Get(ctx, name, metav1.GetOptions{}) +} + +func (rc *ResourceClient) UpdateVirtualRouterCR(ctx context.Context, obj *unstructured.Unstructured) (*unstructured.Unstructured, error) { + client := rc.client.Resource(appmeshutil.GetAppMeshVirtualRouterGVR()).Namespace(obj.GetNamespace()) + return client.Update(ctx, obj, metav1.UpdateOptions{}) +} + +func (rc *ResourceClient) UpdateVirtualNodeCR(ctx context.Context, obj *unstructured.Unstructured) (*unstructured.Unstructured, error) { + client := rc.client.Resource(appmeshutil.GetAppMeshVirtualNodeGVR()).Namespace(obj.GetNamespace()) + return client.Update(ctx, obj, metav1.UpdateOptions{}) +} + +func (rc *ResourceClient) GetVirtualRouterCRForVirtualService(ctx context.Context, uVsvc *unstructured.Unstructured) (*unstructured.Unstructured, error) { + virtualRouterRefMap, found, err := unstructured.NestedMap(uVsvc.Object, "spec", "provider", "virtualRouter", "virtualRouterRef") + if !found { + return nil, errors.New(ErrVirtualServiceNotUsingVirtualRouter) + } + if err != nil { + return nil, err + } + namespace := defaultIfEmpty(virtualRouterRefMap["namespace"], uVsvc.GetNamespace()) + name := virtualRouterRefMap["name"].(string) + return rc.GetVirtualRouterCR(ctx, namespace, name) +} + +func defaultIfEmpty(strI interface{}, defaultStr string) string { + if strI == nil { + return defaultStr + } else { + str, _ := strI.(string) + if str == "" { + return defaultStr + } + return str + } +} diff --git a/rollout/trafficrouting_test.go b/rollout/trafficrouting_test.go index 5cfb1b1341..bff4858866 100644 --- a/rollout/trafficrouting_test.go +++ b/rollout/trafficrouting_test.go @@ -17,6 +17,7 @@ import ( "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/rollout/mocks" "github.com/argoproj/argo-rollouts/rollout/trafficrouting/alb" + "github.com/argoproj/argo-rollouts/rollout/trafficrouting/appmesh" "github.com/argoproj/argo-rollouts/rollout/trafficrouting/istio" "github.com/argoproj/argo-rollouts/rollout/trafficrouting/nginx" "github.com/argoproj/argo-rollouts/rollout/trafficrouting/smi" @@ -605,6 +606,23 @@ func TestNewTrafficRoutingReconciler(t *testing.T) { assert.Equal(t, smi.Type, networkReconciler.Type()) } } + { + tsController := Controller{} + r := newCanaryRollout("foo", 10, nil, steps, pointer.Int32Ptr(1), intstr.FromInt(1), intstr.FromInt(0)) + r.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{ + AppMesh: &v1alpha1.AppMeshTrafficRouting{}, + } + roCtx := &rolloutContext{ + rollout: r, + log: logutil.WithRollout(r), + } + networkReconcilerList, err := tsController.NewTrafficRoutingReconciler(roCtx) + for _, networkReconciler := range networkReconcilerList { + assert.Nil(t, err) + assert.NotNil(t, networkReconciler) + assert.Equal(t, appmesh.Type, networkReconciler.Type()) + } + } { // (2) Multiple Reconcilers (Nginx + SMI) tsController := Controller{} diff --git a/test/e2e/appmesh/appmesh-canary-rollout.yaml b/test/e2e/appmesh/appmesh-canary-rollout.yaml new file mode 100644 index 0000000000..f3bc3a0de1 --- /dev/null +++ b/test/e2e/appmesh/appmesh-canary-rollout.yaml @@ -0,0 +1,163 @@ +apiVersion: appmesh.k8s.aws/v1beta2 +kind: Mesh +metadata: + name: appmesh-canary-rollout +spec: + namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: default + +--- +# This service is used by virtual-service to resolve initial dns requests done by app container +apiVersion: v1 +kind: Service +metadata: + name: my-svc +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: my-app + +--- +apiVersion: v1 +kind: Service +metadata: + name: my-svc-canary +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + # This selector will be updated with the pod-template-hash of the canary ReplicaSet. + app: my-app + +--- +apiVersion: v1 +kind: Service +metadata: + name: my-svc-stable +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + # This selector will be updated with the pod-template-hash of the stable ReplicaSet. + app: my-app + +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualService +metadata: + name: my-svc +spec: + provider: + virtualRouter: + virtualRouterRef: + name: my-vrouter + +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualRouter +metadata: + name: my-vrouter +spec: + listeners: + - portMapping: + port: 80 + protocol: http + routes: + - name: primary + httpRoute: + match: + prefix: / + action: + weightedTargets: + - virtualNodeRef: + name: my-vn-canary + weight: 0 + - virtualNodeRef: + name: my-vn-stable + weight: 100 + +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualNode +metadata: + name: my-vn-canary +spec: + podSelector: + matchLabels: + app: my-app + rollouts-pod-template-hash: canary-tbd + listeners: + - portMapping: + port: 80 + protocol: http + serviceDiscovery: + dns: + hostname: my-svc-canary.appmesh-canary-rollout.svc.cluster.local + +--- +apiVersion: appmesh.k8s.aws/v1beta2 +kind: VirtualNode +metadata: + name: my-vn-stable +spec: + podSelector: + matchLabels: + app: my-app + rollouts-pod-template-hash: stable-tbd + listeners: + - portMapping: + port: 80 + protocol: http + serviceDiscovery: + dns: + hostname: my-svc-stable.appmesh-canary-rollout.svc.cluster.local + +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: my-rollout +spec: + replicas: 2 + selector: + matchLabels: + app: my-app + template: + metadata: + labels: + app: my-app + spec: + containers: + - name: demo + image: argoproj/rollouts-demo:blue + imagePullPolicy: Always + ports: + - name: http + containerPort: 8080 + strategy: + canary: + canaryService: my-svc-canary + stableService: my-svc-stable + trafficRouting: + appMesh: + virtualService: + name: my-svc + virtualNodeGroup: + canaryVirtualNodeRef: + name: my-vn-canary + stableVirtualNodeRef: + name: my-vn-stable + steps: + - setWeight: 50 + - pause: {} diff --git a/test/e2e/appmesh_test.go b/test/e2e/appmesh_test.go new file mode 100644 index 0000000000..c2ab47f290 --- /dev/null +++ b/test/e2e/appmesh_test.go @@ -0,0 +1,97 @@ +// +build e2e + +package e2e + +import ( + "fmt" + "strings" + "testing" + "time" + + "github.com/argoproj/argo-rollouts/test/fixtures" + "github.com/stretchr/testify/suite" + "github.com/tj/assert" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" +) + +type AppMeshSuite struct { + fixtures.E2ESuite +} + +func TestAppMeshSuite(t *testing.T) { + suite.Run(t, new(AppMeshSuite)) +} + +func (s *AppMeshSuite) SetupSuite() { + s.E2ESuite.SetupSuite() + if !s.AppMeshEnabled { + s.T().SkipNow() + } +} + +func (s *AppMeshSuite) TestAppMeshCanaryRollout() { + s.Given(). + RolloutObjects(`@appmesh/appmesh-canary-rollout.yaml`). + When(). + ApplyManifests(). + WaitForRolloutStatus("Healthy"). + Sleep(1 * time.Second). + Then(). + //Before rollout canary should be 0 weight + Assert(func(t *fixtures.Then) { + uVr := t.GetAppMeshVirtualRouter() + canaryWeight := int64(0) + s.assertWeightedTargets(uVr, canaryWeight) + }). + When(). + UpdateSpec(). + WaitForRolloutStatus("Paused"). + Sleep(1 * time.Second). + Then(). + //During deployment canary should increment to stepWeight + Assert(func(t *fixtures.Then) { + uVr := t.GetAppMeshVirtualRouter() + canaryWeight := int64(*(t.Rollout().Spec.Strategy.Canary.Steps[0].SetWeight)) + s.assertWeightedTargets(uVr, canaryWeight) + }). + When(). + PromoteRollout(). + WaitForRolloutStatus("Healthy") +} + +func (s *AppMeshSuite) assertWeightedTargets(uVr *unstructured.Unstructured, canaryWeight int64) { + wtMap := s.getWeightedTargets(uVr) + for routeName, wt := range wtMap { + assert.Equal(s.T(), canaryWeight, wt.canaryWeight, fmt.Sprintf("Route %s has wrong weight for canary", routeName)) + assert.Equal(s.T(), 100-canaryWeight, wt.stableWeight, fmt.Sprintf("Route %s has wrong weight for stable", routeName)) + } +} + +func (s *AppMeshSuite) getWeightedTargets(uVr *unstructured.Unstructured) map[string]weightedTargets { + result := make(map[string]weightedTargets) + routesI, _, _ := unstructured.NestedSlice(uVr.Object, "spec", "routes") + for _, rI := range routesI { + route, _ := rI.(map[string]interface{}) + routeName, _ := route["name"].(string) + wtsI, _, _ := unstructured.NestedSlice(route, "httpRoute", "action", "weightedTargets") + wtStruct := weightedTargets{} + for _, wtI := range wtsI { + wt, _ := wtI.(map[string]interface{}) + vnodeName, _, _ := unstructured.NestedString(wt, "virtualNodeRef", "name") + weight, _, _ := unstructured.NestedInt64(wt, "weight") + fmt.Printf("Found wt %+v with vnodeName (%s), weight (%d)", wt, vnodeName, weight) + if strings.Contains(vnodeName, "canary") { + wtStruct.canaryWeight = weight + } else { + wtStruct.stableWeight = weight + } + } + result[routeName] = wtStruct + } + return result +} + +type weightedTargets struct { + canaryWeight int64 + stableWeight int64 +} diff --git a/test/fixtures/common.go b/test/fixtures/common.go index 9d73f21447..370c80724e 100644 --- a/test/fixtures/common.go +++ b/test/fixtures/common.go @@ -37,6 +37,7 @@ import ( "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/cmd/get" "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/options" "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/viewcontroller" + "github.com/argoproj/argo-rollouts/rollout/trafficrouting/appmesh" "github.com/argoproj/argo-rollouts/rollout/trafficrouting/istio" "github.com/argoproj/argo-rollouts/utils/annotations" istioutil "github.com/argoproj/argo-rollouts/utils/istio" @@ -571,6 +572,19 @@ func (c *Common) GetVirtualService() *istio.VirtualService { return &vsvc } +func (c *Common) GetAppMeshVirtualRouter() *unstructured.Unstructured { + ro := c.Rollout() + ctx := context.TODO() + resClient := appmesh.NewResourceClient(c.dynamicClient) + name := ro.Spec.Strategy.Canary.TrafficRouting.AppMesh.VirtualService.Name + c.log.Infof("GetVirtualServiceCR with namespace(%s), name(%s)", c.namespace, name) + uVsvc, err := resClient.GetVirtualServiceCR(ctx, c.namespace, name) + c.CheckError(err) + uVr, err := resClient.GetVirtualRouterCRForVirtualService(ctx, uVsvc) + c.CheckError(err) + return uVr +} + func (c *Common) GetDestinationRule() *istio.DestinationRule { ro := c.Rollout() name := ro.Spec.Strategy.Canary.TrafficRouting.Istio.DestinationRule.Name diff --git a/test/fixtures/e2e_suite.go b/test/fixtures/e2e_suite.go index ac4df4c66d..0b4267c9db 100644 --- a/test/fixtures/e2e_suite.go +++ b/test/fixtures/e2e_suite.go @@ -26,6 +26,7 @@ import ( rov1 "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" clientset "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned" + appmeshutil "github.com/argoproj/argo-rollouts/utils/appmesh" "github.com/argoproj/argo-rollouts/utils/defaults" istioutil "github.com/argoproj/argo-rollouts/utils/istio" logutil "github.com/argoproj/argo-rollouts/utils/log" @@ -119,8 +120,9 @@ type E2ESuite struct { suite.Suite Common - IstioEnabled bool - SMIEnabled bool + IstioEnabled bool + SMIEnabled bool + AppMeshEnabled bool } func (s *E2ESuite) SetupSuite() { @@ -159,6 +161,10 @@ func (s *E2ESuite) SetupSuite() { if smiutil.DoesSMIExist(s.smiClient, s.namespace) { s.SMIEnabled = true } + + if appmeshutil.DoesAppMeshExist(s.dynamicClient, s.namespace) { + s.AppMeshEnabled = true + } } func (s *E2ESuite) TearDownSuite() { diff --git a/utils/appmesh/appmesh.go b/utils/appmesh/appmesh.go new file mode 100644 index 0000000000..83e77572ff --- /dev/null +++ b/utils/appmesh/appmesh.go @@ -0,0 +1,44 @@ +package appmesh + +import ( + "context" + + "github.com/argoproj/argo-rollouts/utils/defaults" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/dynamic" +) + +const AppMeshCRDGroup = "appmesh.k8s.aws" + +func DoesAppMeshExist(dynamicClient dynamic.Interface, namespace string) bool { + _, err := dynamicClient.Resource(GetAppMeshVirtualServiceGVR()).Namespace(namespace).List(context.TODO(), metav1.ListOptions{Limit: 1}) + if err != nil { + return false + } + return true +} + +func GetAppMeshVirtualServiceGVR() schema.GroupVersionResource { + return schema.GroupVersionResource{ + Group: AppMeshCRDGroup, + Version: defaults.GetAppMeshCRDVersion(), + Resource: "virtualservices", + } +} + +func GetAppMeshVirtualRouterGVR() schema.GroupVersionResource { + return schema.GroupVersionResource{ + Group: AppMeshCRDGroup, + Version: defaults.GetAppMeshCRDVersion(), + Resource: "virtualrouters", + } +} + +func GetAppMeshVirtualNodeGVR() schema.GroupVersionResource { + return schema.GroupVersionResource{ + Group: AppMeshCRDGroup, + Version: defaults.GetAppMeshCRDVersion(), + Resource: "virtualnodes", + } +} diff --git a/utils/defaults/defaults.go b/utils/defaults/defaults.go index 46497816f3..8a9a000675 100644 --- a/utils/defaults/defaults.go +++ b/utils/defaults/defaults.go @@ -48,6 +48,7 @@ const ( DefaultIstioVersion = "v1alpha3" DefaultSMITrafficSplitVersion = "v1alpha1" DefaultTargetGroupBindingAPIVersion = "elbv2.k8s.aws/v1beta1" + DefaultAppMeshCRDVersion = "v1beta2" ) var ( @@ -56,6 +57,7 @@ var ( ambassadorAPIVersion = DefaultAmbassadorVersion smiAPIVersion = DefaultSMITrafficSplitVersion targetGroupBindingAPIVersion = DefaultTargetGroupBindingAPIVersion + appmeshCRDVersion = DefaultAppMeshCRDVersion ) const ( @@ -263,6 +265,14 @@ func GetAmbassadorAPIVersion() string { return ambassadorAPIVersion } +func SetAppMeshCRDVersion(apiVersion string) { + appmeshCRDVersion = apiVersion +} + +func GetAppMeshCRDVersion() string { + return appmeshCRDVersion +} + func SetSMIAPIVersion(apiVersion string) { smiAPIVersion = apiVersion } diff --git a/utils/defaults/defaults_test.go b/utils/defaults/defaults_test.go index d3df2554bc..f5a429f202 100644 --- a/utils/defaults/defaults_test.go +++ b/utils/defaults/defaults_test.go @@ -397,4 +397,9 @@ func TestSetDefaults(t *testing.T) { assert.Equal(t, "v1alpha9", GetTargetGroupBindingAPIVersion()) SetTargetGroupBindingAPIVersion(DefaultTargetGroupBindingAPIVersion) assert.Equal(t, DefaultTargetGroupBindingAPIVersion, GetTargetGroupBindingAPIVersion()) + + assert.Equal(t, DefaultAppMeshCRDVersion, GetAppMeshCRDVersion()) + SetAppMeshCRDVersion("v1beta3") + assert.Equal(t, "v1beta3", GetAppMeshCRDVersion()) + SetAppMeshCRDVersion(DefaultAmbassadorVersion) } From 85de6598aa9c7c700bc5f87584a7e53a5137b5cc Mon Sep 17 00:00:00 2001 From: Henrik Blixt Date: Thu, 3 Feb 2022 17:10:23 -0800 Subject: [PATCH 085/175] docs: Update security.md (#1840) Signed-off-by: Henrik Blixt --- docs/security.md | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/docs/security.md b/docs/security.md index 38bd8a771b..e4b28f7385 100644 --- a/docs/security.md +++ b/docs/security.md @@ -1,10 +1,21 @@ -# Security +# Security Policy for Argo Rollouts -## Reporting Vulnerabilities +## Reporting a Vulnerability -Please report security vulnerabilities by e-mailing: +If you find a security related bug in Argo Rollouts, we kindly ask you for responsible +disclosure and for giving us appropriate time to react, analyze and develop a +fix to mitigate the found security vulnerability. -* [Jesse_Suen@intuit.com](mailto:Jesse_Suen@intuit.com) -* [Alexander_Matyushentsev@intuit.com](mailto:Alexander_Matyushentsev@intuit.com) -* [Edward_Lee@intuit.com](mailto:Edward_Lee@intuit.com) \ No newline at end of file +Please report vulnerabilities by e-mail to the following address: + +* cncf-argo-security@lists.cncf.io + +All vulnerabilites and associated information will be treated with full confidentiality. + +## Public Disclosure + +We will publish security advisiories using the +[GitHub Security Advisories](https://github.com/argoproj/argo-rollouts/security/advisories) +feature to keep our community well informed, and will credit you for your +findings (unless you prefer to stay anonymous, of course). From 34b4375a07125eb744de1bc1835a06d48606092a Mon Sep 17 00:00:00 2001 From: Andrii Perenesenko Date: Thu, 3 Feb 2022 19:31:16 -0800 Subject: [PATCH 086/175] feat: ping-pong service management (#1697) Signed-off-by: Andrii Perenesenko --- docs/features/traffic-management/alb.md | 49 + manifests/crds/rollout-crd.yaml | 12 + manifests/install.yaml | 12 + manifests/namespace-install.yaml | 12 + pkg/apiclient/rollout/rollout.pb.go | 285 ++-- pkg/apiclient/rollout/rollout.proto | 2 + pkg/apiclient/rollout/rollout.swagger.json | 28 + pkg/apis/rollouts/v1alpha1/generated.pb.go | 1250 ++++++++++------- pkg/apis/rollouts/v1alpha1/generated.proto | 15 + .../rollouts/v1alpha1/openapi_generated.go | 46 +- pkg/apis/rollouts/v1alpha1/types.go | 19 + .../v1alpha1/zz_generated.deepcopy.go | 21 + pkg/apis/rollouts/validation/validation.go | 27 +- .../validation/validation_references.go | 19 +- .../validation/validation_references_test.go | 22 +- .../rollouts/validation/validation_test.go | 43 +- pkg/kubectl-argo-rollouts/cmd/get/get.go | 2 + .../cmd/get/get_rollout.go | 8 + pkg/kubectl-argo-rollouts/cmd/get/get_test.go | 48 + pkg/kubectl-argo-rollouts/info/info.go | 2 + pkg/kubectl-argo-rollouts/info/info_test.go | 18 + .../info/replicaset_info.go | 10 + .../info/rollout_info.go | 6 + .../info/testdata/canary/canary-rollout4.yaml | 86 ++ rollout/canary.go | 9 +- rollout/canary_test.go | 83 ++ rollout/controller.go | 95 +- rollout/service.go | 18 +- rollout/sync.go | 8 + rollout/sync_test.go | 23 + rollout/trafficrouting/alb/alb.go | 7 +- rollout/trafficrouting/alb/alb_test.go | 94 +- rollout/trafficrouting/service_helper.go | 33 + test/e2e/aws_test.go | 93 +- test/e2e/functional/alb-pingpong-rollout.yaml | 86 ++ utils/service/service.go | 6 + utils/service/service_test.go | 19 + 37 files changed, 1895 insertions(+), 721 deletions(-) create mode 100644 pkg/kubectl-argo-rollouts/info/testdata/canary/canary-rollout4.yaml create mode 100644 rollout/trafficrouting/service_helper.go create mode 100644 test/e2e/functional/alb-pingpong-rollout.yaml diff --git a/docs/features/traffic-management/alb.md b/docs/features/traffic-management/alb.md index 7f84bb1570..7139c3db7a 100644 --- a/docs/features/traffic-management/alb.md +++ b/docs/features/traffic-management/alb.md @@ -331,6 +331,55 @@ include: * [kube2iam](https://github.com/jtblin/kube2iam) * [EKS ServiceAccount IAM Roles](https://docs.aws.amazon.com/eks/latest/userguide/specify-service-account-role.html) +### Zero-Downtime Updates with Ping-Pong feature + +Above there was described the recommended way by AWS to solve zero-downtime issue. Is a use a [pod readiness gate injection](https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.2/deploy/pod_readiness_gate/) +when running the AWS LoadBalancer in IP mode. There is a challenge with that approach, modifications +of the Service selector labels (`spec.selector`) not allowed the AWS LoadBalancer controller to mutate the readiness gates. +And Ping-Pong feature helps to deal with that challenge. At some particular moment one of the services (e.g. ping) is "wearing a +hat" of stable service another one (e.g. pong) is "wearing a hat" of canary. At the end of the promotion step all 100% of traffic sending +to the "canary" (e.g. pong). And then the Rollout swapped the hats of ping and pong services so the pong became a stable one. +The Rollout status object holds the value of who is currently the stable ping or pong (`status.canary.currentPingPong`). +And this way allows the rollout to use pod readiness gate injection as the +services are not changing their labels at the end of the rollout progress. + +!!!important + + Ping-Pong feature available since Argo Rollouts v1.2 + +## Example +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: example-rollout +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.15.4 + ports: + - containerPort: 80 + strategy: + canary: + pingPong: #Indicates that the ping-pong services enabled + pingService: ping-service + pongService: pong-service + trafficRouting: + alb: + ingress: alb-ingress + servicePort: 80 + steps: + - setWeight: 20 + - pause: {} +``` ### Custom annotations-prefix diff --git a/manifests/crds/rollout-crd.yaml b/manifests/crds/rollout-crd.yaml index 5fc2803570..0d1fa09528 100644 --- a/manifests/crds/rollout-crd.yaml +++ b/manifests/crds/rollout-crd.yaml @@ -387,6 +387,16 @@ spec: - type: integer - type: string x-kubernetes-int-or-string: true + pingPong: + properties: + pingService: + type: string + pongService: + type: string + required: + - pingService + - pongService + type: object scaleDownDelayRevisionLimit: format: int32 type: integer @@ -3202,6 +3212,8 @@ spec: - name - status type: object + stablePingPong: + type: string weights: properties: additional: diff --git a/manifests/install.yaml b/manifests/install.yaml index dbefccff0c..31af7b4ca2 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -11355,6 +11355,16 @@ spec: - type: integer - type: string x-kubernetes-int-or-string: true + pingPong: + properties: + pingService: + type: string + pongService: + type: string + required: + - pingService + - pongService + type: object scaleDownDelayRevisionLimit: format: int32 type: integer @@ -14170,6 +14180,8 @@ spec: - name - status type: object + stablePingPong: + type: string weights: properties: additional: diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 9f48ae0d96..744aebf18b 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -11355,6 +11355,16 @@ spec: - type: integer - type: string x-kubernetes-int-or-string: true + pingPong: + properties: + pingService: + type: string + pongService: + type: string + required: + - pingService + - pongService + type: object scaleDownDelayRevisionLimit: format: int32 type: integer @@ -14170,6 +14180,8 @@ spec: - name - status type: object + stablePingPong: + type: string weights: properties: additional: diff --git a/pkg/apiclient/rollout/rollout.pb.go b/pkg/apiclient/rollout/rollout.pb.go index 3c118fb424..584dc967cd 100644 --- a/pkg/apiclient/rollout/rollout.pb.go +++ b/pkg/apiclient/rollout/rollout.pb.go @@ -1015,6 +1015,8 @@ type ReplicaSetInfo struct { ScaleDownDeadline string `protobuf:"bytes,12,opt,name=scaleDownDeadline,proto3" json:"scaleDownDeadline,omitempty"` Images []string `protobuf:"bytes,13,rep,name=images,proto3" json:"images,omitempty"` Pods []*PodInfo `protobuf:"bytes,14,rep,name=pods,proto3" json:"pods,omitempty"` + Ping bool `protobuf:"varint,15,opt,name=ping,proto3" json:"ping,omitempty"` + Pong bool `protobuf:"varint,16,opt,name=pong,proto3" json:"pong,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1151,6 +1153,20 @@ func (m *ReplicaSetInfo) GetPods() []*PodInfo { return nil } +func (m *ReplicaSetInfo) GetPing() bool { + if m != nil { + return m.Ping + } + return false +} + +func (m *ReplicaSetInfo) GetPong() bool { + if m != nil { + return m.Pong + } + return false +} + type PodInfo struct { ObjectMeta *v1.ObjectMeta `protobuf:"bytes,1,opt,name=objectMeta,proto3" json:"objectMeta,omitempty"` Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` @@ -1486,106 +1502,107 @@ func init() { } var fileDescriptor_99101d942e8912a7 = []byte{ - // 1576 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x18, 0xcd, 0x6f, 0xdc, 0xc4, - 0x57, 0xde, 0xcd, 0x26, 0x9b, 0xd9, 0x7c, 0x4e, 0xd2, 0xd6, 0xdd, 0xf6, 0x17, 0xe5, 0xe7, 0xfe, - 0xa4, 0x5f, 0x1a, 0xc0, 0x4e, 0x4a, 0x95, 0x52, 0x3e, 0x0e, 0xa1, 0x8d, 0x42, 0x51, 0x81, 0xe0, - 0x08, 0x2a, 0x90, 0xa0, 0x9a, 0xf5, 0x4e, 0x36, 0x6e, 0xbd, 0x1e, 0xe3, 0x19, 0x6f, 0x59, 0x45, - 0x7b, 0x80, 0x0b, 0x47, 0x0e, 0xfc, 0x11, 0x88, 0x13, 0x17, 0x2e, 0x1c, 0x38, 0x21, 0x21, 0x4e, - 0x08, 0x89, 0x7f, 0x00, 0x55, 0x5c, 0xf8, 0x2f, 0xd0, 0x3c, 0x8f, 0xc7, 0xf6, 0x66, 0xd3, 0xa6, - 0x4a, 0x20, 0x9c, 0x3c, 0xef, 0xbd, 0x79, 0x1f, 0xe3, 0xf7, 0x31, 0xef, 0x0d, 0xba, 0x12, 0x3d, - 0xec, 0x38, 0x24, 0xf2, 0xbd, 0xc0, 0xa7, 0xa1, 0x70, 0x62, 0x16, 0x04, 0x2c, 0xd1, 0x5f, 0x3b, - 0x8a, 0x99, 0x60, 0x78, 0x42, 0x81, 0xcd, 0xcb, 0x1d, 0xc6, 0x3a, 0x01, 0x95, 0x0c, 0x0e, 0x09, - 0x43, 0x26, 0x88, 0xf0, 0x59, 0xc8, 0xd3, 0x6d, 0xcd, 0xbb, 0x1d, 0x5f, 0xec, 0x27, 0x2d, 0xdb, - 0x63, 0x5d, 0x87, 0xc4, 0x1d, 0x16, 0xc5, 0xec, 0x01, 0x2c, 0x5e, 0x50, 0xfc, 0xdc, 0x51, 0xda, - 0xb8, 0xa3, 0x31, 0xbd, 0x75, 0x12, 0x44, 0xfb, 0x64, 0xdd, 0xe9, 0xd0, 0x90, 0xc6, 0x44, 0xd0, - 0xb6, 0x92, 0x76, 0xfd, 0xe1, 0x4b, 0xdc, 0xf6, 0x99, 0xdc, 0xde, 0x25, 0xde, 0xbe, 0x1f, 0xd2, - 0xb8, 0x9f, 0xf3, 0x77, 0xa9, 0x20, 0x4e, 0xef, 0x30, 0xd7, 0x25, 0x65, 0x21, 0x40, 0xad, 0x64, - 0xcf, 0xa1, 0xdd, 0x48, 0xf4, 0x53, 0xa2, 0x75, 0x1b, 0xcd, 0xb9, 0xa9, 0xde, 0x3b, 0xe1, 0x1e, - 0x7b, 0x37, 0xa1, 0x71, 0x1f, 0x63, 0x34, 0x16, 0x92, 0x2e, 0x35, 0x8d, 0x65, 0x63, 0x65, 0xd2, - 0x85, 0x35, 0xbe, 0x8c, 0x26, 0xe5, 0x97, 0x47, 0xc4, 0xa3, 0x66, 0x05, 0x08, 0x39, 0xc2, 0xba, - 0x8e, 0x16, 0x0b, 0x52, 0xee, 0xfa, 0x5c, 0xa4, 0x92, 0x4a, 0x5c, 0xc6, 0x30, 0xd7, 0x97, 0x06, - 0x9a, 0xdd, 0xa5, 0xe2, 0x4e, 0x97, 0x74, 0xa8, 0x4b, 0x3f, 0x49, 0x28, 0x17, 0xd8, 0x44, 0xd9, - 0x9f, 0x55, 0xfb, 0x33, 0x50, 0xca, 0xf2, 0x58, 0x28, 0x88, 0x3c, 0x75, 0x66, 0x81, 0x46, 0xe0, - 0x45, 0x54, 0xf3, 0xa5, 0x1c, 0xb3, 0x0a, 0x94, 0x14, 0xc0, 0x73, 0xa8, 0x2a, 0x48, 0xc7, 0x1c, - 0x03, 0x9c, 0x5c, 0x96, 0x2d, 0xaa, 0x0d, 0x5b, 0xb4, 0x8f, 0xf0, 0x7b, 0x61, 0x9b, 0xa9, 0xb3, - 0x3c, 0xdd, 0xa6, 0x26, 0xaa, 0xc7, 0xb4, 0xe7, 0x73, 0x9f, 0x85, 0x60, 0x52, 0xd5, 0xd5, 0x70, - 0x59, 0x53, 0x75, 0x58, 0xd3, 0x1d, 0x74, 0xce, 0xa5, 0x5c, 0x90, 0x58, 0x0c, 0x29, 0x7b, 0xf6, - 0x9f, 0xff, 0x11, 0x3a, 0xb7, 0x13, 0xb3, 0x2e, 0x13, 0xf4, 0xa4, 0xa2, 0x24, 0xc7, 0x5e, 0x12, - 0x04, 0x60, 0x6e, 0xdd, 0x85, 0xb5, 0xb5, 0x8d, 0x16, 0x36, 0x5b, 0xec, 0x14, 0xec, 0xdc, 0x46, - 0x0b, 0x2e, 0x15, 0x71, 0xff, 0xc4, 0x82, 0xee, 0xa3, 0x79, 0x25, 0xe3, 0x1e, 0x11, 0xde, 0xfe, - 0x56, 0x8f, 0x86, 0x20, 0x46, 0xf4, 0x23, 0x2d, 0x46, 0xae, 0xf1, 0x06, 0x6a, 0xc4, 0x79, 0x58, - 0x82, 0xa0, 0xc6, 0xb5, 0x45, 0x3b, 0xcb, 0xe4, 0x42, 0xc8, 0xba, 0xc5, 0x8d, 0xd6, 0x7d, 0x34, - 0xfd, 0x76, 0xa6, 0x4d, 0x22, 0x9e, 0x1c, 0xc7, 0x78, 0x0d, 0x2d, 0x90, 0x1e, 0xf1, 0x03, 0xd2, - 0x0a, 0xa8, 0xe6, 0xe3, 0x66, 0x65, 0xb9, 0xba, 0x32, 0xe9, 0x8e, 0x22, 0x59, 0xb7, 0xd0, 0xec, - 0x50, 0xbe, 0xe0, 0x35, 0x54, 0xcf, 0x0a, 0x80, 0x69, 0x2c, 0x57, 0x8f, 0x34, 0x54, 0xef, 0xb2, - 0x6e, 0xa0, 0xc6, 0xfb, 0x34, 0x96, 0xb1, 0x06, 0x36, 0xae, 0xa0, 0xd9, 0x8c, 0xa4, 0xd0, 0xca, - 0xd2, 0x61, 0xb4, 0xf5, 0xf5, 0x38, 0x6a, 0x14, 0x44, 0xe2, 0x1d, 0x84, 0x58, 0xeb, 0x01, 0xf5, - 0xc4, 0x5b, 0x54, 0x10, 0x60, 0x6a, 0x5c, 0x5b, 0xb3, 0xd3, 0x5a, 0x63, 0x17, 0x6b, 0x8d, 0x1d, - 0x3d, 0xec, 0x48, 0x04, 0xb7, 0x65, 0xad, 0xb1, 0x7b, 0xeb, 0xf6, 0x3b, 0x9a, 0xcf, 0x2d, 0xc8, - 0xc0, 0xe7, 0xd1, 0x38, 0x17, 0x44, 0x24, 0x5c, 0x39, 0x4f, 0x41, 0x32, 0x93, 0xba, 0x94, 0xf3, - 0x3c, 0x4f, 0x33, 0x50, 0xba, 0xcf, 0xf7, 0x58, 0xa8, 0x52, 0x15, 0xd6, 0x32, 0xbb, 0xb8, 0x90, - 0x95, 0xac, 0xd3, 0x57, 0xa9, 0xaa, 0x61, 0xb9, 0x9f, 0x0b, 0x1a, 0x99, 0xe3, 0xe9, 0x7e, 0xb9, - 0x96, 0x5e, 0xe2, 0x54, 0xdc, 0xa3, 0x7e, 0x67, 0x5f, 0x98, 0x13, 0xa9, 0x97, 0x34, 0x02, 0x5b, - 0x68, 0x8a, 0x78, 0x22, 0x21, 0x81, 0xda, 0x50, 0x87, 0x0d, 0x25, 0x9c, 0xac, 0x22, 0x31, 0x25, - 0xed, 0xbe, 0x39, 0xb9, 0x6c, 0xac, 0xd4, 0xdc, 0x14, 0x90, 0x56, 0x7b, 0x49, 0x1c, 0xd3, 0x50, - 0x98, 0x08, 0xf0, 0x19, 0x28, 0x29, 0x6d, 0xca, 0xfd, 0x98, 0xb6, 0xcd, 0x46, 0x4a, 0x51, 0xa0, - 0xa4, 0x24, 0x51, 0x5b, 0x56, 0x61, 0x73, 0x2a, 0xa5, 0x28, 0x50, 0x5a, 0xa9, 0x43, 0xc2, 0x9c, - 0x06, 0x5a, 0x8e, 0xc0, 0xcb, 0xa8, 0x11, 0xa7, 0x75, 0x81, 0xb6, 0x37, 0x85, 0x39, 0x03, 0x46, - 0x16, 0x51, 0x78, 0x09, 0x21, 0x55, 0xe1, 0xa5, 0x8b, 0x67, 0x61, 0x43, 0x01, 0x83, 0x6f, 0x4a, - 0x09, 0x51, 0xe0, 0x7b, 0x64, 0x97, 0x0a, 0x6e, 0xce, 0x41, 0x2c, 0x5d, 0xc8, 0x63, 0x49, 0xd3, - 0x54, 0xdc, 0xe7, 0x7b, 0x25, 0x2b, 0xfd, 0x34, 0xa2, 0xb1, 0xdf, 0xa5, 0xa1, 0xe0, 0xe6, 0xfc, - 0x10, 0xeb, 0x96, 0xa6, 0xa5, 0xac, 0x85, 0xbd, 0xf8, 0x55, 0x34, 0x45, 0x42, 0x12, 0xf4, 0xb9, - 0xcf, 0xdd, 0x24, 0xe4, 0x26, 0x06, 0x5e, 0x53, 0xf3, 0x6e, 0xe6, 0x44, 0x60, 0x2e, 0xed, 0xc6, - 0x1b, 0x08, 0xe9, 0x52, 0xce, 0xcd, 0x05, 0xe0, 0x3d, 0xaf, 0x79, 0x6f, 0x65, 0x24, 0xe0, 0x2c, - 0xec, 0xc4, 0x1f, 0xa3, 0x9a, 0xf4, 0x3c, 0x37, 0x17, 0x81, 0xe5, 0x0d, 0x3b, 0xbf, 0x6e, 0xed, - 0xec, 0xba, 0x85, 0xc5, 0xfd, 0x2c, 0x07, 0xf2, 0x10, 0xd6, 0x98, 0xec, 0xba, 0xb5, 0x6f, 0x91, - 0x90, 0xc4, 0xfd, 0x5d, 0x41, 0x23, 0x37, 0x15, 0x6b, 0xfd, 0x50, 0x41, 0x33, 0xe5, 0x53, 0xff, - 0x0d, 0xc9, 0x92, 0x85, 0x7e, 0xa5, 0x1c, 0xfa, 0xfa, 0x62, 0xa9, 0x42, 0x8c, 0xe4, 0x17, 0x4b, - 0x9e, 0x5c, 0x63, 0x47, 0x25, 0x57, 0xad, 0x9c, 0x5c, 0x43, 0x21, 0x31, 0xfe, 0x0c, 0x21, 0x31, - 0xec, 0xd7, 0x89, 0x67, 0xf1, 0xab, 0xf5, 0x4b, 0x15, 0xcd, 0x94, 0xa5, 0xff, 0x83, 0xc5, 0x26, - 0xfb, 0xaf, 0xd5, 0x23, 0xfe, 0xeb, 0xd8, 0xc8, 0xff, 0x2a, 0xb3, 0xb2, 0x06, 0xd7, 0x9f, 0x82, - 0x24, 0xde, 0x83, 0xc8, 0x80, 0x62, 0x53, 0x77, 0x15, 0x24, 0xf1, 0xc4, 0x13, 0x7e, 0x8f, 0x42, - 0xad, 0xa9, 0xbb, 0x0a, 0x92, 0x7e, 0x88, 0xa4, 0x50, 0xfa, 0x08, 0x6a, 0x4c, 0xdd, 0xcd, 0xc0, - 0x54, 0x3b, 0xfc, 0x0d, 0xae, 0x2a, 0x8c, 0x86, 0xcb, 0x65, 0x01, 0x0d, 0x97, 0x85, 0x26, 0xaa, - 0x0b, 0xda, 0x8d, 0x02, 0x22, 0x28, 0x54, 0x9a, 0x49, 0x57, 0xc3, 0xf8, 0x79, 0x34, 0xcf, 0x3d, - 0x12, 0xd0, 0xdb, 0xec, 0x51, 0x78, 0x9b, 0x92, 0x76, 0xe0, 0x87, 0x14, 0x8a, 0xce, 0xa4, 0x7b, - 0x98, 0x20, 0xad, 0x86, 0xde, 0x88, 0x9b, 0xd3, 0x70, 0x3f, 0x29, 0x08, 0xff, 0x0f, 0x8d, 0x45, - 0xac, 0xcd, 0xcd, 0x19, 0x70, 0xf0, 0x9c, 0x76, 0xf0, 0x0e, 0x6b, 0x83, 0x63, 0x81, 0x6a, 0x7d, - 0x6f, 0xa0, 0x09, 0x85, 0x39, 0x63, 0x4f, 0xea, 0x52, 0x9d, 0x26, 0x81, 0x2a, 0xd5, 0xf0, 0x87, - 0xa1, 0x56, 0x72, 0xf0, 0x22, 0xfc, 0xe1, 0x14, 0xb6, 0x6e, 0xa2, 0xe9, 0x52, 0x25, 0x19, 0xd9, - 0x79, 0xe8, 0x3e, 0xb2, 0x52, 0xe8, 0x23, 0xad, 0x2f, 0x0c, 0x34, 0xf1, 0x26, 0x6b, 0x9d, 0xfd, - 0xb1, 0xad, 0x1f, 0x2b, 0x68, 0x76, 0x28, 0xe7, 0xfe, 0xc5, 0x25, 0x69, 0x09, 0x21, 0x9e, 0x78, - 0x1e, 0xe5, 0x7c, 0x2f, 0x09, 0x94, 0x43, 0x0a, 0x18, 0xc9, 0xb7, 0x47, 0xfc, 0x80, 0xb6, 0x21, - 0xb5, 0x6a, 0xae, 0x82, 0xe4, 0x5d, 0xed, 0x87, 0x1e, 0x0b, 0xbd, 0x20, 0xe1, 0x59, 0x82, 0xd5, - 0xdc, 0x12, 0x4e, 0x7a, 0x8a, 0xc6, 0x31, 0x8b, 0x21, 0xc9, 0x6a, 0x6e, 0x0a, 0xc8, 0x30, 0x7e, - 0xc0, 0x5a, 0x32, 0xbd, 0xca, 0x61, 0xac, 0xbc, 0xe7, 0x02, 0xf5, 0xda, 0x9f, 0xd3, 0x68, 0x46, - 0x75, 0x40, 0xbb, 0x34, 0xee, 0xf9, 0x1e, 0xc5, 0x1c, 0xcd, 0x6c, 0x53, 0x51, 0x6c, 0x8b, 0x2e, - 0x8e, 0xea, 0xbf, 0x60, 0xae, 0x69, 0x8e, 0x6c, 0xcd, 0xac, 0xb5, 0xcf, 0x7f, 0xfb, 0xe3, 0xab, - 0xca, 0x2a, 0x5e, 0x81, 0x61, 0xb0, 0xb7, 0x9e, 0x4f, 0x74, 0x07, 0xba, 0x59, 0x1c, 0xa4, 0xeb, - 0x81, 0xe3, 0x4b, 0x15, 0x03, 0x34, 0x07, 0x2d, 0xec, 0x89, 0xd4, 0x6e, 0x80, 0xda, 0x35, 0x6c, - 0x1f, 0x57, 0xad, 0xf3, 0x48, 0xea, 0x5c, 0x33, 0x70, 0x0f, 0xcd, 0xc9, 0xde, 0xb3, 0x20, 0x8c, - 0xe3, 0xff, 0x8c, 0xd2, 0xa1, 0x27, 0xba, 0xa6, 0x79, 0x14, 0xd9, 0xba, 0x0a, 0x66, 0x5c, 0xc1, - 0xff, 0x7d, 0xa2, 0x19, 0x70, 0xec, 0xcf, 0x0c, 0x34, 0x3f, 0x7c, 0xee, 0xa7, 0x6a, 0x6e, 0x0e, - 0x93, 0xf3, 0xe6, 0xdf, 0x72, 0x40, 0xf7, 0x55, 0xfc, 0xff, 0xa7, 0xea, 0xd6, 0x67, 0xff, 0x00, - 0x4d, 0x6d, 0x53, 0xa1, 0x7b, 0x72, 0x7c, 0xde, 0x4e, 0xc7, 0x64, 0x3b, 0x1b, 0x93, 0xed, 0x2d, - 0x39, 0x26, 0x37, 0xf3, 0x36, 0xa4, 0x34, 0x12, 0x58, 0x17, 0x41, 0xe5, 0x02, 0x9e, 0xcf, 0x54, - 0xe6, 0xf3, 0xc0, 0xb7, 0x86, 0xbc, 0xf5, 0x8a, 0xc3, 0x1d, 0x5e, 0x2a, 0x5c, 0xb6, 0x23, 0xa6, - 0xbe, 0xe6, 0xd6, 0xc9, 0x3a, 0x17, 0x25, 0x2d, 0x0b, 0x85, 0xe6, 0x73, 0xc7, 0x09, 0x05, 0x55, - 0x18, 0x5f, 0x36, 0x56, 0xc1, 0xe2, 0xf2, 0x0c, 0x59, 0xb0, 0x78, 0xe4, 0x70, 0x79, 0x26, 0x16, - 0x47, 0xa9, 0x25, 0xd2, 0xe2, 0x6f, 0x0c, 0x34, 0x55, 0x1c, 0x4b, 0xf1, 0xe5, 0xbc, 0x25, 0x39, - 0x3c, 0xad, 0x9e, 0x96, 0xb5, 0xd7, 0xc1, 0x5a, 0xbb, 0x79, 0xf5, 0x38, 0xd6, 0x12, 0x69, 0x87, - 0xb4, 0xf5, 0xa7, 0xf4, 0x9d, 0x23, 0x8b, 0x6a, 0x78, 0x99, 0xc8, 0xf3, 0x68, 0xe8, 0x05, 0xe4, - 0xb4, 0x4c, 0x75, 0xc1, 0xd4, 0xbb, 0xcd, 0xed, 0x27, 0x9b, 0xaa, 0xb0, 0x03, 0x87, 0x53, 0xe1, - 0x1c, 0xe8, 0xd6, 0x7a, 0xe0, 0x1c, 0xc0, 0xcd, 0xf7, 0xda, 0xea, 0xea, 0xc0, 0x39, 0x10, 0xa4, - 0x33, 0x90, 0x07, 0xf9, 0xce, 0x40, 0x8d, 0xc2, 0xfb, 0x08, 0xbe, 0xa4, 0x0f, 0x71, 0xf8, 0xd5, - 0xe4, 0xb4, 0xce, 0xb1, 0x09, 0xe7, 0x78, 0xa5, 0xb9, 0x71, 0xcc, 0x73, 0x24, 0x61, 0x9b, 0x39, - 0x07, 0xd9, 0xcd, 0x34, 0xc8, 0x62, 0xa5, 0xf8, 0xf2, 0x50, 0x88, 0x95, 0x11, 0x0f, 0x12, 0x67, - 0x12, 0x2b, 0xb1, 0xb4, 0x43, 0xda, 0xba, 0x83, 0x26, 0xd4, 0x98, 0x7e, 0x64, 0x45, 0xca, 0x6f, - 0x81, 0xc2, 0xf8, 0x6f, 0x5d, 0x00, 0x75, 0xf3, 0x78, 0x36, 0x53, 0xd7, 0x4b, 0x89, 0xaf, 0x6f, - 0xfd, 0xfc, 0x78, 0xc9, 0xf8, 0xf5, 0xf1, 0x92, 0xf1, 0xfb, 0xe3, 0x25, 0xe3, 0xc3, 0x1b, 0xc7, - 0x7e, 0x90, 0x2c, 0x3f, 0x7f, 0xb6, 0xc6, 0xc1, 0x8a, 0x17, 0xff, 0x0a, 0x00, 0x00, 0xff, 0xff, - 0xc0, 0xbd, 0xfe, 0xe3, 0x1e, 0x15, 0x00, 0x00, + // 1600 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0x4f, 0x6f, 0x1c, 0x45, + 0x16, 0x57, 0x7b, 0x3c, 0xf6, 0xb8, 0xc6, 0x7f, 0xcb, 0x4e, 0xd2, 0x99, 0x64, 0x2d, 0x6f, 0x67, + 0xa5, 0x75, 0xbc, 0xbb, 0xdd, 0x76, 0x36, 0x72, 0x36, 0xbb, 0xcb, 0xc1, 0x24, 0x96, 0x09, 0x0a, + 0x60, 0xda, 0x82, 0x08, 0x24, 0x88, 0x6a, 0x7a, 0xca, 0xed, 0x4e, 0x7a, 0xba, 0x9a, 0xae, 0xea, + 0x09, 0x23, 0x6b, 0x0e, 0x70, 0xe1, 0xc8, 0x81, 0x0f, 0x81, 0x38, 0x71, 0xe1, 0xc2, 0x81, 0x13, + 0x12, 0xe2, 0x88, 0xc4, 0x17, 0x40, 0x11, 0x17, 0xbe, 0x00, 0x67, 0x54, 0xaf, 0xab, 0xab, 0xbb, + 0xc7, 0xe3, 0xc4, 0x91, 0x0d, 0xe6, 0xd4, 0xf5, 0xde, 0xab, 0xf7, 0xde, 0xaf, 0xfa, 0xfd, 0xa9, + 0x3f, 0xe8, 0x5a, 0xfc, 0xd8, 0x77, 0x48, 0x1c, 0x78, 0x61, 0x40, 0x23, 0xe1, 0x24, 0x2c, 0x0c, + 0x59, 0xaa, 0xbf, 0x76, 0x9c, 0x30, 0xc1, 0xf0, 0xa4, 0x22, 0x5b, 0x57, 0x7d, 0xc6, 0xfc, 0x90, + 0x4a, 0x05, 0x87, 0x44, 0x11, 0x13, 0x44, 0x04, 0x2c, 0xe2, 0xd9, 0xb4, 0xd6, 0x7d, 0x3f, 0x10, + 0x07, 0x69, 0xdb, 0xf6, 0x58, 0xd7, 0x21, 0x89, 0xcf, 0xe2, 0x84, 0x3d, 0x82, 0xc1, 0xbf, 0x94, + 0x3e, 0x77, 0x94, 0x37, 0xee, 0x68, 0x4e, 0x6f, 0x83, 0x84, 0xf1, 0x01, 0xd9, 0x70, 0x7c, 0x1a, + 0xd1, 0x84, 0x08, 0xda, 0x51, 0xd6, 0x6e, 0x3e, 0xfe, 0x0f, 0xb7, 0x03, 0x26, 0xa7, 0x77, 0x89, + 0x77, 0x10, 0x44, 0x34, 0xe9, 0x17, 0xfa, 0x5d, 0x2a, 0x88, 0xd3, 0x3b, 0xaa, 0x75, 0x45, 0x21, + 0x04, 0xaa, 0x9d, 0xee, 0x3b, 0xb4, 0x1b, 0x8b, 0x7e, 0x26, 0xb4, 0xee, 0xa2, 0x79, 0x37, 0xf3, + 0x7b, 0x2f, 0xda, 0x67, 0x6f, 0xa6, 0x34, 0xe9, 0x63, 0x8c, 0xc6, 0x23, 0xd2, 0xa5, 0xa6, 0xb1, + 0x62, 0xac, 0x4e, 0xb9, 0x30, 0xc6, 0x57, 0xd1, 0x94, 0xfc, 0xf2, 0x98, 0x78, 0xd4, 0x1c, 0x03, + 0x41, 0xc1, 0xb0, 0x6e, 0xa2, 0xa5, 0x92, 0x95, 0xfb, 0x01, 0x17, 0x99, 0xa5, 0x8a, 0x96, 0x31, + 0xac, 0xf5, 0xa9, 0x81, 0xe6, 0xf6, 0xa8, 0xb8, 0xd7, 0x25, 0x3e, 0x75, 0xe9, 0x07, 0x29, 0xe5, + 0x02, 0x9b, 0x28, 0xff, 0xb3, 0x6a, 0x7e, 0x4e, 0x4a, 0x5b, 0x1e, 0x8b, 0x04, 0x91, 0xab, 0xce, + 0x11, 0x68, 0x06, 0x5e, 0x42, 0xf5, 0x40, 0xda, 0x31, 0x6b, 0x20, 0xc9, 0x08, 0x3c, 0x8f, 0x6a, + 0x82, 0xf8, 0xe6, 0x38, 0xf0, 0xe4, 0xb0, 0x8a, 0xa8, 0x3e, 0x8c, 0xe8, 0x00, 0xe1, 0xb7, 0xa2, + 0x0e, 0x53, 0x6b, 0x79, 0x3e, 0xa6, 0x16, 0x6a, 0x24, 0xb4, 0x17, 0xf0, 0x80, 0x45, 0x00, 0xa9, + 0xe6, 0x6a, 0xba, 0xea, 0xa9, 0x36, 0xec, 0xe9, 0x1e, 0xba, 0xe0, 0x52, 0x2e, 0x48, 0x22, 0x86, + 0x9c, 0xbd, 0xf8, 0xcf, 0x7f, 0x0f, 0x5d, 0xd8, 0x4d, 0x58, 0x97, 0x09, 0x7a, 0x5a, 0x53, 0x52, + 0x63, 0x3f, 0x0d, 0x43, 0x80, 0xdb, 0x70, 0x61, 0x6c, 0xed, 0xa0, 0xc5, 0xad, 0x36, 0x3b, 0x03, + 0x9c, 0x3b, 0x68, 0xd1, 0xa5, 0x22, 0xe9, 0x9f, 0xda, 0xd0, 0x43, 0xb4, 0xa0, 0x6c, 0x3c, 0x20, + 0xc2, 0x3b, 0xd8, 0xee, 0xd1, 0x08, 0xcc, 0x88, 0x7e, 0xac, 0xcd, 0xc8, 0x31, 0xde, 0x44, 0xcd, + 0xa4, 0x48, 0x4b, 0x30, 0xd4, 0xbc, 0xb1, 0x64, 0xe7, 0x95, 0x5c, 0x4a, 0x59, 0xb7, 0x3c, 0xd1, + 0x7a, 0x88, 0x66, 0x5e, 0xcf, 0xbd, 0x49, 0xc6, 0xb3, 0xf3, 0x18, 0xaf, 0xa3, 0x45, 0xd2, 0x23, + 0x41, 0x48, 0xda, 0x21, 0xd5, 0x7a, 0xdc, 0x1c, 0x5b, 0xa9, 0xad, 0x4e, 0xb9, 0xa3, 0x44, 0xd6, + 0x1d, 0x34, 0x37, 0x54, 0x2f, 0x78, 0x1d, 0x35, 0xf2, 0x06, 0x60, 0x1a, 0x2b, 0xb5, 0x63, 0x81, + 0xea, 0x59, 0xd6, 0x2d, 0xd4, 0x7c, 0x9b, 0x26, 0x32, 0xd7, 0x00, 0xe3, 0x2a, 0x9a, 0xcb, 0x45, + 0x8a, 0xad, 0x90, 0x0e, 0xb3, 0xad, 0xcf, 0x27, 0x50, 0xb3, 0x64, 0x12, 0xef, 0x22, 0xc4, 0xda, + 0x8f, 0xa8, 0x27, 0x5e, 0xa3, 0x82, 0x80, 0x52, 0xf3, 0xc6, 0xba, 0x9d, 0xf5, 0x1a, 0xbb, 0xdc, + 0x6b, 0xec, 0xf8, 0xb1, 0x2f, 0x19, 0xdc, 0x96, 0xbd, 0xc6, 0xee, 0x6d, 0xd8, 0x6f, 0x68, 0x3d, + 0xb7, 0x64, 0x03, 0x5f, 0x44, 0x13, 0x5c, 0x10, 0x91, 0x72, 0x15, 0x3c, 0x45, 0xc9, 0x4a, 0xea, + 0x52, 0xce, 0x8b, 0x3a, 0xcd, 0x49, 0x19, 0xbe, 0xc0, 0x63, 0x91, 0x2a, 0x55, 0x18, 0xcb, 0xea, + 0xe2, 0x42, 0x76, 0x32, 0xbf, 0xaf, 0x4a, 0x55, 0xd3, 0x72, 0x3e, 0x17, 0x34, 0x36, 0x27, 0xb2, + 0xf9, 0x72, 0x2c, 0xa3, 0xc4, 0xa9, 0x78, 0x40, 0x03, 0xff, 0x40, 0x98, 0x93, 0x59, 0x94, 0x34, + 0x03, 0x5b, 0x68, 0x9a, 0x78, 0x22, 0x25, 0xa1, 0x9a, 0xd0, 0x80, 0x09, 0x15, 0x9e, 0xec, 0x22, + 0x09, 0x25, 0x9d, 0xbe, 0x39, 0xb5, 0x62, 0xac, 0xd6, 0xdd, 0x8c, 0x90, 0xa8, 0xbd, 0x34, 0x49, + 0x68, 0x24, 0x4c, 0x04, 0xfc, 0x9c, 0x94, 0x92, 0x0e, 0xe5, 0x41, 0x42, 0x3b, 0x66, 0x33, 0x93, + 0x28, 0x52, 0x4a, 0xd2, 0xb8, 0x23, 0xbb, 0xb0, 0x39, 0x9d, 0x49, 0x14, 0x29, 0x51, 0xea, 0x94, + 0x30, 0x67, 0x40, 0x56, 0x30, 0xf0, 0x0a, 0x6a, 0x26, 0x59, 0x5f, 0xa0, 0x9d, 0x2d, 0x61, 0xce, + 0x02, 0xc8, 0x32, 0x0b, 0x2f, 0x23, 0xa4, 0x3a, 0xbc, 0x0c, 0xf1, 0x1c, 0x4c, 0x28, 0x71, 0xf0, + 0x6d, 0x69, 0x21, 0x0e, 0x03, 0x8f, 0xec, 0x51, 0xc1, 0xcd, 0x79, 0xc8, 0xa5, 0x4b, 0x45, 0x2e, + 0x69, 0x99, 0xca, 0xfb, 0x62, 0xae, 0x54, 0xa5, 0x1f, 0xc6, 0x34, 0x09, 0xba, 0x34, 0x12, 0xdc, + 0x5c, 0x18, 0x52, 0xdd, 0xd6, 0xb2, 0x4c, 0xb5, 0x34, 0x17, 0xff, 0x1f, 0x4d, 0x93, 0x88, 0x84, + 0x7d, 0x1e, 0x70, 0x37, 0x8d, 0xb8, 0x89, 0x41, 0xd7, 0xd4, 0xba, 0x5b, 0x85, 0x10, 0x94, 0x2b, + 0xb3, 0xf1, 0x26, 0x42, 0xba, 0x95, 0x73, 0x73, 0x11, 0x74, 0x2f, 0x6a, 0xdd, 0x3b, 0xb9, 0x08, + 0x34, 0x4b, 0x33, 0xf1, 0xfb, 0xa8, 0x2e, 0x23, 0xcf, 0xcd, 0x25, 0x50, 0x79, 0xc5, 0x2e, 0xb6, + 0x5b, 0x3b, 0xdf, 0x6e, 0x61, 0xf0, 0x30, 0xaf, 0x81, 0x22, 0x85, 0x35, 0x27, 0xdf, 0x6e, 0xed, + 0x3b, 0x24, 0x22, 0x49, 0x7f, 0x4f, 0xd0, 0xd8, 0xcd, 0xcc, 0x5a, 0xdf, 0x8c, 0xa1, 0xd9, 0xea, + 0xaa, 0x7f, 0x87, 0x62, 0xc9, 0x53, 0x7f, 0xac, 0x9a, 0xfa, 0x7a, 0x63, 0xa9, 0x41, 0x8e, 0x14, + 0x1b, 0x4b, 0x51, 0x5c, 0xe3, 0xc7, 0x15, 0x57, 0xbd, 0x5a, 0x5c, 0x43, 0x29, 0x31, 0xf1, 0x02, + 0x29, 0x31, 0x1c, 0xd7, 0xc9, 0x17, 0x89, 0xab, 0xf5, 0x6b, 0x0d, 0xcd, 0x56, 0xad, 0xff, 0x81, + 0xcd, 0x26, 0xff, 0xaf, 0xb5, 0x63, 0xfe, 0xeb, 0xf8, 0xc8, 0xff, 0x2a, 0xab, 0xb2, 0x0e, 0xdb, + 0x9f, 0xa2, 0x24, 0xdf, 0x83, 0xcc, 0x80, 0x66, 0xd3, 0x70, 0x15, 0x25, 0xf9, 0xc4, 0x13, 0x41, + 0x8f, 0x42, 0xaf, 0x69, 0xb8, 0x8a, 0x92, 0x71, 0x88, 0xa5, 0x51, 0xfa, 0x04, 0x7a, 0x4c, 0xc3, + 0xcd, 0xc9, 0xcc, 0x3b, 0xfc, 0x0d, 0xae, 0x3a, 0x8c, 0xa6, 0xab, 0x6d, 0x01, 0x0d, 0xb7, 0x85, + 0x16, 0x6a, 0x08, 0xda, 0x8d, 0x43, 0x22, 0x28, 0x74, 0x9a, 0x29, 0x57, 0xd3, 0xf8, 0x9f, 0x68, + 0x81, 0x7b, 0x24, 0xa4, 0x77, 0xd9, 0x93, 0xe8, 0x2e, 0x25, 0x9d, 0x30, 0x88, 0x28, 0x34, 0x9d, + 0x29, 0xf7, 0xa8, 0x40, 0xa2, 0x86, 0xb3, 0x11, 0x37, 0x67, 0x60, 0x7f, 0x52, 0x14, 0xfe, 0x1b, + 0x1a, 0x8f, 0x59, 0x87, 0x9b, 0xb3, 0x10, 0xe0, 0x79, 0x1d, 0xe0, 0x5d, 0xd6, 0x81, 0xc0, 0x82, + 0x54, 0xfe, 0xd3, 0x38, 0x88, 0x7c, 0x68, 0x3b, 0x0d, 0x17, 0xc6, 0xc0, 0x63, 0x91, 0x6f, 0xce, + 0x2b, 0x1e, 0x8b, 0x7c, 0xeb, 0x6b, 0x03, 0x4d, 0x2a, 0xcd, 0x73, 0x8e, 0xb8, 0x6e, 0xe9, 0x59, + 0xb1, 0xa8, 0x96, 0x0e, 0x91, 0x80, 0x9e, 0xca, 0x21, 0xda, 0x10, 0x89, 0x8c, 0xb6, 0x6e, 0xa3, + 0x99, 0x4a, 0xc7, 0x19, 0x79, 0x42, 0xd1, 0xe7, 0xcd, 0xb1, 0xd2, 0x79, 0xd3, 0xfa, 0xc4, 0x40, + 0x93, 0xaf, 0xb2, 0xf6, 0xf9, 0x2f, 0xdb, 0xfa, 0x76, 0x0c, 0xcd, 0x0d, 0xd5, 0xe6, 0x9f, 0xb8, + 0x75, 0x2d, 0x23, 0xc4, 0x53, 0xcf, 0xa3, 0x9c, 0xef, 0xa7, 0xa1, 0x0a, 0x48, 0x89, 0x23, 0xf5, + 0xf6, 0x49, 0x10, 0xd2, 0x0e, 0x94, 0x60, 0xdd, 0x55, 0x94, 0xdc, 0xd3, 0x83, 0xc8, 0x63, 0x91, + 0x17, 0xa6, 0x3c, 0x2f, 0xc4, 0xba, 0x5b, 0xe1, 0xc9, 0x48, 0xd1, 0x24, 0x61, 0x09, 0x14, 0x63, + 0xdd, 0xcd, 0x08, 0x99, 0xee, 0x8f, 0x58, 0x5b, 0x96, 0x61, 0x35, 0xdd, 0x55, 0xf4, 0x5c, 0x90, + 0xde, 0xf8, 0x65, 0x06, 0xcd, 0xaa, 0x93, 0xd2, 0x1e, 0x4d, 0x7a, 0x81, 0x47, 0x31, 0x47, 0xb3, + 0x3b, 0x54, 0x94, 0x8f, 0x4f, 0x97, 0x47, 0x9d, 0xd3, 0xe0, 0xfe, 0xd3, 0x1a, 0x79, 0x84, 0xb3, + 0xd6, 0x3f, 0xfe, 0xf1, 0xe7, 0xcf, 0xc6, 0xd6, 0xf0, 0x2a, 0x5c, 0x1a, 0x7b, 0x1b, 0xc5, 0xcd, + 0xef, 0x50, 0x1f, 0x2a, 0x07, 0xd9, 0x78, 0xe0, 0x04, 0xd2, 0xc5, 0x00, 0xcd, 0xc3, 0x51, 0xf7, + 0x54, 0x6e, 0x37, 0xc1, 0xed, 0x3a, 0xb6, 0x4f, 0xea, 0xd6, 0x79, 0x22, 0x7d, 0xae, 0x1b, 0xb8, + 0x87, 0xe6, 0xe5, 0x19, 0xb5, 0x64, 0x8c, 0xe3, 0xbf, 0x8c, 0xf2, 0xa1, 0x6f, 0x7e, 0x2d, 0xf3, + 0x38, 0xb1, 0x75, 0x1d, 0x60, 0x5c, 0xc3, 0x7f, 0x7d, 0x26, 0x0c, 0x58, 0xf6, 0x47, 0x06, 0x5a, + 0x18, 0x5e, 0xf7, 0x73, 0x3d, 0xb7, 0x86, 0xc5, 0xc5, 0x25, 0xc1, 0x72, 0xc0, 0xf7, 0x75, 0xfc, + 0xf7, 0xe7, 0xfa, 0xd6, 0x6b, 0x7f, 0x07, 0x4d, 0xef, 0x50, 0xa1, 0xcf, 0xee, 0xf8, 0xa2, 0x9d, + 0x5d, 0xa7, 0xed, 0xfc, 0x3a, 0x6d, 0x6f, 0xcb, 0xeb, 0x74, 0xab, 0x38, 0xae, 0x54, 0xae, 0x0e, + 0xd6, 0x65, 0x70, 0xb9, 0x88, 0x17, 0x72, 0x97, 0xc5, 0xbd, 0xe1, 0x4b, 0x43, 0xee, 0x8e, 0xe5, + 0x4b, 0x20, 0x5e, 0x2e, 0x6d, 0xca, 0x23, 0x6e, 0x87, 0xad, 0xed, 0xd3, 0x9d, 0x70, 0x94, 0xb5, + 0x3c, 0x15, 0x5a, 0xff, 0x38, 0x49, 0x2a, 0xa8, 0xc6, 0xf8, 0x5f, 0x63, 0x0d, 0x10, 0x57, 0xef, + 0x9a, 0x25, 0xc4, 0x23, 0x2f, 0xa1, 0xe7, 0x82, 0x38, 0xce, 0x90, 0x48, 0xc4, 0x5f, 0x18, 0x68, + 0xba, 0x7c, 0x7d, 0xc5, 0x57, 0x8b, 0xa3, 0xcb, 0xd1, 0x5b, 0xed, 0x59, 0xa1, 0xbd, 0x09, 0x68, + 0xed, 0xd6, 0xf5, 0x93, 0xa0, 0x25, 0x12, 0x87, 0xc4, 0xfa, 0x5d, 0xf6, 0x1e, 0x92, 0x67, 0x35, + 0xbc, 0x60, 0x14, 0x75, 0x34, 0xf4, 0x52, 0x72, 0x56, 0x50, 0x5d, 0x80, 0x7a, 0xbf, 0xb5, 0xf3, + 0x6c, 0xa8, 0x8a, 0x3b, 0x70, 0x38, 0x15, 0xce, 0xa1, 0x3e, 0x82, 0x0f, 0x9c, 0x43, 0xd8, 0xf9, + 0x5e, 0x5a, 0x5b, 0x1b, 0x38, 0x87, 0x82, 0xf8, 0x03, 0xb9, 0x90, 0xaf, 0x0c, 0xd4, 0x2c, 0xbd, + 0xa3, 0xe0, 0x2b, 0x7a, 0x11, 0x47, 0x5f, 0x57, 0xce, 0x6a, 0x1d, 0x5b, 0xb0, 0x8e, 0xff, 0xb5, + 0x36, 0x4f, 0xb8, 0x8e, 0x34, 0xea, 0x30, 0xe7, 0x30, 0xdf, 0x99, 0x06, 0x79, 0xae, 0x94, 0x5f, + 0x28, 0x4a, 0xb9, 0x32, 0xe2, 0xe1, 0xe2, 0x5c, 0x72, 0x25, 0x91, 0x38, 0x24, 0xd6, 0x5d, 0x34, + 0xa9, 0xae, 0xf3, 0xc7, 0x76, 0xa4, 0x62, 0x17, 0x28, 0x3d, 0x13, 0x58, 0x97, 0xc0, 0xdd, 0x02, + 0x9e, 0xcb, 0xdd, 0xf5, 0x32, 0xe1, 0xcb, 0xdb, 0xdf, 0x3f, 0x5d, 0x36, 0x7e, 0x78, 0xba, 0x6c, + 0xfc, 0xf4, 0x74, 0xd9, 0x78, 0xf7, 0xd6, 0x89, 0x1f, 0x2e, 0xab, 0xcf, 0xa4, 0xed, 0x09, 0x40, + 0xf1, 0xef, 0xdf, 0x02, 0x00, 0x00, 0xff, 0xff, 0xe8, 0x30, 0x8c, 0x5d, 0x46, 0x15, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2964,6 +2981,28 @@ func (m *ReplicaSetInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Pong { + i-- + if m.Pong { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x80 + } + if m.Ping { + i-- + if m.Ping { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x78 + } if len(m.Pods) > 0 { for iNdEx := len(m.Pods) - 1; iNdEx >= 0; iNdEx-- { { @@ -3796,6 +3835,12 @@ func (m *ReplicaSetInfo) Size() (n int) { n += 1 + l + sovRollout(uint64(l)) } } + if m.Ping { + n += 2 + } + if m.Pong { + n += 3 + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -6659,6 +6704,46 @@ func (m *ReplicaSetInfo) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 15: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Ping", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollout + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Ping = bool(v != 0) + case 16: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Pong", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollout + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Pong = bool(v != 0) default: iNdEx = preIndex skippy, err := skipRollout(dAtA[iNdEx:]) diff --git a/pkg/apiclient/rollout/rollout.proto b/pkg/apiclient/rollout/rollout.proto index 0150a5196c..27bd0337cd 100644 --- a/pkg/apiclient/rollout/rollout.proto +++ b/pkg/apiclient/rollout/rollout.proto @@ -123,6 +123,8 @@ message ReplicaSetInfo { string scaleDownDeadline = 12; repeated string images = 13; repeated PodInfo pods = 14; + bool ping = 15; + bool pong = 16; } message PodInfo { diff --git a/pkg/apiclient/rollout/rollout.swagger.json b/pkg/apiclient/rollout/rollout.swagger.json index 99fc79a04c..10d5eb02d0 100644 --- a/pkg/apiclient/rollout/rollout.swagger.json +++ b/pkg/apiclient/rollout/rollout.swagger.json @@ -789,6 +789,10 @@ "weights": { "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.TrafficWeights", "title": "Weights records the weights which have been set on traffic provider. Only valid when using traffic routing" + }, + "stablePingPong": { + "type": "string", + "title": "StablePingPong For the ping-pong feature holds the current stable service, ping or pong" } }, "title": "CanaryStatus status fields that only pertain to the canary rollout" @@ -884,6 +888,10 @@ "dynamicStableScale": { "type": "boolean", "description": "DynamicStableScale is a traffic routing feature which dynamically scales the stable\nReplicaSet to minimize total pods which are running during an update. This is calculated by\nscaling down the stable as traffic is increased to canary. When disabled (the default behavior)\nthe stable ReplicaSet remains fully scaled to support instantaneous aborts." + }, + "pingPong": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.PingPongSpec", + "title": "PingPongSpec holds the ping and pong services" } }, "title": "CanaryStrategy defines parameters for a Replica Based Canary" @@ -1036,6 +1044,20 @@ }, "title": "PauseCondition the reason for a pause and when it started" }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.PingPongSpec": { + "type": "object", + "properties": { + "pingService": { + "type": "string", + "title": "name of the ping service" + }, + "pongService": { + "type": "string", + "title": "name of the pong service" + } + }, + "description": "PingPongSpec holds the ping and pong service name." + }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.PodTemplateMetadata": { "type": "object", "properties": { @@ -4563,6 +4585,12 @@ "items": { "$ref": "#/definitions/rollout.PodInfo" } + }, + "ping": { + "type": "boolean" + }, + "pong": { + "type": "boolean" } } }, diff --git a/pkg/apis/rollouts/v1alpha1/generated.pb.go b/pkg/apis/rollouts/v1alpha1/generated.pb.go index 1124c687f0..72a7752573 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.pb.go +++ b/pkg/apis/rollouts/v1alpha1/generated.pb.go @@ -1700,10 +1700,38 @@ func (m *PauseCondition) XXX_DiscardUnknown() { var xxx_messageInfo_PauseCondition proto.InternalMessageInfo +func (m *PingPongSpec) Reset() { *m = PingPongSpec{} } +func (*PingPongSpec) ProtoMessage() {} +func (*PingPongSpec) Descriptor() ([]byte, []int) { + return fileDescriptor_e0e705f843545fab, []int{59} +} +func (m *PingPongSpec) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PingPongSpec) 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 *PingPongSpec) XXX_Merge(src proto.Message) { + xxx_messageInfo_PingPongSpec.Merge(m, src) +} +func (m *PingPongSpec) XXX_Size() int { + return m.Size() +} +func (m *PingPongSpec) XXX_DiscardUnknown() { + xxx_messageInfo_PingPongSpec.DiscardUnknown(m) +} + +var xxx_messageInfo_PingPongSpec proto.InternalMessageInfo + func (m *PodTemplateMetadata) Reset() { *m = PodTemplateMetadata{} } func (*PodTemplateMetadata) ProtoMessage() {} func (*PodTemplateMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{59} + return fileDescriptor_e0e705f843545fab, []int{60} } func (m *PodTemplateMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1733,7 +1761,7 @@ func (m *PreferredDuringSchedulingIgnoredDuringExecution) Reset() { } func (*PreferredDuringSchedulingIgnoredDuringExecution) ProtoMessage() {} func (*PreferredDuringSchedulingIgnoredDuringExecution) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{60} + return fileDescriptor_e0e705f843545fab, []int{61} } func (m *PreferredDuringSchedulingIgnoredDuringExecution) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1761,7 +1789,7 @@ var xxx_messageInfo_PreferredDuringSchedulingIgnoredDuringExecution proto.Intern func (m *PrometheusMetric) Reset() { *m = PrometheusMetric{} } func (*PrometheusMetric) ProtoMessage() {} func (*PrometheusMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{61} + return fileDescriptor_e0e705f843545fab, []int{62} } func (m *PrometheusMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1791,7 +1819,7 @@ func (m *RequiredDuringSchedulingIgnoredDuringExecution) Reset() { } func (*RequiredDuringSchedulingIgnoredDuringExecution) ProtoMessage() {} func (*RequiredDuringSchedulingIgnoredDuringExecution) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{62} + return fileDescriptor_e0e705f843545fab, []int{63} } func (m *RequiredDuringSchedulingIgnoredDuringExecution) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1819,7 +1847,7 @@ var xxx_messageInfo_RequiredDuringSchedulingIgnoredDuringExecution proto.Interna func (m *Rollout) Reset() { *m = Rollout{} } func (*Rollout) ProtoMessage() {} func (*Rollout) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{63} + return fileDescriptor_e0e705f843545fab, []int{64} } func (m *Rollout) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1847,7 +1875,7 @@ var xxx_messageInfo_Rollout proto.InternalMessageInfo func (m *RolloutAnalysis) Reset() { *m = RolloutAnalysis{} } func (*RolloutAnalysis) ProtoMessage() {} func (*RolloutAnalysis) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{64} + return fileDescriptor_e0e705f843545fab, []int{65} } func (m *RolloutAnalysis) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1875,7 +1903,7 @@ var xxx_messageInfo_RolloutAnalysis proto.InternalMessageInfo func (m *RolloutAnalysisBackground) Reset() { *m = RolloutAnalysisBackground{} } func (*RolloutAnalysisBackground) ProtoMessage() {} func (*RolloutAnalysisBackground) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{65} + return fileDescriptor_e0e705f843545fab, []int{66} } func (m *RolloutAnalysisBackground) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1903,7 +1931,7 @@ var xxx_messageInfo_RolloutAnalysisBackground proto.InternalMessageInfo func (m *RolloutAnalysisRunStatus) Reset() { *m = RolloutAnalysisRunStatus{} } func (*RolloutAnalysisRunStatus) ProtoMessage() {} func (*RolloutAnalysisRunStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{66} + return fileDescriptor_e0e705f843545fab, []int{67} } func (m *RolloutAnalysisRunStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1931,7 +1959,7 @@ var xxx_messageInfo_RolloutAnalysisRunStatus proto.InternalMessageInfo func (m *RolloutAnalysisTemplate) Reset() { *m = RolloutAnalysisTemplate{} } func (*RolloutAnalysisTemplate) ProtoMessage() {} func (*RolloutAnalysisTemplate) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{67} + return fileDescriptor_e0e705f843545fab, []int{68} } func (m *RolloutAnalysisTemplate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1959,7 +1987,7 @@ var xxx_messageInfo_RolloutAnalysisTemplate proto.InternalMessageInfo func (m *RolloutCondition) Reset() { *m = RolloutCondition{} } func (*RolloutCondition) ProtoMessage() {} func (*RolloutCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{68} + return fileDescriptor_e0e705f843545fab, []int{69} } func (m *RolloutCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1987,7 +2015,7 @@ var xxx_messageInfo_RolloutCondition proto.InternalMessageInfo func (m *RolloutExperimentStep) Reset() { *m = RolloutExperimentStep{} } func (*RolloutExperimentStep) ProtoMessage() {} func (*RolloutExperimentStep) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{69} + return fileDescriptor_e0e705f843545fab, []int{70} } func (m *RolloutExperimentStep) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2017,7 +2045,7 @@ func (m *RolloutExperimentStepAnalysisTemplateRef) Reset() { } func (*RolloutExperimentStepAnalysisTemplateRef) ProtoMessage() {} func (*RolloutExperimentStepAnalysisTemplateRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{70} + return fileDescriptor_e0e705f843545fab, []int{71} } func (m *RolloutExperimentStepAnalysisTemplateRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2045,7 +2073,7 @@ var xxx_messageInfo_RolloutExperimentStepAnalysisTemplateRef proto.InternalMessa func (m *RolloutExperimentTemplate) Reset() { *m = RolloutExperimentTemplate{} } func (*RolloutExperimentTemplate) ProtoMessage() {} func (*RolloutExperimentTemplate) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{71} + return fileDescriptor_e0e705f843545fab, []int{72} } func (m *RolloutExperimentTemplate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2073,7 +2101,7 @@ var xxx_messageInfo_RolloutExperimentTemplate proto.InternalMessageInfo func (m *RolloutList) Reset() { *m = RolloutList{} } func (*RolloutList) ProtoMessage() {} func (*RolloutList) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{72} + return fileDescriptor_e0e705f843545fab, []int{73} } func (m *RolloutList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2101,7 +2129,7 @@ var xxx_messageInfo_RolloutList proto.InternalMessageInfo func (m *RolloutPause) Reset() { *m = RolloutPause{} } func (*RolloutPause) ProtoMessage() {} func (*RolloutPause) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{73} + return fileDescriptor_e0e705f843545fab, []int{74} } func (m *RolloutPause) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2129,7 +2157,7 @@ var xxx_messageInfo_RolloutPause proto.InternalMessageInfo func (m *RolloutSpec) Reset() { *m = RolloutSpec{} } func (*RolloutSpec) ProtoMessage() {} func (*RolloutSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{74} + return fileDescriptor_e0e705f843545fab, []int{75} } func (m *RolloutSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2157,7 +2185,7 @@ var xxx_messageInfo_RolloutSpec proto.InternalMessageInfo func (m *RolloutStatus) Reset() { *m = RolloutStatus{} } func (*RolloutStatus) ProtoMessage() {} func (*RolloutStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{75} + return fileDescriptor_e0e705f843545fab, []int{76} } func (m *RolloutStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2185,7 +2213,7 @@ var xxx_messageInfo_RolloutStatus proto.InternalMessageInfo func (m *RolloutStrategy) Reset() { *m = RolloutStrategy{} } func (*RolloutStrategy) ProtoMessage() {} func (*RolloutStrategy) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{76} + return fileDescriptor_e0e705f843545fab, []int{77} } func (m *RolloutStrategy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2213,7 +2241,7 @@ var xxx_messageInfo_RolloutStrategy proto.InternalMessageInfo func (m *RolloutTrafficRouting) Reset() { *m = RolloutTrafficRouting{} } func (*RolloutTrafficRouting) ProtoMessage() {} func (*RolloutTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{77} + return fileDescriptor_e0e705f843545fab, []int{78} } func (m *RolloutTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2241,7 +2269,7 @@ var xxx_messageInfo_RolloutTrafficRouting proto.InternalMessageInfo func (m *RunSummary) Reset() { *m = RunSummary{} } func (*RunSummary) ProtoMessage() {} func (*RunSummary) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{78} + return fileDescriptor_e0e705f843545fab, []int{79} } func (m *RunSummary) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2269,7 +2297,7 @@ var xxx_messageInfo_RunSummary proto.InternalMessageInfo func (m *SMITrafficRouting) Reset() { *m = SMITrafficRouting{} } func (*SMITrafficRouting) ProtoMessage() {} func (*SMITrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{79} + return fileDescriptor_e0e705f843545fab, []int{80} } func (m *SMITrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2297,7 +2325,7 @@ var xxx_messageInfo_SMITrafficRouting proto.InternalMessageInfo func (m *ScopeDetail) Reset() { *m = ScopeDetail{} } func (*ScopeDetail) ProtoMessage() {} func (*ScopeDetail) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{80} + return fileDescriptor_e0e705f843545fab, []int{81} } func (m *ScopeDetail) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2325,7 +2353,7 @@ var xxx_messageInfo_ScopeDetail proto.InternalMessageInfo func (m *SecretKeyRef) Reset() { *m = SecretKeyRef{} } func (*SecretKeyRef) ProtoMessage() {} func (*SecretKeyRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{81} + return fileDescriptor_e0e705f843545fab, []int{82} } func (m *SecretKeyRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2353,7 +2381,7 @@ var xxx_messageInfo_SecretKeyRef proto.InternalMessageInfo func (m *SetCanaryScale) Reset() { *m = SetCanaryScale{} } func (*SetCanaryScale) ProtoMessage() {} func (*SetCanaryScale) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{82} + return fileDescriptor_e0e705f843545fab, []int{83} } func (m *SetCanaryScale) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2381,7 +2409,7 @@ var xxx_messageInfo_SetCanaryScale proto.InternalMessageInfo func (m *StickinessConfig) Reset() { *m = StickinessConfig{} } func (*StickinessConfig) ProtoMessage() {} func (*StickinessConfig) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{83} + return fileDescriptor_e0e705f843545fab, []int{84} } func (m *StickinessConfig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2409,7 +2437,7 @@ var xxx_messageInfo_StickinessConfig proto.InternalMessageInfo func (m *TLSRoute) Reset() { *m = TLSRoute{} } func (*TLSRoute) ProtoMessage() {} func (*TLSRoute) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{84} + return fileDescriptor_e0e705f843545fab, []int{85} } func (m *TLSRoute) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2437,7 +2465,7 @@ var xxx_messageInfo_TLSRoute proto.InternalMessageInfo func (m *TemplateService) Reset() { *m = TemplateService{} } func (*TemplateService) ProtoMessage() {} func (*TemplateService) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{85} + return fileDescriptor_e0e705f843545fab, []int{86} } func (m *TemplateService) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2465,7 +2493,7 @@ var xxx_messageInfo_TemplateService proto.InternalMessageInfo func (m *TemplateSpec) Reset() { *m = TemplateSpec{} } func (*TemplateSpec) ProtoMessage() {} func (*TemplateSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{86} + return fileDescriptor_e0e705f843545fab, []int{87} } func (m *TemplateSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2493,7 +2521,7 @@ var xxx_messageInfo_TemplateSpec proto.InternalMessageInfo func (m *TemplateStatus) Reset() { *m = TemplateStatus{} } func (*TemplateStatus) ProtoMessage() {} func (*TemplateStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{87} + return fileDescriptor_e0e705f843545fab, []int{88} } func (m *TemplateStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2521,7 +2549,7 @@ var xxx_messageInfo_TemplateStatus proto.InternalMessageInfo func (m *TrafficWeights) Reset() { *m = TrafficWeights{} } func (*TrafficWeights) ProtoMessage() {} func (*TrafficWeights) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{88} + return fileDescriptor_e0e705f843545fab, []int{89} } func (m *TrafficWeights) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2549,7 +2577,7 @@ var xxx_messageInfo_TrafficWeights proto.InternalMessageInfo func (m *ValueFrom) Reset() { *m = ValueFrom{} } func (*ValueFrom) ProtoMessage() {} func (*ValueFrom) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{89} + return fileDescriptor_e0e705f843545fab, []int{90} } func (m *ValueFrom) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2577,7 +2605,7 @@ var xxx_messageInfo_ValueFrom proto.InternalMessageInfo func (m *WavefrontMetric) Reset() { *m = WavefrontMetric{} } func (*WavefrontMetric) ProtoMessage() {} func (*WavefrontMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{90} + return fileDescriptor_e0e705f843545fab, []int{91} } func (m *WavefrontMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2605,7 +2633,7 @@ var xxx_messageInfo_WavefrontMetric proto.InternalMessageInfo func (m *WebMetric) Reset() { *m = WebMetric{} } func (*WebMetric) ProtoMessage() {} func (*WebMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{91} + return fileDescriptor_e0e705f843545fab, []int{92} } func (m *WebMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2633,7 +2661,7 @@ var xxx_messageInfo_WebMetric proto.InternalMessageInfo func (m *WebMetricHeader) Reset() { *m = WebMetricHeader{} } func (*WebMetricHeader) ProtoMessage() {} func (*WebMetricHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{92} + return fileDescriptor_e0e705f843545fab, []int{93} } func (m *WebMetricHeader) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2661,7 +2689,7 @@ var xxx_messageInfo_WebMetricHeader proto.InternalMessageInfo func (m *WeightDestination) Reset() { *m = WeightDestination{} } func (*WeightDestination) ProtoMessage() {} func (*WeightDestination) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{93} + return fileDescriptor_e0e705f843545fab, []int{94} } func (m *WeightDestination) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2749,6 +2777,7 @@ func init() { proto.RegisterMapType((map[string]string)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.NginxTrafficRouting.AdditionalIngressAnnotationsEntry") proto.RegisterType((*ObjectRef)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ObjectRef") proto.RegisterType((*PauseCondition)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.PauseCondition") + proto.RegisterType((*PingPongSpec)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.PingPongSpec") proto.RegisterType((*PodTemplateMetadata)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.PodTemplateMetadata") proto.RegisterMapType((map[string]string)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.PodTemplateMetadata.AnnotationsEntry") proto.RegisterMapType((map[string]string)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.PodTemplateMetadata.LabelsEntry") @@ -2793,447 +2822,452 @@ func init() { } var fileDescriptor_e0e705f843545fab = []byte{ - // 7031 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x5d, 0x8c, 0x24, 0x57, - 0x75, 0xb0, 0xab, 0x7b, 0x7a, 0xa6, 0xe7, 0xcc, 0xff, 0xdd, 0x59, 0x76, 0xbc, 0xf6, 0x6e, 0x9b, - 0x32, 0xf2, 0x67, 0xbe, 0x0f, 0x66, 0xc1, 0x3f, 0xdf, 0x67, 0x30, 0xf2, 0x97, 0xee, 0x99, 0x5d, - 0xef, 0xac, 0x67, 0x76, 0x67, 0x4f, 0xcf, 0x7a, 0xc1, 0x60, 0x42, 0x4d, 0xf7, 0x9d, 0x9e, 0xda, - 0xed, 0xae, 0x6a, 0xaa, 0xaa, 0x67, 0x77, 0x0c, 0x02, 0x3b, 0xc8, 0x0e, 0x89, 0x40, 0x38, 0x01, - 0x14, 0x45, 0x11, 0x11, 0x8a, 0x90, 0x12, 0x85, 0x3c, 0x44, 0x28, 0x51, 0x5e, 0x90, 0x12, 0x05, - 0x50, 0xc8, 0x43, 0x22, 0x22, 0x25, 0x01, 0x22, 0xe8, 0xc4, 0x43, 0x5e, 0x12, 0x25, 0x8a, 0x22, - 0x11, 0x45, 0xec, 0x53, 0x74, 0x7f, 0xea, 0xd6, 0xad, 0xea, 0xea, 0xd9, 0xee, 0xe9, 0x9a, 0xc5, - 0x4a, 0x78, 0xeb, 0xbe, 0xe7, 0xdc, 0x73, 0xee, 0xef, 0x39, 0xe7, 0x9e, 0x7b, 0xee, 0x29, 0x58, - 0x6f, 0xd8, 0xc1, 0x6e, 0x67, 0x7b, 0xb9, 0xe6, 0xb6, 0xce, 0x59, 0x5e, 0xc3, 0x6d, 0x7b, 0xee, - 0x0d, 0xfe, 0xe3, 0x9d, 0x9e, 0xdb, 0x6c, 0xba, 0x9d, 0xc0, 0x3f, 0xd7, 0xbe, 0xd9, 0x38, 0x67, - 0xb5, 0x6d, 0xff, 0x9c, 0x2a, 0xd9, 0x7b, 0xb7, 0xd5, 0x6c, 0xef, 0x5a, 0xef, 0x3e, 0xd7, 0xa0, - 0x0e, 0xf5, 0xac, 0x80, 0xd6, 0x97, 0xdb, 0x9e, 0x1b, 0xb8, 0xe4, 0x7d, 0x11, 0xb5, 0xe5, 0x90, - 0x1a, 0xff, 0xf1, 0xf3, 0x61, 0xdd, 0xe5, 0xf6, 0xcd, 0xc6, 0x32, 0xa3, 0xb6, 0xac, 0x4a, 0x42, - 0x6a, 0xa7, 0xdf, 0xa9, 0xb5, 0xa5, 0xe1, 0x36, 0xdc, 0x73, 0x9c, 0xe8, 0x76, 0x67, 0x87, 0xff, - 0xe3, 0x7f, 0xf8, 0x2f, 0xc1, 0xec, 0xf4, 0xc3, 0x37, 0x9f, 0xf2, 0x97, 0x6d, 0x97, 0xb5, 0xed, - 0xdc, 0xb6, 0x15, 0xd4, 0x76, 0xcf, 0xed, 0xf5, 0xb4, 0xe8, 0xb4, 0xa9, 0x21, 0xd5, 0x5c, 0x8f, - 0xa6, 0xe1, 0x3c, 0x11, 0xe1, 0xb4, 0xac, 0xda, 0xae, 0xed, 0x50, 0x6f, 0x3f, 0xea, 0x75, 0x8b, - 0x06, 0x56, 0x5a, 0xad, 0x73, 0xfd, 0x6a, 0x79, 0x1d, 0x27, 0xb0, 0x5b, 0xb4, 0xa7, 0xc2, 0xff, - 0xbd, 0x5b, 0x05, 0xbf, 0xb6, 0x4b, 0x5b, 0x56, 0x4f, 0xbd, 0xc7, 0xfb, 0xd5, 0xeb, 0x04, 0x76, - 0xf3, 0x9c, 0xed, 0x04, 0x7e, 0xe0, 0x25, 0x2b, 0x99, 0xdf, 0xcc, 0xc3, 0x64, 0x79, 0xbd, 0x52, - 0x0d, 0xac, 0xa0, 0xe3, 0x93, 0xd7, 0x0c, 0x98, 0x6e, 0xba, 0x56, 0xbd, 0x62, 0x35, 0x2d, 0xa7, - 0x46, 0xbd, 0x25, 0xe3, 0x21, 0xe3, 0xd1, 0xa9, 0xc7, 0xd6, 0x97, 0x47, 0x99, 0xaf, 0xe5, 0xf2, - 0x2d, 0x1f, 0xa9, 0xef, 0x76, 0xbc, 0x1a, 0x45, 0xba, 0x53, 0x59, 0xfc, 0x76, 0xb7, 0x74, 0xdf, - 0x41, 0xb7, 0x34, 0xbd, 0xae, 0x71, 0xc2, 0x18, 0x5f, 0xf2, 0x45, 0x03, 0x16, 0x6a, 0x96, 0x63, - 0x79, 0xfb, 0x5b, 0x96, 0xd7, 0xa0, 0xc1, 0xb3, 0x9e, 0xdb, 0x69, 0x2f, 0xe5, 0x8e, 0xa1, 0x35, - 0xf7, 0xcb, 0xd6, 0x2c, 0xac, 0x24, 0xd9, 0x61, 0x6f, 0x0b, 0x78, 0xbb, 0xfc, 0xc0, 0xda, 0x6e, - 0x52, 0xbd, 0x5d, 0xf9, 0xe3, 0x6c, 0x57, 0x35, 0xc9, 0x0e, 0x7b, 0x5b, 0x60, 0xbe, 0x9a, 0x87, - 0x85, 0xf2, 0x7a, 0x65, 0xcb, 0xb3, 0x76, 0x76, 0xec, 0x1a, 0xba, 0x9d, 0xc0, 0x76, 0x1a, 0xe4, - 0xed, 0x30, 0x61, 0x3b, 0x0d, 0x8f, 0xfa, 0x3e, 0x9f, 0xc8, 0xc9, 0xca, 0x9c, 0x24, 0x3a, 0xb1, - 0x26, 0x8a, 0x31, 0x84, 0x93, 0x27, 0x61, 0xca, 0xa7, 0xde, 0x9e, 0x5d, 0xa3, 0x9b, 0xae, 0x17, - 0xf0, 0x91, 0x2e, 0x54, 0x4e, 0x48, 0xf4, 0xa9, 0x6a, 0x04, 0x42, 0x1d, 0x8f, 0x55, 0xf3, 0x5c, - 0x37, 0x90, 0x70, 0x3e, 0x10, 0x93, 0x51, 0x35, 0x8c, 0x40, 0xa8, 0xe3, 0x91, 0xd7, 0x0d, 0x98, - 0xf7, 0x03, 0xbb, 0x76, 0xd3, 0x76, 0xa8, 0xef, 0xaf, 0xb8, 0xce, 0x8e, 0xdd, 0x58, 0x2a, 0xf0, - 0x51, 0xbc, 0x3c, 0xda, 0x28, 0x56, 0x13, 0x54, 0x2b, 0x8b, 0x07, 0xdd, 0xd2, 0x7c, 0xb2, 0x14, - 0x7b, 0xb8, 0x93, 0x55, 0x98, 0xb7, 0x1c, 0xc7, 0x0d, 0xac, 0xc0, 0x76, 0x9d, 0x4d, 0x8f, 0xee, - 0xd8, 0xb7, 0x97, 0xc6, 0x78, 0x77, 0x96, 0x64, 0x77, 0xe6, 0xcb, 0x09, 0x38, 0xf6, 0xd4, 0x30, - 0x57, 0x61, 0xa9, 0xdc, 0xda, 0xb6, 0x7c, 0xdf, 0xaa, 0xbb, 0x5e, 0x62, 0x36, 0x1e, 0x85, 0x62, - 0xcb, 0x6a, 0xb7, 0x6d, 0xa7, 0xc1, 0xa6, 0x23, 0xff, 0xe8, 0x64, 0x65, 0xfa, 0xa0, 0x5b, 0x2a, - 0x6e, 0xc8, 0x32, 0x54, 0x50, 0xf3, 0xfb, 0x39, 0x98, 0x2a, 0x3b, 0x56, 0x73, 0xdf, 0xb7, 0x7d, - 0xec, 0x38, 0xe4, 0x23, 0x50, 0x64, 0xd2, 0xa5, 0x6e, 0x05, 0x96, 0xdc, 0x91, 0xef, 0x5a, 0x16, - 0x9b, 0x7d, 0x59, 0xdf, 0xec, 0xd1, 0xb8, 0x30, 0xec, 0xe5, 0xbd, 0x77, 0x2f, 0x5f, 0xd9, 0xbe, - 0x41, 0x6b, 0xc1, 0x06, 0x0d, 0xac, 0x0a, 0x91, 0xbd, 0x80, 0xa8, 0x0c, 0x15, 0x55, 0xe2, 0xc2, - 0x98, 0xdf, 0xa6, 0x35, 0xb9, 0xc3, 0x36, 0x46, 0x5c, 0xc9, 0x51, 0xd3, 0xab, 0x6d, 0x5a, 0xab, - 0x4c, 0x4b, 0xd6, 0x63, 0xec, 0x1f, 0x72, 0x46, 0xe4, 0x16, 0x8c, 0xfb, 0x5c, 0xe6, 0xc8, 0xcd, - 0x73, 0x25, 0x3b, 0x96, 0x9c, 0x6c, 0x65, 0x56, 0x32, 0x1d, 0x17, 0xff, 0x51, 0xb2, 0x33, 0xff, - 0xce, 0x80, 0x13, 0x1a, 0x76, 0xd9, 0x6b, 0x74, 0x5a, 0xd4, 0x09, 0xc8, 0x43, 0x30, 0xe6, 0x58, - 0x2d, 0x2a, 0x37, 0x8a, 0x6a, 0xf2, 0x65, 0xab, 0x45, 0x91, 0x43, 0xc8, 0xc3, 0x50, 0xd8, 0xb3, - 0x9a, 0x1d, 0xca, 0x07, 0x69, 0xb2, 0x32, 0x23, 0x51, 0x0a, 0xcf, 0xb3, 0x42, 0x14, 0x30, 0xf2, - 0x71, 0x98, 0xe4, 0x3f, 0x2e, 0x78, 0x6e, 0x2b, 0xa3, 0xae, 0xc9, 0x16, 0x3e, 0x1f, 0x92, 0xad, - 0xcc, 0x1c, 0x74, 0x4b, 0x93, 0xea, 0x2f, 0x46, 0x0c, 0xcd, 0xbf, 0x37, 0x60, 0x4e, 0xeb, 0xdc, - 0xba, 0xed, 0x07, 0xe4, 0x43, 0x3d, 0x8b, 0x67, 0x79, 0xb0, 0xc5, 0xc3, 0x6a, 0xf3, 0xa5, 0x33, - 0x2f, 0x7b, 0x5a, 0x0c, 0x4b, 0xb4, 0x85, 0xe3, 0x40, 0xc1, 0x0e, 0x68, 0xcb, 0x5f, 0xca, 0x3d, - 0x94, 0x7f, 0x74, 0xea, 0xb1, 0xb5, 0xcc, 0xa6, 0x31, 0x1a, 0xdf, 0x35, 0x46, 0x1f, 0x05, 0x1b, - 0xf3, 0x6b, 0x63, 0xb1, 0x1e, 0xb2, 0x15, 0x45, 0x5c, 0x98, 0x68, 0xd1, 0xc0, 0xb3, 0x6b, 0x62, - 0x5f, 0x4d, 0x3d, 0xb6, 0x3a, 0x5a, 0x2b, 0x36, 0x38, 0xb1, 0x48, 0x58, 0x8a, 0xff, 0x3e, 0x86, - 0x5c, 0xc8, 0x2e, 0x8c, 0x59, 0x5e, 0x23, 0xec, 0xf3, 0x85, 0x6c, 0xe6, 0x37, 0x5a, 0x73, 0x65, - 0xaf, 0xe1, 0x23, 0xe7, 0x40, 0xce, 0xc1, 0x64, 0x40, 0xbd, 0x96, 0xed, 0x58, 0x81, 0x90, 0xae, - 0xc5, 0xca, 0x82, 0x44, 0x9b, 0xdc, 0x0a, 0x01, 0x18, 0xe1, 0x90, 0x26, 0x8c, 0xd7, 0xbd, 0x7d, - 0xec, 0x38, 0x4b, 0x63, 0x59, 0x0c, 0xc5, 0x2a, 0xa7, 0x15, 0x6d, 0x26, 0xf1, 0x1f, 0x25, 0x0f, - 0xf2, 0x15, 0x03, 0x16, 0x5b, 0xd4, 0xf2, 0x3b, 0x1e, 0x65, 0x5d, 0x40, 0x1a, 0x50, 0x87, 0x49, - 0xc3, 0xa5, 0x02, 0x67, 0x8e, 0xa3, 0xce, 0x43, 0x2f, 0xe5, 0xca, 0x83, 0xb2, 0x29, 0x8b, 0x69, - 0x50, 0x4c, 0x6d, 0x8d, 0xf9, 0xfd, 0x31, 0x58, 0xe8, 0x91, 0x10, 0xe4, 0x09, 0x28, 0xb4, 0x77, - 0x2d, 0x3f, 0xdc, 0xf2, 0x67, 0xc3, 0xf5, 0xb6, 0xc9, 0x0a, 0xef, 0x74, 0x4b, 0x33, 0x61, 0x15, - 0x5e, 0x80, 0x02, 0x99, 0xe9, 0xd4, 0x16, 0xf5, 0x7d, 0xab, 0x11, 0xca, 0x01, 0x6d, 0x99, 0xf0, - 0x62, 0x0c, 0xe1, 0xe4, 0x17, 0x0d, 0x98, 0x11, 0x4b, 0x06, 0xa9, 0xdf, 0x69, 0x06, 0x4c, 0xd6, - 0xb1, 0x61, 0xb9, 0x94, 0xc5, 0xf2, 0x14, 0x24, 0x2b, 0x27, 0x25, 0xf7, 0x19, 0xbd, 0xd4, 0xc7, - 0x38, 0x5f, 0x72, 0x1d, 0x26, 0xfd, 0xc0, 0xf2, 0x02, 0x5a, 0x2f, 0x07, 0x5c, 0xab, 0x4d, 0x3d, - 0xf6, 0xbf, 0x07, 0x13, 0x02, 0x5b, 0x76, 0x8b, 0x0a, 0x81, 0x53, 0x0d, 0x09, 0x60, 0x44, 0x8b, - 0x7c, 0x1c, 0xc0, 0xeb, 0x38, 0xd5, 0x4e, 0xab, 0x65, 0x79, 0xfb, 0x52, 0x83, 0x5f, 0x1c, 0xad, - 0x7b, 0xa8, 0xe8, 0x45, 0x3a, 0x2b, 0x2a, 0x43, 0x8d, 0x1f, 0x79, 0xc5, 0x80, 0x19, 0xb1, 0x12, - 0xc3, 0x16, 0x8c, 0x67, 0xdc, 0x82, 0x05, 0x36, 0xb4, 0xab, 0x3a, 0x0b, 0x8c, 0x73, 0x34, 0xff, - 0x26, 0xae, 0x4f, 0xaa, 0x01, 0xb3, 0xae, 0x1b, 0xfb, 0xe4, 0x83, 0x70, 0xbf, 0xdf, 0xa9, 0xd5, - 0xa8, 0xef, 0xef, 0x74, 0x9a, 0xd8, 0x71, 0x2e, 0xda, 0x7e, 0xe0, 0x7a, 0xfb, 0xeb, 0x76, 0xcb, - 0x0e, 0xf8, 0x8a, 0x2b, 0x54, 0xce, 0x1c, 0x74, 0x4b, 0xf7, 0x57, 0xfb, 0x21, 0x61, 0xff, 0xfa, - 0xc4, 0x82, 0x07, 0x3a, 0x4e, 0x7f, 0xf2, 0xc2, 0x7a, 0x2b, 0x1d, 0x74, 0x4b, 0x0f, 0x5c, 0xeb, - 0x8f, 0x86, 0x87, 0xd1, 0x30, 0xff, 0xd9, 0x80, 0xf9, 0xb0, 0x5f, 0x5b, 0xb4, 0xd5, 0x6e, 0x32, - 0xe9, 0x72, 0xfc, 0x86, 0x48, 0x10, 0x33, 0x44, 0x30, 0x1b, 0x75, 0x12, 0xb6, 0xbf, 0x9f, 0x35, - 0x62, 0xfe, 0x93, 0x01, 0x8b, 0x49, 0xe4, 0x7b, 0xa0, 0x3c, 0xfd, 0xb8, 0xf2, 0xbc, 0x9c, 0x6d, - 0x6f, 0xfb, 0x68, 0xd0, 0xd7, 0xc6, 0x7a, 0xfb, 0xfa, 0xdf, 0x5d, 0x8d, 0x46, 0x5a, 0x31, 0xff, - 0xd3, 0xd4, 0x8a, 0x63, 0x6f, 0x2a, 0xad, 0xf8, 0x3b, 0x63, 0x30, 0x5d, 0x76, 0x02, 0xbb, 0xbc, - 0xb3, 0x63, 0x3b, 0x76, 0xb0, 0x4f, 0x3e, 0x93, 0x83, 0x73, 0x6d, 0x8f, 0xee, 0x50, 0xcf, 0xa3, - 0xf5, 0xd5, 0x8e, 0x67, 0x3b, 0x8d, 0x6a, 0x6d, 0x97, 0xd6, 0x3b, 0x4d, 0xdb, 0x69, 0xac, 0x35, - 0x1c, 0x57, 0x15, 0x9f, 0xbf, 0x4d, 0x6b, 0x1d, 0xde, 0x25, 0xb1, 0x29, 0x5a, 0xa3, 0x75, 0x69, - 0x73, 0x38, 0xa6, 0x95, 0xc7, 0x0f, 0xba, 0xa5, 0x73, 0x43, 0x56, 0xc2, 0x61, 0xbb, 0x46, 0x3e, - 0x9d, 0x83, 0x65, 0x8f, 0x7e, 0xb4, 0x63, 0x0f, 0x3e, 0x1a, 0x42, 0x6a, 0x35, 0x47, 0x54, 0x3f, - 0x43, 0xf1, 0xac, 0x3c, 0x76, 0xd0, 0x2d, 0x0d, 0x59, 0x07, 0x87, 0xec, 0x97, 0xf9, 0x8d, 0x1c, - 0x9c, 0x2c, 0xb7, 0xdb, 0x1b, 0xd4, 0xdf, 0x4d, 0x1c, 0x6a, 0x3f, 0x67, 0xc0, 0xec, 0x9e, 0xed, - 0x05, 0x1d, 0xab, 0x19, 0x3a, 0x01, 0xc4, 0x92, 0xa8, 0x8e, 0xb8, 0x9d, 0x05, 0xb7, 0xe7, 0x63, - 0xa4, 0x2b, 0xe4, 0xa0, 0x5b, 0x9a, 0x8d, 0x97, 0x61, 0x82, 0x3d, 0xf9, 0x35, 0x03, 0xe6, 0x65, - 0xd1, 0x65, 0xb7, 0x4e, 0x75, 0xcf, 0xd1, 0xb5, 0x2c, 0xdb, 0xa4, 0x88, 0x0b, 0x17, 0x43, 0xb2, - 0x14, 0x7b, 0x1a, 0x61, 0xfe, 0x6b, 0x0e, 0x4e, 0xf5, 0xa1, 0x41, 0x7e, 0xdb, 0x80, 0x45, 0xe1, - 0x6e, 0xd2, 0x40, 0x48, 0x77, 0xe4, 0x68, 0x7e, 0x20, 0xeb, 0x96, 0x23, 0xdb, 0x0b, 0xd4, 0xa9, - 0xd1, 0xca, 0x12, 0x13, 0x1b, 0x2b, 0x29, 0xac, 0x31, 0xb5, 0x41, 0xbc, 0xa5, 0xc2, 0x01, 0x95, - 0x68, 0x69, 0xee, 0x9e, 0xb4, 0xb4, 0x9a, 0xc2, 0x1a, 0x53, 0x1b, 0x64, 0xfe, 0x7f, 0x78, 0xe0, - 0x10, 0x72, 0x77, 0x3f, 0xf1, 0x9b, 0x2f, 0xaa, 0x55, 0x1f, 0x5f, 0x73, 0x03, 0x38, 0x0b, 0x4c, - 0x18, 0xf7, 0xdc, 0x4e, 0x40, 0x85, 0x76, 0x9b, 0xac, 0x00, 0xd3, 0x13, 0xc8, 0x4b, 0x50, 0x42, - 0xcc, 0x6f, 0x18, 0x50, 0x1c, 0xc2, 0xff, 0x50, 0x8a, 0xfb, 0x1f, 0x26, 0x7b, 0x7c, 0x0f, 0x41, - 0xaf, 0xef, 0xe1, 0xd9, 0xd1, 0x66, 0x63, 0x10, 0x9f, 0xc3, 0xbf, 0x19, 0xb0, 0xd0, 0xe3, 0xa3, - 0x20, 0xbb, 0xb0, 0xd8, 0x76, 0xeb, 0xa1, 0x7d, 0x71, 0xd1, 0xf2, 0x77, 0x39, 0x4c, 0x76, 0xef, - 0x09, 0x36, 0x93, 0x9b, 0x29, 0xf0, 0x3b, 0xdd, 0xd2, 0x92, 0x22, 0x92, 0x40, 0xc0, 0x54, 0x8a, - 0xa4, 0x0d, 0xc5, 0x1d, 0x9b, 0x36, 0xeb, 0xd1, 0x12, 0x1c, 0xd1, 0x92, 0xb8, 0x20, 0xa9, 0x09, - 0xf7, 0x5c, 0xf8, 0x0f, 0x15, 0x17, 0xf3, 0x2a, 0xcc, 0xc6, 0x9d, 0xb5, 0x03, 0x4c, 0xde, 0x19, - 0xc8, 0x5b, 0x9e, 0x23, 0xa7, 0x6e, 0x4a, 0x22, 0xe4, 0xcb, 0x78, 0x19, 0x59, 0xb9, 0xf9, 0x93, - 0x31, 0x98, 0xab, 0x34, 0x3b, 0xf4, 0x59, 0x8f, 0xd2, 0xf0, 0x7c, 0x5a, 0x86, 0xb9, 0xb6, 0x47, - 0xf7, 0x6c, 0x7a, 0xab, 0x4a, 0x9b, 0xb4, 0x16, 0xb8, 0x9e, 0xa4, 0x7f, 0x4a, 0x56, 0x9f, 0xdb, - 0x8c, 0x83, 0x31, 0x89, 0x4f, 0x9e, 0x81, 0x59, 0xab, 0x16, 0xd8, 0x7b, 0x54, 0x51, 0x10, 0x0d, - 0x78, 0x8b, 0xa4, 0x30, 0x5b, 0x8e, 0x41, 0x31, 0x81, 0x4d, 0x3e, 0x04, 0x4b, 0x7e, 0xcd, 0x6a, - 0xd2, 0x6b, 0x6d, 0xc9, 0x6a, 0x65, 0x97, 0xd6, 0x6e, 0x6e, 0xba, 0xb6, 0x13, 0x48, 0x6f, 0xc4, - 0x43, 0x92, 0xd2, 0x52, 0xb5, 0x0f, 0x1e, 0xf6, 0xa5, 0x40, 0xfe, 0xd8, 0x80, 0x33, 0x6d, 0x8f, - 0x6e, 0x7a, 0x6e, 0xcb, 0x65, 0x6a, 0xa6, 0xe7, 0x88, 0x2e, 0x8f, 0xaa, 0xcf, 0x8f, 0xa8, 0x4f, - 0x45, 0x49, 0xaf, 0x8b, 0xf0, 0xad, 0x07, 0xdd, 0xd2, 0x99, 0xcd, 0xc3, 0x1a, 0x80, 0x87, 0xb7, - 0x8f, 0xfc, 0xa9, 0x01, 0x67, 0xdb, 0xae, 0x1f, 0x1c, 0xd2, 0x85, 0xc2, 0xb1, 0x76, 0xc1, 0x3c, - 0xe8, 0x96, 0xce, 0x6e, 0x1e, 0xda, 0x02, 0xbc, 0x4b, 0x0b, 0xcd, 0x83, 0x29, 0x58, 0xd0, 0xd6, - 0x9e, 0x3c, 0xbf, 0x3e, 0x0d, 0x33, 0xe1, 0x62, 0x88, 0xd4, 0xfa, 0x64, 0xe4, 0x6f, 0x28, 0xeb, - 0x40, 0x8c, 0xe3, 0xb2, 0x75, 0xa7, 0x96, 0xa2, 0xa8, 0x9d, 0x58, 0x77, 0x9b, 0x31, 0x28, 0x26, - 0xb0, 0xc9, 0x1a, 0x9c, 0x90, 0x25, 0x48, 0xdb, 0x4d, 0xbb, 0x66, 0xad, 0xb8, 0x1d, 0xb9, 0xe4, - 0x0a, 0x95, 0x53, 0x07, 0xdd, 0xd2, 0x89, 0xcd, 0x5e, 0x30, 0xa6, 0xd5, 0x21, 0xeb, 0xb0, 0x68, - 0x75, 0x02, 0x57, 0xf5, 0xff, 0xbc, 0xc3, 0x34, 0x45, 0x9d, 0x2f, 0xad, 0xa2, 0x50, 0x29, 0xe5, - 0x14, 0x38, 0xa6, 0xd6, 0x22, 0x9b, 0x09, 0x6a, 0x55, 0x5a, 0x73, 0x9d, 0xba, 0x98, 0xe5, 0x42, - 0x64, 0x85, 0x97, 0x53, 0x70, 0x30, 0xb5, 0x26, 0x69, 0xc2, 0x6c, 0xcb, 0xba, 0x7d, 0xcd, 0xb1, - 0xf6, 0x2c, 0xbb, 0xc9, 0x98, 0x48, 0x1f, 0x46, 0xff, 0x83, 0x75, 0x27, 0xb0, 0x9b, 0xcb, 0xe2, - 0x3a, 0x6f, 0x79, 0xcd, 0x09, 0xae, 0x78, 0xd5, 0x80, 0x59, 0x6b, 0xc2, 0x38, 0xda, 0x88, 0xd1, - 0xc2, 0x04, 0x6d, 0x72, 0x05, 0x4e, 0xf2, 0xed, 0xb8, 0xea, 0xde, 0x72, 0x56, 0x69, 0xd3, 0xda, - 0x0f, 0x3b, 0x30, 0xc1, 0x3b, 0x70, 0xff, 0x41, 0xb7, 0x74, 0xb2, 0x9a, 0x86, 0x80, 0xe9, 0xf5, - 0x88, 0x05, 0x0f, 0xc4, 0x01, 0x48, 0xf7, 0x6c, 0xdf, 0x76, 0x1d, 0xe1, 0x89, 0x28, 0x46, 0x9e, - 0x88, 0x6a, 0x7f, 0x34, 0x3c, 0x8c, 0x06, 0xf9, 0x0d, 0x03, 0x16, 0xd3, 0xb6, 0xe1, 0xd2, 0x64, - 0x16, 0x97, 0x15, 0x89, 0xad, 0x25, 0x56, 0x44, 0xaa, 0x50, 0x48, 0x6d, 0x04, 0x79, 0xd9, 0x80, - 0x69, 0x4b, 0x3b, 0x45, 0x2d, 0x01, 0x6f, 0xd5, 0xa5, 0x51, 0xcf, 0xf2, 0x11, 0xc5, 0xca, 0xfc, - 0x41, 0xb7, 0x14, 0x3b, 0xa9, 0x61, 0x8c, 0x23, 0xf9, 0x4d, 0x03, 0x4e, 0xa6, 0xee, 0xf1, 0xa5, - 0xa9, 0xe3, 0x18, 0x21, 0xbe, 0x48, 0xd2, 0x65, 0x4e, 0x7a, 0x33, 0xc8, 0xeb, 0x86, 0x52, 0x65, - 0x1b, 0xa1, 0x37, 0x65, 0x9a, 0x37, 0xed, 0xea, 0x88, 0x07, 0xc7, 0xc8, 0x20, 0x08, 0x09, 0x57, - 0x4e, 0x68, 0x9a, 0x31, 0x2c, 0xc4, 0x24, 0x7b, 0xf2, 0x59, 0x23, 0x54, 0x8d, 0xaa, 0x45, 0x33, - 0xc7, 0xd5, 0x22, 0x12, 0x69, 0x5a, 0xd5, 0xa0, 0x04, 0x73, 0xf2, 0x61, 0x38, 0x6d, 0x6d, 0xbb, - 0x5e, 0x90, 0xba, 0xf9, 0x96, 0x66, 0xf9, 0x36, 0x3a, 0x7b, 0xd0, 0x2d, 0x9d, 0x2e, 0xf7, 0xc5, - 0xc2, 0x43, 0x28, 0x98, 0x3f, 0x18, 0x83, 0x69, 0x61, 0xe4, 0x4b, 0xd5, 0xf5, 0x75, 0x03, 0x1e, - 0xac, 0x75, 0x3c, 0x8f, 0x3a, 0x41, 0x35, 0xa0, 0xed, 0x5e, 0xc5, 0x65, 0x1c, 0xab, 0xe2, 0x7a, - 0xe8, 0xa0, 0x5b, 0x7a, 0x70, 0xe5, 0x10, 0xfe, 0x78, 0x68, 0xeb, 0xc8, 0x5f, 0x1a, 0x60, 0x4a, - 0x84, 0x8a, 0x55, 0xbb, 0xd9, 0xf0, 0xdc, 0x8e, 0x53, 0xef, 0xed, 0x44, 0xee, 0x58, 0x3b, 0xf1, - 0xc8, 0x41, 0xb7, 0x64, 0xae, 0xdc, 0xb5, 0x15, 0x38, 0x40, 0x4b, 0xc9, 0xb3, 0xb0, 0x20, 0xb1, - 0xce, 0xdf, 0x6e, 0x53, 0xcf, 0x66, 0xe6, 0xb4, 0xbc, 0x4f, 0x8f, 0x42, 0x14, 0x92, 0x08, 0xd8, - 0x5b, 0x87, 0xf8, 0x30, 0x71, 0x8b, 0xda, 0x8d, 0xdd, 0x20, 0x34, 0x9f, 0x46, 0x8c, 0x4b, 0x90, - 0x07, 0xfe, 0xeb, 0x82, 0x66, 0x65, 0xea, 0xa0, 0x5b, 0x9a, 0x90, 0x7f, 0x30, 0xe4, 0x64, 0xfe, - 0xfe, 0x18, 0x40, 0xb8, 0xbc, 0x68, 0x9b, 0xfc, 0x1f, 0x98, 0xf4, 0x69, 0x20, 0xb0, 0xa4, 0xb3, - 0x5b, 0xdc, 0x21, 0x84, 0x85, 0x18, 0xc1, 0xc9, 0x4d, 0x28, 0xb4, 0xad, 0x8e, 0x4f, 0xe5, 0x64, - 0x5d, 0xca, 0x64, 0xb2, 0x36, 0x19, 0x45, 0x71, 0x46, 0xe2, 0x3f, 0x51, 0xf0, 0x20, 0x9f, 0x32, - 0x00, 0x68, 0x7c, 0x80, 0x47, 0xf6, 0x55, 0x48, 0x96, 0xd1, 0x1c, 0xb0, 0x31, 0xa8, 0xcc, 0x1e, - 0x74, 0x4b, 0xa0, 0x4d, 0x95, 0xc6, 0x96, 0xdc, 0x82, 0xa2, 0x15, 0xca, 0xe8, 0xb1, 0xe3, 0x90, - 0xd1, 0xfc, 0xe8, 0xa2, 0x16, 0x99, 0x62, 0x46, 0x3e, 0x6d, 0xc0, 0xac, 0x4f, 0x03, 0x39, 0x55, - 0x4c, 0x52, 0x48, 0x03, 0x75, 0xc4, 0x45, 0x52, 0x8d, 0xd1, 0x14, 0x12, 0x2f, 0x5e, 0x86, 0x09, - 0xbe, 0xe6, 0x0f, 0xa6, 0x60, 0x36, 0x5c, 0x32, 0x91, 0xcd, 0x29, 0x5c, 0x0e, 0x7d, 0x6c, 0xce, - 0x15, 0x1d, 0x88, 0x71, 0x5c, 0x56, 0x59, 0x78, 0x01, 0xe2, 0x26, 0xa7, 0xaa, 0x5c, 0xd5, 0x81, - 0x18, 0xc7, 0x25, 0x2d, 0x28, 0xf8, 0x01, 0x6d, 0x87, 0x37, 0x74, 0x23, 0x5e, 0x20, 0x45, 0x3b, - 0x21, 0xf2, 0xc1, 0xb3, 0x7f, 0x3e, 0x0a, 0x2e, 0xdc, 0x6b, 0x16, 0xc4, 0x1c, 0x69, 0x72, 0x19, - 0x64, 0xb3, 0x12, 0xe3, 0x3e, 0x3a, 0x31, 0x1b, 0xf1, 0x32, 0x4c, 0xb0, 0x4f, 0x31, 0x43, 0x0b, - 0xc7, 0x68, 0x86, 0xbe, 0x00, 0xc5, 0x96, 0x75, 0xbb, 0xda, 0xf1, 0x1a, 0x47, 0x37, 0x77, 0x65, - 0xf0, 0x8c, 0xa0, 0x82, 0x8a, 0x1e, 0x79, 0xc5, 0xd0, 0x36, 0xd7, 0x04, 0x27, 0x7e, 0x3d, 0xdb, - 0xcd, 0xa5, 0xa4, 0x78, 0xdf, 0x6d, 0xd6, 0x63, 0x14, 0x16, 0xef, 0xb9, 0x51, 0xc8, 0x0c, 0x1c, - 0xb1, 0x41, 0x94, 0x81, 0x33, 0x79, 0xac, 0x06, 0xce, 0x4a, 0x8c, 0x19, 0x26, 0x98, 0xf3, 0xf6, - 0x88, 0x3d, 0xa7, 0xda, 0x03, 0xc7, 0xda, 0x9e, 0x6a, 0x8c, 0x19, 0x26, 0x98, 0xf7, 0x3f, 0x09, - 0x4d, 0x1d, 0xcf, 0x49, 0x68, 0x3a, 0x83, 0x93, 0xd0, 0xe1, 0x46, 0xe2, 0xcc, 0xa8, 0x46, 0x22, - 0xb9, 0x04, 0xa4, 0xbe, 0xef, 0x58, 0x2d, 0xbb, 0x26, 0x85, 0x25, 0x57, 0x10, 0xb3, 0xfc, 0xa4, - 0x7c, 0x5a, 0x0a, 0x32, 0xb2, 0xda, 0x83, 0x81, 0x29, 0xb5, 0xcc, 0xff, 0x30, 0x60, 0x7e, 0xa5, - 0xe9, 0x76, 0xea, 0xd7, 0xad, 0xa0, 0xb6, 0x2b, 0xee, 0xfe, 0xc8, 0x33, 0x50, 0xb4, 0x9d, 0x80, - 0x7a, 0x7b, 0x56, 0x53, 0xca, 0x76, 0x33, 0xbc, 0x1e, 0x5d, 0x93, 0xe5, 0x77, 0xba, 0xa5, 0xd9, - 0xd5, 0x8e, 0xc7, 0x83, 0xea, 0xc4, 0x4e, 0x47, 0x55, 0x87, 0x7c, 0xd9, 0x80, 0x05, 0x71, 0x7b, - 0xb8, 0x6a, 0x05, 0xd6, 0xd5, 0x0e, 0xf5, 0x6c, 0x1a, 0xde, 0x1f, 0x8e, 0xb8, 0xc9, 0x93, 0x6d, - 0x0d, 0x19, 0xec, 0x47, 0xe6, 0xd7, 0x46, 0x92, 0x33, 0xf6, 0x36, 0xc6, 0xfc, 0x7c, 0x1e, 0xee, - 0xef, 0x4b, 0x8b, 0x9c, 0x86, 0x9c, 0x5d, 0x97, 0x5d, 0x07, 0x49, 0x37, 0xb7, 0x56, 0xc7, 0x9c, - 0x5d, 0x27, 0xcb, 0xdc, 0x32, 0xf1, 0xa8, 0xef, 0x87, 0x57, 0x49, 0x93, 0xca, 0x88, 0x90, 0xa5, - 0xa8, 0x61, 0x90, 0x12, 0x14, 0x9a, 0xd6, 0x36, 0x6d, 0x4a, 0x2b, 0x91, 0xdb, 0x3a, 0xeb, 0xac, - 0x00, 0x45, 0x39, 0xf9, 0x05, 0x03, 0x40, 0x34, 0x90, 0xd9, 0x98, 0x52, 0xc3, 0x60, 0xb6, 0xc3, - 0xc4, 0x28, 0x8b, 0x56, 0x46, 0xff, 0x51, 0xe3, 0x4a, 0xb6, 0x60, 0x9c, 0x99, 0x3d, 0x6e, 0xfd, - 0xc8, 0x0a, 0x85, 0xbb, 0xce, 0x37, 0x39, 0x0d, 0x94, 0xb4, 0xd8, 0x58, 0x79, 0x34, 0xe8, 0x78, - 0x0e, 0x1b, 0x5a, 0xae, 0x42, 0x8a, 0xa2, 0x15, 0xa8, 0x4a, 0x51, 0xc3, 0x30, 0xff, 0x28, 0x07, - 0x8b, 0x69, 0x4d, 0x67, 0x92, 0x7a, 0x5c, 0xb4, 0x56, 0x1e, 0x78, 0xde, 0x9f, 0xfd, 0xf8, 0xc8, - 0x8b, 0x70, 0x75, 0x5d, 0x2c, 0x43, 0x75, 0x24, 0x5f, 0xf2, 0x7e, 0x35, 0x42, 0xb9, 0x23, 0x8e, - 0x90, 0xa2, 0x9c, 0x18, 0xa5, 0x87, 0x60, 0xcc, 0x67, 0x33, 0x9f, 0x8f, 0xbb, 0xa5, 0xf9, 0x1c, - 0x71, 0x08, 0xc3, 0xe8, 0x38, 0x76, 0x20, 0x23, 0x5d, 0x15, 0xc6, 0x35, 0xc7, 0x0e, 0x90, 0x43, - 0xcc, 0x2f, 0xe6, 0xe0, 0x74, 0xff, 0x4e, 0x91, 0x2f, 0x1a, 0x00, 0x75, 0x66, 0xd4, 0xb2, 0x25, - 0x19, 0x06, 0x0e, 0x58, 0xc7, 0x35, 0x86, 0xab, 0x21, 0xa7, 0x28, 0x8a, 0x44, 0x15, 0xf9, 0xa8, - 0x35, 0x84, 0x3c, 0x16, 0x2e, 0xfd, 0xcb, 0x56, 0x2b, 0x34, 0x05, 0x55, 0x9d, 0x0d, 0x05, 0x41, - 0x0d, 0x8b, 0x9d, 0x5a, 0x1c, 0xab, 0x45, 0xfd, 0xb6, 0xa5, 0x42, 0x99, 0xf9, 0xa9, 0xe5, 0x72, - 0x58, 0x88, 0x11, 0xdc, 0x6c, 0xc2, 0xc3, 0x03, 0xb4, 0x33, 0xa3, 0xb0, 0x52, 0xf3, 0xdf, 0x0d, - 0x38, 0xb5, 0xd2, 0xec, 0xf8, 0x01, 0xf5, 0xfe, 0xc7, 0x04, 0xe5, 0xfc, 0xa7, 0x01, 0x0f, 0xf4, - 0xe9, 0xf3, 0x3d, 0x88, 0xcd, 0x79, 0x29, 0x1e, 0x9b, 0x73, 0x6d, 0xd4, 0x25, 0x9d, 0xda, 0x8f, - 0x3e, 0x21, 0x3a, 0x01, 0xcc, 0x30, 0xa9, 0x55, 0x77, 0x1b, 0x19, 0xe9, 0xcd, 0x87, 0xa1, 0xf0, - 0x51, 0xa6, 0x7f, 0x92, 0x6b, 0x8c, 0x2b, 0x25, 0x14, 0x30, 0xf3, 0x7d, 0x20, 0x03, 0x59, 0x12, - 0x9b, 0xc7, 0x18, 0x64, 0xf3, 0x98, 0x7f, 0x9b, 0x03, 0xed, 0xb4, 0x7b, 0x0f, 0x16, 0xa5, 0x13, - 0x5b, 0x94, 0x23, 0x9e, 0x5f, 0xb5, 0xb3, 0x7b, 0xbf, 0x88, 0xf5, 0xbd, 0x44, 0xc4, 0xfa, 0xe5, - 0xcc, 0x38, 0x1e, 0x1e, 0xb0, 0xfe, 0x5d, 0x03, 0x1e, 0x88, 0x90, 0x7b, 0x1d, 0x47, 0x77, 0x97, - 0x30, 0x4f, 0xc2, 0x94, 0x15, 0x55, 0x93, 0x6b, 0x40, 0x3d, 0xd2, 0xd0, 0x28, 0xa2, 0x8e, 0x17, - 0xc5, 0xc7, 0xe6, 0x8f, 0x18, 0x1f, 0x3b, 0x76, 0x78, 0x7c, 0xac, 0xf9, 0xe3, 0x1c, 0x9c, 0xe9, - 0xed, 0x59, 0xb8, 0x37, 0x06, 0xbb, 0x57, 0x7d, 0x0a, 0xa6, 0x03, 0x59, 0x41, 0x93, 0xf4, 0xea, - 0x89, 0xd1, 0x96, 0x06, 0xc3, 0x18, 0x26, 0xab, 0x59, 0x13, 0xbb, 0xb2, 0x5a, 0x73, 0xdb, 0x61, - 0x74, 0xb5, 0xaa, 0xb9, 0xa2, 0xc1, 0x30, 0x86, 0xa9, 0xe2, 0xd6, 0xc6, 0x8e, 0x3d, 0x6e, 0xad, - 0x0a, 0x27, 0xc3, 0x48, 0x9d, 0x0b, 0xae, 0xb7, 0xe2, 0xb6, 0xda, 0x4d, 0x2a, 0xe3, 0xab, 0x59, - 0x63, 0xcf, 0xc8, 0x2a, 0x27, 0x31, 0x0d, 0x09, 0xd3, 0xeb, 0x9a, 0xdf, 0xcd, 0xc3, 0x89, 0x68, - 0xd8, 0x57, 0x5c, 0xa7, 0x6e, 0xf3, 0x78, 0xa7, 0xa7, 0x61, 0x2c, 0xd8, 0x6f, 0x87, 0x83, 0xfd, - 0xbf, 0xc2, 0xe6, 0x6c, 0xed, 0xb7, 0xd9, 0x6c, 0x9f, 0x4a, 0xa9, 0xc2, 0x40, 0xc8, 0x2b, 0x91, - 0x75, 0xb5, 0x3b, 0xc4, 0x0c, 0x3c, 0x11, 0x5f, 0xcd, 0x77, 0xba, 0xa5, 0x94, 0x17, 0x76, 0xcb, - 0x8a, 0x52, 0x7c, 0xcd, 0x93, 0x1b, 0x30, 0xdb, 0xb4, 0xfc, 0xe0, 0x5a, 0xbb, 0x6e, 0x05, 0x74, - 0xcb, 0x6e, 0x51, 0xb9, 0xe7, 0x86, 0x09, 0x5a, 0x56, 0x77, 0x8d, 0xeb, 0x31, 0x4a, 0x98, 0xa0, - 0x4c, 0xf6, 0x80, 0xb0, 0x92, 0x2d, 0xcf, 0x72, 0x7c, 0xd1, 0x2b, 0xc6, 0x6f, 0xf8, 0x20, 0x69, - 0x75, 0x40, 0x5a, 0xef, 0xa1, 0x86, 0x29, 0x1c, 0xc8, 0x23, 0x30, 0xee, 0x51, 0xcb, 0x97, 0x93, - 0x39, 0x19, 0xed, 0x7f, 0xe4, 0xa5, 0x28, 0xa1, 0xfa, 0x86, 0x1a, 0xbf, 0xcb, 0x86, 0xfa, 0xa1, - 0x01, 0xb3, 0xd1, 0x34, 0xdd, 0x03, 0x25, 0xd9, 0x8a, 0x2b, 0xc9, 0x8b, 0x59, 0x89, 0xc4, 0x3e, - 0x7a, 0xf1, 0xcf, 0xc6, 0xf5, 0xfe, 0xf1, 0xa0, 0xd5, 0x8f, 0xc1, 0x64, 0xb8, 0xab, 0x43, 0xeb, - 0x73, 0x44, 0x2f, 0x4b, 0xcc, 0x2e, 0xd1, 0x1e, 0x5b, 0x48, 0x26, 0x18, 0xf1, 0x63, 0x6a, 0xb9, - 0x2e, 0x55, 0xae, 0x5c, 0xf6, 0x4a, 0x2d, 0x87, 0xaa, 0x38, 0x4d, 0x2d, 0x87, 0x75, 0xc8, 0x35, - 0x38, 0xd5, 0xf6, 0x5c, 0xfe, 0x00, 0x6f, 0x95, 0x5a, 0xf5, 0xa6, 0xed, 0xd0, 0xf0, 0x30, 0x2f, - 0xae, 0xba, 0x1f, 0x38, 0xe8, 0x96, 0x4e, 0x6d, 0xa6, 0xa3, 0x60, 0xbf, 0xba, 0xf1, 0x47, 0x23, - 0x63, 0x03, 0x3c, 0x1a, 0xf9, 0x25, 0xe5, 0x32, 0xa3, 0xbe, 0x7c, 0xba, 0xf1, 0xc1, 0xac, 0xa6, - 0x32, 0x45, 0xac, 0x47, 0x4b, 0xaa, 0x2c, 0x99, 0xa2, 0x62, 0xdf, 0xdf, 0x2f, 0x33, 0x7e, 0x44, - 0xbf, 0x4c, 0x14, 0xfb, 0x3b, 0xf1, 0xd3, 0x8c, 0xfd, 0x2d, 0xbe, 0xa9, 0x62, 0x7f, 0x5f, 0x2d, - 0xc0, 0x7c, 0xd2, 0x02, 0x39, 0xfe, 0x07, 0x31, 0xbf, 0x6a, 0xc0, 0x7c, 0xb8, 0x7b, 0x04, 0x4f, - 0x1a, 0x7a, 0xdc, 0xd7, 0x33, 0xda, 0xb4, 0xc2, 0x96, 0x52, 0x4f, 0x36, 0xb7, 0x12, 0xdc, 0xb0, - 0x87, 0x3f, 0x79, 0x11, 0xa6, 0x94, 0x63, 0xfa, 0x48, 0xaf, 0x63, 0xe6, 0xb8, 0x15, 0x15, 0x91, - 0x40, 0x9d, 0x1e, 0x79, 0xd5, 0x00, 0xa8, 0x85, 0x6a, 0x2e, 0xdc, 0x5d, 0x57, 0xb3, 0xda, 0x5d, - 0x4a, 0x81, 0x46, 0xc6, 0xb2, 0x2a, 0xf2, 0x51, 0x63, 0x4c, 0x3e, 0xcf, 0x5d, 0xd2, 0xca, 0xba, - 0x63, 0xfb, 0x29, 0x3f, 0x7a, 0xb8, 0xe6, 0x21, 0x86, 0x69, 0x64, 0x4a, 0x69, 0x20, 0x1f, 0x63, - 0x8d, 0x30, 0x9f, 0x06, 0x15, 0x60, 0xc7, 0xc4, 0x16, 0x0f, 0xb1, 0xdb, 0xb4, 0x82, 0x5d, 0xb9, - 0x04, 0x95, 0xd8, 0xba, 0x10, 0x02, 0x30, 0xc2, 0x31, 0x3f, 0x02, 0xb3, 0xcf, 0x7a, 0x56, 0x7b, - 0xd7, 0xe6, 0xae, 0x5f, 0x76, 0x4e, 0x7a, 0x3b, 0x4c, 0x58, 0xf5, 0x7a, 0xda, 0x83, 0xe7, 0xb2, - 0x28, 0xc6, 0x10, 0x3e, 0xd8, 0x91, 0xe8, 0x9b, 0x06, 0x2c, 0xae, 0xf9, 0x81, 0xed, 0xae, 0x52, - 0x3f, 0x60, 0xb2, 0x92, 0xed, 0xa8, 0x4e, 0x73, 0x90, 0x00, 0xd0, 0x55, 0x98, 0x97, 0xf7, 0x53, - 0x9d, 0x6d, 0x9f, 0x06, 0x9a, 0x71, 0xaa, 0x16, 0xe7, 0x4a, 0x02, 0x8e, 0x3d, 0x35, 0x18, 0x15, - 0x79, 0x51, 0x15, 0x51, 0xc9, 0xc7, 0xa9, 0x54, 0x13, 0x70, 0xec, 0xa9, 0x61, 0x7e, 0x27, 0x0f, - 0x27, 0x78, 0x37, 0x12, 0xc1, 0xdb, 0x9f, 0xed, 0x17, 0xbc, 0x3d, 0xe2, 0xfa, 0xe4, 0xbc, 0x8e, - 0x10, 0xba, 0xfd, 0x2b, 0x06, 0xcc, 0xd5, 0xe3, 0x23, 0x9d, 0x8d, 0xcf, 0x21, 0x6d, 0x0e, 0x45, - 0xa0, 0x48, 0xa2, 0x10, 0x93, 0xfc, 0xc9, 0x17, 0x0c, 0x98, 0x8b, 0x37, 0x33, 0x14, 0x59, 0xc7, - 0x30, 0x48, 0x2a, 0xb2, 0x33, 0x5e, 0xee, 0x63, 0xb2, 0x09, 0xe6, 0x5f, 0x1b, 0x72, 0x4a, 0x8f, - 0x23, 0x32, 0x99, 0xdc, 0x82, 0xc9, 0xa0, 0xe9, 0x8b, 0x42, 0xd9, 0xdb, 0x11, 0x8f, 0x39, 0x5b, - 0xeb, 0x55, 0x4e, 0x4e, 0xb3, 0x44, 0x64, 0x09, 0xb3, 0xa8, 0x42, 0x5e, 0xe6, 0x57, 0x0d, 0x98, - 0xbc, 0xe4, 0x6e, 0xcb, 0xed, 0xfc, 0xe1, 0x0c, 0x9c, 0x08, 0xca, 0xd6, 0x50, 0x37, 0x41, 0x91, - 0xf9, 0xfa, 0x4c, 0xcc, 0x85, 0xf0, 0xa0, 0x46, 0x7b, 0x99, 0x27, 0x0a, 0x61, 0xa4, 0x2e, 0xb9, - 0xdb, 0x7d, 0x3d, 0x54, 0xbf, 0x55, 0x80, 0x99, 0xe7, 0xac, 0x7d, 0xea, 0x04, 0xd6, 0xf0, 0x02, - 0x88, 0x9d, 0xca, 0xdb, 0x3c, 0x50, 0x51, 0xb3, 0x1f, 0xa3, 0x53, 0x79, 0x04, 0x42, 0x1d, 0x2f, - 0x92, 0x2b, 0x22, 0x6f, 0x41, 0x9a, 0x44, 0x58, 0x49, 0xc0, 0xb1, 0xa7, 0x06, 0xb9, 0x04, 0x44, - 0xbe, 0xc2, 0x2a, 0xd7, 0x6a, 0x6e, 0xc7, 0x11, 0x92, 0x45, 0x1c, 0xd8, 0xd5, 0x41, 0x66, 0xa3, - 0x07, 0x03, 0x53, 0x6a, 0x91, 0x0f, 0xc1, 0x52, 0x8d, 0x53, 0x96, 0x66, 0xad, 0x4e, 0x51, 0x1c, - 0x6d, 0x54, 0x90, 0xf0, 0x4a, 0x1f, 0x3c, 0xec, 0x4b, 0x81, 0xb5, 0xd4, 0x0f, 0x5c, 0xcf, 0x6a, - 0x50, 0x9d, 0xee, 0x78, 0xbc, 0xa5, 0xd5, 0x1e, 0x0c, 0x4c, 0xa9, 0x45, 0x3e, 0x09, 0x93, 0xc1, - 0xae, 0x47, 0xfd, 0x5d, 0xb7, 0x59, 0x97, 0x57, 0xc3, 0x23, 0x7a, 0x71, 0xe4, 0xec, 0x6f, 0x85, - 0x54, 0xb5, 0xe5, 0x1d, 0x16, 0x61, 0xc4, 0x93, 0x78, 0x30, 0xee, 0xd7, 0xdc, 0x36, 0xf5, 0xa5, - 0x39, 0x78, 0x29, 0x13, 0xee, 0xdc, 0x2b, 0xa1, 0xf9, 0x8f, 0x38, 0x07, 0x94, 0x9c, 0xcc, 0x6f, - 0xe5, 0x60, 0x5a, 0x47, 0x1c, 0x40, 0x44, 0x7c, 0xca, 0x80, 0xe9, 0x9a, 0xeb, 0x04, 0x9e, 0xdb, - 0x14, 0xbe, 0x11, 0xb1, 0x41, 0x46, 0x7c, 0xdc, 0xcf, 0x49, 0xad, 0xd2, 0xc0, 0xb2, 0x9b, 0x9a, - 0x9b, 0x45, 0x63, 0x83, 0x31, 0xa6, 0xe4, 0x33, 0x06, 0xcc, 0x45, 0x31, 0x33, 0x91, 0x93, 0x26, - 0xd3, 0x86, 0x28, 0x89, 0x7b, 0x3e, 0xce, 0x09, 0x93, 0xac, 0xcd, 0x6d, 0x98, 0x4f, 0xce, 0x36, - 0x1b, 0xca, 0xb6, 0x25, 0xf7, 0x7a, 0x3e, 0x1a, 0xca, 0x4d, 0xcb, 0xf7, 0x91, 0x43, 0xc8, 0x3b, - 0xa0, 0xd8, 0xb2, 0xbc, 0x86, 0xed, 0x58, 0x4d, 0x3e, 0x8a, 0x79, 0x4d, 0x20, 0xc9, 0x72, 0x54, - 0x18, 0xe6, 0x8f, 0xc6, 0x60, 0x4a, 0xb3, 0xe2, 0x8f, 0xdf, 0x22, 0x8f, 0x3d, 0x0c, 0xcf, 0x67, - 0xf8, 0x30, 0xfc, 0x05, 0x80, 0x1d, 0xdb, 0xb1, 0xfd, 0xdd, 0x23, 0x3e, 0x39, 0xe7, 0x97, 0x79, - 0x17, 0x14, 0x05, 0xd4, 0xa8, 0x45, 0x37, 0x26, 0x85, 0x43, 0x12, 0x71, 0xbc, 0x6a, 0x68, 0xca, - 0x63, 0x3c, 0x8b, 0x1b, 0x62, 0x6d, 0x62, 0x96, 0x43, 0x65, 0x72, 0xde, 0x09, 0xbc, 0xfd, 0x43, - 0x75, 0xcc, 0x16, 0x14, 0x3d, 0xea, 0x77, 0x5a, 0xec, 0x6c, 0x31, 0x31, 0xf4, 0x30, 0xf0, 0x00, - 0x13, 0x94, 0xf5, 0x51, 0x51, 0x3a, 0xfd, 0x34, 0xcc, 0xc4, 0x9a, 0x40, 0xe6, 0x21, 0x7f, 0x93, - 0xee, 0x8b, 0x75, 0x82, 0xec, 0x27, 0x59, 0x8c, 0xdd, 0x2b, 0xc9, 0x61, 0x79, 0x6f, 0xee, 0x29, - 0xc3, 0x74, 0x21, 0xf5, 0xa8, 0x78, 0x14, 0xb7, 0x3f, 0x9b, 0x8b, 0xa6, 0xf6, 0xe6, 0x5c, 0xcd, - 0x85, 0x88, 0x66, 0x10, 0x30, 0xf3, 0xc7, 0xe3, 0x20, 0x2f, 0x3d, 0x07, 0x10, 0x3e, 0xfa, 0x5d, - 0x47, 0xee, 0x08, 0x77, 0x1d, 0x97, 0x60, 0xda, 0x76, 0xec, 0xc0, 0xb6, 0x9a, 0xdc, 0x0d, 0x20, - 0x95, 0xe3, 0x23, 0xa1, 0xc0, 0x59, 0xd3, 0x60, 0x29, 0x74, 0x62, 0x75, 0xc9, 0x55, 0x28, 0x70, - 0xed, 0x21, 0x17, 0xf0, 0xf0, 0x37, 0xb3, 0xfc, 0x52, 0x5e, 0xbc, 0x4e, 0x10, 0x94, 0xb8, 0x45, - 0x2f, 0x1e, 0xdd, 0xab, 0x83, 0x9a, 0x5c, 0xc7, 0x91, 0x45, 0x9f, 0x80, 0x63, 0x4f, 0x0d, 0x46, - 0x65, 0xc7, 0xb2, 0x9b, 0x1d, 0x8f, 0x46, 0x54, 0xc6, 0xe3, 0x54, 0x2e, 0x24, 0xe0, 0xd8, 0x53, - 0x83, 0xec, 0xc0, 0xb4, 0x2c, 0x13, 0x31, 0x2a, 0x13, 0x47, 0xec, 0x25, 0x8f, 0x45, 0xba, 0xa0, - 0x51, 0xc2, 0x18, 0x5d, 0xd2, 0x81, 0x05, 0xdb, 0xa9, 0xb9, 0x4e, 0xad, 0xd9, 0xf1, 0xed, 0x3d, - 0x1a, 0x3d, 0x0d, 0x38, 0x0a, 0xb3, 0x93, 0x07, 0xdd, 0xd2, 0xc2, 0x5a, 0x92, 0x1c, 0xf6, 0x72, - 0x20, 0xaf, 0x18, 0x70, 0xb2, 0xe6, 0x3a, 0x3e, 0x7f, 0xc5, 0xba, 0x47, 0xcf, 0x7b, 0x9e, 0xeb, - 0x09, 0xde, 0x93, 0x47, 0xe4, 0xcd, 0xbd, 0x4f, 0x2b, 0x69, 0x24, 0x31, 0x9d, 0x13, 0x79, 0x09, - 0x8a, 0x6d, 0xcf, 0xdd, 0xb3, 0xeb, 0xd4, 0x93, 0xf1, 0x4e, 0xeb, 0x59, 0xbc, 0xaa, 0xdf, 0x94, - 0x34, 0x23, 0xd1, 0x13, 0x96, 0xa0, 0xe2, 0x67, 0xfe, 0x5e, 0x11, 0x66, 0xe3, 0xe8, 0xe4, 0x13, - 0x00, 0x6d, 0xcf, 0x6d, 0xd1, 0x60, 0x97, 0xaa, 0x10, 0xef, 0xcb, 0xa3, 0x3e, 0xde, 0x0e, 0xe9, - 0x85, 0x71, 0x0e, 0x4c, 0x5c, 0x44, 0xa5, 0xa8, 0x71, 0x24, 0x1e, 0x4c, 0xdc, 0x14, 0x4a, 0x54, - 0xda, 0x14, 0xcf, 0x65, 0x62, 0x01, 0x49, 0xce, 0x3c, 0x36, 0x59, 0x16, 0x61, 0xc8, 0x88, 0x6c, - 0x43, 0xfe, 0x16, 0xdd, 0xce, 0xe6, 0x41, 0xe4, 0x75, 0x2a, 0xcf, 0x26, 0x95, 0x89, 0x83, 0x6e, - 0x29, 0x7f, 0x9d, 0x6e, 0x23, 0x23, 0xce, 0xfa, 0x55, 0x17, 0x37, 0xb6, 0x52, 0x54, 0x8c, 0xd8, - 0xaf, 0xd8, 0xf5, 0xaf, 0xe8, 0x97, 0x2c, 0xc2, 0x90, 0x11, 0x79, 0x09, 0x26, 0x6f, 0x59, 0x7b, - 0x74, 0xc7, 0x73, 0x9d, 0x40, 0x06, 0xd7, 0x8c, 0x18, 0x45, 0x7c, 0x3d, 0x24, 0x27, 0xf9, 0x72, - 0xf5, 0xae, 0x0a, 0x31, 0x62, 0x47, 0xf6, 0xa0, 0xe8, 0xd0, 0x5b, 0x48, 0x9b, 0x76, 0x4d, 0x06, - 0x70, 0x8e, 0xb8, 0xac, 0x2f, 0x4b, 0x6a, 0x92, 0x33, 0xd7, 0x7b, 0x61, 0x19, 0x2a, 0x5e, 0x6c, - 0x2e, 0x6f, 0xb8, 0xdb, 0x52, 0x50, 0x8d, 0x38, 0x97, 0xea, 0x9c, 0x29, 0xe6, 0xf2, 0x92, 0xbb, - 0x8d, 0x8c, 0x38, 0xdb, 0x23, 0x35, 0x15, 0xd9, 0x21, 0xc5, 0xd4, 0xe5, 0x6c, 0x23, 0x5a, 0xc4, - 0x1e, 0x89, 0x4a, 0x51, 0xe3, 0xc8, 0xc6, 0xb6, 0x21, 0xdd, 0x5a, 0x52, 0x50, 0x8d, 0x38, 0xb6, - 0x71, 0x27, 0x99, 0x18, 0xdb, 0xb0, 0x0c, 0x15, 0x2f, 0xf3, 0xab, 0xe3, 0x30, 0xad, 0x67, 0x11, - 0x1a, 0x40, 0x57, 0x2b, 0xfb, 0x34, 0x37, 0x8c, 0x7d, 0xca, 0x8e, 0x17, 0x9a, 0x57, 0x3a, 0xf4, - 0x30, 0xac, 0x65, 0x66, 0x9e, 0x45, 0xc7, 0x0b, 0xad, 0xd0, 0xc7, 0x18, 0xd3, 0x21, 0x2e, 0xaa, - 0x99, 0x91, 0x23, 0xcc, 0x80, 0x42, 0xdc, 0xc8, 0x89, 0x29, 0xf6, 0xc7, 0x00, 0xa2, 0x6c, 0x3a, - 0xf2, 0xb6, 0x42, 0x59, 0x4f, 0x5a, 0x96, 0x1f, 0x0d, 0x8b, 0x3c, 0x02, 0xe3, 0x4c, 0x51, 0xd2, - 0xba, 0x7c, 0x7f, 0xa7, 0xce, 0x70, 0x17, 0x78, 0x29, 0x4a, 0x28, 0x79, 0x8a, 0xd9, 0x34, 0x91, - 0x7a, 0x93, 0xcf, 0xea, 0x16, 0x23, 0x9b, 0x26, 0x82, 0x61, 0x0c, 0x93, 0x35, 0x9d, 0x32, 0x6d, - 0xc4, 0x57, 0x92, 0xd6, 0x74, 0xae, 0xa2, 0x50, 0xc0, 0xb8, 0x4f, 0x21, 0xa1, 0xbd, 0xb8, 0xb2, - 0x2a, 0x68, 0x3e, 0x85, 0x04, 0x1c, 0x7b, 0x6a, 0xb0, 0xce, 0xc8, 0x8b, 0x96, 0x29, 0x11, 0x8f, - 0xd7, 0xe7, 0x8a, 0xe4, 0x35, 0xdd, 0x32, 0x9f, 0xe6, 0x53, 0xff, 0xfe, 0xec, 0x32, 0x62, 0x0d, - 0x6e, 0x9a, 0x8f, 0x66, 0x44, 0x7f, 0x04, 0x66, 0xe3, 0x32, 0x8b, 0x2d, 0xa8, 0xb6, 0xe7, 0xee, - 0xd8, 0x4d, 0x9a, 0xf4, 0xfd, 0x6c, 0x8a, 0x62, 0x0c, 0xe1, 0x83, 0x39, 0x9f, 0xff, 0x3c, 0x0f, - 0x27, 0x2e, 0x37, 0x6c, 0xe7, 0x76, 0xc2, 0x6b, 0x9b, 0x96, 0xa9, 0xd2, 0x18, 0x36, 0x53, 0x65, - 0xf4, 0x5c, 0x42, 0xa6, 0x02, 0x4d, 0x7f, 0x2e, 0x11, 0xe6, 0x09, 0x8d, 0xe3, 0x92, 0x1f, 0x1a, - 0xf0, 0xa0, 0x55, 0x17, 0x56, 0xa4, 0xd5, 0x94, 0xa5, 0x11, 0xd3, 0x70, 0x47, 0xfb, 0x23, 0xea, - 0x84, 0xde, 0xce, 0x2f, 0x97, 0x0f, 0xe1, 0x2a, 0x66, 0xfc, 0x6d, 0xb2, 0x07, 0x0f, 0x1e, 0x86, - 0x8a, 0x87, 0x36, 0xff, 0xf4, 0x15, 0x78, 0xeb, 0x5d, 0x19, 0x0d, 0xb5, 0x5a, 0x3e, 0x65, 0xc0, - 0xa4, 0x70, 0x4a, 0x22, 0xdd, 0x61, 0xa2, 0xc2, 0x6a, 0xdb, 0xcf, 0x53, 0xcf, 0x0f, 0x53, 0xe8, - 0x68, 0x07, 0xad, 0xf2, 0xe6, 0x9a, 0x84, 0xa0, 0x86, 0xc5, 0x84, 0xf1, 0x4d, 0xdb, 0xa9, 0xcb, - 0x69, 0x52, 0xc2, 0xf8, 0x39, 0xdb, 0xa9, 0x23, 0x87, 0x28, 0x71, 0x9d, 0xef, 0x9b, 0xcf, 0xe2, - 0x2b, 0x06, 0xcc, 0xf2, 0xd7, 0x50, 0xd1, 0x11, 0xe0, 0x49, 0x15, 0x85, 0x20, 0x9a, 0x71, 0x26, - 0x1e, 0x85, 0x70, 0xa7, 0x5b, 0x9a, 0x12, 0xef, 0xa7, 0xe2, 0x41, 0x09, 0x1f, 0x94, 0x7e, 0x03, - 0x1e, 0x2b, 0x91, 0x1b, 0xfa, 0x58, 0xab, 0xbc, 0x64, 0xd5, 0x90, 0x08, 0x46, 0xf4, 0xcc, 0x3f, - 0xc8, 0xc3, 0x89, 0x94, 0xb0, 0x7e, 0x76, 0xa4, 0x1f, 0xe7, 0x91, 0xcd, 0xe1, 0x4d, 0xff, 0x8b, - 0x99, 0x3f, 0x1d, 0x58, 0xe6, 0x01, 0xd4, 0x72, 0x25, 0x29, 0x01, 0x26, 0x0a, 0x51, 0x32, 0x27, - 0xbf, 0x6e, 0xc0, 0x94, 0xa5, 0x2d, 0x76, 0x11, 0xfc, 0xb0, 0x9d, 0x7d, 0x63, 0x7a, 0xd6, 0xb6, - 0x16, 0xb4, 0x15, 0x2d, 0x65, 0xbd, 0x2d, 0xa7, 0xdf, 0x03, 0x53, 0x5a, 0x17, 0x86, 0x59, 0xa3, - 0xa7, 0x9f, 0x81, 0xf9, 0x91, 0xd6, 0xf8, 0x07, 0x60, 0xd8, 0x9c, 0x4c, 0x4c, 0x65, 0xdc, 0xd2, - 0x1f, 0x09, 0xaa, 0x11, 0x97, 0xaf, 0x04, 0x25, 0xd4, 0xdc, 0x86, 0xf9, 0xe4, 0x31, 0x23, 0xf3, - 0xbb, 0xbe, 0x77, 0xc1, 0x90, 0x59, 0x94, 0xcc, 0xbf, 0xc8, 0xc1, 0x84, 0x7c, 0x1b, 0x74, 0x0f, - 0xe2, 0x1d, 0x6f, 0xc6, 0x2e, 0x2b, 0xd6, 0x32, 0x79, 0xd2, 0xd4, 0x37, 0xd8, 0xd1, 0x4f, 0x04, - 0x3b, 0x3e, 0x97, 0x0d, 0xbb, 0xc3, 0x23, 0x1d, 0xbf, 0x32, 0x06, 0x73, 0x89, 0xb7, 0x56, 0xcc, - 0x58, 0xe8, 0x09, 0xf0, 0xb9, 0x96, 0xe9, 0x73, 0x2e, 0x15, 0x8b, 0x7b, 0x78, 0xac, 0x8f, 0x1f, - 0x4b, 0x56, 0x77, 0x35, 0xb3, 0x3c, 0xb7, 0x3f, 0xcb, 0x5b, 0x37, 0x6c, 0xec, 0xca, 0x3f, 0x1a, - 0x70, 0x7f, 0xdf, 0x27, 0x79, 0x3c, 0xd7, 0x80, 0x17, 0x87, 0xca, 0x0d, 0x99, 0xf1, 0x13, 0x5b, - 0x75, 0x73, 0x90, 0x7c, 0x1e, 0x9e, 0x64, 0x4f, 0x9e, 0x80, 0x69, 0xae, 0xdc, 0x98, 0x4c, 0x09, - 0x68, 0x5b, 0xba, 0x4a, 0xb9, 0xd3, 0xac, 0xaa, 0x95, 0x63, 0x0c, 0xcb, 0xfc, 0xb2, 0x01, 0x4b, - 0xfd, 0x5e, 0x9e, 0x0f, 0x70, 0x34, 0xfb, 0x7f, 0x89, 0x80, 0xcc, 0x52, 0x4f, 0x40, 0x66, 0xe2, - 0x70, 0x16, 0xc6, 0x5e, 0x6a, 0xe7, 0xa2, 0xfc, 0x5d, 0xe2, 0x0d, 0x3f, 0x6b, 0xc0, 0xa9, 0x3e, - 0xbb, 0xa9, 0x27, 0x30, 0xd7, 0x38, 0x72, 0x60, 0x6e, 0x6e, 0xd0, 0xc0, 0x5c, 0xf3, 0xaf, 0xf2, - 0x30, 0x2f, 0xdb, 0x13, 0x59, 0x38, 0x4f, 0xc5, 0xc2, 0x5a, 0xdf, 0x96, 0x08, 0x6b, 0x5d, 0x4c, - 0xe2, 0xff, 0x2c, 0xa6, 0xf5, 0xcd, 0x15, 0xd3, 0xfa, 0x93, 0x1c, 0x9c, 0x4c, 0x7d, 0x60, 0x4f, - 0x3e, 0x9d, 0xa2, 0x1a, 0xae, 0x67, 0xfc, 0x92, 0x7f, 0x40, 0xe5, 0x30, 0x6a, 0x20, 0xe8, 0x17, - 0xf4, 0x00, 0x4c, 0x21, 0xea, 0x77, 0x8e, 0x21, 0x27, 0xc1, 0x90, 0xb1, 0x98, 0xe6, 0x2f, 0xe7, - 0xe1, 0xd1, 0x41, 0x09, 0xbd, 0x49, 0x63, 0xf5, 0xfd, 0x58, 0xac, 0xfe, 0x3d, 0x52, 0xdb, 0xc7, - 0x12, 0xb6, 0xff, 0xd5, 0xbc, 0x52, 0x7b, 0xbd, 0xeb, 0x73, 0xa0, 0x7b, 0xb5, 0x09, 0x66, 0xda, - 0x85, 0x69, 0xf2, 0x22, 0x51, 0x38, 0x51, 0x15, 0xc5, 0x77, 0xba, 0xa5, 0x05, 0x99, 0x3a, 0xab, - 0x4a, 0x03, 0x59, 0x88, 0x61, 0x25, 0xf2, 0x28, 0x14, 0x3d, 0x01, 0x0d, 0xa3, 0x93, 0xe5, 0xe5, - 0xa4, 0x28, 0x43, 0x05, 0x25, 0x9f, 0xd4, 0x6c, 0xe1, 0xb1, 0xe3, 0x7a, 0xe3, 0x7d, 0xd8, 0x9d, - 0xeb, 0x8b, 0x50, 0xf4, 0xc3, 0x84, 0x77, 0xc2, 0x31, 0xfe, 0xf8, 0x80, 0x41, 0xef, 0xec, 0xe8, - 0x14, 0x66, 0xbf, 0x13, 0xfd, 0x53, 0xb9, 0xf1, 0x14, 0x49, 0x62, 0xaa, 0x53, 0x8b, 0xf0, 0xf2, - 0x41, 0xca, 0x89, 0xe5, 0xbb, 0x06, 0x4c, 0xc9, 0xd9, 0xba, 0x07, 0x71, 0xf8, 0x37, 0xe2, 0x71, - 0xf8, 0xe7, 0x33, 0x91, 0x1d, 0x7d, 0x82, 0xf0, 0x6f, 0xc0, 0xb4, 0x9e, 0x63, 0x85, 0xbc, 0xa0, - 0xc9, 0x3e, 0x63, 0x94, 0x5c, 0x0e, 0xa1, 0x74, 0x8c, 0xe4, 0xa2, 0xf9, 0xa5, 0xa2, 0x1a, 0x45, - 0x1e, 0xed, 0xaf, 0xaf, 0x41, 0xe3, 0xd0, 0x35, 0xa8, 0x2f, 0x81, 0x5c, 0xf6, 0x4b, 0xe0, 0x2a, - 0x14, 0x43, 0x01, 0x25, 0xd5, 0xf8, 0xc3, 0x7a, 0xf4, 0x18, 0xb3, 0x05, 0x18, 0x31, 0x6d, 0xe1, - 0xf2, 0xa3, 0x96, 0x9a, 0x43, 0x25, 0x38, 0x15, 0x19, 0xf2, 0x12, 0x4c, 0xdd, 0x72, 0xbd, 0x9b, - 0x4d, 0xd7, 0xe2, 0xa9, 0x2c, 0x21, 0x8b, 0x2b, 0x0e, 0xe5, 0x72, 0x12, 0x41, 0xca, 0xd7, 0x23, - 0xfa, 0xa8, 0x33, 0x23, 0x65, 0x98, 0x6b, 0xd9, 0x0e, 0x52, 0xab, 0xae, 0xc2, 0xed, 0xc7, 0x44, - 0xae, 0xbd, 0xd0, 0xc8, 0xdd, 0x88, 0x83, 0x31, 0x89, 0x4f, 0x3e, 0x06, 0x45, 0x5f, 0xe6, 0x71, - 0xc9, 0xe6, 0x32, 0x4a, 0x9d, 0x19, 0x05, 0xd1, 0x68, 0xec, 0xc2, 0x12, 0x54, 0x0c, 0xc9, 0x3a, - 0x2c, 0x7a, 0x32, 0x53, 0x42, 0x2c, 0x11, 0xbe, 0xd8, 0x9f, 0x3c, 0xa5, 0x1b, 0xa6, 0xc0, 0x31, - 0xb5, 0x16, 0xb3, 0x62, 0x78, 0xb2, 0x20, 0xe1, 0x95, 0xd7, 0x1c, 0xd9, 0x7c, 0xc1, 0xd7, 0x51, - 0x42, 0x0f, 0x7b, 0xbe, 0x51, 0x1c, 0xe1, 0xf9, 0x46, 0x15, 0x4e, 0x26, 0x41, 0x3c, 0x9f, 0x03, - 0x4f, 0x21, 0xa1, 0x69, 0x8f, 0xcd, 0x34, 0x24, 0x4c, 0xaf, 0x4b, 0xae, 0xc3, 0xa4, 0x47, 0xf9, - 0xf9, 0xa2, 0x1c, 0x5e, 0x7f, 0x0f, 0x1d, 0xe8, 0x83, 0x21, 0x01, 0x8c, 0x68, 0xb1, 0x79, 0xb7, - 0xe2, 0xe9, 0xe6, 0xae, 0x66, 0xf8, 0x29, 0x1f, 0x39, 0xf7, 0x7d, 0xf2, 0xac, 0x98, 0x6f, 0xcc, - 0xc2, 0x4c, 0xcc, 0xb7, 0x40, 0x1e, 0x86, 0x02, 0x4f, 0x70, 0xc1, 0xc5, 0x43, 0x31, 0x12, 0x61, - 0x62, 0x70, 0x04, 0x8c, 0x7c, 0xce, 0x80, 0xb9, 0x76, 0xcc, 0x0f, 0x1a, 0x4a, 0xce, 0x11, 0x6f, - 0xda, 0xe2, 0xce, 0x55, 0x2d, 0x51, 0x6b, 0x9c, 0x19, 0x26, 0xb9, 0xb3, 0x0d, 0x28, 0x63, 0xdf, - 0x9a, 0xd4, 0xe3, 0xd8, 0xd2, 0xc6, 0x51, 0x24, 0x56, 0xe2, 0x60, 0x4c, 0xe2, 0xb3, 0x19, 0xe6, - 0xbd, 0x1b, 0xe5, 0x1b, 0x1f, 0xe5, 0x90, 0x00, 0x46, 0xb4, 0xc8, 0x33, 0x30, 0x2b, 0xb3, 0x8c, - 0x6d, 0xba, 0xf5, 0x8b, 0x96, 0xbf, 0x2b, 0x8d, 0x7b, 0x75, 0x18, 0x59, 0x89, 0x41, 0x31, 0x81, - 0xcd, 0xfb, 0x16, 0xa5, 0x72, 0xe3, 0x04, 0xc6, 0xe3, 0x79, 0x6c, 0x57, 0xe2, 0x60, 0x4c, 0xe2, - 0x93, 0x77, 0x68, 0x72, 0x5f, 0xdc, 0x94, 0x29, 0x69, 0x90, 0x22, 0xfb, 0xcb, 0x30, 0xd7, 0xe1, - 0x67, 0xa1, 0x7a, 0x08, 0x94, 0xfb, 0x51, 0x31, 0xbc, 0x16, 0x07, 0x63, 0x12, 0x9f, 0x3c, 0x0d, - 0x33, 0x1e, 0x93, 0x6e, 0x8a, 0x80, 0xb8, 0x3e, 0x53, 0xb7, 0x23, 0xa8, 0x03, 0x31, 0x8e, 0x4b, - 0x9e, 0x85, 0x85, 0x28, 0xf5, 0x51, 0x48, 0x40, 0xdc, 0xa7, 0xa9, 0x5c, 0x22, 0xe5, 0x24, 0x02, - 0xf6, 0xd6, 0x21, 0x3f, 0x07, 0xf3, 0xda, 0x48, 0xac, 0x39, 0x75, 0x7a, 0x5b, 0xa6, 0xa7, 0xe1, - 0x29, 0xc7, 0x57, 0x12, 0x30, 0xec, 0xc1, 0x26, 0xef, 0x85, 0xd9, 0x9a, 0xdb, 0x6c, 0x72, 0x19, - 0x27, 0x72, 0xa8, 0x8a, 0x3c, 0x34, 0x22, 0x63, 0x4f, 0x0c, 0x82, 0x09, 0x4c, 0x72, 0x09, 0x88, - 0xbb, 0xed, 0x53, 0x6f, 0x8f, 0xd6, 0x9f, 0x15, 0x5f, 0x0d, 0x64, 0x2a, 0x7e, 0x26, 0x1e, 0x79, - 0x7b, 0xa5, 0x07, 0x03, 0x53, 0x6a, 0xf1, 0x54, 0x24, 0xda, 0x2b, 0x98, 0xd9, 0x2c, 0xbe, 0x77, - 0x91, 0x3c, 0xb9, 0xdf, 0xf5, 0x09, 0x8c, 0x07, 0xe3, 0x22, 0x10, 0x7a, 0x69, 0x2e, 0x8b, 0x74, - 0x4c, 0x7a, 0x3a, 0xc5, 0x48, 0x47, 0x88, 0x52, 0x94, 0x9c, 0xc8, 0x27, 0x60, 0x72, 0x3b, 0xcc, - 0xad, 0xbb, 0x34, 0x9f, 0x85, 0x5e, 0x4c, 0xa4, 0x89, 0x8e, 0x4e, 0xa6, 0x0a, 0x80, 0x11, 0x4b, - 0xf2, 0x08, 0x4c, 0x5d, 0xdc, 0x2c, 0xab, 0x55, 0xb8, 0xc0, 0x67, 0x7f, 0x8c, 0x55, 0x41, 0x1d, - 0xc0, 0x76, 0x98, 0xb2, 0x97, 0x08, 0x9f, 0xe2, 0x48, 0xdf, 0xf6, 0x9a, 0x3f, 0x0c, 0x9b, 0x5f, - 0x08, 0x62, 0x75, 0xe9, 0x44, 0x02, 0x5b, 0x96, 0xa3, 0xc2, 0x20, 0x2f, 0xc2, 0x94, 0xd4, 0x17, - 0x5c, 0x36, 0x2d, 0x1e, 0xed, 0x85, 0x15, 0x46, 0x24, 0x50, 0xa7, 0x47, 0x9e, 0x84, 0xa9, 0x36, - 0x4f, 0x39, 0x4a, 0x2f, 0x74, 0x9a, 0xcd, 0xa5, 0x93, 0x5c, 0x6e, 0xaa, 0x9b, 0x92, 0xcd, 0x08, - 0x84, 0x3a, 0x1e, 0x79, 0x3c, 0x8c, 0x5d, 0x78, 0x4b, 0xec, 0xe2, 0x4b, 0xc5, 0x2e, 0x28, 0x2b, - 0xb7, 0x4f, 0x68, 0xed, 0xa9, 0xbb, 0x04, 0x0d, 0x6c, 0xc3, 0xe9, 0xd0, 0xc4, 0xea, 0xdd, 0x24, - 0x4b, 0x4b, 0x31, 0x2f, 0xc1, 0xe9, 0xeb, 0x7d, 0x31, 0xf1, 0x10, 0x2a, 0x64, 0x1b, 0xf2, 0x56, - 0x73, 0x7b, 0xe9, 0xfe, 0x2c, 0x6c, 0x45, 0xf5, 0x15, 0x50, 0x11, 0x0e, 0x53, 0x5e, 0xaf, 0x20, - 0x23, 0x6e, 0xbe, 0x92, 0x53, 0x5e, 0x79, 0x95, 0xa8, 0xef, 0xe3, 0xfa, 0xaa, 0x36, 0xb2, 0xf8, - 0xca, 0x5d, 0x4f, 0x02, 0x6a, 0xa1, 0x90, 0x52, 0xd7, 0x74, 0x5b, 0xed, 0xe3, 0x4c, 0x72, 0x3f, - 0xc4, 0x93, 0x10, 0x8a, 0xd3, 0x5c, 0x7c, 0x17, 0x9b, 0x3f, 0x28, 0x28, 0x27, 0x54, 0xe2, 0x32, - 0xde, 0x83, 0x82, 0xed, 0x07, 0xb6, 0x9b, 0xe1, 0xc3, 0xa9, 0x44, 0xf6, 0x3e, 0x1e, 0x42, 0xca, - 0x01, 0x28, 0x58, 0x31, 0x9e, 0x4e, 0xc3, 0x76, 0x6e, 0xcb, 0xee, 0x5f, 0xcd, 0xfc, 0x96, 0x5d, - 0xf0, 0xe4, 0x00, 0x14, 0xac, 0xc8, 0x0d, 0xb1, 0xd2, 0xb2, 0xf9, 0xa2, 0x61, 0xf2, 0x43, 0xa5, - 0xf1, 0x15, 0xc7, 0x78, 0xf9, 0x2d, 0x5b, 0xda, 0x30, 0x23, 0xf2, 0xaa, 0x6e, 0xac, 0xa5, 0xf1, - 0xaa, 0x6e, 0xac, 0x21, 0x63, 0x42, 0x5e, 0x33, 0x00, 0x2c, 0xf5, 0xc5, 0xce, 0x6c, 0xb2, 0xb5, - 0xf7, 0xfb, 0x02, 0xa8, 0x88, 0xfa, 0x8a, 0xa0, 0xa8, 0x71, 0x26, 0x2f, 0xc1, 0x84, 0x25, 0xbe, - 0x35, 0x21, 0x03, 0xea, 0xb2, 0xf9, 0x80, 0x4a, 0xa2, 0x05, 0x3c, 0x92, 0x50, 0x82, 0x30, 0x64, - 0x68, 0xfe, 0x8b, 0x01, 0xda, 0x27, 0xd6, 0xa2, 0x70, 0x27, 0x63, 0xe0, 0x70, 0xa7, 0xdc, 0x90, - 0xe1, 0x4e, 0xf9, 0xa1, 0xc2, 0x9d, 0xc6, 0x86, 0x0f, 0x77, 0x2a, 0xf4, 0x0f, 0x77, 0x32, 0x5f, - 0x37, 0x60, 0xa1, 0x67, 0x5d, 0x24, 0x3f, 0x65, 0x6b, 0x0c, 0xf8, 0x29, 0xdb, 0x55, 0x98, 0x97, - 0xa9, 0x34, 0xab, 0xed, 0xa6, 0x9d, 0xfa, 0xce, 0x73, 0x2b, 0x01, 0xc7, 0x9e, 0x1a, 0xe6, 0x9f, - 0x18, 0x30, 0xa5, 0x3d, 0x4b, 0x61, 0xfd, 0xe0, 0xcf, 0x77, 0x64, 0x33, 0xa2, 0x2c, 0xa2, 0xdc, - 0xc5, 0x29, 0x60, 0xc2, 0xdb, 0xde, 0xd0, 0x92, 0xc5, 0x45, 0xde, 0x76, 0x56, 0x8a, 0x12, 0x2a, - 0xd2, 0x80, 0x51, 0xf1, 0x99, 0xe2, 0xbc, 0x9e, 0x06, 0x8c, 0xb6, 0x91, 0x43, 0x38, 0x3b, 0xa6, - 0x4f, 0x65, 0x24, 0x9c, 0x96, 0xb4, 0xd4, 0x62, 0xa7, 0x26, 0x0e, 0x23, 0x67, 0x20, 0x4f, 0x9d, - 0xba, 0x34, 0xfe, 0xd5, 0x27, 0x2c, 0xce, 0x3b, 0x75, 0x64, 0xe5, 0xe6, 0x15, 0x98, 0xae, 0xd2, - 0x9a, 0x47, 0x83, 0xe7, 0xe8, 0xfe, 0xc0, 0xdf, 0xc4, 0xb8, 0x49, 0xf7, 0x93, 0xdf, 0xc4, 0x60, - 0xd5, 0x59, 0xb9, 0xf9, 0xbb, 0x06, 0x24, 0x72, 0xc8, 0x6a, 0x9e, 0x37, 0xa3, 0x9f, 0xe7, 0x2d, - 0xe6, 0x23, 0xca, 0x1d, 0xea, 0x23, 0xba, 0x04, 0xa4, 0x65, 0x05, 0xb5, 0xdd, 0x58, 0x86, 0x63, - 0x79, 0xee, 0x8a, 0x1e, 0xc1, 0xf5, 0x60, 0x60, 0x4a, 0x2d, 0xf3, 0x65, 0x03, 0x7a, 0xbe, 0x32, - 0xcc, 0xac, 0x05, 0x2a, 0x3f, 0x37, 0x20, 0x8e, 0xa3, 0xca, 0x5a, 0x08, 0xbf, 0x32, 0x10, 0xc2, - 0xd9, 0x99, 0x25, 0xf4, 0x7a, 0x85, 0x3e, 0x04, 0xf1, 0x5c, 0x48, 0x9d, 0x59, 0x56, 0xe3, 0x60, - 0x4c, 0xe2, 0x9b, 0xcf, 0x43, 0x31, 0x7c, 0x53, 0xc9, 0x1f, 0x26, 0x85, 0xa7, 0x60, 0xfd, 0x61, - 0x12, 0x3b, 0x04, 0x73, 0x08, 0x1b, 0x26, 0xdf, 0xb1, 0x2f, 0xba, 0x7e, 0x10, 0x3e, 0x04, 0x15, - 0xbe, 0xae, 0xcb, 0x6b, 0xbc, 0x0c, 0x15, 0xd4, 0x5c, 0x80, 0x39, 0xe5, 0xc4, 0x12, 0x8b, 0xde, - 0xfc, 0x56, 0x1e, 0xa6, 0x63, 0xdf, 0x8e, 0xbb, 0xfb, 0x64, 0x0f, 0x3e, 0x2d, 0x29, 0xce, 0xa8, - 0xfc, 0x90, 0xce, 0x28, 0xdd, 0xfb, 0x37, 0x76, 0xbc, 0xde, 0xbf, 0x42, 0x36, 0xde, 0xbf, 0x00, - 0x26, 0xe4, 0x77, 0xb5, 0xa5, 0xf8, 0xdf, 0xc8, 0x28, 0x21, 0x82, 0x7c, 0x59, 0xcc, 0x05, 0x7f, - 0x28, 0xc0, 0x42, 0x56, 0xe6, 0xd7, 0x0b, 0x30, 0x1b, 0x4f, 0x91, 0x30, 0xc0, 0x4c, 0xbe, 0xa3, - 0x67, 0x26, 0x87, 0x3c, 0x8c, 0xe7, 0x47, 0x3d, 0x8c, 0x8f, 0x8d, 0x7a, 0x18, 0x2f, 0x1c, 0xe1, - 0x30, 0xde, 0x7b, 0x94, 0x1e, 0x1f, 0xf8, 0x28, 0xfd, 0x3e, 0x75, 0x93, 0x3c, 0x11, 0xbb, 0x7a, - 0x89, 0x6e, 0x92, 0x49, 0x7c, 0x1a, 0x56, 0xdc, 0x7a, 0xea, 0x8d, 0x7c, 0xf1, 0x2e, 0x87, 0x0e, - 0x2f, 0xf5, 0xe2, 0x77, 0x78, 0x7f, 0xdf, 0x5b, 0x86, 0xb8, 0xf4, 0x8d, 0x3e, 0x1d, 0xcf, 0x95, - 0x1f, 0xc4, 0x15, 0x67, 0x35, 0x02, 0xa1, 0x8e, 0xc7, 0x3f, 0x6f, 0x14, 0xff, 0x9e, 0x13, 0xf7, - 0x6d, 0xe8, 0x9f, 0x37, 0x4a, 0x7c, 0xff, 0x29, 0x89, 0x6f, 0x7e, 0x2d, 0x0f, 0xb3, 0xf1, 0xf4, - 0xf4, 0xe4, 0x96, 0x3a, 0x1b, 0x64, 0x72, 0x2c, 0x11, 0x64, 0xb5, 0x24, 0x01, 0x7d, 0x0f, 0xfa, - 0xe2, 0x83, 0xe6, 0xdb, 0x2a, 0x63, 0xc1, 0xf1, 0x31, 0x96, 0x27, 0x6c, 0xc9, 0x8e, 0x67, 0xb4, - 0x8f, 0x82, 0x59, 0xe5, 0xed, 0x71, 0xe6, 0xdc, 0xa3, 0xf0, 0x54, 0xc5, 0x0a, 0x35, 0xb6, 0x4c, - 0xbc, 0xef, 0x51, 0xcf, 0xde, 0xb1, 0xd5, 0xa7, 0x75, 0xb8, 0xf0, 0x7c, 0x5e, 0x96, 0xa1, 0x82, - 0x9a, 0x2f, 0xe7, 0x20, 0xfa, 0x90, 0x18, 0xcf, 0x94, 0xed, 0x6b, 0x66, 0x83, 0x9c, 0xb6, 0x4b, - 0xa3, 0xa6, 0xa3, 0x8f, 0x28, 0xca, 0x40, 0x1b, 0xad, 0x04, 0x63, 0x1c, 0x7f, 0x0a, 0x1f, 0x10, - 0xb3, 0x60, 0x2e, 0xf1, 0xd4, 0x26, 0xf3, 0x68, 0xc6, 0x2f, 0xe5, 0x61, 0x52, 0x3d, 0x56, 0x22, - 0xef, 0xe1, 0x49, 0x6e, 0x77, 0xdd, 0x30, 0xf5, 0xf0, 0x5b, 0xb5, 0x54, 0xb4, 0xbb, 0x6e, 0xfd, - 0x4e, 0xb7, 0x34, 0xa7, 0x90, 0x45, 0x11, 0xca, 0x0a, 0xcc, 0x48, 0xeb, 0x78, 0xcd, 0xa4, 0x91, - 0x76, 0x0d, 0xd7, 0x91, 0x95, 0x93, 0xdb, 0x30, 0xb1, 0x4b, 0xad, 0x3a, 0xf5, 0xc2, 0xb8, 0x85, - 0x8d, 0x8c, 0x1e, 0x58, 0x5d, 0xe4, 0x54, 0xa3, 0x61, 0x10, 0xff, 0x7d, 0x0c, 0xd9, 0x31, 0x45, - 0xb5, 0xed, 0xd6, 0xf7, 0x93, 0xa9, 0x6b, 0x2b, 0x6e, 0x7d, 0x1f, 0x39, 0x84, 0x3c, 0x03, 0xb3, - 0x81, 0xdd, 0xa2, 0x6e, 0x27, 0xd0, 0x3f, 0xd3, 0x94, 0x8f, 0x1c, 0xd7, 0x5b, 0x31, 0x28, 0x26, - 0xb0, 0x99, 0xa2, 0xbb, 0xe1, 0xbb, 0x0e, 0xcf, 0x47, 0x33, 0x1e, 0xf7, 0x72, 0x5d, 0xaa, 0x5e, - 0xb9, 0xcc, 0xd3, 0xd1, 0x28, 0x0c, 0x86, 0x6d, 0xf3, 0x17, 0x11, 0x1e, 0x95, 0xf7, 0x46, 0xf3, - 0xd1, 0xbb, 0x55, 0x51, 0x8e, 0x0a, 0xc3, 0xbc, 0x06, 0x73, 0x89, 0xae, 0x86, 0xe6, 0xb0, 0x91, - 0x6e, 0x0e, 0x0f, 0x96, 0x27, 0xf6, 0x0f, 0x0d, 0x58, 0xe8, 0xd9, 0xbc, 0x83, 0x86, 0xd9, 0x26, - 0x25, 0x79, 0xee, 0xe8, 0x92, 0x3c, 0x3f, 0x9c, 0x24, 0xaf, 0x2c, 0x7f, 0xfb, 0x8d, 0xb3, 0xf7, - 0x7d, 0xe7, 0x8d, 0xb3, 0xf7, 0x7d, 0xef, 0x8d, 0xb3, 0xf7, 0xbd, 0x7c, 0x70, 0xd6, 0xf8, 0xf6, - 0xc1, 0x59, 0xe3, 0x3b, 0x07, 0x67, 0x8d, 0xef, 0x1d, 0x9c, 0x35, 0xfe, 0xe1, 0xe0, 0xac, 0xf1, - 0xfa, 0x8f, 0xce, 0xde, 0xf7, 0x42, 0x31, 0x5c, 0x26, 0xff, 0x15, 0x00, 0x00, 0xff, 0xff, 0xbe, - 0x64, 0xb8, 0x28, 0x8f, 0x88, 0x00, 0x00, + // 7118 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x5d, 0x8c, 0x24, 0xd7, + 0x55, 0xb0, 0xab, 0x7b, 0x7a, 0xa6, 0xfb, 0xcc, 0xff, 0xdd, 0xd9, 0xec, 0x78, 0xed, 0xdd, 0x76, + 0xca, 0x91, 0x3f, 0xe7, 0xfb, 0x92, 0xd9, 0xc4, 0x3f, 0x1f, 0x4e, 0x1c, 0x19, 0xba, 0x67, 0x76, + 0xbd, 0xb3, 0x9e, 0x99, 0x9d, 0xbd, 0x3d, 0xbb, 0x9b, 0x38, 0x71, 0x48, 0x4d, 0xf7, 0x9d, 0x9e, + 0xda, 0xed, 0xae, 0xea, 0x54, 0x55, 0xcf, 0xee, 0x38, 0x56, 0x62, 0x13, 0xd9, 0x04, 0x94, 0x28, + 0x86, 0x24, 0x42, 0x08, 0x05, 0x45, 0x28, 0x12, 0x88, 0xe4, 0x01, 0x45, 0x20, 0x5e, 0x22, 0x81, + 0x48, 0x22, 0xc2, 0x03, 0x28, 0x20, 0x20, 0x09, 0x22, 0x0d, 0x9e, 0xf0, 0x02, 0x02, 0x21, 0xa4, + 0x20, 0x94, 0x7d, 0x42, 0xf7, 0xb7, 0x6e, 0xfd, 0xf4, 0x6c, 0xf7, 0x74, 0xcd, 0xc6, 0x82, 0xbc, + 0x75, 0xdf, 0x73, 0xee, 0x39, 0xf7, 0xf7, 0x9c, 0x73, 0xcf, 0x3d, 0xf7, 0x14, 0xac, 0x35, 0xed, + 0x60, 0xb7, 0xbb, 0xbd, 0x54, 0x77, 0xdb, 0xe7, 0x2c, 0xaf, 0xe9, 0x76, 0x3c, 0xf7, 0x06, 0xfb, + 0xf1, 0x4e, 0xcf, 0x6d, 0xb5, 0xdc, 0x6e, 0xe0, 0x9f, 0xeb, 0xdc, 0x6c, 0x9e, 0xb3, 0x3a, 0xb6, + 0x7f, 0x4e, 0x95, 0xec, 0xbd, 0xdb, 0x6a, 0x75, 0x76, 0xad, 0x77, 0x9f, 0x6b, 0x12, 0x87, 0x78, + 0x56, 0x40, 0x1a, 0x4b, 0x1d, 0xcf, 0x0d, 0x5c, 0xf4, 0xbe, 0x90, 0xda, 0x92, 0xa4, 0xc6, 0x7e, + 0xfc, 0xbc, 0xac, 0xbb, 0xd4, 0xb9, 0xd9, 0x5c, 0xa2, 0xd4, 0x96, 0x54, 0x89, 0xa4, 0x76, 0xfa, + 0x9d, 0x5a, 0x5b, 0x9a, 0x6e, 0xd3, 0x3d, 0xc7, 0x88, 0x6e, 0x77, 0x77, 0xd8, 0x3f, 0xf6, 0x87, + 0xfd, 0xe2, 0xcc, 0x4e, 0x3f, 0x7c, 0xf3, 0x29, 0x7f, 0xc9, 0x76, 0x69, 0xdb, 0xce, 0x6d, 0x5b, + 0x41, 0x7d, 0xf7, 0xdc, 0x5e, 0xa2, 0x45, 0xa7, 0x4d, 0x0d, 0xa9, 0xee, 0x7a, 0x24, 0x0d, 0xe7, + 0x89, 0x10, 0xa7, 0x6d, 0xd5, 0x77, 0x6d, 0x87, 0x78, 0xfb, 0x61, 0xaf, 0xdb, 0x24, 0xb0, 0xd2, + 0x6a, 0x9d, 0xeb, 0x57, 0xcb, 0xeb, 0x3a, 0x81, 0xdd, 0x26, 0x89, 0x0a, 0xff, 0xff, 0x6e, 0x15, + 0xfc, 0xfa, 0x2e, 0x69, 0x5b, 0x89, 0x7a, 0x8f, 0xf7, 0xab, 0xd7, 0x0d, 0xec, 0xd6, 0x39, 0xdb, + 0x09, 0xfc, 0xc0, 0x8b, 0x57, 0x32, 0xbf, 0x99, 0x87, 0x52, 0x65, 0xad, 0x5a, 0x0b, 0xac, 0xa0, + 0xeb, 0xa3, 0xd7, 0x0c, 0x98, 0x6a, 0xb9, 0x56, 0xa3, 0x6a, 0xb5, 0x2c, 0xa7, 0x4e, 0xbc, 0x45, + 0xe3, 0x21, 0xe3, 0xd1, 0xc9, 0xc7, 0xd6, 0x96, 0x46, 0x99, 0xaf, 0xa5, 0xca, 0x2d, 0x1f, 0x13, + 0xdf, 0xed, 0x7a, 0x75, 0x82, 0xc9, 0x4e, 0x75, 0xe1, 0xdb, 0xbd, 0xf2, 0x7d, 0x07, 0xbd, 0xf2, + 0xd4, 0x9a, 0xc6, 0x09, 0x47, 0xf8, 0xa2, 0x2f, 0x18, 0x30, 0x5f, 0xb7, 0x1c, 0xcb, 0xdb, 0xdf, + 0xb2, 0xbc, 0x26, 0x09, 0x9e, 0xf5, 0xdc, 0x6e, 0x67, 0x31, 0x77, 0x0c, 0xad, 0xb9, 0x5f, 0xb4, + 0x66, 0x7e, 0x39, 0xce, 0x0e, 0x27, 0x5b, 0xc0, 0xda, 0xe5, 0x07, 0xd6, 0x76, 0x8b, 0xe8, 0xed, + 0xca, 0x1f, 0x67, 0xbb, 0x6a, 0x71, 0x76, 0x38, 0xd9, 0x02, 0xf3, 0xd5, 0x3c, 0xcc, 0x57, 0xd6, + 0xaa, 0x5b, 0x9e, 0xb5, 0xb3, 0x63, 0xd7, 0xb1, 0xdb, 0x0d, 0x6c, 0xa7, 0x89, 0xde, 0x0e, 0x13, + 0xb6, 0xd3, 0xf4, 0x88, 0xef, 0xb3, 0x89, 0x2c, 0x55, 0x67, 0x05, 0xd1, 0x89, 0x55, 0x5e, 0x8c, + 0x25, 0x1c, 0x3d, 0x09, 0x93, 0x3e, 0xf1, 0xf6, 0xec, 0x3a, 0xd9, 0x74, 0xbd, 0x80, 0x8d, 0x74, + 0xa1, 0x7a, 0x42, 0xa0, 0x4f, 0xd6, 0x42, 0x10, 0xd6, 0xf1, 0x68, 0x35, 0xcf, 0x75, 0x03, 0x01, + 0x67, 0x03, 0x51, 0x0a, 0xab, 0xe1, 0x10, 0x84, 0x75, 0x3c, 0xf4, 0xba, 0x01, 0x73, 0x7e, 0x60, + 0xd7, 0x6f, 0xda, 0x0e, 0xf1, 0xfd, 0x65, 0xd7, 0xd9, 0xb1, 0x9b, 0x8b, 0x05, 0x36, 0x8a, 0x1b, + 0xa3, 0x8d, 0x62, 0x2d, 0x46, 0xb5, 0xba, 0x70, 0xd0, 0x2b, 0xcf, 0xc5, 0x4b, 0x71, 0x82, 0x3b, + 0x5a, 0x81, 0x39, 0xcb, 0x71, 0xdc, 0xc0, 0x0a, 0x6c, 0xd7, 0xd9, 0xf4, 0xc8, 0x8e, 0x7d, 0x7b, + 0x71, 0x8c, 0x75, 0x67, 0x51, 0x74, 0x67, 0xae, 0x12, 0x83, 0xe3, 0x44, 0x0d, 0x73, 0x05, 0x16, + 0x2b, 0xed, 0x6d, 0xcb, 0xf7, 0xad, 0x86, 0xeb, 0xc5, 0x66, 0xe3, 0x51, 0x28, 0xb6, 0xad, 0x4e, + 0xc7, 0x76, 0x9a, 0x74, 0x3a, 0xf2, 0x8f, 0x96, 0xaa, 0x53, 0x07, 0xbd, 0x72, 0x71, 0x5d, 0x94, + 0x61, 0x05, 0x35, 0xbf, 0x9f, 0x83, 0xc9, 0x8a, 0x63, 0xb5, 0xf6, 0x7d, 0xdb, 0xc7, 0x5d, 0x07, + 0x7d, 0x04, 0x8a, 0x54, 0xba, 0x34, 0xac, 0xc0, 0x12, 0x3b, 0xf2, 0x5d, 0x4b, 0x7c, 0xb3, 0x2f, + 0xe9, 0x9b, 0x3d, 0x1c, 0x17, 0x8a, 0xbd, 0xb4, 0xf7, 0xee, 0xa5, 0xcb, 0xdb, 0x37, 0x48, 0x3d, + 0x58, 0x27, 0x81, 0x55, 0x45, 0xa2, 0x17, 0x10, 0x96, 0x61, 0x45, 0x15, 0xb9, 0x30, 0xe6, 0x77, + 0x48, 0x5d, 0xec, 0xb0, 0xf5, 0x11, 0x57, 0x72, 0xd8, 0xf4, 0x5a, 0x87, 0xd4, 0xab, 0x53, 0x82, + 0xf5, 0x18, 0xfd, 0x87, 0x19, 0x23, 0x74, 0x0b, 0xc6, 0x7d, 0x26, 0x73, 0xc4, 0xe6, 0xb9, 0x9c, + 0x1d, 0x4b, 0x46, 0xb6, 0x3a, 0x23, 0x98, 0x8e, 0xf3, 0xff, 0x58, 0xb0, 0x33, 0xff, 0xce, 0x80, + 0x13, 0x1a, 0x76, 0xc5, 0x6b, 0x76, 0xdb, 0xc4, 0x09, 0xd0, 0x43, 0x30, 0xe6, 0x58, 0x6d, 0x22, + 0x36, 0x8a, 0x6a, 0xf2, 0x86, 0xd5, 0x26, 0x98, 0x41, 0xd0, 0xc3, 0x50, 0xd8, 0xb3, 0x5a, 0x5d, + 0xc2, 0x06, 0xa9, 0x54, 0x9d, 0x16, 0x28, 0x85, 0x6b, 0xb4, 0x10, 0x73, 0x18, 0x7a, 0x09, 0x4a, + 0xec, 0xc7, 0x05, 0xcf, 0x6d, 0x67, 0xd4, 0x35, 0xd1, 0xc2, 0x6b, 0x92, 0x6c, 0x75, 0xfa, 0xa0, + 0x57, 0x2e, 0xa9, 0xbf, 0x38, 0x64, 0x68, 0xfe, 0x83, 0x01, 0xb3, 0x5a, 0xe7, 0xd6, 0x6c, 0x3f, + 0x40, 0x1f, 0x4a, 0x2c, 0x9e, 0xa5, 0xc1, 0x16, 0x0f, 0xad, 0xcd, 0x96, 0xce, 0x9c, 0xe8, 0x69, + 0x51, 0x96, 0x68, 0x0b, 0xc7, 0x81, 0x82, 0x1d, 0x90, 0xb6, 0xbf, 0x98, 0x7b, 0x28, 0xff, 0xe8, + 0xe4, 0x63, 0xab, 0x99, 0x4d, 0x63, 0x38, 0xbe, 0xab, 0x94, 0x3e, 0xe6, 0x6c, 0xcc, 0xaf, 0x8d, + 0x45, 0x7a, 0x48, 0x57, 0x14, 0x72, 0x61, 0xa2, 0x4d, 0x02, 0xcf, 0xae, 0xf3, 0x7d, 0x35, 0xf9, + 0xd8, 0xca, 0x68, 0xad, 0x58, 0x67, 0xc4, 0x42, 0x61, 0xc9, 0xff, 0xfb, 0x58, 0x72, 0x41, 0xbb, + 0x30, 0x66, 0x79, 0x4d, 0xd9, 0xe7, 0x0b, 0xd9, 0xcc, 0x6f, 0xb8, 0xe6, 0x2a, 0x5e, 0xd3, 0xc7, + 0x8c, 0x03, 0x3a, 0x07, 0xa5, 0x80, 0x78, 0x6d, 0xdb, 0xb1, 0x02, 0x2e, 0x5d, 0x8b, 0xd5, 0x79, + 0x81, 0x56, 0xda, 0x92, 0x00, 0x1c, 0xe2, 0xa0, 0x16, 0x8c, 0x37, 0xbc, 0x7d, 0xdc, 0x75, 0x16, + 0xc7, 0xb2, 0x18, 0x8a, 0x15, 0x46, 0x2b, 0xdc, 0x4c, 0xfc, 0x3f, 0x16, 0x3c, 0xd0, 0x97, 0x0d, + 0x58, 0x68, 0x13, 0xcb, 0xef, 0x7a, 0x84, 0x76, 0x01, 0x93, 0x80, 0x38, 0x54, 0x1a, 0x2e, 0x16, + 0x18, 0x73, 0x3c, 0xea, 0x3c, 0x24, 0x29, 0x57, 0x1f, 0x14, 0x4d, 0x59, 0x48, 0x83, 0xe2, 0xd4, + 0xd6, 0x98, 0xdf, 0x1f, 0x83, 0xf9, 0x84, 0x84, 0x40, 0x4f, 0x40, 0xa1, 0xb3, 0x6b, 0xf9, 0x72, + 0xcb, 0x9f, 0x95, 0xeb, 0x6d, 0x93, 0x16, 0xde, 0xe9, 0x95, 0xa7, 0x65, 0x15, 0x56, 0x80, 0x39, + 0x32, 0xd5, 0xa9, 0x6d, 0xe2, 0xfb, 0x56, 0x53, 0xca, 0x01, 0x6d, 0x99, 0xb0, 0x62, 0x2c, 0xe1, + 0xe8, 0x17, 0x0d, 0x98, 0xe6, 0x4b, 0x06, 0x13, 0xbf, 0xdb, 0x0a, 0xa8, 0xac, 0xa3, 0xc3, 0x72, + 0x29, 0x8b, 0xe5, 0xc9, 0x49, 0x56, 0x4f, 0x0a, 0xee, 0xd3, 0x7a, 0xa9, 0x8f, 0xa3, 0x7c, 0xd1, + 0x75, 0x28, 0xf9, 0x81, 0xe5, 0x05, 0xa4, 0x51, 0x09, 0x98, 0x56, 0x9b, 0x7c, 0xec, 0xff, 0x0e, + 0x26, 0x04, 0xb6, 0xec, 0x36, 0xe1, 0x02, 0xa7, 0x26, 0x09, 0xe0, 0x90, 0x16, 0x7a, 0x09, 0xc0, + 0xeb, 0x3a, 0xb5, 0x6e, 0xbb, 0x6d, 0x79, 0xfb, 0x42, 0x83, 0x5f, 0x1c, 0xad, 0x7b, 0x58, 0xd1, + 0x0b, 0x75, 0x56, 0x58, 0x86, 0x35, 0x7e, 0xe8, 0x15, 0x03, 0xa6, 0xf9, 0x4a, 0x94, 0x2d, 0x18, + 0xcf, 0xb8, 0x05, 0xf3, 0x74, 0x68, 0x57, 0x74, 0x16, 0x38, 0xca, 0xd1, 0xfc, 0x9b, 0xa8, 0x3e, + 0xa9, 0x05, 0xd4, 0xba, 0x6e, 0xee, 0xa3, 0x0f, 0xc2, 0xfd, 0x7e, 0xb7, 0x5e, 0x27, 0xbe, 0xbf, + 0xd3, 0x6d, 0xe1, 0xae, 0x73, 0xd1, 0xf6, 0x03, 0xd7, 0xdb, 0x5f, 0xb3, 0xdb, 0x76, 0xc0, 0x56, + 0x5c, 0xa1, 0x7a, 0xe6, 0xa0, 0x57, 0xbe, 0xbf, 0xd6, 0x0f, 0x09, 0xf7, 0xaf, 0x8f, 0x2c, 0x78, + 0xa0, 0xeb, 0xf4, 0x27, 0xcf, 0xad, 0xb7, 0xf2, 0x41, 0xaf, 0xfc, 0xc0, 0xd5, 0xfe, 0x68, 0xf8, + 0x30, 0x1a, 0xe6, 0xbf, 0x18, 0x30, 0x27, 0xfb, 0xb5, 0x45, 0xda, 0x9d, 0x16, 0x95, 0x2e, 0xc7, + 0x6f, 0x88, 0x04, 0x11, 0x43, 0x04, 0x67, 0xa3, 0x4e, 0x64, 0xfb, 0xfb, 0x59, 0x23, 0xe6, 0x3f, + 0x1b, 0xb0, 0x10, 0x47, 0xbe, 0x07, 0xca, 0xd3, 0x8f, 0x2a, 0xcf, 0x8d, 0x6c, 0x7b, 0xdb, 0x47, + 0x83, 0xbe, 0x36, 0x96, 0xec, 0xeb, 0xff, 0x74, 0x35, 0x1a, 0x6a, 0xc5, 0xfc, 0x4f, 0x52, 0x2b, + 0x8e, 0xbd, 0xa9, 0xb4, 0xe2, 0xef, 0x8c, 0xc1, 0x54, 0xc5, 0x09, 0xec, 0xca, 0xce, 0x8e, 0xed, + 0xd8, 0xc1, 0x3e, 0xfa, 0x74, 0x0e, 0xce, 0x75, 0x3c, 0xb2, 0x43, 0x3c, 0x8f, 0x34, 0x56, 0xba, + 0x9e, 0xed, 0x34, 0x6b, 0xf5, 0x5d, 0xd2, 0xe8, 0xb6, 0x6c, 0xa7, 0xb9, 0xda, 0x74, 0x5c, 0x55, + 0x7c, 0xfe, 0x36, 0xa9, 0x77, 0x59, 0x97, 0xf8, 0xa6, 0x68, 0x8f, 0xd6, 0xa5, 0xcd, 0xe1, 0x98, + 0x56, 0x1f, 0x3f, 0xe8, 0x95, 0xcf, 0x0d, 0x59, 0x09, 0x0f, 0xdb, 0x35, 0xf4, 0xa9, 0x1c, 0x2c, + 0x79, 0xe4, 0xa3, 0x5d, 0x7b, 0xf0, 0xd1, 0xe0, 0x52, 0xab, 0x35, 0xa2, 0xfa, 0x19, 0x8a, 0x67, + 0xf5, 0xb1, 0x83, 0x5e, 0x79, 0xc8, 0x3a, 0x78, 0xc8, 0x7e, 0x99, 0xdf, 0xc8, 0xc1, 0xc9, 0x4a, + 0xa7, 0xb3, 0x4e, 0xfc, 0xdd, 0xd8, 0xa1, 0xf6, 0xb3, 0x06, 0xcc, 0xec, 0xd9, 0x5e, 0xd0, 0xb5, + 0x5a, 0xd2, 0x09, 0xc0, 0x97, 0x44, 0x6d, 0xc4, 0xed, 0xcc, 0xb9, 0x5d, 0x8b, 0x90, 0xae, 0xa2, + 0x83, 0x5e, 0x79, 0x26, 0x5a, 0x86, 0x63, 0xec, 0xd1, 0xaf, 0x19, 0x30, 0x27, 0x8a, 0x36, 0xdc, + 0x06, 0xd1, 0x3d, 0x47, 0x57, 0xb3, 0x6c, 0x93, 0x22, 0xce, 0x5d, 0x0c, 0xf1, 0x52, 0x9c, 0x68, + 0x84, 0xf9, 0x6f, 0x39, 0x38, 0xd5, 0x87, 0x06, 0xfa, 0x6d, 0x03, 0x16, 0xb8, 0xbb, 0x49, 0x03, + 0x61, 0xb2, 0x23, 0x46, 0xf3, 0x03, 0x59, 0xb7, 0x1c, 0xd3, 0xbd, 0x40, 0x9c, 0x3a, 0xa9, 0x2e, + 0x52, 0xb1, 0xb1, 0x9c, 0xc2, 0x1a, 0xa7, 0x36, 0x88, 0xb5, 0x94, 0x3b, 0xa0, 0x62, 0x2d, 0xcd, + 0xdd, 0x93, 0x96, 0xd6, 0x52, 0x58, 0xe3, 0xd4, 0x06, 0x99, 0x3f, 0x0b, 0x0f, 0x1c, 0x42, 0xee, + 0xee, 0x27, 0x7e, 0xf3, 0x05, 0xb5, 0xea, 0xa3, 0x6b, 0x6e, 0x00, 0x67, 0x81, 0x09, 0xe3, 0x9e, + 0xdb, 0x0d, 0x08, 0xd7, 0x6e, 0xa5, 0x2a, 0x50, 0x3d, 0x81, 0x59, 0x09, 0x16, 0x10, 0xf3, 0x1b, + 0x06, 0x14, 0x87, 0xf0, 0x3f, 0x94, 0xa3, 0xfe, 0x87, 0x52, 0xc2, 0xf7, 0x10, 0x24, 0x7d, 0x0f, + 0xcf, 0x8e, 0x36, 0x1b, 0x83, 0xf8, 0x1c, 0xfe, 0xdd, 0x80, 0xf9, 0x84, 0x8f, 0x02, 0xed, 0xc2, + 0x42, 0xc7, 0x6d, 0x48, 0xfb, 0xe2, 0xa2, 0xe5, 0xef, 0x32, 0x98, 0xe8, 0xde, 0x13, 0x74, 0x26, + 0x37, 0x53, 0xe0, 0x77, 0x7a, 0xe5, 0x45, 0x45, 0x24, 0x86, 0x80, 0x53, 0x29, 0xa2, 0x0e, 0x14, + 0x77, 0x6c, 0xd2, 0x6a, 0x84, 0x4b, 0x70, 0x44, 0x4b, 0xe2, 0x82, 0xa0, 0xc6, 0xdd, 0x73, 0xf2, + 0x1f, 0x56, 0x5c, 0xcc, 0x2b, 0x30, 0x13, 0x75, 0xd6, 0x0e, 0x30, 0x79, 0x67, 0x20, 0x6f, 0x79, + 0x8e, 0x98, 0xba, 0x49, 0x81, 0x90, 0xaf, 0xe0, 0x0d, 0x4c, 0xcb, 0xcd, 0x1f, 0x8f, 0xc1, 0x6c, + 0xb5, 0xd5, 0x25, 0xcf, 0x7a, 0x84, 0xc8, 0xf3, 0x69, 0x05, 0x66, 0x3b, 0x1e, 0xd9, 0xb3, 0xc9, + 0xad, 0x1a, 0x69, 0x91, 0x7a, 0xe0, 0x7a, 0x82, 0xfe, 0x29, 0x51, 0x7d, 0x76, 0x33, 0x0a, 0xc6, + 0x71, 0x7c, 0xf4, 0x0c, 0xcc, 0x58, 0xf5, 0xc0, 0xde, 0x23, 0x8a, 0x02, 0x6f, 0xc0, 0x5b, 0x04, + 0x85, 0x99, 0x4a, 0x04, 0x8a, 0x63, 0xd8, 0xe8, 0x43, 0xb0, 0xe8, 0xd7, 0xad, 0x16, 0xb9, 0xda, + 0x11, 0xac, 0x96, 0x77, 0x49, 0xfd, 0xe6, 0xa6, 0x6b, 0x3b, 0x81, 0xf0, 0x46, 0x3c, 0x24, 0x28, + 0x2d, 0xd6, 0xfa, 0xe0, 0xe1, 0xbe, 0x14, 0xd0, 0x1f, 0x19, 0x70, 0xa6, 0xe3, 0x91, 0x4d, 0xcf, + 0x6d, 0xbb, 0x54, 0xcd, 0x24, 0x8e, 0xe8, 0xe2, 0xa8, 0x7a, 0x6d, 0x44, 0x7d, 0xca, 0x4b, 0x92, + 0x2e, 0xc2, 0xb7, 0x1e, 0xf4, 0xca, 0x67, 0x36, 0x0f, 0x6b, 0x00, 0x3e, 0xbc, 0x7d, 0xe8, 0x4f, + 0x0c, 0x38, 0xdb, 0x71, 0xfd, 0xe0, 0x90, 0x2e, 0x14, 0x8e, 0xb5, 0x0b, 0xe6, 0x41, 0xaf, 0x7c, + 0x76, 0xf3, 0xd0, 0x16, 0xe0, 0xbb, 0xb4, 0xd0, 0x3c, 0x98, 0x84, 0x79, 0x6d, 0xed, 0x89, 0xf3, + 0xeb, 0xd3, 0x30, 0x2d, 0x17, 0x43, 0xa8, 0xd6, 0x4b, 0xa1, 0xbf, 0xa1, 0xa2, 0x03, 0x71, 0x14, + 0x97, 0xae, 0x3b, 0xb5, 0x14, 0x79, 0xed, 0xd8, 0xba, 0xdb, 0x8c, 0x40, 0x71, 0x0c, 0x1b, 0xad, + 0xc2, 0x09, 0x51, 0x82, 0x49, 0xa7, 0x65, 0xd7, 0xad, 0x65, 0xb7, 0x2b, 0x96, 0x5c, 0xa1, 0x7a, + 0xea, 0xa0, 0x57, 0x3e, 0xb1, 0x99, 0x04, 0xe3, 0xb4, 0x3a, 0x68, 0x0d, 0x16, 0xac, 0x6e, 0xe0, + 0xaa, 0xfe, 0x9f, 0x77, 0xa8, 0xa6, 0x68, 0xb0, 0xa5, 0x55, 0xe4, 0x2a, 0xa5, 0x92, 0x02, 0xc7, + 0xa9, 0xb5, 0xd0, 0x66, 0x8c, 0x5a, 0x8d, 0xd4, 0x5d, 0xa7, 0xc1, 0x67, 0xb9, 0x10, 0x5a, 0xe1, + 0x95, 0x14, 0x1c, 0x9c, 0x5a, 0x13, 0xb5, 0x60, 0xa6, 0x6d, 0xdd, 0xbe, 0xea, 0x58, 0x7b, 0x96, + 0xdd, 0xa2, 0x4c, 0x84, 0x0f, 0xa3, 0xff, 0xc1, 0xba, 0x1b, 0xd8, 0xad, 0x25, 0x7e, 0x9d, 0xb7, + 0xb4, 0xea, 0x04, 0x97, 0xbd, 0x5a, 0x40, 0xad, 0x35, 0x6e, 0x1c, 0xad, 0x47, 0x68, 0xe1, 0x18, + 0x6d, 0x74, 0x19, 0x4e, 0xb2, 0xed, 0xb8, 0xe2, 0xde, 0x72, 0x56, 0x48, 0xcb, 0xda, 0x97, 0x1d, + 0x98, 0x60, 0x1d, 0xb8, 0xff, 0xa0, 0x57, 0x3e, 0x59, 0x4b, 0x43, 0xc0, 0xe9, 0xf5, 0x90, 0x05, + 0x0f, 0x44, 0x01, 0x98, 0xec, 0xd9, 0xbe, 0xed, 0x3a, 0xdc, 0x13, 0x51, 0x0c, 0x3d, 0x11, 0xb5, + 0xfe, 0x68, 0xf8, 0x30, 0x1a, 0xe8, 0x37, 0x0c, 0x58, 0x48, 0xdb, 0x86, 0x8b, 0xa5, 0x2c, 0x2e, + 0x2b, 0x62, 0x5b, 0x8b, 0xaf, 0x88, 0x54, 0xa1, 0x90, 0xda, 0x08, 0xf4, 0xb2, 0x01, 0x53, 0x96, + 0x76, 0x8a, 0x5a, 0x04, 0xd6, 0xaa, 0x4b, 0xa3, 0x9e, 0xe5, 0x43, 0x8a, 0xd5, 0xb9, 0x83, 0x5e, + 0x39, 0x72, 0x52, 0xc3, 0x11, 0x8e, 0xe8, 0x37, 0x0d, 0x38, 0x99, 0xba, 0xc7, 0x17, 0x27, 0x8f, + 0x63, 0x84, 0xd8, 0x22, 0x49, 0x97, 0x39, 0xe9, 0xcd, 0x40, 0xaf, 0x1b, 0x4a, 0x95, 0xad, 0x4b, + 0x6f, 0xca, 0x14, 0x6b, 0xda, 0x95, 0x11, 0x0f, 0x8e, 0xa1, 0x41, 0x20, 0x09, 0x57, 0x4f, 0x68, + 0x9a, 0x51, 0x16, 0xe2, 0x38, 0x7b, 0xf4, 0x19, 0x43, 0xaa, 0x46, 0xd5, 0xa2, 0xe9, 0xe3, 0x6a, + 0x11, 0x0a, 0x35, 0xad, 0x6a, 0x50, 0x8c, 0x39, 0xfa, 0x30, 0x9c, 0xb6, 0xb6, 0x5d, 0x2f, 0x48, + 0xdd, 0x7c, 0x8b, 0x33, 0x6c, 0x1b, 0x9d, 0x3d, 0xe8, 0x95, 0x4f, 0x57, 0xfa, 0x62, 0xe1, 0x43, + 0x28, 0x98, 0x5f, 0x2d, 0xc0, 0x14, 0x37, 0xf2, 0x85, 0xea, 0xfa, 0xba, 0x01, 0x0f, 0xd6, 0xbb, + 0x9e, 0x47, 0x9c, 0xa0, 0x16, 0x90, 0x4e, 0x52, 0x71, 0x19, 0xc7, 0xaa, 0xb8, 0x1e, 0x3a, 0xe8, + 0x95, 0x1f, 0x5c, 0x3e, 0x84, 0x3f, 0x3e, 0xb4, 0x75, 0xe8, 0x2f, 0x0c, 0x30, 0x05, 0x42, 0xd5, + 0xaa, 0xdf, 0x6c, 0x7a, 0x6e, 0xd7, 0x69, 0x24, 0x3b, 0x91, 0x3b, 0xd6, 0x4e, 0x3c, 0x72, 0xd0, + 0x2b, 0x9b, 0xcb, 0x77, 0x6d, 0x05, 0x1e, 0xa0, 0xa5, 0xe8, 0x59, 0x98, 0x17, 0x58, 0xe7, 0x6f, + 0x77, 0x88, 0x67, 0x53, 0x73, 0x5a, 0xdc, 0xa7, 0x87, 0x21, 0x0a, 0x71, 0x04, 0x9c, 0xac, 0x83, + 0x7c, 0x98, 0xb8, 0x45, 0xec, 0xe6, 0x6e, 0x20, 0xcd, 0xa7, 0x11, 0xe3, 0x12, 0xc4, 0x81, 0xff, + 0x3a, 0xa7, 0x59, 0x9d, 0x3c, 0xe8, 0x95, 0x27, 0xc4, 0x1f, 0x2c, 0x39, 0xa1, 0x0d, 0x98, 0xe1, + 0x47, 0xb0, 0x4d, 0xdb, 0x69, 0x6e, 0xba, 0x0e, 0xbf, 0xcd, 0x2f, 0x55, 0x1f, 0x91, 0x0a, 0xbf, + 0x16, 0x81, 0xde, 0xe9, 0x95, 0xa7, 0xe4, 0xef, 0xad, 0xfd, 0x0e, 0xc1, 0xb1, 0xda, 0xe6, 0xef, + 0x8d, 0x01, 0xc8, 0xe5, 0x4a, 0x3a, 0xe8, 0xff, 0x41, 0xc9, 0x27, 0x01, 0xe7, 0x2a, 0x9c, 0xe7, + 0xfc, 0x4e, 0x42, 0x16, 0xe2, 0x10, 0x8e, 0x6e, 0x42, 0xa1, 0x63, 0x75, 0x7d, 0x22, 0x26, 0xff, + 0x52, 0x26, 0x93, 0xbf, 0x49, 0x29, 0xf2, 0x33, 0x17, 0xfb, 0x89, 0x39, 0x0f, 0xf4, 0x49, 0x03, + 0x80, 0x44, 0x27, 0x6c, 0x64, 0xdf, 0x87, 0x60, 0x19, 0xce, 0x29, 0x1d, 0x83, 0xea, 0xcc, 0x41, + 0xaf, 0x0c, 0xda, 0xd4, 0x6b, 0x6c, 0xd1, 0x2d, 0x28, 0x5a, 0x52, 0xe6, 0x8f, 0x1d, 0x87, 0xcc, + 0x67, 0x47, 0x21, 0xb5, 0x68, 0x15, 0x33, 0xf4, 0x29, 0x03, 0x66, 0x7c, 0x12, 0x88, 0xa9, 0xa2, + 0x92, 0x47, 0x18, 0xbc, 0x23, 0x2e, 0xba, 0x5a, 0x84, 0x26, 0x97, 0xa0, 0xd1, 0x32, 0x1c, 0xe3, + 0x6b, 0xfe, 0xd5, 0x14, 0xcc, 0xc8, 0x25, 0x13, 0xda, 0xb0, 0xdc, 0x85, 0xd1, 0xc7, 0x86, 0x5d, + 0xd6, 0x81, 0x38, 0x8a, 0x4b, 0x2b, 0xf3, 0x45, 0x19, 0x35, 0x61, 0x55, 0xe5, 0x9a, 0x0e, 0xc4, + 0x51, 0x5c, 0xd4, 0x86, 0x82, 0x1f, 0x90, 0x8e, 0xbc, 0xf1, 0x1b, 0xf1, 0x42, 0x2a, 0xdc, 0x09, + 0xa1, 0x4f, 0x9f, 0xfe, 0xf3, 0x31, 0xe7, 0xc2, 0xbc, 0x70, 0x41, 0xc4, 0x31, 0x27, 0x96, 0x41, + 0x36, 0x2b, 0x31, 0xea, 0xf3, 0xe3, 0xb3, 0x11, 0x2d, 0xc3, 0x31, 0xf6, 0x29, 0x66, 0x6d, 0xe1, + 0x18, 0xcd, 0xda, 0xe7, 0xa1, 0xd8, 0xb6, 0x6e, 0xd7, 0xba, 0x5e, 0xf3, 0xe8, 0xe6, 0xb3, 0x08, + 0xc6, 0xe1, 0x54, 0xb0, 0xa2, 0x87, 0x5e, 0x31, 0xb4, 0xcd, 0x35, 0xc1, 0x88, 0x5f, 0xcf, 0x76, + 0x73, 0x29, 0xad, 0xd0, 0x77, 0x9b, 0x25, 0x8c, 0xcc, 0xe2, 0x3d, 0x37, 0x32, 0xa9, 0xc1, 0xc4, + 0x37, 0x88, 0x32, 0x98, 0x4a, 0xc7, 0x6a, 0x30, 0x2d, 0x47, 0x98, 0xe1, 0x18, 0x73, 0xd6, 0x1e, + 0xbe, 0xe7, 0x54, 0x7b, 0xe0, 0x58, 0xdb, 0x53, 0x8b, 0x30, 0xc3, 0x31, 0xe6, 0xfd, 0x4f, 0x56, + 0x93, 0xc7, 0x73, 0xb2, 0x9a, 0xca, 0xe0, 0x64, 0x75, 0xb8, 0xd1, 0x39, 0x3d, 0xaa, 0xd1, 0x89, + 0x2e, 0x01, 0x6a, 0xec, 0x3b, 0x56, 0xdb, 0xae, 0x0b, 0x61, 0xc9, 0x14, 0xc4, 0x0c, 0x3b, 0x79, + 0x9f, 0x16, 0x82, 0x0c, 0xad, 0x24, 0x30, 0x70, 0x4a, 0x2d, 0x14, 0x40, 0xb1, 0x23, 0x6d, 0x8b, + 0xd9, 0x2c, 0x56, 0xbf, 0xb4, 0x35, 0xf8, 0xa5, 0x30, 0xdd, 0x78, 0xb2, 0x04, 0x2b, 0x4e, 0xe6, + 0x7f, 0x1a, 0x30, 0xb7, 0xdc, 0x72, 0xbb, 0x8d, 0xeb, 0x56, 0x50, 0xdf, 0xe5, 0x37, 0x98, 0xe8, + 0x19, 0x28, 0xda, 0x4e, 0x40, 0xbc, 0x3d, 0xab, 0x25, 0x34, 0x8a, 0x29, 0x2f, 0x79, 0x57, 0x45, + 0xf9, 0x9d, 0x5e, 0x79, 0x66, 0xa5, 0xeb, 0xb1, 0xd0, 0x40, 0x2e, 0x5f, 0xb0, 0xaa, 0x83, 0xbe, + 0x64, 0xc0, 0x3c, 0xbf, 0x03, 0x5d, 0xb1, 0x02, 0xeb, 0x4a, 0x97, 0x78, 0x36, 0x91, 0xb7, 0xa0, + 0x23, 0x8a, 0x96, 0x78, 0x5b, 0x25, 0x83, 0xfd, 0xd0, 0x88, 0x5c, 0x8f, 0x73, 0xc6, 0xc9, 0xc6, + 0x98, 0x9f, 0xcb, 0xc3, 0xfd, 0x7d, 0x69, 0xa1, 0xd3, 0x90, 0xb3, 0x1b, 0xa2, 0xeb, 0x20, 0xe8, + 0xe6, 0x56, 0x1b, 0x38, 0x67, 0x37, 0xd0, 0x12, 0xb3, 0x87, 0x3c, 0xe2, 0xfb, 0xf2, 0x42, 0xac, + 0xa4, 0x4c, 0x17, 0x51, 0x8a, 0x35, 0x0c, 0x54, 0x86, 0x42, 0xcb, 0xda, 0x26, 0x2d, 0x61, 0xeb, + 0x32, 0x0b, 0x6b, 0x8d, 0x16, 0x60, 0x5e, 0x8e, 0x7e, 0xc1, 0x00, 0xe0, 0x0d, 0xa4, 0x96, 0xb2, + 0xd0, 0x6b, 0x38, 0xdb, 0x61, 0xa2, 0x94, 0x79, 0x2b, 0xc3, 0xff, 0x58, 0xe3, 0x8a, 0xb6, 0x60, + 0x9c, 0x1a, 0x5b, 0x6e, 0xe3, 0xc8, 0x6a, 0x8c, 0x5d, 0x00, 0x6c, 0x32, 0x1a, 0x58, 0xd0, 0xa2, + 0x63, 0xe5, 0x91, 0xa0, 0xeb, 0x39, 0x74, 0x68, 0x99, 0xe2, 0x2a, 0xf2, 0x56, 0x60, 0x55, 0x8a, + 0x35, 0x0c, 0xf3, 0x0f, 0x73, 0xb0, 0x90, 0xd6, 0x74, 0xaa, 0x1f, 0xc6, 0x79, 0x6b, 0xc5, 0xb1, + 0xed, 0xfd, 0xd9, 0x8f, 0x8f, 0xb8, 0xce, 0x57, 0x97, 0xde, 0x22, 0xe0, 0x48, 0xf0, 0x45, 0xef, + 0x57, 0x23, 0x94, 0x3b, 0xe2, 0x08, 0x29, 0xca, 0xb1, 0x51, 0x7a, 0x08, 0xc6, 0x7c, 0x3a, 0xf3, + 0xf9, 0xa8, 0x73, 0x9d, 0xcd, 0x11, 0x83, 0x50, 0x8c, 0xae, 0x63, 0x07, 0x22, 0x5e, 0x57, 0x61, + 0x5c, 0x75, 0xec, 0x00, 0x33, 0x88, 0xf9, 0x85, 0x1c, 0x9c, 0xee, 0xdf, 0x29, 0xf4, 0x05, 0x03, + 0xa0, 0x41, 0x4d, 0x69, 0xba, 0x24, 0x65, 0xf8, 0x83, 0x75, 0x5c, 0x63, 0xb8, 0x22, 0x39, 0x85, + 0xb1, 0x30, 0xaa, 0xc8, 0xc7, 0x5a, 0x43, 0xd0, 0x63, 0x72, 0xe9, 0x6f, 0x58, 0x6d, 0x69, 0x80, + 0xaa, 0x3a, 0xeb, 0x0a, 0x82, 0x35, 0x2c, 0x7a, 0x56, 0x72, 0xac, 0x36, 0xf1, 0x3b, 0x96, 0x0a, + 0xc8, 0x66, 0x67, 0xa5, 0x0d, 0x59, 0x88, 0x43, 0xb8, 0xd9, 0x82, 0x87, 0x07, 0x68, 0x67, 0x46, + 0xc1, 0xb1, 0xe6, 0x7f, 0x18, 0x70, 0x6a, 0xb9, 0xd5, 0xf5, 0x03, 0xe2, 0xfd, 0xaf, 0x09, 0x2d, + 0xfa, 0x2f, 0x03, 0x1e, 0xe8, 0xd3, 0xe7, 0x7b, 0x10, 0x61, 0xf4, 0x62, 0x34, 0xc2, 0xe8, 0xea, + 0xa8, 0x4b, 0x3a, 0xb5, 0x1f, 0x7d, 0x02, 0x8d, 0x02, 0x98, 0xa6, 0x52, 0xab, 0xe1, 0x36, 0x33, + 0xd2, 0x9b, 0x0f, 0x43, 0xe1, 0xa3, 0x54, 0xff, 0xc4, 0xd7, 0x18, 0x53, 0x4a, 0x98, 0xc3, 0xcc, + 0xf7, 0x81, 0x08, 0xc7, 0x89, 0x6d, 0x1e, 0x63, 0x90, 0xcd, 0x63, 0xfe, 0x6d, 0x0e, 0xb4, 0x33, + 0xf6, 0x3d, 0x58, 0x94, 0x4e, 0x64, 0x51, 0x8e, 0x78, 0x6a, 0xd6, 0x3c, 0x06, 0xfd, 0xe2, 0xee, + 0xf7, 0x62, 0x71, 0xf7, 0x1b, 0x99, 0x71, 0x3c, 0x3c, 0xec, 0xfe, 0xbb, 0x06, 0x3c, 0x10, 0x22, + 0x27, 0xdd, 0x5f, 0x77, 0x97, 0x30, 0x4f, 0xc2, 0xa4, 0x15, 0x56, 0x13, 0x6b, 0x40, 0x3d, 0x35, + 0xd1, 0x28, 0x62, 0x1d, 0x2f, 0x8c, 0xf2, 0xcd, 0x1f, 0x31, 0xca, 0x77, 0xec, 0xf0, 0x28, 0x5f, + 0xf3, 0x47, 0x39, 0x38, 0x93, 0xec, 0x99, 0xdc, 0x1b, 0x83, 0xdd, 0x0e, 0x3f, 0x05, 0x53, 0x81, + 0xa8, 0xa0, 0x49, 0x7a, 0xf5, 0x50, 0x6a, 0x4b, 0x83, 0xe1, 0x08, 0x26, 0xad, 0x59, 0xe7, 0xbb, + 0xb2, 0x56, 0x77, 0x3b, 0x32, 0x46, 0x5c, 0xd5, 0x5c, 0xd6, 0x60, 0x38, 0x82, 0xa9, 0xa2, 0xef, + 0xc6, 0x8e, 0x3d, 0xfa, 0xae, 0x06, 0x27, 0x65, 0xbc, 0xd1, 0x05, 0xd7, 0x5b, 0x76, 0xdb, 0x9d, + 0x16, 0x11, 0x51, 0xe2, 0xb4, 0xb1, 0x67, 0x44, 0x95, 0x93, 0x38, 0x0d, 0x09, 0xa7, 0xd7, 0x35, + 0xbf, 0x9b, 0x87, 0x13, 0xe1, 0xb0, 0x2f, 0xbb, 0x4e, 0xc3, 0x66, 0x51, 0x5b, 0x4f, 0xc3, 0x58, + 0xb0, 0xdf, 0x91, 0x83, 0xfd, 0x7f, 0x64, 0x73, 0xb6, 0xf6, 0x3b, 0x74, 0xb6, 0x4f, 0xa5, 0x54, + 0x61, 0x0e, 0x48, 0x56, 0x09, 0xad, 0xa9, 0xdd, 0xc1, 0x67, 0xe0, 0x89, 0xe8, 0x6a, 0xbe, 0xd3, + 0x2b, 0xa7, 0xbc, 0x13, 0x5c, 0x52, 0x94, 0xa2, 0x6b, 0x1e, 0xdd, 0x80, 0x99, 0x96, 0xe5, 0x07, + 0x57, 0x3b, 0x0d, 0x2b, 0x20, 0x5b, 0x76, 0x9b, 0x88, 0x3d, 0x37, 0x4c, 0xe8, 0xb5, 0xba, 0x31, + 0x5d, 0x8b, 0x50, 0xc2, 0x31, 0xca, 0x68, 0x0f, 0x10, 0x2d, 0xd9, 0xf2, 0x2c, 0xc7, 0xe7, 0xbd, + 0xa2, 0xfc, 0x86, 0x0f, 0xf5, 0x56, 0xc7, 0xb2, 0xb5, 0x04, 0x35, 0x9c, 0xc2, 0x01, 0x3d, 0x02, + 0xe3, 0x1e, 0xb1, 0x7c, 0x31, 0x99, 0xa5, 0x70, 0xff, 0x63, 0x56, 0x8a, 0x05, 0x54, 0xdf, 0x50, + 0xe3, 0x77, 0xd9, 0x50, 0x3f, 0x30, 0x60, 0x26, 0x9c, 0xa6, 0x7b, 0xa0, 0x24, 0xdb, 0x51, 0x25, + 0x79, 0x31, 0x2b, 0x91, 0xd8, 0x47, 0x2f, 0xfe, 0xe9, 0xb8, 0xde, 0x3f, 0x16, 0x7a, 0xfb, 0x31, + 0x28, 0xc9, 0x5d, 0x2d, 0xad, 0xcf, 0x11, 0x4f, 0xb7, 0x11, 0xbb, 0x44, 0x7b, 0x32, 0x22, 0x98, + 0xe0, 0x90, 0x1f, 0x55, 0xcb, 0x0d, 0xa1, 0x72, 0xc5, 0xb2, 0x57, 0x6a, 0x59, 0xaa, 0xe2, 0x34, + 0xb5, 0x2c, 0xeb, 0xa0, 0xab, 0x70, 0xaa, 0xe3, 0xb9, 0xec, 0x19, 0xe1, 0x0a, 0xb1, 0x1a, 0x2d, + 0xdb, 0x21, 0xd2, 0x85, 0xc0, 0x2f, 0xec, 0x1f, 0x38, 0xe8, 0x95, 0x4f, 0x6d, 0xa6, 0xa3, 0xe0, + 0x7e, 0x75, 0xa3, 0x4f, 0x5f, 0xc6, 0x06, 0x78, 0xfa, 0xf2, 0x4b, 0xca, 0x51, 0x47, 0x7c, 0xf1, + 0x00, 0xe5, 0x83, 0x59, 0x4d, 0x65, 0x8a, 0x58, 0x0f, 0x97, 0x54, 0x45, 0x30, 0xc5, 0x8a, 0x7d, + 0x7f, 0x6f, 0xd0, 0xf8, 0x11, 0xbd, 0x41, 0x61, 0x04, 0xf3, 0xc4, 0x4f, 0x32, 0x82, 0xb9, 0xf8, + 0xa6, 0x8a, 0x60, 0x7e, 0xb5, 0x00, 0x73, 0x71, 0x0b, 0xe4, 0xf8, 0x9f, 0xf5, 0xfc, 0xaa, 0x01, + 0x73, 0x72, 0xf7, 0x70, 0x9e, 0x44, 0xfa, 0xf9, 0xd7, 0x32, 0xda, 0xb4, 0xdc, 0x96, 0x52, 0x0f, + 0x4f, 0xb7, 0x62, 0xdc, 0x70, 0x82, 0x3f, 0x7a, 0x01, 0x26, 0x95, 0x3b, 0xfc, 0x48, 0x6f, 0x7c, + 0x66, 0x99, 0x15, 0x15, 0x92, 0xc0, 0x3a, 0x3d, 0xf4, 0xaa, 0x01, 0x50, 0x97, 0x6a, 0x4e, 0xee, + 0xae, 0x2b, 0x59, 0xed, 0x2e, 0xa5, 0x40, 0x43, 0x63, 0x59, 0x15, 0xf9, 0x58, 0x63, 0x8c, 0x3e, + 0xc7, 0x1c, 0xe1, 0xca, 0xba, 0xa3, 0xfb, 0x29, 0x3f, 0x7a, 0xd0, 0xe9, 0x21, 0x86, 0x69, 0x68, + 0x4a, 0x69, 0x20, 0x1f, 0x47, 0x1a, 0x61, 0x3e, 0x0d, 0x2a, 0x4c, 0x90, 0x8a, 0x2d, 0x16, 0x28, + 0xb8, 0x69, 0x05, 0xbb, 0x62, 0x09, 0x2a, 0xb1, 0x75, 0x41, 0x02, 0x70, 0x88, 0x63, 0x7e, 0x04, + 0x66, 0x9e, 0xf5, 0xac, 0xce, 0xae, 0xcd, 0x1c, 0xce, 0xf4, 0x9c, 0xf4, 0x76, 0x98, 0xb0, 0x1a, + 0x8d, 0xb4, 0x67, 0xdb, 0x15, 0x5e, 0x8c, 0x25, 0x7c, 0xb0, 0x23, 0xd1, 0x37, 0x0d, 0x58, 0x58, + 0xf5, 0x03, 0xdb, 0x5d, 0x21, 0x7e, 0x40, 0x65, 0x25, 0xdd, 0x51, 0xdd, 0xd6, 0x20, 0x61, 0xac, + 0x2b, 0x30, 0x27, 0x6e, 0xc5, 0xba, 0xdb, 0x3e, 0x09, 0x34, 0xe3, 0x54, 0x2d, 0xce, 0xe5, 0x18, + 0x1c, 0x27, 0x6a, 0x50, 0x2a, 0xe2, 0x7a, 0x2c, 0xa4, 0x92, 0x8f, 0x52, 0xa9, 0xc5, 0xe0, 0x38, + 0x51, 0xc3, 0xfc, 0x4e, 0x1e, 0x4e, 0xb0, 0x6e, 0xc4, 0x42, 0xd0, 0x3f, 0xd3, 0x2f, 0x04, 0x7d, + 0xc4, 0xf5, 0xc9, 0x78, 0x1d, 0x21, 0x00, 0xfd, 0x57, 0x0c, 0x98, 0x6d, 0x44, 0x47, 0x3a, 0x1b, + 0x9f, 0x43, 0xda, 0x1c, 0xf2, 0x70, 0x97, 0x58, 0x21, 0x8e, 0xf3, 0x47, 0x9f, 0x37, 0x60, 0x36, + 0xda, 0x4c, 0x29, 0xb2, 0x8e, 0x61, 0x90, 0x54, 0x7c, 0x6a, 0xb4, 0xdc, 0xc7, 0xf1, 0x26, 0x98, + 0x7f, 0x6d, 0x88, 0x29, 0x3d, 0x8e, 0xf8, 0x6a, 0x74, 0x0b, 0x4a, 0x41, 0xcb, 0xe7, 0x85, 0xa2, + 0xb7, 0x23, 0x1e, 0x73, 0xb6, 0xd6, 0x6a, 0x8c, 0x9c, 0x66, 0x89, 0x88, 0x12, 0x6a, 0x51, 0x49, + 0x5e, 0xe6, 0x57, 0x0c, 0x28, 0x5d, 0x72, 0xb7, 0xc5, 0x76, 0xfe, 0x70, 0x06, 0x4e, 0x04, 0x65, + 0x6b, 0xa8, 0xfb, 0xa7, 0xd0, 0x7c, 0x7d, 0x26, 0xe2, 0x42, 0x78, 0x50, 0xa3, 0xbd, 0xc4, 0xd2, + 0x9d, 0x50, 0x52, 0x97, 0xdc, 0xed, 0xbe, 0x1e, 0xaa, 0xdf, 0x2a, 0xc0, 0xf4, 0x73, 0xd6, 0x3e, + 0x71, 0x02, 0x6b, 0x78, 0x01, 0x44, 0x4f, 0xe5, 0x1d, 0x16, 0x6e, 0xa9, 0xd9, 0x8f, 0xe1, 0xa9, + 0x3c, 0x04, 0x61, 0x1d, 0x2f, 0x94, 0x2b, 0x3c, 0xfb, 0x42, 0x9a, 0x44, 0x58, 0x8e, 0xc1, 0x71, + 0xa2, 0x06, 0xba, 0x04, 0x48, 0xbc, 0x25, 0xab, 0xd4, 0xeb, 0x6e, 0xd7, 0xe1, 0x92, 0x85, 0x1f, + 0xd8, 0xd5, 0x41, 0x66, 0x3d, 0x81, 0x81, 0x53, 0x6a, 0xa1, 0x0f, 0xc1, 0x62, 0x9d, 0x51, 0x16, + 0x66, 0xad, 0x4e, 0x91, 0x1f, 0x6d, 0x54, 0xa8, 0xf3, 0x72, 0x1f, 0x3c, 0xdc, 0x97, 0x02, 0x6d, + 0xa9, 0x1f, 0xb8, 0x9e, 0xd5, 0x24, 0x3a, 0xdd, 0xf1, 0x68, 0x4b, 0x6b, 0x09, 0x0c, 0x9c, 0x52, + 0x0b, 0x7d, 0x02, 0x4a, 0xc1, 0xae, 0x47, 0xfc, 0x5d, 0xb7, 0xd5, 0x10, 0x17, 0xd2, 0x23, 0x7a, + 0x71, 0xc4, 0xec, 0x6f, 0x49, 0xaa, 0xda, 0xf2, 0x96, 0x45, 0x38, 0xe4, 0x89, 0x3c, 0x18, 0xf7, + 0xeb, 0x6e, 0x87, 0xf8, 0xc2, 0x1c, 0xbc, 0x94, 0x09, 0x77, 0xe6, 0x95, 0xd0, 0xfc, 0x47, 0x8c, + 0x03, 0x16, 0x9c, 0xcc, 0x6f, 0xe5, 0x60, 0x4a, 0x47, 0x1c, 0x40, 0x44, 0x7c, 0xd2, 0x80, 0xa9, + 0xba, 0xeb, 0x04, 0x9e, 0xdb, 0xe2, 0xbe, 0x11, 0xbe, 0x41, 0x46, 0x4c, 0x51, 0xc0, 0x48, 0xad, + 0x90, 0xc0, 0xb2, 0x5b, 0x9a, 0x9b, 0x45, 0x63, 0x83, 0x23, 0x4c, 0xd1, 0xa7, 0x0d, 0x98, 0x0d, + 0x23, 0x75, 0x42, 0x27, 0x4d, 0xa6, 0x0d, 0x51, 0x12, 0xf7, 0x7c, 0x94, 0x13, 0x8e, 0xb3, 0x36, + 0xb7, 0x61, 0x2e, 0x3e, 0xdb, 0x74, 0x28, 0x3b, 0x96, 0xd8, 0xeb, 0xf9, 0x70, 0x28, 0x37, 0x2d, + 0xdf, 0xc7, 0x0c, 0x82, 0xde, 0x01, 0xc5, 0xb6, 0xe5, 0x35, 0x6d, 0xc7, 0x6a, 0xb1, 0x51, 0xcc, + 0x6b, 0x02, 0x49, 0x94, 0x63, 0x85, 0x61, 0xfe, 0x70, 0x0c, 0x26, 0x35, 0x2b, 0xfe, 0xf8, 0x2d, + 0xf2, 0xc8, 0xf3, 0xf6, 0x7c, 0x86, 0xcf, 0xdb, 0x9f, 0x07, 0xd8, 0xb1, 0x1d, 0xdb, 0xdf, 0x3d, + 0xe2, 0xc3, 0x79, 0x76, 0x99, 0x77, 0x41, 0x51, 0xc0, 0x1a, 0xb5, 0xf0, 0xc6, 0xa4, 0x70, 0x48, + 0x3a, 0x91, 0x57, 0x0d, 0x4d, 0x79, 0x8c, 0x67, 0x71, 0x43, 0xac, 0x4d, 0xcc, 0x92, 0x54, 0x26, + 0xe7, 0x9d, 0xc0, 0xdb, 0x3f, 0x54, 0xc7, 0x6c, 0x41, 0xd1, 0x23, 0x7e, 0xb7, 0x4d, 0xcf, 0x16, + 0x13, 0x43, 0x0f, 0x03, 0xbb, 0x5d, 0xc7, 0xa2, 0x3e, 0x56, 0x94, 0x4e, 0x3f, 0x0d, 0xd3, 0x91, + 0x26, 0xa0, 0x39, 0xc8, 0xdf, 0x24, 0xfb, 0x7c, 0x9d, 0x60, 0xfa, 0x13, 0x2d, 0x44, 0xee, 0x95, + 0xc4, 0xb0, 0xbc, 0x37, 0xf7, 0x94, 0x61, 0xba, 0x90, 0x7a, 0x54, 0x3c, 0x8a, 0xdb, 0x9f, 0xce, + 0x45, 0x4b, 0x7b, 0x39, 0xaf, 0xe6, 0x82, 0xc7, 0x50, 0x70, 0x98, 0xf9, 0xa3, 0x71, 0x10, 0x97, + 0x9e, 0x03, 0x08, 0x1f, 0xfd, 0xae, 0x23, 0x77, 0x84, 0xbb, 0x8e, 0x4b, 0x30, 0x65, 0x3b, 0x76, + 0x60, 0x5b, 0x2d, 0xe6, 0x06, 0x10, 0xca, 0x51, 0x86, 0x53, 0x4e, 0xad, 0x6a, 0xb0, 0x14, 0x3a, + 0x91, 0xba, 0xe8, 0x0a, 0x14, 0x98, 0xf6, 0x10, 0x0b, 0x78, 0xf8, 0x9b, 0x59, 0x76, 0x29, 0xcf, + 0xdf, 0x58, 0x70, 0x4a, 0xcc, 0xa2, 0xe7, 0xa9, 0x03, 0xd4, 0x41, 0x4d, 0xac, 0xe3, 0xd0, 0xa2, + 0x8f, 0xc1, 0x71, 0xa2, 0x06, 0xa5, 0xb2, 0x63, 0xd9, 0xad, 0xae, 0x47, 0x42, 0x2a, 0xe3, 0x51, + 0x2a, 0x17, 0x62, 0x70, 0x9c, 0xa8, 0x81, 0x76, 0x60, 0x4a, 0x94, 0xf1, 0xc8, 0x98, 0x89, 0x23, + 0xf6, 0x92, 0x45, 0x40, 0x5d, 0xd0, 0x28, 0xe1, 0x08, 0x5d, 0xd4, 0x85, 0x79, 0xdb, 0xa9, 0xbb, + 0x4e, 0xbd, 0xd5, 0xf5, 0xed, 0x3d, 0x12, 0x3e, 0x70, 0x38, 0x0a, 0xb3, 0x93, 0x07, 0xbd, 0xf2, + 0xfc, 0x6a, 0x9c, 0x1c, 0x4e, 0x72, 0x40, 0xaf, 0x18, 0x70, 0xb2, 0xee, 0x3a, 0x3e, 0x7b, 0x8b, + 0xbb, 0x47, 0xce, 0x7b, 0x9e, 0xeb, 0x71, 0xde, 0xa5, 0x23, 0xf2, 0x66, 0xde, 0xa7, 0xe5, 0x34, + 0x92, 0x38, 0x9d, 0x13, 0x7a, 0x11, 0x8a, 0x1d, 0xcf, 0xdd, 0xb3, 0x1b, 0xc4, 0x13, 0x51, 0x56, + 0x6b, 0x59, 0xe4, 0x06, 0xd8, 0x14, 0x34, 0x43, 0xd1, 0x23, 0x4b, 0xb0, 0xe2, 0x67, 0x7e, 0xb5, + 0x08, 0x33, 0x51, 0x74, 0xf4, 0x71, 0x80, 0x8e, 0xe7, 0xb6, 0x49, 0xb0, 0x4b, 0x54, 0xa0, 0xfa, + 0xc6, 0xa8, 0x4f, 0xd0, 0x25, 0x3d, 0x19, 0xe7, 0x40, 0xc5, 0x45, 0x58, 0x8a, 0x35, 0x8e, 0xc8, + 0x83, 0x89, 0x9b, 0x5c, 0x89, 0x0a, 0x9b, 0xe2, 0xb9, 0x4c, 0x2c, 0x20, 0xc1, 0x99, 0x45, 0x58, + 0x8b, 0x22, 0x2c, 0x19, 0xa1, 0x6d, 0xc8, 0xdf, 0x22, 0xdb, 0xd9, 0x3c, 0xeb, 0xbc, 0x4e, 0xc4, + 0xd9, 0xa4, 0x3a, 0x71, 0xd0, 0x2b, 0xe7, 0xaf, 0x93, 0x6d, 0x4c, 0x89, 0xd3, 0x7e, 0x35, 0xf8, + 0x8d, 0xad, 0x10, 0x15, 0x23, 0xf6, 0x2b, 0x72, 0xfd, 0xcb, 0xfb, 0x25, 0x8a, 0xb0, 0x64, 0x84, + 0x5e, 0x84, 0xd2, 0x2d, 0x6b, 0x8f, 0xec, 0x78, 0xae, 0x13, 0x88, 0xe0, 0x9a, 0x11, 0x63, 0x97, + 0xaf, 0x4b, 0x72, 0x82, 0x2f, 0x53, 0xef, 0xaa, 0x10, 0x87, 0xec, 0xd0, 0x1e, 0x14, 0x1d, 0x72, + 0x0b, 0x93, 0x96, 0x5d, 0x17, 0x61, 0xa3, 0x23, 0x2e, 0xeb, 0x0d, 0x41, 0x4d, 0x70, 0x66, 0x7a, + 0x4f, 0x96, 0x61, 0xc5, 0x8b, 0xce, 0xe5, 0x0d, 0x77, 0x5b, 0x08, 0xaa, 0x11, 0xe7, 0x52, 0x9d, + 0x33, 0xf9, 0x5c, 0x5e, 0x72, 0xb7, 0x31, 0x25, 0x4e, 0xf7, 0x48, 0x5d, 0x45, 0x76, 0x08, 0x31, + 0xb5, 0x91, 0x6d, 0x44, 0x0b, 0xdf, 0x23, 0x61, 0x29, 0xd6, 0x38, 0xd2, 0xb1, 0x6d, 0x0a, 0xb7, + 0x96, 0x10, 0x54, 0x23, 0x8e, 0x6d, 0xd4, 0x49, 0xc6, 0xc7, 0x56, 0x96, 0x61, 0xc5, 0xcb, 0xfc, + 0xca, 0x38, 0x4c, 0xe9, 0xb9, 0x90, 0x06, 0xd0, 0xd5, 0xca, 0x3e, 0xcd, 0x0d, 0x63, 0x9f, 0xd2, + 0xe3, 0x85, 0xe6, 0x95, 0x96, 0x1e, 0x86, 0xd5, 0xcc, 0xcc, 0xb3, 0xf0, 0x78, 0xa1, 0x15, 0xfa, + 0x38, 0xc2, 0x74, 0x88, 0x8b, 0x6a, 0x6a, 0xe4, 0x70, 0x33, 0xa0, 0x10, 0x35, 0x72, 0x22, 0x8a, + 0xfd, 0x31, 0x80, 0x30, 0x27, 0x90, 0xb8, 0xad, 0x50, 0xd6, 0x93, 0x96, 0xab, 0x48, 0xc3, 0x42, + 0x8f, 0xc0, 0x38, 0x55, 0x94, 0xa4, 0x21, 0x5e, 0x11, 0xaa, 0x33, 0xdc, 0x05, 0x56, 0x8a, 0x05, + 0x14, 0x3d, 0x45, 0x6d, 0x9a, 0x50, 0xbd, 0x89, 0xc7, 0x81, 0x0b, 0xa1, 0x4d, 0x13, 0xc2, 0x70, + 0x04, 0x93, 0x36, 0x9d, 0x50, 0x6d, 0xc4, 0x56, 0x92, 0xd6, 0x74, 0xa6, 0xa2, 0x30, 0x87, 0x31, + 0x9f, 0x42, 0x4c, 0x7b, 0x31, 0x65, 0x55, 0xd0, 0x7c, 0x0a, 0x31, 0x38, 0x4e, 0xd4, 0xa0, 0x9d, + 0x11, 0x17, 0x2d, 0x93, 0x3c, 0x1e, 0xaf, 0xcf, 0x15, 0xc9, 0x6b, 0xba, 0x65, 0x3e, 0xc5, 0xa6, + 0xfe, 0xfd, 0xd9, 0xe5, 0xf5, 0x1a, 0xdc, 0x34, 0x1f, 0xcd, 0x88, 0xfe, 0x08, 0xcc, 0x44, 0x65, + 0x16, 0x5d, 0x50, 0x1d, 0xcf, 0xdd, 0xb1, 0x5b, 0x24, 0xee, 0xfb, 0xd9, 0xe4, 0xc5, 0x58, 0xc2, + 0x07, 0x73, 0x3e, 0xff, 0x59, 0x1e, 0x4e, 0x6c, 0x34, 0x6d, 0xe7, 0x76, 0xcc, 0x6b, 0x9b, 0x96, + 0x6f, 0xd3, 0x18, 0x36, 0xdf, 0x66, 0xf8, 0x48, 0x43, 0x24, 0x34, 0x4d, 0x7f, 0xa4, 0x21, 0xb3, + 0x9d, 0x46, 0x71, 0xd1, 0x0f, 0x0c, 0x78, 0xd0, 0x6a, 0x70, 0x2b, 0xd2, 0x6a, 0x89, 0xd2, 0x90, + 0xa9, 0xdc, 0xd1, 0xfe, 0x88, 0x3a, 0x21, 0xd9, 0xf9, 0xa5, 0xca, 0x21, 0x5c, 0xf9, 0x8c, 0xbf, + 0x4d, 0xf4, 0xe0, 0xc1, 0xc3, 0x50, 0xf1, 0xa1, 0xcd, 0x3f, 0x7d, 0x19, 0xde, 0x7a, 0x57, 0x46, + 0x43, 0xad, 0x96, 0x4f, 0x1a, 0x50, 0xe2, 0x4e, 0x49, 0x4c, 0x76, 0xa8, 0xa8, 0xb0, 0x3a, 0xf6, + 0x35, 0xe2, 0xf9, 0x32, 0x11, 0x90, 0x76, 0xd0, 0xaa, 0x6c, 0xae, 0x0a, 0x08, 0xd6, 0xb0, 0xa8, + 0x30, 0xbe, 0x69, 0x3b, 0x0d, 0x31, 0x4d, 0x4a, 0x18, 0x3f, 0x67, 0x3b, 0x0d, 0xcc, 0x20, 0x4a, + 0x5c, 0xe7, 0xfb, 0x66, 0xe5, 0xf8, 0xb2, 0x01, 0x33, 0xec, 0x0d, 0x56, 0x78, 0x04, 0x78, 0x52, + 0x45, 0x21, 0xf0, 0x66, 0x9c, 0x89, 0x46, 0x21, 0xdc, 0xe9, 0x95, 0x27, 0xf9, 0xab, 0xad, 0x68, + 0x50, 0xc2, 0x07, 0x85, 0xdf, 0x80, 0xc5, 0x4a, 0xe4, 0x86, 0x3e, 0xd6, 0x2a, 0x2f, 0x59, 0x4d, + 0x12, 0xc1, 0x21, 0x3d, 0xf3, 0x25, 0x98, 0xd2, 0x43, 0xcc, 0xd1, 0x93, 0x30, 0xd9, 0xb1, 0x9d, + 0x66, 0xf4, 0x29, 0x92, 0xf2, 0x94, 0x6e, 0x86, 0x20, 0xac, 0xe3, 0xb1, 0x6a, 0x6e, 0x58, 0x2d, + 0xe6, 0x60, 0xdd, 0x74, 0xf5, 0x6a, 0xe1, 0x1f, 0xf3, 0xf7, 0xf3, 0x70, 0x22, 0xe5, 0x29, 0x03, + 0x7a, 0xd5, 0x80, 0x71, 0x16, 0x57, 0x2d, 0xe3, 0x0c, 0x5e, 0xc8, 0xfc, 0xb9, 0xc4, 0x12, 0x0b, + 0xdf, 0x16, 0xeb, 0x58, 0x89, 0x4f, 0x5e, 0x88, 0x05, 0x73, 0xf4, 0xeb, 0x06, 0x4c, 0x5a, 0xda, + 0x56, 0xe3, 0xa1, 0x17, 0xdb, 0xd9, 0x37, 0x26, 0xb1, 0xb3, 0xb4, 0x90, 0xb1, 0x70, 0x23, 0xe9, + 0x6d, 0x39, 0xfd, 0x1e, 0x98, 0xd4, 0xba, 0x30, 0xcc, 0x0e, 0x39, 0xfd, 0x0c, 0xcc, 0x8d, 0xb4, + 0xc3, 0x3e, 0x00, 0xc3, 0xe6, 0xb5, 0xa2, 0x0a, 0xeb, 0x96, 0xfe, 0x30, 0x52, 0x8d, 0xb8, 0x78, + 0x19, 0x29, 0xa0, 0xe6, 0x36, 0xcc, 0xc5, 0x0f, 0x39, 0x99, 0xdf, 0x34, 0xbe, 0x0b, 0x86, 0xcc, + 0x44, 0x65, 0xfe, 0x79, 0x0e, 0x26, 0xc4, 0x7b, 0xa8, 0x7b, 0x10, 0x6d, 0x79, 0x33, 0x72, 0x55, + 0xb2, 0x9a, 0xc9, 0x33, 0xae, 0xbe, 0xa1, 0x96, 0x7e, 0x2c, 0xd4, 0xf2, 0xb9, 0x6c, 0xd8, 0x1d, + 0x1e, 0x67, 0xf9, 0xe5, 0x31, 0x98, 0x8d, 0xbd, 0x2f, 0xa3, 0xa6, 0x4a, 0x22, 0xbc, 0xe8, 0x6a, + 0xa6, 0x4f, 0xd8, 0x54, 0x24, 0xf0, 0xe1, 0x91, 0x46, 0x7e, 0x24, 0xe1, 0xdf, 0x95, 0xcc, 0x72, + 0x05, 0xff, 0x34, 0xf7, 0xdf, 0xb0, 0x91, 0x33, 0xff, 0x64, 0xc0, 0xfd, 0x7d, 0x9f, 0x21, 0xb2, + 0x7c, 0x0d, 0x5e, 0x14, 0x2a, 0x36, 0x64, 0xc6, 0xcf, 0x8a, 0xd5, 0xbd, 0x45, 0xfc, 0x89, 0x7d, + 0x9c, 0x3d, 0x7a, 0x02, 0xa6, 0x98, 0x6a, 0xa5, 0x32, 0x25, 0x20, 0x1d, 0xe1, 0xa8, 0x65, 0x2e, + 0xbb, 0x9a, 0x56, 0x8e, 0x23, 0x58, 0xe6, 0x97, 0x0c, 0x58, 0xec, 0xf7, 0x7a, 0x7f, 0x80, 0x83, + 0xe1, 0xcf, 0xc4, 0xc2, 0x41, 0xcb, 0x89, 0x70, 0xd0, 0xd8, 0xd1, 0x50, 0x46, 0x7e, 0x6a, 0xa7, + 0xb2, 0xfc, 0x5d, 0xa2, 0x1d, 0x3f, 0x63, 0xc0, 0xa9, 0x3e, 0xbb, 0x29, 0x11, 0x16, 0x6c, 0x1c, + 0x39, 0x2c, 0x38, 0x37, 0x68, 0x58, 0xb0, 0xf9, 0x97, 0x79, 0x98, 0x13, 0xed, 0x09, 0xed, 0xab, + 0xa7, 0x22, 0x41, 0xb5, 0x6f, 0x8b, 0x05, 0xd5, 0x2e, 0xc4, 0xf1, 0x7f, 0x1a, 0x51, 0xfb, 0xe6, + 0x8a, 0xa8, 0xfd, 0x71, 0x0e, 0x4e, 0xa6, 0x26, 0x15, 0x40, 0x9f, 0x4a, 0x51, 0x0d, 0xd7, 0x33, + 0xce, 0x5e, 0x30, 0xa0, 0x72, 0x18, 0x35, 0x0c, 0xf5, 0xf3, 0x7a, 0xf8, 0x27, 0x17, 0xf5, 0x3b, + 0xc7, 0x90, 0x87, 0x61, 0xc8, 0x48, 0x50, 0xf3, 0x97, 0xf3, 0xf0, 0xe8, 0xa0, 0x84, 0xde, 0xa4, + 0x2f, 0x05, 0xfc, 0xc8, 0x4b, 0x81, 0x7b, 0xa4, 0xb6, 0x8f, 0xe5, 0xd1, 0xc0, 0x57, 0xf2, 0x4a, + 0xed, 0x25, 0xd7, 0xe7, 0x40, 0xb7, 0x7a, 0x13, 0xd4, 0xb4, 0x93, 0xa9, 0x06, 0x43, 0x51, 0x38, + 0x51, 0xe3, 0xc5, 0x77, 0x7a, 0xe5, 0x79, 0x91, 0x7e, 0xac, 0x46, 0x02, 0x51, 0x88, 0x65, 0x25, + 0xf4, 0x28, 0x14, 0x3d, 0x0e, 0x95, 0xb1, 0xd1, 0xe2, 0x6a, 0x94, 0x97, 0x61, 0x05, 0x45, 0x9f, + 0xd0, 0x6c, 0xe1, 0xb1, 0xe3, 0x7a, 0xd7, 0x7e, 0xd8, 0x8d, 0xef, 0x0b, 0x50, 0xf4, 0x65, 0xd2, + 0x40, 0xee, 0x96, 0x7f, 0x7c, 0xc0, 0x90, 0x7b, 0x7a, 0x74, 0x92, 0x19, 0x04, 0x79, 0xff, 0x54, + 0x7e, 0x41, 0x45, 0x12, 0x99, 0xea, 0xd4, 0xc2, 0x7d, 0x8c, 0x90, 0x72, 0x62, 0xf9, 0xae, 0x01, + 0x93, 0x62, 0xb6, 0xee, 0xc1, 0x2b, 0x80, 0x1b, 0xd1, 0x57, 0x00, 0xe7, 0x33, 0x91, 0x1d, 0x7d, + 0x9e, 0x00, 0xdc, 0x80, 0x29, 0x3d, 0xaf, 0x0c, 0x7a, 0x5e, 0x93, 0x7d, 0xc6, 0x28, 0xf9, 0x2b, + 0xa4, 0x74, 0x0c, 0xe5, 0xa2, 0xf9, 0xc5, 0xa2, 0x1a, 0x45, 0xe6, 0x87, 0xd0, 0xd7, 0xa0, 0x71, + 0xe8, 0x1a, 0xd4, 0x97, 0x40, 0x2e, 0xfb, 0x25, 0x70, 0x05, 0x8a, 0x52, 0x40, 0x09, 0x35, 0xfe, + 0xb0, 0x1e, 0xbb, 0x46, 0x6d, 0x01, 0x4a, 0x4c, 0x5b, 0xb8, 0xec, 0xa8, 0xa5, 0xe6, 0x50, 0x09, + 0x4e, 0x45, 0x06, 0xbd, 0x08, 0x93, 0xb7, 0x5c, 0xef, 0x66, 0xcb, 0xb5, 0x58, 0x3a, 0x50, 0xc8, + 0xe2, 0x82, 0x45, 0x39, 0xbc, 0x78, 0x88, 0xf4, 0xf5, 0x90, 0x3e, 0xd6, 0x99, 0xa1, 0x0a, 0xcc, + 0xb6, 0x6d, 0x07, 0x13, 0xab, 0xa1, 0x82, 0xfd, 0xc7, 0x78, 0xbe, 0x42, 0x69, 0xe4, 0xae, 0x47, + 0xc1, 0x38, 0x8e, 0x8f, 0x3e, 0x06, 0x45, 0x5f, 0xe4, 0xae, 0xc9, 0xe6, 0x2a, 0x4c, 0x9d, 0x19, + 0x39, 0xd1, 0x70, 0xec, 0x64, 0x09, 0x56, 0x0c, 0xd1, 0x1a, 0x2c, 0x78, 0x22, 0x3b, 0x44, 0xe4, + 0x63, 0x02, 0x7c, 0x7f, 0xb2, 0xb4, 0x78, 0x38, 0x05, 0x8e, 0x53, 0x6b, 0x51, 0x2b, 0x86, 0x25, + 0x48, 0xe2, 0x77, 0x02, 0x9a, 0x1b, 0x9d, 0x2d, 0xf8, 0x06, 0x16, 0xd0, 0xc3, 0x1e, 0x8f, 0x14, + 0x47, 0x78, 0x3c, 0x52, 0x83, 0x93, 0x71, 0x10, 0xcb, 0x61, 0xc1, 0xd2, 0x66, 0x68, 0xda, 0x63, + 0x33, 0x0d, 0x09, 0xa7, 0xd7, 0x45, 0xd7, 0xa1, 0xe4, 0x11, 0x76, 0xbe, 0xa8, 0xc8, 0xcb, 0xf7, + 0xa1, 0xc3, 0x8c, 0xb0, 0x24, 0x80, 0x43, 0x5a, 0x74, 0xde, 0xad, 0x68, 0xca, 0xbe, 0x2b, 0x19, + 0x7e, 0x0e, 0x49, 0xcc, 0x7d, 0x9f, 0xdc, 0x32, 0xe6, 0x1b, 0x33, 0x30, 0x1d, 0xf1, 0x2d, 0xa0, + 0x87, 0xa1, 0xc0, 0x92, 0x7a, 0x30, 0xf1, 0x50, 0x0c, 0x45, 0x18, 0x1f, 0x1c, 0x0e, 0x43, 0x9f, + 0x35, 0x60, 0xb6, 0x13, 0xf1, 0xc2, 0x4a, 0xc9, 0x39, 0xe2, 0x3d, 0x5f, 0xd4, 0xb5, 0xab, 0x25, + 0xbb, 0x8d, 0x32, 0xc3, 0x71, 0xee, 0x74, 0x03, 0x8a, 0xc8, 0xbb, 0x16, 0xf1, 0x18, 0xb6, 0xb0, + 0x71, 0x14, 0x89, 0xe5, 0x28, 0x18, 0xc7, 0xf1, 0xe9, 0x0c, 0xb3, 0xde, 0x8d, 0xf2, 0x9d, 0x94, + 0x8a, 0x24, 0x80, 0x43, 0x5a, 0xe8, 0x19, 0x98, 0x11, 0x99, 0xda, 0x36, 0xdd, 0xc6, 0x45, 0xcb, + 0xdf, 0x15, 0xc6, 0xbd, 0x3a, 0x8c, 0x2c, 0x47, 0xa0, 0x38, 0x86, 0xcd, 0xfa, 0x16, 0xa6, 0xc3, + 0x63, 0x04, 0xc6, 0xa3, 0xb9, 0x80, 0x97, 0xa3, 0x60, 0x1c, 0xc7, 0x47, 0xef, 0xd0, 0xe4, 0x3e, + 0xbf, 0xa7, 0x53, 0xd2, 0x20, 0x45, 0xf6, 0x57, 0x60, 0xb6, 0xcb, 0xce, 0x42, 0x0d, 0x09, 0x14, + 0xfb, 0x51, 0x31, 0xbc, 0x1a, 0x05, 0xe3, 0x38, 0x3e, 0x7a, 0x1a, 0xa6, 0x3d, 0x2a, 0xdd, 0x14, + 0x01, 0x7e, 0x79, 0xa7, 0xee, 0x66, 0xb0, 0x0e, 0xc4, 0x51, 0x5c, 0xf4, 0x2c, 0xcc, 0x87, 0xe9, + 0x9e, 0x24, 0x01, 0x7e, 0x9b, 0xa7, 0x32, 0x99, 0x54, 0xe2, 0x08, 0x38, 0x59, 0x07, 0xfd, 0x1c, + 0xcc, 0x69, 0x23, 0xb1, 0xea, 0x34, 0xc8, 0x6d, 0x91, 0x92, 0x87, 0xa5, 0x6d, 0x5f, 0x8e, 0xc1, + 0x70, 0x02, 0x1b, 0xbd, 0x17, 0x66, 0xea, 0x6e, 0xab, 0xc5, 0x64, 0x1c, 0xcf, 0x43, 0xcb, 0x73, + 0xef, 0xf0, 0x2c, 0x45, 0x11, 0x08, 0x8e, 0x61, 0xa2, 0x4b, 0x80, 0xdc, 0x6d, 0x9f, 0x78, 0x7b, + 0xa4, 0xf1, 0x2c, 0xff, 0xf2, 0x22, 0x55, 0xf1, 0xd3, 0xd1, 0xb8, 0xdf, 0xcb, 0x09, 0x0c, 0x9c, + 0x52, 0x8b, 0x25, 0x42, 0xd1, 0xde, 0xe0, 0xcc, 0x64, 0xf1, 0xcd, 0x90, 0xf8, 0xc9, 0xfd, 0xae, + 0x0f, 0x70, 0x3c, 0x18, 0xe7, 0x61, 0xd8, 0xd9, 0x24, 0xe1, 0xd1, 0x53, 0x52, 0x86, 0x3a, 0x82, + 0x97, 0x62, 0xc1, 0x09, 0x7d, 0x1c, 0x4a, 0xdb, 0x32, 0x3f, 0xf1, 0xe2, 0x5c, 0x16, 0x7a, 0x31, + 0x96, 0x6a, 0x3b, 0x3c, 0x99, 0x2a, 0x00, 0x0e, 0x59, 0xa2, 0x47, 0x60, 0xf2, 0xe2, 0x66, 0x45, + 0xad, 0xc2, 0x79, 0x36, 0xfb, 0x63, 0xb4, 0x0a, 0xd6, 0x01, 0x74, 0x87, 0x29, 0x7b, 0x09, 0xb1, + 0x29, 0x0e, 0xf5, 0x6d, 0xd2, 0xfc, 0xa1, 0xd8, 0xec, 0x3a, 0x12, 0xd7, 0x16, 0x4f, 0xc4, 0xb0, + 0x45, 0x39, 0x56, 0x18, 0xe8, 0x05, 0x98, 0x14, 0xfa, 0x82, 0xc9, 0xa6, 0x85, 0xa3, 0xbd, 0xef, + 0xc2, 0x21, 0x09, 0xac, 0xd3, 0x63, 0xb7, 0x4c, 0x2c, 0x6d, 0x2b, 0xb9, 0xd0, 0x6d, 0xb5, 0x16, + 0x4f, 0x32, 0xb9, 0x19, 0xde, 0x32, 0x85, 0x20, 0xac, 0xe3, 0xa1, 0xc7, 0x65, 0xe4, 0xc4, 0x5b, + 0x22, 0xd7, 0x6e, 0x2a, 0x72, 0x42, 0x59, 0xb9, 0x7d, 0x02, 0x7b, 0x4f, 0xdd, 0x25, 0x64, 0x61, + 0x1b, 0x4e, 0x4b, 0x13, 0x2b, 0xb9, 0x49, 0x16, 0x17, 0x23, 0x5e, 0x82, 0xd3, 0xd7, 0xfb, 0x62, + 0xe2, 0x43, 0xa8, 0xa0, 0x6d, 0xc8, 0x5b, 0xad, 0xed, 0xc5, 0xfb, 0xb3, 0xb0, 0x15, 0xd5, 0x97, + 0x54, 0x79, 0x30, 0x4e, 0x65, 0xad, 0x8a, 0x29, 0x71, 0xf3, 0x95, 0x9c, 0xf2, 0xca, 0xab, 0xe4, + 0x84, 0x2f, 0xe9, 0xab, 0xda, 0xc8, 0xe2, 0x4b, 0x81, 0x89, 0x24, 0xde, 0x5c, 0x21, 0xa5, 0xae, + 0xe9, 0x8e, 0xda, 0xc7, 0x99, 0x64, 0x9e, 0x88, 0x26, 0x5e, 0xe4, 0xa7, 0xb9, 0xe8, 0x2e, 0x36, + 0xff, 0xbe, 0xa0, 0x9c, 0x50, 0xb1, 0x50, 0x00, 0x0f, 0x0a, 0xb6, 0x1f, 0xd8, 0x6e, 0x86, 0xcf, + 0xb6, 0x62, 0x19, 0x0b, 0x59, 0x00, 0x2b, 0x03, 0x60, 0xce, 0x8a, 0xf2, 0x74, 0x9a, 0xb6, 0x73, + 0x5b, 0x74, 0xff, 0x4a, 0xe6, 0x77, 0xfc, 0x9c, 0x27, 0x03, 0x60, 0xce, 0x0a, 0xdd, 0xe0, 0x2b, + 0x2d, 0x9b, 0xaf, 0x42, 0xc6, 0x3f, 0xf6, 0x1a, 0x5d, 0x71, 0x94, 0x97, 0xdf, 0xb6, 0x85, 0x0d, + 0x33, 0x22, 0xaf, 0xda, 0xfa, 0x6a, 0x1a, 0xaf, 0xda, 0xfa, 0x2a, 0xa6, 0x4c, 0xd0, 0x6b, 0x06, + 0x80, 0xa5, 0xbe, 0x7a, 0x9a, 0x4d, 0xc6, 0xfb, 0x7e, 0x5f, 0x51, 0xe5, 0x31, 0x67, 0x21, 0x14, + 0x6b, 0x9c, 0xd1, 0x8b, 0x30, 0x61, 0xf1, 0xef, 0x75, 0x88, 0x70, 0xbe, 0x6c, 0x3e, 0x42, 0x13, + 0x6b, 0x01, 0x8b, 0x63, 0x14, 0x20, 0x2c, 0x19, 0x9a, 0xff, 0x6a, 0x80, 0xf6, 0x99, 0xba, 0x30, + 0xd8, 0xca, 0x18, 0x38, 0xd8, 0x2a, 0x37, 0x64, 0xb0, 0x55, 0x7e, 0xa8, 0x60, 0xab, 0xb1, 0xe1, + 0x83, 0xad, 0x0a, 0xfd, 0x83, 0xad, 0xcc, 0xd7, 0x0d, 0x98, 0x4f, 0xac, 0x8b, 0xf8, 0xe7, 0x80, + 0x8d, 0x01, 0x3f, 0x07, 0xbc, 0x02, 0x73, 0x22, 0x7d, 0x68, 0xad, 0xd3, 0xb2, 0x53, 0x5f, 0x99, + 0x6e, 0xc5, 0xe0, 0x38, 0x51, 0xc3, 0xfc, 0x63, 0x03, 0x26, 0xb5, 0x47, 0x31, 0xb4, 0x1f, 0xec, + 0xf1, 0x90, 0x68, 0x46, 0x98, 0x39, 0x95, 0xb9, 0x38, 0x39, 0x8c, 0x7b, 0xdb, 0x9b, 0x5a, 0xaa, + 0xba, 0xd0, 0xdb, 0x4e, 0x4b, 0xb1, 0x80, 0xf2, 0x24, 0x64, 0x84, 0x7f, 0xea, 0x39, 0xaf, 0x27, + 0x21, 0x23, 0x1d, 0xcc, 0x20, 0x8c, 0x1d, 0xd5, 0xa7, 0x22, 0x0e, 0x4f, 0x4b, 0xd4, 0x6a, 0xd1, + 0x53, 0x13, 0x83, 0xa1, 0x33, 0x90, 0x27, 0x4e, 0x43, 0x18, 0xff, 0xea, 0x33, 0x20, 0xe7, 0x9d, + 0x06, 0xa6, 0xe5, 0xe6, 0x65, 0x98, 0xaa, 0x91, 0xba, 0x47, 0x82, 0xe7, 0xc8, 0xfe, 0xc0, 0xdf, + 0x15, 0xb9, 0x49, 0xf6, 0xe3, 0xdf, 0x15, 0xa1, 0xd5, 0x69, 0xb9, 0xf9, 0xbb, 0x06, 0xc4, 0xf2, + 0xe6, 0x6a, 0x9e, 0x37, 0xa3, 0x9f, 0xe7, 0x2d, 0xe2, 0x23, 0xca, 0x1d, 0xea, 0x23, 0xba, 0x04, + 0xa8, 0x6d, 0x05, 0xf5, 0xdd, 0x48, 0x96, 0x68, 0x71, 0xee, 0x0a, 0x9f, 0xe0, 0x25, 0x30, 0x70, + 0x4a, 0x2d, 0xf3, 0x65, 0x03, 0x12, 0x5f, 0x6a, 0xa6, 0xd6, 0x02, 0x11, 0x9f, 0x6c, 0xe0, 0xc7, + 0x51, 0x65, 0x2d, 0xc8, 0x2f, 0x35, 0x48, 0x38, 0x3d, 0xb3, 0x48, 0xaf, 0x97, 0xf4, 0x21, 0xf0, + 0xc7, 0x4a, 0xea, 0xcc, 0xb2, 0x12, 0x05, 0xe3, 0x38, 0xbe, 0x79, 0x0d, 0x8a, 0xf2, 0x45, 0x27, + 0x7b, 0x16, 0x25, 0x4f, 0xc1, 0xfa, 0xb3, 0x28, 0x7a, 0x08, 0x66, 0x10, 0x3a, 0x4c, 0xbe, 0x63, + 0x5f, 0x74, 0xfd, 0x40, 0x3e, 0x43, 0xe5, 0xbe, 0xae, 0x8d, 0x55, 0x56, 0x86, 0x15, 0xd4, 0x9c, + 0x87, 0x59, 0xe5, 0xc4, 0x12, 0x11, 0x3a, 0xdf, 0xca, 0xc3, 0x54, 0xe4, 0xfb, 0x7b, 0x77, 0x9f, + 0xec, 0xc1, 0xa7, 0x25, 0xc5, 0x19, 0x95, 0x1f, 0xd2, 0x19, 0xa5, 0x7b, 0xff, 0xc6, 0x8e, 0xd7, + 0xfb, 0x57, 0xc8, 0xc6, 0xfb, 0x17, 0xc0, 0x84, 0xf8, 0x36, 0xb9, 0x10, 0xff, 0xeb, 0x19, 0xa5, + 0x63, 0x10, 0xef, 0x9a, 0x99, 0xe0, 0x97, 0x02, 0x4c, 0xb2, 0x32, 0xbf, 0x5e, 0x80, 0x99, 0x68, + 0x82, 0x86, 0x01, 0x66, 0xf2, 0x1d, 0x89, 0x99, 0x1c, 0xf2, 0x30, 0x9e, 0x1f, 0xf5, 0x30, 0x3e, + 0x36, 0xea, 0x61, 0xbc, 0x70, 0x84, 0xc3, 0x78, 0xf2, 0x28, 0x3d, 0x3e, 0xf0, 0x51, 0xfa, 0x7d, + 0xea, 0x26, 0x79, 0x22, 0x72, 0xf5, 0x12, 0xde, 0x24, 0xa3, 0xe8, 0x34, 0x2c, 0xbb, 0x8d, 0xd4, + 0x1b, 0xf9, 0xe2, 0x5d, 0x0e, 0x1d, 0x5e, 0xea, 0xc5, 0xef, 0xf0, 0xfe, 0xbe, 0xb7, 0x0c, 0x71, + 0xe9, 0x1b, 0x7e, 0x7e, 0x9f, 0x29, 0x3f, 0x88, 0x2a, 0xce, 0x5a, 0x08, 0xc2, 0x3a, 0x1e, 0xfb, + 0x44, 0x54, 0xf4, 0x9b, 0x58, 0xcc, 0xb7, 0xa1, 0x7f, 0x22, 0x2a, 0xf6, 0x0d, 0xad, 0x38, 0xbe, + 0xf9, 0xb5, 0x3c, 0xcc, 0x44, 0x53, 0xfc, 0xa3, 0x5b, 0xea, 0x6c, 0x90, 0xc9, 0xb1, 0x84, 0x93, + 0xd5, 0x52, 0x14, 0xf4, 0x3d, 0xe8, 0xf3, 0x8f, 0xc2, 0x6f, 0xab, 0x7c, 0x09, 0xc7, 0xc7, 0x58, + 0x9c, 0xb0, 0x05, 0x3b, 0x96, 0xc5, 0x3f, 0x0c, 0xa5, 0x15, 0xb7, 0xc7, 0x99, 0x73, 0x0f, 0x83, + 0x63, 0x15, 0x2b, 0xac, 0xb1, 0xa5, 0xe2, 0x7d, 0x8f, 0x78, 0xf6, 0x8e, 0xad, 0x3e, 0x4f, 0xc4, + 0x84, 0xe7, 0x35, 0x51, 0x86, 0x15, 0xd4, 0x7c, 0x39, 0x07, 0xe1, 0xc7, 0xd8, 0x58, 0x76, 0x70, + 0x5f, 0x33, 0x1b, 0xc4, 0xb4, 0x5d, 0x1a, 0x35, 0x05, 0x7f, 0x48, 0x51, 0x04, 0xda, 0x68, 0x25, + 0x38, 0xc2, 0xf1, 0x27, 0xf0, 0x11, 0x36, 0x0b, 0x66, 0x63, 0x0f, 0x7d, 0x32, 0x8f, 0x66, 0xfc, + 0x62, 0x1e, 0x4a, 0xea, 0xa9, 0x14, 0x7a, 0x0f, 0x4b, 0xb1, 0xbb, 0xeb, 0xca, 0xc4, 0xc7, 0x6f, + 0xd5, 0x12, 0xe1, 0xee, 0xba, 0x8d, 0x3b, 0xbd, 0xf2, 0xac, 0x42, 0xe6, 0x45, 0x58, 0x54, 0xa0, + 0x46, 0x5a, 0xd7, 0x6b, 0xc5, 0x8d, 0xb4, 0xab, 0x78, 0x0d, 0xd3, 0x72, 0x74, 0x1b, 0x26, 0x76, + 0x89, 0xd5, 0x20, 0x9e, 0x8c, 0x5b, 0x58, 0xcf, 0xe8, 0x79, 0xd7, 0x45, 0x46, 0x35, 0x1c, 0x06, + 0xfe, 0xdf, 0xc7, 0x92, 0x1d, 0x55, 0x54, 0xdb, 0x6e, 0x63, 0x3f, 0x9e, 0x38, 0xb7, 0xea, 0x36, + 0xf6, 0x31, 0x83, 0xa0, 0x67, 0x60, 0x26, 0xb0, 0xdb, 0xc4, 0xed, 0x06, 0xfa, 0xa7, 0xae, 0xf2, + 0xa1, 0xe3, 0x7a, 0x2b, 0x02, 0xc5, 0x31, 0x6c, 0xaa, 0xe8, 0x6e, 0xf8, 0xae, 0xc3, 0xb2, 0xe1, + 0x8c, 0x47, 0xbd, 0x5c, 0x97, 0x6a, 0x97, 0x37, 0x58, 0x32, 0x1c, 0x85, 0x41, 0xb1, 0x6d, 0xf6, + 0x1e, 0xc3, 0x23, 0xe2, 0xde, 0x68, 0x2e, 0x7c, 0x35, 0xcb, 0xcb, 0xb1, 0xc2, 0x30, 0xaf, 0xc2, + 0x6c, 0xac, 0xab, 0xd2, 0x1c, 0x36, 0xd2, 0xcd, 0xe1, 0xc1, 0xb2, 0xd4, 0xfe, 0x81, 0x01, 0xf3, + 0x89, 0xcd, 0x3b, 0x68, 0x98, 0x6d, 0x5c, 0x92, 0xe7, 0x8e, 0x2e, 0xc9, 0xf3, 0xc3, 0x49, 0xf2, + 0xea, 0xd2, 0xb7, 0xdf, 0x38, 0x7b, 0xdf, 0x77, 0xde, 0x38, 0x7b, 0xdf, 0xf7, 0xde, 0x38, 0x7b, + 0xdf, 0xcb, 0x07, 0x67, 0x8d, 0x6f, 0x1f, 0x9c, 0x35, 0xbe, 0x73, 0x70, 0xd6, 0xf8, 0xde, 0xc1, + 0x59, 0xe3, 0x1f, 0x0f, 0xce, 0x1a, 0xaf, 0xff, 0xf0, 0xec, 0x7d, 0xcf, 0x17, 0xe5, 0x32, 0xf9, + 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x08, 0xc1, 0x61, 0x7b, 0xd3, 0x89, 0x00, 0x00, } func (m *ALBStatus) Marshal() (dAtA []byte, err error) { @@ -4440,6 +4474,11 @@ func (m *CanaryStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + i -= len(m.StablePingPong) + copy(dAtA[i:], m.StablePingPong) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.StablePingPong))) + i-- + dAtA[i] = 0x2a if m.Weights != nil { { size, err := m.Weights.MarshalToSizedBuffer(dAtA[:i]) @@ -4580,6 +4619,18 @@ func (m *CanaryStrategy) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.PingPong != nil { + { + size, err := m.PingPong.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x7a + } i-- if m.DynamicStableScale { dAtA[i] = 1 @@ -6618,6 +6669,39 @@ func (m *PauseCondition) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *PingPongSpec) 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 *PingPongSpec) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PingPongSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.PongService) + copy(dAtA[i:], m.PongService) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.PongService))) + i-- + dAtA[i] = 0x12 + i -= len(m.PingService) + copy(dAtA[i:], m.PingService) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.PingService))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *PodTemplateMetadata) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -9015,6 +9099,8 @@ func (m *CanaryStatus) Size() (n int) { l = m.Weights.Size() n += 1 + l + sovGenerated(uint64(l)) } + l = len(m.StablePingPong) + n += 1 + l + sovGenerated(uint64(l)) return n } @@ -9100,6 +9186,10 @@ func (m *CanaryStrategy) Size() (n int) { n += 1 + sovGenerated(uint64(*m.AbortScaleDownDelaySeconds)) } n += 2 + if m.PingPong != nil { + l = m.PingPong.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -9803,6 +9893,19 @@ func (m *PauseCondition) Size() (n int) { return n } +func (m *PingPongSpec) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PingService) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.PongService) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + func (m *PodTemplateMetadata) Size() (n int) { if m == nil { return 0 @@ -10837,6 +10940,7 @@ func (this *CanaryStatus) String() string { `CurrentBackgroundAnalysisRunStatus:` + strings.Replace(this.CurrentBackgroundAnalysisRunStatus.String(), "RolloutAnalysisRunStatus", "RolloutAnalysisRunStatus", 1) + `,`, `CurrentExperiment:` + fmt.Sprintf("%v", this.CurrentExperiment) + `,`, `Weights:` + strings.Replace(this.Weights.String(), "TrafficWeights", "TrafficWeights", 1) + `,`, + `StablePingPong:` + fmt.Sprintf("%v", this.StablePingPong) + `,`, `}`, }, "") return s @@ -10879,6 +10983,7 @@ func (this *CanaryStrategy) String() string { `ScaleDownDelayRevisionLimit:` + valueToStringGenerated(this.ScaleDownDelayRevisionLimit) + `,`, `AbortScaleDownDelaySeconds:` + valueToStringGenerated(this.AbortScaleDownDelaySeconds) + `,`, `DynamicStableScale:` + fmt.Sprintf("%v", this.DynamicStableScale) + `,`, + `PingPong:` + strings.Replace(this.PingPong.String(), "PingPongSpec", "PingPongSpec", 1) + `,`, `}`, }, "") return s @@ -11434,6 +11539,17 @@ func (this *PauseCondition) String() string { }, "") return s } +func (this *PingPongSpec) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&PingPongSpec{`, + `PingService:` + fmt.Sprintf("%v", this.PingService) + `,`, + `PongService:` + fmt.Sprintf("%v", this.PongService) + `,`, + `}`, + }, "") + return s +} func (this *PodTemplateMetadata) String() string { if this == nil { return "nil" @@ -15569,6 +15685,38 @@ func (m *CanaryStatus) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StablePingPong", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StablePingPong = PingPongType(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -16263,6 +16411,42 @@ func (m *CanaryStrategy) Unmarshal(dAtA []byte) error { } } m.DynamicStableScale = bool(v != 0) + case 15: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PingPong", 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.PingPong == nil { + m.PingPong = &PingPongSpec{} + } + if err := m.PingPong.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -22526,6 +22710,120 @@ func (m *PauseCondition) Unmarshal(dAtA []byte) error { } return nil } +func (m *PingPongSpec) 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: PingPongSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PingPongSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PingService", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PingService = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PongService", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PongService = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *PodTemplateMetadata) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/pkg/apis/rollouts/v1alpha1/generated.proto b/pkg/apis/rollouts/v1alpha1/generated.proto index 4f19568d00..b388a99398 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.proto +++ b/pkg/apis/rollouts/v1alpha1/generated.proto @@ -378,6 +378,9 @@ message CanaryStatus { // Weights records the weights which have been set on traffic provider. Only valid when using traffic routing optional TrafficWeights weights = 4; + + // StablePingPong For the ping-pong feature holds the current stable service, ping or pong + optional string stablePingPong = 5; } // CanaryStep defines a step of a canary deployment. @@ -483,6 +486,9 @@ message CanaryStrategy { // scaling down the stable as traffic is increased to canary. When disabled (the default behavior) // the stable ReplicaSet remains fully scaled to support instantaneous aborts. optional bool dynamicStableScale = 14; + + // PingPongSpec holds the ping and pong services + optional PingPongSpec pingPong = 15; } // CloudWatchMetric defines the cloudwatch query to perform canary analysis @@ -1003,6 +1009,15 @@ message PauseCondition { optional k8s.io.apimachinery.pkg.apis.meta.v1.Time startTime = 2; } +// PingPongSpec holds the ping and pong service name. +message PingPongSpec { + // name of the ping service + optional string pingService = 1; + + // name of the pong service + optional string pongService = 2; +} + // PodTemplateMetadata extra labels to add to the template message PodTemplateMetadata { // Labels Additional labels to add to the experiment diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index a0ee737923..1e32f065f5 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -89,6 +89,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.NginxTrafficRouting": schema_pkg_apis_rollouts_v1alpha1_NginxTrafficRouting(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ObjectRef": schema_pkg_apis_rollouts_v1alpha1_ObjectRef(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PauseCondition": schema_pkg_apis_rollouts_v1alpha1_PauseCondition(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PingPongSpec": schema_pkg_apis_rollouts_v1alpha1_PingPongSpec(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PodTemplateMetadata": schema_pkg_apis_rollouts_v1alpha1_PodTemplateMetadata(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PreferredDuringSchedulingIgnoredDuringExecution": schema_pkg_apis_rollouts_v1alpha1_PreferredDuringSchedulingIgnoredDuringExecution(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PrometheusMetric": schema_pkg_apis_rollouts_v1alpha1_PrometheusMetric(ref), @@ -1175,6 +1176,13 @@ func schema_pkg_apis_rollouts_v1alpha1_CanaryStatus(ref common.ReferenceCallback Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TrafficWeights"), }, }, + "stablePingPong": { + SchemaProps: spec.SchemaProps{ + Description: "StablePingPong For the ping-pong feature holds the current stable service, ping or pong", + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, @@ -1334,11 +1342,17 @@ func schema_pkg_apis_rollouts_v1alpha1_CanaryStrategy(ref common.ReferenceCallba Format: "", }, }, + "pingPong": { + SchemaProps: spec.SchemaProps{ + Description: "PingPongSpec holds the ping and pong services", + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PingPongSpec"), + }, + }, }, }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AntiAffinity", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.CanaryStep", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PodTemplateMetadata", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutAnalysisBackground", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutTrafficRouting", "k8s.io/apimachinery/pkg/util/intstr.IntOrString"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AntiAffinity", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.CanaryStep", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PingPongSpec", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PodTemplateMetadata", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutAnalysisBackground", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutTrafficRouting", "k8s.io/apimachinery/pkg/util/intstr.IntOrString"}, } } @@ -2988,6 +3002,36 @@ func schema_pkg_apis_rollouts_v1alpha1_PauseCondition(ref common.ReferenceCallba } } +func schema_pkg_apis_rollouts_v1alpha1_PingPongSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PingPongSpec holds the ping and pong service name.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "pingService": { + SchemaProps: spec.SchemaProps{ + Description: "name of the ping service", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "pongService": { + SchemaProps: spec.SchemaProps{ + Description: "name of the pong service", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"pingService", "pongService"}, + }, + }, + } +} + func schema_pkg_apis_rollouts_v1alpha1_PodTemplateMetadata(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/pkg/apis/rollouts/v1alpha1/types.go b/pkg/apis/rollouts/v1alpha1/types.go index 6a81900b74..b86c69f0e9 100644 --- a/pkg/apis/rollouts/v1alpha1/types.go +++ b/pkg/apis/rollouts/v1alpha1/types.go @@ -305,6 +305,16 @@ type CanaryStrategy struct { // scaling down the stable as traffic is increased to canary. When disabled (the default behavior) // the stable ReplicaSet remains fully scaled to support instantaneous aborts. DynamicStableScale bool `json:"dynamicStableScale,omitempty" protobuf:"varint,14,opt,name=dynamicStableScale"` + // PingPongSpec holds the ping and pong services + PingPong *PingPongSpec `json:"pingPong,omitempty" protobuf:"varint,15,opt,name=pingPong"` +} + +// PingPongSpec holds the ping and pong service name. +type PingPongSpec struct { + // name of the ping service + PingService string `json:"pingService" protobuf:"bytes,1,opt,name=pingService"` + // name of the pong service + PongService string `json:"pongService" protobuf:"bytes,2,opt,name=pongService"` } // AnalysisRunStrategy configuration for the analysis runs and experiments to retain @@ -824,8 +834,17 @@ type CanaryStatus struct { CurrentExperiment string `json:"currentExperiment,omitempty" protobuf:"bytes,3,opt,name=currentExperiment"` // Weights records the weights which have been set on traffic provider. Only valid when using traffic routing Weights *TrafficWeights `json:"weights,omitempty" protobuf:"bytes,4,opt,name=weights"` + // StablePingPong For the ping-pong feature holds the current stable service, ping or pong + StablePingPong PingPongType `json:"stablePingPong,omitempty" protobuf:"bytes,5,opt,name=stablePingPong"` } +type PingPongType string + +const ( + PPPing PingPongType = "ping" + PPPong PingPongType = "pong" +) + // TrafficWeights describes the current status of how traffic has been split type TrafficWeights struct { // Canary is the current traffic weight split to canary ReplicaSet diff --git a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go index e18e5ade4b..9eed7b6376 100644 --- a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go @@ -781,6 +781,11 @@ func (in *CanaryStrategy) DeepCopyInto(out *CanaryStrategy) { *out = new(int32) **out = **in } + if in.PingPong != nil { + in, out := &in.PingPong, &out.PingPong + *out = new(PingPongSpec) + **out = **in + } return } @@ -1651,6 +1656,22 @@ func (in *PauseCondition) DeepCopy() *PauseCondition { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PingPongSpec) DeepCopyInto(out *PingPongSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PingPongSpec. +func (in *PingPongSpec) DeepCopy() *PingPongSpec { + if in == nil { + return nil + } + out := new(PingPongSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PodTemplateMetadata) DeepCopyInto(out *PodTemplateMetadata) { *out = *in diff --git a/pkg/apis/rollouts/validation/validation.go b/pkg/apis/rollouts/validation/validation.go index 4a56c0fa30..b5e5506ed2 100644 --- a/pkg/apis/rollouts/validation/validation.go +++ b/pkg/apis/rollouts/validation/validation.go @@ -62,6 +62,14 @@ const ( InvalidCanaryDynamicStableScale = "Canary dynamicStableScale can only be used with traffic routing" // InvalidCanaryDynamicStableScaleWithScaleDownDelay indicates that canary.dynamicStableScale cannot be used with scaleDownDelaySeconds InvalidCanaryDynamicStableScaleWithScaleDownDelay = "Canary dynamicStableScale cannot be used with scaleDownDelaySeconds" + // InvalidPingPongProvidedMessage indicates that both ping and pong service must be set to use Ping-Pong feature + InvalidPingPongProvidedMessage = "Ping service and Pong service must to be set to use Ping-Pong feature" + // DuplicatedPingPongServicesMessage indicates that the rollout uses the same service for the ping and pong services + DuplicatedPingPongServicesMessage = "This rollout uses the same service for the ping and pong services, but two different services are required." + // MissedAlbRootServiceMessage indicates that the rollout with ALB TrafficRouting and ping pong feature enabled must have root service provided + MissedAlbRootServiceMessage = "Root service field is required for the configuration with ALB and ping-pong feature enabled" + // PingPongWithAlbOnlyMessage At this moment ping-pong feature works with the ALB traffic routing only + PingPongWithAlbOnlyMessage = "Ping-pong feature works with the ALB traffic routing only" ) // allowAllPodValidationOptions allows all pod options to be true for the purposes of rollout pod @@ -211,7 +219,7 @@ func ValidateRolloutStrategyBlueGreen(rollout *v1alpha1.Rollout, fldPath *field. // canary.canaryService to be defined func requireCanaryStableServices(rollout *v1alpha1.Rollout) bool { canary := rollout.Spec.Strategy.Canary - if canary.TrafficRouting == nil || (canary.TrafficRouting.Istio != nil && canary.TrafficRouting.Istio.DestinationRule != nil) { + if canary.TrafficRouting == nil || (canary.TrafficRouting.Istio != nil && canary.TrafficRouting.Istio.DestinationRule != nil) || (canary.PingPong != nil) { return false } return true @@ -224,6 +232,23 @@ func ValidateRolloutStrategyCanary(rollout *v1alpha1.Rollout, fldPath *field.Pat if canary.CanaryService != "" && canary.StableService != "" && canary.CanaryService == canary.StableService { allErrs = append(allErrs, field.Invalid(fldPath.Child("stableService"), canary.StableService, DuplicatedServicesCanaryMessage)) } + if canary.PingPong != nil { + if canary.TrafficRouting != nil && canary.TrafficRouting.ALB == nil { + allErrs = append(allErrs, field.Invalid(fldPath.Child("trafficRouting").Child("alb"), canary.TrafficRouting.ALB, PingPongWithAlbOnlyMessage)) + } + if canary.PingPong.PingService == "" { + allErrs = append(allErrs, field.Invalid(fldPath.Child("pingPong").Child("pingService"), canary.PingPong.PingService, InvalidPingPongProvidedMessage)) + } + if canary.PingPong.PongService == "" { + allErrs = append(allErrs, field.Invalid(fldPath.Child("pingPong").Child("pongService"), canary.PingPong.PongService, InvalidPingPongProvidedMessage)) + } + if canary.PingPong.PingService == canary.PingPong.PongService { + allErrs = append(allErrs, field.Invalid(fldPath.Child("pingPong").Child("pingService"), canary.PingPong.PingService, DuplicatedPingPongServicesMessage)) + } + if canary.TrafficRouting != nil && canary.TrafficRouting.ALB != nil && canary.TrafficRouting.ALB.RootService == "" { + allErrs = append(allErrs, field.Invalid(fldPath.Child("trafficRouting").Child("alb").Child("rootService"), canary.TrafficRouting.ALB.RootService, MissedAlbRootServiceMessage)) + } + } if requireCanaryStableServices(rollout) { if canary.StableService == "" { allErrs = append(allErrs, field.Invalid(fldPath.Child("stableService"), canary.StableService, InvalidTrafficRoutingMessage)) diff --git a/pkg/apis/rollouts/validation/validation_references.go b/pkg/apis/rollouts/validation/validation_references.go index 6a223b2fe5..a980216413 100644 --- a/pkg/apis/rollouts/validation/validation_references.go +++ b/pkg/apis/rollouts/validation/validation_references.go @@ -3,15 +3,9 @@ package validation import ( "fmt" - analysisutil "github.com/argoproj/argo-rollouts/utils/analysis" - "github.com/argoproj/argo-rollouts/utils/conditions" - istioutil "github.com/argoproj/argo-rollouts/utils/istio" - serviceutil "github.com/argoproj/argo-rollouts/utils/service" appsv1 "k8s.io/api/apps/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - ingressutil "github.com/argoproj/argo-rollouts/utils/ingress" corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/util/validation/field" @@ -19,6 +13,11 @@ import ( "github.com/argoproj/argo-rollouts/rollout/trafficrouting/ambassador" "github.com/argoproj/argo-rollouts/rollout/trafficrouting/appmesh" "github.com/argoproj/argo-rollouts/rollout/trafficrouting/istio" + analysisutil "github.com/argoproj/argo-rollouts/utils/analysis" + "github.com/argoproj/argo-rollouts/utils/conditions" + ingressutil "github.com/argoproj/argo-rollouts/utils/ingress" + istioutil "github.com/argoproj/argo-rollouts/utils/istio" + serviceutil "github.com/argoproj/argo-rollouts/utils/service" ) // Controller will validate references in reconciliation @@ -47,6 +46,8 @@ type ServiceType string const ( StableService ServiceType = "StableService" CanaryService ServiceType = "CanaryService" + PingService ServiceType = "PingService" + PongService ServiceType = "PongService" ActiveService ServiceType = "ActiveService" PreviewService ServiceType = "PreviewService" ) @@ -388,6 +389,10 @@ func GetServiceWithTypeFieldPath(serviceType ServiceType) *field.Path { fldPath = fldPath.Child("canary", "canaryService") case StableService: fldPath = fldPath.Child("canary", "stableService") + case PingService: + fldPath = fldPath.Child("canary", "pingPong", "pingService") + case PongService: + fldPath = fldPath.Child("canary", "pingPong", "pongService") default: return nil } diff --git a/pkg/apis/rollouts/validation/validation_references_test.go b/pkg/apis/rollouts/validation/validation_references_test.go index 104844b4b0..15465d09a3 100644 --- a/pkg/apis/rollouts/validation/validation_references_test.go +++ b/pkg/apis/rollouts/validation/validation_references_test.go @@ -4,11 +4,6 @@ import ( "fmt" "testing" - "k8s.io/utils/pointer" - - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" - ingressutil "github.com/argoproj/argo-rollouts/utils/ingress" - "github.com/argoproj/argo-rollouts/utils/unstructured" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" "k8s.io/api/extensions/v1beta1" @@ -17,6 +12,11 @@ import ( "k8s.io/apimachinery/pkg/runtime/serializer/yaml" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/utils/pointer" + + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + ingressutil "github.com/argoproj/argo-rollouts/utils/ingress" + "github.com/argoproj/argo-rollouts/utils/unstructured" ) const successCaseVsvc = `apiVersion: networking.istio.io/v1alpha3 @@ -618,6 +618,18 @@ func TestGetServiceWithTypeFieldPath(t *testing.T) { assert.Equal(t, expectedFldPath.String(), fldPath.String()) }) + t.Run("get pingService fieldPath", func(t *testing.T) { + fldPath := GetServiceWithTypeFieldPath(PingService) + expectedFldPath := field.NewPath("spec", "strategy", "canary", "pingPong", "pingService") + assert.Equal(t, expectedFldPath.String(), fldPath.String()) + }) + + t.Run("get pongService fieldPath", func(t *testing.T) { + fldPath := GetServiceWithTypeFieldPath(PongService) + expectedFldPath := field.NewPath("spec", "strategy", "canary", "pingPong", "pongService") + assert.Equal(t, expectedFldPath.String(), fldPath.String()) + }) + t.Run("get fieldPath for serviceType that does not exist", func(t *testing.T) { fldPath := GetServiceWithTypeFieldPath("DoesNotExist") assert.Nil(t, fldPath) diff --git a/pkg/apis/rollouts/validation/validation_test.go b/pkg/apis/rollouts/validation/validation_test.go index 936030a95b..c88c91ca9a 100644 --- a/pkg/apis/rollouts/validation/validation_test.go +++ b/pkg/apis/rollouts/validation/validation_test.go @@ -133,7 +133,7 @@ func TestValidateRolloutStrategyCanary(t *testing.T) { CanaryService: "canary", StableService: "stable", TrafficRouting: &v1alpha1.RolloutTrafficRouting{ - SMI: &v1alpha1.SMITrafficRouting{}, + ALB: &v1alpha1.ALBTrafficRouting{RootService: "root-service"}, }, Steps: []v1alpha1.CanaryStep{{}}, } @@ -171,6 +171,47 @@ func TestValidateRolloutStrategyCanary(t *testing.T) { assert.Equal(t, DuplicatedServicesCanaryMessage, allErrs[0].Detail) }) + t.Run("duplicate ping pong services", func(t *testing.T) { + invalidRo := ro.DeepCopy() + invalidRo.Spec.Strategy.Canary.PingPong = &v1alpha1.PingPongSpec{PingService: "ping", PongService: "ping"} + allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) + assert.Equal(t, DuplicatedPingPongServicesMessage, allErrs[0].Detail) + }) + + t.Run("ping services using only", func(t *testing.T) { + invalidRo := ro.DeepCopy() + invalidRo.Spec.Strategy.Canary.PingPong = &v1alpha1.PingPongSpec{PingService: "ping", PongService: ""} + allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) + assert.Equal(t, InvalidPingPongProvidedMessage, allErrs[0].Detail) + }) + + t.Run("pong service using only", func(t *testing.T) { + invalidRo := ro.DeepCopy() + invalidRo.Spec.Strategy.Canary.PingPong = &v1alpha1.PingPongSpec{PingService: "", PongService: "pong"} + allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) + assert.Equal(t, InvalidPingPongProvidedMessage, allErrs[0].Detail) + }) + + t.Run("missed ALB root service for the ping-pong feature", func(t *testing.T) { + invalidRo := ro.DeepCopy() + invalidRo.Spec.Strategy.Canary.PingPong = &v1alpha1.PingPongSpec{PingService: "ping", PongService: "pong"} + invalidRo.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{ + ALB: &v1alpha1.ALBTrafficRouting{RootService: ""}, + } + allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) + assert.Equal(t, MissedAlbRootServiceMessage, allErrs[0].Detail) + }) + + t.Run("ping-pong feature without the ALB traffic routing", func(t *testing.T) { + invalidRo := ro.DeepCopy() + invalidRo.Spec.Strategy.Canary.PingPong = &v1alpha1.PingPongSpec{PingService: "ping", PongService: "pong"} + invalidRo.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{ + Nginx: &v1alpha1.NginxTrafficRouting{StableIngress: "stable-ingress"}, + } + allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) + assert.Equal(t, PingPongWithAlbOnlyMessage, allErrs[0].Detail) + }) + t.Run("invalid traffic routing", func(t *testing.T) { invalidRo := ro.DeepCopy() invalidRo.Spec.Strategy.Canary.CanaryService = "" diff --git a/pkg/kubectl-argo-rollouts/cmd/get/get.go b/pkg/kubectl-argo-rollouts/cmd/get/get.go index bb29d692e9..3576484518 100644 --- a/pkg/kubectl-argo-rollouts/cmd/get/get.go +++ b/pkg/kubectl-argo-rollouts/cmd/get/get.go @@ -31,6 +31,8 @@ var ( info.InfoTagStable: FgGreen, info.InfoTagActive: FgGreen, info.InfoTagPreview: FgHiBlue, + info.InfoTagPing: FgHiBlue, + info.InfoTagPong: FgHiBlue, // Colors for highlighting experiment/analysisruns string(v1alpha1.AnalysisPhasePending): FgHiBlue, diff --git a/pkg/kubectl-argo-rollouts/cmd/get/get_rollout.go b/pkg/kubectl-argo-rollouts/cmd/get/get_rollout.go index 92eab92477..03a7465751 100644 --- a/pkg/kubectl-argo-rollouts/cmd/get/get_rollout.go +++ b/pkg/kubectl-argo-rollouts/cmd/get/get_rollout.go @@ -212,6 +212,14 @@ func (o *GetOptions) PrintReplicaSetInfo(w io.Writer, rsInfo rollout.ReplicaSetI infoCols = append(infoCols, o.colorize(info.InfoTagPreview)) name = o.colorizeStatus(name, info.InfoTagPreview) } + if rsInfo.Ping { + infoCols = append(infoCols, o.colorize(info.InfoTagPing)) + name = o.colorizeStatus(name, info.InfoTagPing) + } + if rsInfo.Pong { + infoCols = append(infoCols, o.colorize(info.InfoTagPong)) + name = o.colorizeStatus(name, info.InfoTagPong) + } if rsInfo.ScaleDownDeadline != "" { infoCols = append(infoCols, fmt.Sprintf("delay:%s", info.ScaleDownDelay(rsInfo))) } diff --git a/pkg/kubectl-argo-rollouts/cmd/get/get_test.go b/pkg/kubectl-argo-rollouts/cmd/get/get_test.go index 8758d11145..6c89ca5b12 100644 --- a/pkg/kubectl-argo-rollouts/cmd/get/get_test.go +++ b/pkg/kubectl-argo-rollouts/cmd/get/get_test.go @@ -304,6 +304,54 @@ NAME KIND STATUS AGE IN assertStdout(t, expectedOut, o.IOStreams) } +func TestGetCanaryPingPongRollout(t *testing.T) { + rolloutObjs := testdata.NewCanaryRollout() + + tf, o := options.NewFakeArgoRolloutsOptions(rolloutObjs.AllObjects()...) + o.RESTClientGetter = tf.WithNamespace(rolloutObjs.Rollouts[3].Namespace) + defer tf.Cleanup() + cmd := NewCmdGetRollout(o) + cmd.PersistentPreRunE = o.PersistentPreRunE + cmd.SetArgs([]string{rolloutObjs.Rollouts[3].Name, "--no-color"}) + err := cmd.Execute() + assert.NoError(t, err) + + expectedOut := strings.TrimPrefix(` +Name: canary-demo-pingpong +Namespace: jesse-test +Status: ✖ Degraded +Message: ProgressDeadlineExceeded: ReplicaSet "canary-demo-65fb5ffc84" has timed out progressing. +Strategy: Canary + Step: 0/8 + SetWeight: 20 + ActualWeight: 0 +Images: argoproj/rollouts-demo:does-not-exist (canary, ping) + argoproj/rollouts-demo:green (stable, pong) +Replicas: + Desired: 5 + Current: 6 + Updated: 1 + Ready: 5 + Available: 5 + +NAME KIND STATUS AGE INFO +⟳ canary-demo-pingpong Rollout ✖ Degraded 7d +├──# revision:31 +│ └──⧉ canary-demo-65fb5ffc84 ReplicaSet ◌ Progressing 7d canary,ping +│ └──□ canary-demo-65fb5ffc84-9wf5r Pod ⚠ ImagePullBackOff 7d ready:0/1 +├──# revision:30 +│ └──⧉ canary-demo-877894d5b ReplicaSet ✔ Healthy 7d stable,pong +│ ├──□ canary-demo-877894d5b-6jfpt Pod ✔ Running 7d ready:1/1 +│ ├──□ canary-demo-877894d5b-7jmqw Pod ✔ Running 7d ready:1/1 +│ ├──□ canary-demo-877894d5b-j8g2b Pod ✔ Running 7d ready:1/1 +│ ├──□ canary-demo-877894d5b-jw5qm Pod ✔ Running 7d ready:1/1 +│ └──□ canary-demo-877894d5b-kh7x4 Pod ✔ Running 7d ready:1/1 +└──# revision:29 + └──⧉ canary-demo-859c99b45c ReplicaSet • ScaledDown 7d +`, "\n") + assertStdout(t, expectedOut, o.IOStreams) +} + func TestExperimentRollout(t *testing.T) { rolloutObjs := testdata.NewExperimentAnalysisRollout() diff --git a/pkg/kubectl-argo-rollouts/info/info.go b/pkg/kubectl-argo-rollouts/info/info.go index bbc65c289b..92e2cef729 100644 --- a/pkg/kubectl-argo-rollouts/info/info.go +++ b/pkg/kubectl-argo-rollouts/info/info.go @@ -29,6 +29,8 @@ const ( InfoTagStable = "stable" InfoTagActive = "active" InfoTagPreview = "preview" + InfoTagPing = "ping" + InfoTagPong = "pong" ) type Metadata v1.ObjectMeta diff --git a/pkg/kubectl-argo-rollouts/info/info_test.go b/pkg/kubectl-argo-rollouts/info/info_test.go index 2f69d2dd6c..33515e9ad4 100644 --- a/pkg/kubectl-argo-rollouts/info/info_test.go +++ b/pkg/kubectl-argo-rollouts/info/info_test.go @@ -37,6 +37,24 @@ func TestCanaryRolloutInfo(t *testing.T) { }) } +func TestPingPongCanaryRolloutInfo(t *testing.T) { + rolloutObjs := testdata.NewCanaryRollout() + roInfo := NewRolloutInfo(rolloutObjs.Rollouts[3], rolloutObjs.ReplicaSets, rolloutObjs.Pods, rolloutObjs.Experiments, rolloutObjs.AnalysisRuns, nil) + assert.Equal(t, roInfo.ObjectMeta.Name, rolloutObjs.Rollouts[3].Name) + assert.Len(t, Revisions(roInfo), 3) + + assert.Equal(t, Images(roInfo), []ImageInfo{ + { + Image: "argoproj/rollouts-demo:does-not-exist", + Tags: []string{InfoTagCanary, InfoTagPing}, + }, + { + Image: "argoproj/rollouts-demo:green", + Tags: []string{InfoTagStable, InfoTagPong}, + }, + }) +} + func TestBlueGreenRolloutInfo(t *testing.T) { { rolloutObjs := testdata.NewBlueGreenRollout() diff --git a/pkg/kubectl-argo-rollouts/info/replicaset_info.go b/pkg/kubectl-argo-rollouts/info/replicaset_info.go index ade7b287dc..d7d0655370 100644 --- a/pkg/kubectl-argo-rollouts/info/replicaset_info.go +++ b/pkg/kubectl-argo-rollouts/info/replicaset_info.go @@ -12,6 +12,7 @@ import ( "github.com/argoproj/argo-rollouts/pkg/apiclient/rollout" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + "github.com/argoproj/argo-rollouts/rollout/trafficrouting" replicasetutil "github.com/argoproj/argo-rollouts/utils/replicaset" timeutil "github.com/argoproj/argo-rollouts/utils/time" ) @@ -42,10 +43,19 @@ func GetReplicaSetInfo(ownerUID types.UID, ro *v1alpha1.Rollout, allReplicaSets if ro != nil { podTemplateHash := replicasetutil.GetPodTemplateHash(rs) if ro.Spec.Strategy.Canary != nil { + stableRsIsPing := trafficrouting.IsStablePing(ro) if ro.Status.StableRS == podTemplateHash { rsInfo.Stable = true + if trafficrouting.IsPingPongEnabled(ro) { + rsInfo.Ping = stableRsIsPing + rsInfo.Pong = !stableRsIsPing + } } else if ro.Status.CurrentPodHash == podTemplateHash { rsInfo.Canary = true + if trafficrouting.IsPingPongEnabled(ro) { + rsInfo.Ping = !stableRsIsPing + rsInfo.Pong = stableRsIsPing + } } } if ro.Spec.Strategy.BlueGreen != nil { diff --git a/pkg/kubectl-argo-rollouts/info/rollout_info.go b/pkg/kubectl-argo-rollouts/info/rollout_info.go index 2f67876f2b..f50e778ed5 100644 --- a/pkg/kubectl-argo-rollouts/info/rollout_info.go +++ b/pkg/kubectl-argo-rollouts/info/rollout_info.go @@ -147,6 +147,12 @@ func Images(r *rollout.RolloutInfo) []ImageInfo { if rsInfo.Preview { newImage.Tags = append(newImage.Tags, InfoTagPreview) } + if rsInfo.Ping { + newImage.Tags = append(newImage.Tags, InfoTagPing) + } + if rsInfo.Pong { + newImage.Tags = append(newImage.Tags, InfoTagPong) + } images = mergeImageAndTags(newImage, images) } } diff --git a/pkg/kubectl-argo-rollouts/info/testdata/canary/canary-rollout4.yaml b/pkg/kubectl-argo-rollouts/info/testdata/canary/canary-rollout4.yaml new file mode 100644 index 0000000000..6ec2f0795a --- /dev/null +++ b/pkg/kubectl-argo-rollouts/info/testdata/canary/canary-rollout4.yaml @@ -0,0 +1,86 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + annotations: + rollout.argoproj.io/revision: "31" + creationTimestamp: "2019-10-25T06:07:18Z" + generation: 429 + labels: + app: canary-demo + app.kubernetes.io/instance: jesse-test + name: canary-demo-pingpong + namespace: jesse-test + resourceVersion: "28253567" + selfLink: /apis/argoproj.io/v1alpha1/namespaces/jesse-test/rollouts/canary-demo + uid: b350ba76-f6ed-11e9-a15b-42010aa80033 +spec: + progressDeadlineSeconds: 30 + replicas: 5 + revisionHistoryLimit: 3 + selector: + matchLabels: + app: canary-demo + strategy: + canary: + pingPong: + pingService: ping-service + pongService: pong-service + steps: + - setWeight: 20 + - pause: {} + - setWeight: 40 + - pause: + duration: 10s + - setWeight: 60 + - pause: + duration: 10s + - setWeight: 80 + - pause: + duration: 10s + template: + metadata: + creationTimestamp: null + labels: + app: canary-demo + spec: + containers: + - image: argoproj/rollouts-demo:does-not-exist + imagePullPolicy: Always + name: canary-demo + ports: + - containerPort: 8080 + name: http + protocol: TCP + resources: + requests: + cpu: 5m + memory: 32Mi +status: + HPAReplicas: 6 + availableReplicas: 5 + blueGreen: {} + canary: { + stablePingPong: pong + } + stableRS: 877894d5b + conditions: + - lastTransitionTime: "2019-10-25T06:07:29Z" + lastUpdateTime: "2019-10-25T06:07:29Z" + message: Rollout has minimum availability + reason: AvailableReason + status: "True" + type: Available + - lastTransitionTime: "2019-10-28T04:52:55Z" + lastUpdateTime: "2019-10-28T04:52:55Z" + message: ReplicaSet "canary-demo-65fb5ffc84" has timed out progressing. + reason: ProgressDeadlineExceeded + status: "False" + type: Progressing + currentPodHash: 65fb5ffc84 + currentStepHash: f64cdc9d + currentStepIndex: 0 + observedGeneration: "429" + readyReplicas: 5 + replicas: 6 + selector: app=canary-demo + updatedReplicas: 1 diff --git a/rollout/canary.go b/rollout/canary.go index c5f3014107..dd8b53f4c6 100644 --- a/rollout/canary.go +++ b/rollout/canary.go @@ -8,6 +8,7 @@ import ( "k8s.io/utils/pointer" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + "github.com/argoproj/argo-rollouts/rollout/trafficrouting" "github.com/argoproj/argo-rollouts/utils/conditions" "github.com/argoproj/argo-rollouts/utils/defaults" "github.com/argoproj/argo-rollouts/utils/record" @@ -44,6 +45,10 @@ func (c *rolloutContext) rolloutCanary() error { return err } + if err := c.reconcilePingAndPongService(); err != nil { + return err + } + if err := c.reconcileStableAndCanaryService(); err != nil { return err } @@ -288,7 +293,8 @@ func (c *rolloutContext) canProceedWithScaleDownAnnotation(oldRSs []*appsv1.Repl // AWS API calls. return true, nil } - stableSvc, err := c.servicesLister.Services(c.rollout.Namespace).Get(c.rollout.Spec.Strategy.Canary.StableService) + stableSvcName, _ := trafficrouting.GetStableAndCanaryServices(c.rollout) + stableSvc, err := c.servicesLister.Services(c.rollout.Namespace).Get(stableSvcName) if err != nil { return false, err } @@ -340,6 +346,7 @@ func (c *rolloutContext) syncRolloutStatusCanary() error { newStatus.AvailableReplicas = replicasetutil.GetAvailableReplicaCountForReplicaSets(c.allRSs) newStatus.HPAReplicas = replicasetutil.GetActualReplicaCountForReplicaSets(c.allRSs) newStatus.Selector = metav1.FormatLabelSelector(c.rollout.Spec.Selector) + newStatus.Canary.StablePingPong = c.rollout.Status.Canary.StablePingPong currentStep, currentStepIndex := replicasetutil.GetCurrentCanaryStep(c.rollout) newStatus.StableRS = c.rollout.Status.StableRS diff --git a/rollout/canary_test.go b/rollout/canary_test.go index 9b4504000d..8cc1c3b0df 100644 --- a/rollout/canary_test.go +++ b/rollout/canary_test.go @@ -1361,6 +1361,89 @@ func TestCanaryRolloutWithInvalidStableServiceName(t *testing.T) { assert.Equal(t, "The Rollout \"foo\" is invalid: spec.strategy.canary.stableService: Invalid value: \"invalid-stable\": service \"invalid-stable\" not found", condition["message"]) } +func TestCanaryRolloutWithPingPongServices(t *testing.T) { + f := newFixture(t) + defer f.Close() + + r := newCanaryRollout("foo", 1, nil, nil, nil, intstr.FromInt(1), intstr.FromInt(0)) + pingSvc := newService("ping-service", 80, nil, r) + pongSvc := newService("pong-service", 80, nil, r) + rs1 := newReplicaSetWithStatus(r, 1, 1) + r.Spec.Strategy.Canary.PingPong = &v1alpha1.PingPongSpec{PingService: pingSvc.Name, PongService: pongSvc.Name} + + f.rolloutLister = append(f.rolloutLister, r) + f.objects = append(f.objects, r) + f.kubeobjects = append(f.kubeobjects, pingSvc, pongSvc, rs1) + f.serviceLister = append(f.serviceLister, pingSvc, pongSvc) + + _ = f.expectPatchServiceAction(pingSvc, r.Status.CurrentPodHash) + _ = f.expectPatchRolloutAction(r) + f.run(getKey(r, t)) +} + +func TestCanaryRolloutWithInvalidPingServiceName(t *testing.T) { + f := newFixture(t) + defer f.Close() + + r := newCanaryRollout("foo", 0, nil, nil, nil, intstr.FromInt(1), intstr.FromInt(0)) + r.Spec.Strategy.Canary.PingPong = &v1alpha1.PingPongSpec{PingService: "ping-service", PongService: "pong-service"} + + f.rolloutLister = append(f.rolloutLister, r) + f.objects = append(f.objects, r) + f.kubeobjects = append(f.kubeobjects) + f.serviceLister = append(f.serviceLister) + + patchIndex := f.expectPatchRolloutAction(r) + f.run(getKey(r, t)) + + patch := make(map[string]interface{}) + patchData := f.getPatchedRollout(patchIndex) + err := json.Unmarshal([]byte(patchData), &patch) + assert.NoError(t, err) + + c, ok, err := unstructured.NestedSlice(patch, "status", "conditions") + assert.NoError(t, err) + assert.True(t, ok) + assert.Len(t, c, 2) + + condition, ok := c[1].(map[string]interface{}) + assert.True(t, ok) + assert.Equal(t, conditions.InvalidSpecReason, condition["reason"]) + assert.Equal(t, "The Rollout \"foo\" is invalid: spec.strategy.canary.pingPong.pingService: Invalid value: \"ping-service\": service \"ping-service\" not found", condition["message"]) +} + +func TestCanaryRolloutWithInvalidPongServiceName(t *testing.T) { + f := newFixture(t) + defer f.Close() + + r := newCanaryRollout("foo", 0, nil, nil, nil, intstr.FromInt(1), intstr.FromInt(0)) + pingSvc := newService("ping-service", 80, nil, r) + r.Spec.Strategy.Canary.PingPong = &v1alpha1.PingPongSpec{PingService: pingSvc.Name, PongService: "pong-service"} + + f.rolloutLister = append(f.rolloutLister, r) + f.objects = append(f.objects, r) + f.kubeobjects = append(f.kubeobjects, pingSvc) + f.serviceLister = append(f.serviceLister, pingSvc) + + patchIndex := f.expectPatchRolloutAction(r) + f.run(getKey(r, t)) + + patch := make(map[string]interface{}) + patchData := f.getPatchedRollout(patchIndex) + err := json.Unmarshal([]byte(patchData), &patch) + assert.NoError(t, err) + + c, ok, err := unstructured.NestedSlice(patch, "status", "conditions") + assert.NoError(t, err) + assert.True(t, ok) + assert.Len(t, c, 2) + + condition, ok := c[1].(map[string]interface{}) + assert.True(t, ok) + assert.Equal(t, conditions.InvalidSpecReason, condition["reason"]) + assert.Equal(t, "The Rollout \"foo\" is invalid: spec.strategy.canary.pingPong.pongService: Invalid value: \"pong-service\": service \"pong-service\" not found", condition["message"]) +} + func TestCanaryRolloutScaleWhilePaused(t *testing.T) { f := newFixture(t) defer f.Close() diff --git a/rollout/controller.go b/rollout/controller.go index 6e7f354133..827c7a7a20 100644 --- a/rollout/controller.go +++ b/rollout/controller.go @@ -629,69 +629,60 @@ func (c *rolloutContext) getAmbassadorMappings() ([]unstructured.Unstructured, e } func (c *rolloutContext) getReferencedServices() (*[]validation.ServiceWithType, error) { - services := []validation.ServiceWithType{} - if c.rollout.Spec.Strategy.BlueGreen != nil { - if c.rollout.Spec.Strategy.BlueGreen.ActiveService != "" { - activeSvc, err := c.servicesLister.Services(c.rollout.Namespace).Get(c.rollout.Spec.Strategy.BlueGreen.ActiveService) - if k8serrors.IsNotFound(err) { - fldPath := validation.GetServiceWithTypeFieldPath(validation.ActiveService) - return nil, field.Invalid(fldPath, c.rollout.Spec.Strategy.BlueGreen.ActiveService, err.Error()) - } - if err != nil { - return nil, err - } - services = append(services, validation.ServiceWithType{ - Service: activeSvc, - Type: validation.ActiveService, - }) + var services []validation.ServiceWithType + if bluegreenSpec := c.rollout.Spec.Strategy.BlueGreen; bluegreenSpec != nil { + if service, err := c.getReferencedService(bluegreenSpec.ActiveService, validation.ActiveService); service != nil { + services = append(services, *service) + } else if err != nil { + return nil, err } - if c.rollout.Spec.Strategy.BlueGreen.PreviewService != "" { - previewSvc, err := c.servicesLister.Services(c.rollout.Namespace).Get(c.rollout.Spec.Strategy.BlueGreen.PreviewService) - if k8serrors.IsNotFound(err) { - fldPath := validation.GetServiceWithTypeFieldPath(validation.PreviewService) - return nil, field.Invalid(fldPath, c.rollout.Spec.Strategy.BlueGreen.PreviewService, err.Error()) - } - if err != nil { - return nil, err - } - services = append(services, validation.ServiceWithType{ - Service: previewSvc, - Type: validation.PreviewService, - }) + if service, err := c.getReferencedService(bluegreenSpec.PreviewService, validation.PreviewService); service != nil { + services = append(services, *service) + } else if err != nil { + return nil, err } - } else if c.rollout.Spec.Strategy.Canary != nil { - if c.rollout.Spec.Strategy.Canary.StableService != "" { - stableSvc, err := c.servicesLister.Services(c.rollout.Namespace).Get(c.rollout.Spec.Strategy.Canary.StableService) - if k8serrors.IsNotFound(err) { - fldPath := validation.GetServiceWithTypeFieldPath(validation.StableService) - return nil, field.Invalid(fldPath, c.rollout.Spec.Strategy.Canary.StableService, err.Error()) - } - if err != nil { - return nil, err - } - services = append(services, validation.ServiceWithType{ - Service: stableSvc, - Type: validation.StableService, - }) + } else if canarySpec := c.rollout.Spec.Strategy.Canary; canarySpec != nil { + if service, err := c.getReferencedService(canarySpec.StableService, validation.StableService); service != nil { + services = append(services, *service) + } else if err != nil { + return nil, err } - if c.rollout.Spec.Strategy.Canary.CanaryService != "" { - canarySvc, err := c.servicesLister.Services(c.rollout.Namespace).Get(c.rollout.Spec.Strategy.Canary.CanaryService) - if k8serrors.IsNotFound(err) { - fldPath := validation.GetServiceWithTypeFieldPath(validation.CanaryService) - return nil, field.Invalid(fldPath, c.rollout.Spec.Strategy.Canary.CanaryService, err.Error()) + if service, err := c.getReferencedService(canarySpec.CanaryService, validation.CanaryService); service != nil { + services = append(services, *service) + } else if err != nil { + return nil, err + } + if canarySpec.PingPong != nil { + if service, err := c.getReferencedService(canarySpec.PingPong.PingService, validation.PingService); service != nil { + services = append(services, *service) + } else if err != nil { + return nil, err } - if err != nil { + if service, err := c.getReferencedService(canarySpec.PingPong.PongService, validation.PongService); service != nil { + services = append(services, *service) + } else if err != nil { return nil, err } - services = append(services, validation.ServiceWithType{ - Service: canarySvc, - Type: validation.CanaryService, - }) } } return &services, nil } +func (c *rolloutContext) getReferencedService(serviceName string, serviceType validation.ServiceType) (*validation.ServiceWithType, error) { + if serviceName != "" { + svc, err := c.servicesLister.Services(c.rollout.Namespace).Get(serviceName) + if k8serrors.IsNotFound(err) { + fldPath := validation.GetServiceWithTypeFieldPath(serviceType) + return nil, field.Invalid(fldPath, serviceName, err.Error()) + } + if err != nil { + return nil, err + } + return &validation.ServiceWithType{Service: svc, Type: serviceType}, nil + } + return nil, nil +} + func (c *rolloutContext) getReferencedRolloutAnalyses() (*[]validation.AnalysisTemplatesWithType, error) { analysisTemplates := make([]validation.AnalysisTemplatesWithType, 0) if c.rollout.Spec.Strategy.BlueGreen != nil { diff --git a/rollout/service.go b/rollout/service.go index b0ba6588b1..a2861be0c2 100644 --- a/rollout/service.go +++ b/rollout/service.go @@ -11,6 +11,7 @@ import ( "k8s.io/utils/pointer" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + "github.com/argoproj/argo-rollouts/rollout/trafficrouting" "github.com/argoproj/argo-rollouts/utils/annotations" "github.com/argoproj/argo-rollouts/utils/aws" "github.com/argoproj/argo-rollouts/utils/conditions" @@ -18,6 +19,7 @@ import ( logutil "github.com/argoproj/argo-rollouts/utils/log" "github.com/argoproj/argo-rollouts/utils/record" replicasetutil "github.com/argoproj/argo-rollouts/utils/replicaset" + rolloututils "github.com/argoproj/argo-rollouts/utils/rollout" serviceutil "github.com/argoproj/argo-rollouts/utils/service" ) @@ -240,15 +242,23 @@ func (c *rolloutContext) getPreviewAndActiveServices() (*corev1.Service, *corev1 return previewSvc, activeSvc, nil } +func (c *rolloutContext) reconcilePingAndPongService() error { + if trafficrouting.IsPingPongEnabled(c.rollout) && !rolloututils.IsFullyPromoted(c.rollout) { + _, canaryService := trafficrouting.GetStableAndCanaryServices(c.rollout) + return c.ensureSVCTargets(canaryService, c.newRS, false) + } + return nil +} + func (c *rolloutContext) reconcileStableAndCanaryService() error { if c.rollout.Spec.Strategy.Canary == nil { return nil } - err := c.ensureSVCTargets(c.rollout.Spec.Strategy.Canary.StableService, c.stableRS) + err := c.ensureSVCTargets(c.rollout.Spec.Strategy.Canary.StableService, c.stableRS, true) if err != nil { return err } - err = c.ensureSVCTargets(c.rollout.Spec.Strategy.Canary.CanaryService, c.newRS) + err = c.ensureSVCTargets(c.rollout.Spec.Strategy.Canary.CanaryService, c.newRS, true) if err != nil { return err } @@ -257,7 +267,7 @@ func (c *rolloutContext) reconcileStableAndCanaryService() error { // ensureSVCTargets updates the service with the given name to point to the given ReplicaSet, // but only if that ReplicaSet has full availability. -func (c *rolloutContext) ensureSVCTargets(svcName string, rs *appsv1.ReplicaSet) error { +func (c *rolloutContext) ensureSVCTargets(svcName string, rs *appsv1.ReplicaSet, checkRsAvailability bool) error { if rs == nil || svcName == "" { return nil } @@ -269,7 +279,7 @@ func (c *rolloutContext) ensureSVCTargets(svcName string, rs *appsv1.ReplicaSet) desiredSelector := rs.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] if currSelector != desiredSelector { // ensure ReplicaSet is fully available, otherwise we will point the service to nothing or an underprovisioned ReplicaSet - if !replicasetutil.IsReplicaSetAvailable(rs) { + if checkRsAvailability && !replicasetutil.IsReplicaSetAvailable(rs) { logCtx := c.log.WithField(logutil.ServiceKey, svc.Name) logCtx.Infof("delaying service switch from %s to %s: ReplicaSet not fully available", currSelector, desiredSelector) return nil diff --git a/rollout/sync.go b/rollout/sync.go index 5472dbb526..fc260f8633 100644 --- a/rollout/sync.go +++ b/rollout/sync.go @@ -17,6 +17,7 @@ import ( "k8s.io/utils/pointer" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + "github.com/argoproj/argo-rollouts/rollout/trafficrouting" analysisutil "github.com/argoproj/argo-rollouts/utils/analysis" "github.com/argoproj/argo-rollouts/utils/annotations" "github.com/argoproj/argo-rollouts/utils/conditions" @@ -914,6 +915,13 @@ func (c *rolloutContext) promoteStable(newStatus *v1alpha1.RolloutStatus, reason previousStableHash := newStatus.StableRS if previousStableHash != newStatus.CurrentPodHash { // only emit this event when we switched stable + if trafficrouting.IsPingPongEnabled(c.rollout) { + if trafficrouting.IsStablePing(c.rollout) { + newStatus.Canary.StablePingPong = v1alpha1.PPPong + } else { + newStatus.Canary.StablePingPong = v1alpha1.PPPing + } + } newStatus.StableRS = newStatus.CurrentPodHash revision, _ := replicasetutil.Revision(c.rollout) c.recorder.Eventf(c.rollout, record.EventOptions{EventReason: conditions.RolloutCompletedReason}, diff --git a/rollout/sync_test.go b/rollout/sync_test.go index ca92ba1b35..77205db2c6 100644 --- a/rollout/sync_test.go +++ b/rollout/sync_test.go @@ -264,6 +264,29 @@ func TestPersistWorkloadRefGeneration(t *testing.T) { } } +func TestPingPongCanaryPromoteStable(t *testing.T) { + ro := &v1alpha1.Rollout{} + ro.Spec.Strategy.Canary = &v1alpha1.CanaryStrategy{PingPong: &v1alpha1.PingPongSpec{}} + ro.Status.Canary.StablePingPong = v1alpha1.PPPing + roCtx := &rolloutContext{ + pauseContext: &pauseContext{}, + rollout: ro, + reconcilerBase: reconcilerBase{ + recorder: record.NewFakeEventRecorder(), + }, + } + newStatus := &v1alpha1.RolloutStatus{ + CurrentPodHash: "2f646bf702", + StableRS: "15fb5ffc01", + } + + // test call + err := roCtx.promoteStable(newStatus, "reason") + + assert.Nil(t, err) + assert.Equal(t, v1alpha1.PPPong, newStatus.Canary.StablePingPong) +} + // TestCanaryPromoteFull verifies skip pause, analysis, steps when promote full is set for a canary rollout func TestCanaryPromoteFull(t *testing.T) { f := newFixture(t) diff --git a/rollout/trafficrouting/alb/alb.go b/rollout/trafficrouting/alb/alb.go index e7ced03efb..861df37e06 100644 --- a/rollout/trafficrouting/alb/alb.go +++ b/rollout/trafficrouting/alb/alb.go @@ -13,6 +13,7 @@ import ( "k8s.io/utils/pointer" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + "github.com/argoproj/argo-rollouts/rollout/trafficrouting" "github.com/argoproj/argo-rollouts/utils/aws" "github.com/argoproj/argo-rollouts/utils/conditions" "github.com/argoproj/argo-rollouts/utils/defaults" @@ -136,9 +137,8 @@ func (r *Reconciler) VerifyWeight(desiredWeight int32, additionalDestinations .. } resourceIDToDest := map[string]v1alpha1.WeightDestination{} - canaryService := rollout.Spec.Strategy.Canary.CanaryService + stableService, canaryService := trafficrouting.GetStableAndCanaryServices(rollout) canaryResourceID := aws.BuildTargetGroupResourceID(rollout.Namespace, ingress.GetName(), canaryService, rollout.Spec.Strategy.Canary.TrafficRouting.ALB.ServicePort) - stableService := rollout.Spec.Strategy.Canary.StableService stableResourceID := aws.BuildTargetGroupResourceID(rollout.Namespace, ingress.GetName(), stableService, rollout.Spec.Strategy.Canary.TrafficRouting.ALB.ServicePort) for _, dest := range additionalDestinations { @@ -212,8 +212,7 @@ func (r *Reconciler) VerifyWeight(desiredWeight int32, additionalDestinations .. } func getForwardActionString(r *v1alpha1.Rollout, port int32, desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) (string, error) { - stableService := r.Spec.Strategy.Canary.StableService - canaryService := r.Spec.Strategy.Canary.CanaryService + stableService, canaryService := trafficrouting.GetStableAndCanaryServices(r) portStr := strconv.Itoa(int(port)) stableWeight := int32(100) targetGroups := make([]ingressutil.ALBTargetGroup, 0) diff --git a/rollout/trafficrouting/alb/alb_test.go b/rollout/trafficrouting/alb/alb_test.go index deca405037..469be0c4b9 100644 --- a/rollout/trafficrouting/alb/alb_test.go +++ b/rollout/trafficrouting/alb/alb_test.go @@ -29,8 +29,10 @@ import ( const STABLE_SVC = "stable-svc" const CANARY_SVC = "canary-svc" +const PING_SVC = "ping-service" +const PONG_SVC = "pong-service" -func fakeRollout(stableSvc, canarySvc, stableIng string, port int32) *v1alpha1.Rollout { +func fakeRollout(stableSvc, canarySvc string, pingPong *v1alpha1.PingPongSpec, stableIng string, port int32) *v1alpha1.Rollout { return &v1alpha1.Rollout{ ObjectMeta: metav1.ObjectMeta{ Name: "rollout", @@ -41,6 +43,7 @@ func fakeRollout(stableSvc, canarySvc, stableIng string, port int32) *v1alpha1.R Canary: &v1alpha1.CanaryStrategy{ StableService: stableSvc, CanaryService: canarySvc, + PingPong: pingPong, TrafficRouting: &v1alpha1.RolloutTrafficRouting{ ALB: &v1alpha1.ALBTrafficRouting{ Ingress: stableIng, @@ -97,8 +100,8 @@ func albActionAnnotation(stable string) string { return fmt.Sprintf("%s%s%s", ingressutil.ALBIngressAnnotation, ingressutil.ALBActionPrefix, stable) } -func ingress(name string, stableSvc, canarySvc string, port, weight int32, managedBy string, includeStickyConfig bool) *extensionsv1beta1.Ingress { - managedByValue := fmt.Sprintf("%s:%s", managedBy, albActionAnnotation(stableSvc)) +func ingress(name, stableSvc, canarySvc, actionService string, port, weight int32, managedBy string, includeStickyConfig bool) *extensionsv1beta1.Ingress { + managedByValue := fmt.Sprintf("%s:%s", managedBy, albActionAnnotation(actionService)) action := fmt.Sprintf(actionTemplate, canarySvc, port, weight, stableSvc, port, 100-weight) if includeStickyConfig { action = fmt.Sprintf(actionTemplateWithStickyConfig, canarySvc, port, weight, stableSvc, port, 100-weight) @@ -114,7 +117,7 @@ func ingress(name string, stableSvc, canarySvc string, port, weight int32, manag Name: name, Namespace: metav1.NamespaceDefault, Annotations: map[string]string{ - albActionAnnotation(stableSvc): string(jsonutil.MustMarshal(a)), + albActionAnnotation(actionService): string(jsonutil.MustMarshal(a)), ingressutil.ManagedActionsAnnotation: managedByValue, }, }, @@ -126,7 +129,7 @@ func ingress(name string, stableSvc, canarySvc string, port, weight int32, manag Paths: []extensionsv1beta1.HTTPIngressPath{ { Backend: extensionsv1beta1.IngressBackend{ - ServiceName: stableSvc, + ServiceName: actionService, ServicePort: intstr.Parse("use-annotation"), }, }, @@ -142,7 +145,7 @@ func ingress(name string, stableSvc, canarySvc string, port, weight int32, manag func TestType(t *testing.T) { client := fake.NewSimpleClientset() - rollout := fakeRollout("stable-service", "canary-service", "stable-ingress", 443) + rollout := fakeRollout("stable-service", "canary-service", nil, "stable-ingress", 443) r, err := NewReconciler(ReconcilerConfig{ Rollout: rollout, Client: client, @@ -154,7 +157,7 @@ func TestType(t *testing.T) { } func TestIngressNotFound(t *testing.T) { - ro := fakeRollout("stable-service", "canary-service", "stable-ingress", 443) + ro := fakeRollout("stable-service", "canary-service", nil, "stable-ingress", 443) client := fake.NewSimpleClientset() k8sI := kubeinformers.NewSharedInformerFactory(client, 0) ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) @@ -174,9 +177,9 @@ func TestIngressNotFound(t *testing.T) { } func TestServiceNotFoundInIngress(t *testing.T) { - ro := fakeRollout("stable-stable", "canary-service", "ingress", 443) + ro := fakeRollout("stable-stable", "canary-service", nil, "ingress", 443) ro.Spec.Strategy.Canary.TrafficRouting.ALB.RootService = "invalid-svc" - i := ingress("ingress", "stable-service", CANARY_SVC, 443, 50, ro.Name, false) + i := ingress("ingress", STABLE_SVC, CANARY_SVC, STABLE_SVC, 443, 50, ro.Name, false) client := fake.NewSimpleClientset() k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) @@ -197,8 +200,8 @@ func TestServiceNotFoundInIngress(t *testing.T) { } func TestNoChanges(t *testing.T) { - ro := fakeRollout(STABLE_SVC, CANARY_SVC, "ingress", 443) - i := ingress("ingress", STABLE_SVC, CANARY_SVC, 443, 10, ro.Name, false) + ro := fakeRollout(STABLE_SVC, CANARY_SVC, nil, "ingress", 443) + i := ingress("ingress", STABLE_SVC, CANARY_SVC, STABLE_SVC, 443, 10, ro.Name, false) client := fake.NewSimpleClientset() k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) @@ -220,8 +223,8 @@ func TestNoChanges(t *testing.T) { } func TestErrorOnInvalidManagedBy(t *testing.T) { - ro := fakeRollout(STABLE_SVC, CANARY_SVC, "ingress", 443) - i := ingress("ingress", STABLE_SVC, CANARY_SVC, 443, 5, ro.Name, false) + ro := fakeRollout(STABLE_SVC, CANARY_SVC, nil, "ingress", 443) + i := ingress("ingress", STABLE_SVC, CANARY_SVC, STABLE_SVC, 443, 5, ro.Name, false) i.Annotations[ingressutil.ManagedActionsAnnotation] = "test" client := fake.NewSimpleClientset(i) k8sI := kubeinformers.NewSharedInformerFactory(client, 0) @@ -243,8 +246,8 @@ func TestErrorOnInvalidManagedBy(t *testing.T) { } func TestSetInitialDesiredWeight(t *testing.T) { - ro := fakeRollout(STABLE_SVC, CANARY_SVC, "ingress", 443) - i := ingress("ingress", STABLE_SVC, CANARY_SVC, 443, 5, ro.Name, false) + ro := fakeRollout(STABLE_SVC, CANARY_SVC, nil, "ingress", 443) + i := ingress("ingress", STABLE_SVC, CANARY_SVC, STABLE_SVC, 443, 5, ro.Name, false) i.Annotations = map[string]string{} client := fake.NewSimpleClientset(i) k8sI := kubeinformers.NewSharedInformerFactory(client, 0) @@ -266,9 +269,38 @@ func TestSetInitialDesiredWeight(t *testing.T) { assert.Len(t, client.Actions(), 1) } +func TestSetWeightPingPong(t *testing.T) { + pp := &v1alpha1.PingPongSpec{PingService: PING_SVC, PongService: PONG_SVC} + ro := fakeRollout("", "", pp, "ingress", 443) + ro.Spec.Strategy.Canary.TrafficRouting.ALB.RootService = "root-service" + ro.Status.Canary.StablePingPong = PONG_SVC + i := ingress("ingress", PING_SVC, PONG_SVC, "root-service", 443, 10, ro.Name, false) + //i.Spec. + i.Annotations = map[string]string{} + client := fake.NewSimpleClientset(i) + k8sI := kubeinformers.NewSharedInformerFactory(client, 0) + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } + r, err := NewReconciler(ReconcilerConfig{ + Rollout: ro, + Client: client, + Recorder: record.NewFakeEventRecorder(), + ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, + IngressWrapper: ingressWrapper, + }) + assert.NoError(t, err) + err = r.SetWeight(10) + assert.Nil(t, err) + actions := client.Actions() + assert.Len(t, actions, 1) +} + func TestUpdateDesiredWeightWithStickyConfig(t *testing.T) { - ro := fakeRollout(STABLE_SVC, CANARY_SVC, "ingress", 443) - i := ingress("ingress", STABLE_SVC, CANARY_SVC, 443, 5, ro.Name, true) + ro := fakeRollout(STABLE_SVC, CANARY_SVC, nil, "ingress", 443) + i := ingress("ingress", STABLE_SVC, CANARY_SVC, STABLE_SVC, 443, 5, ro.Name, true) client := fake.NewSimpleClientset(i) k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) @@ -288,8 +320,8 @@ func TestUpdateDesiredWeightWithStickyConfig(t *testing.T) { } func TestUpdateDesiredWeight(t *testing.T) { - ro := fakeRollout(STABLE_SVC, CANARY_SVC, "ingress", 443) - i := ingress("ingress", STABLE_SVC, CANARY_SVC, 443, 5, ro.Name, false) + ro := fakeRollout(STABLE_SVC, CANARY_SVC, nil, "ingress", 443) + i := ingress("ingress", STABLE_SVC, CANARY_SVC, STABLE_SVC, 443, 5, ro.Name, false) client := fake.NewSimpleClientset(i) k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) @@ -313,7 +345,7 @@ func TestUpdateDesiredWeight(t *testing.T) { // TestGetForwardActionStringMarshalsZeroCorrectly ensures that the annotation does not omit default value zero when marshalling // the forward action func TestGetForwardActionStringMarshalsZeroCorrectly(t *testing.T) { - r := fakeRollout("stable", "canary", "ingress", 443) + r := fakeRollout("stable", "canary", nil, "ingress", 443) forwardAction, err := getForwardActionString(r, 443, 0) if err != nil { t.Fatal(err) @@ -322,7 +354,7 @@ func TestGetForwardActionStringMarshalsZeroCorrectly(t *testing.T) { } func TestGetForwardActionStringMarshalsDisabledStickyConfigCorrectly(t *testing.T) { - r := fakeRollout("stable", "canary", "ingress", 443) + r := fakeRollout("stable", "canary", nil, "ingress", 443) stickinessConfig := v1alpha1.StickinessConfig{ Enabled: false, DurationSeconds: 0, @@ -336,7 +368,7 @@ func TestGetForwardActionStringMarshalsDisabledStickyConfigCorrectly(t *testing. } func TestGetForwardActionStringDetectsNegativeStickyConfigDuration(t *testing.T) { - r := fakeRollout("stable", "canary", "ingress", 443) + r := fakeRollout("stable", "canary", nil, "ingress", 443) stickinessConfig := v1alpha1.StickinessConfig{ Enabled: true, DurationSeconds: 0, @@ -350,7 +382,7 @@ func TestGetForwardActionStringDetectsNegativeStickyConfigDuration(t *testing.T) } func TestGetForwardActionStringDetectsTooLargeStickyConfigDuration(t *testing.T) { - r := fakeRollout("stable", "canary", "ingress", 443) + r := fakeRollout("stable", "canary", nil, "ingress", 443) stickinessConfig := v1alpha1.StickinessConfig{ Enabled: true, DurationSeconds: 604800 + 1, @@ -364,8 +396,8 @@ func TestGetForwardActionStringDetectsTooLargeStickyConfigDuration(t *testing.T) } func TestErrorPatching(t *testing.T) { - ro := fakeRollout(STABLE_SVC, CANARY_SVC, "ingress", 443) - i := ingress("ingress", STABLE_SVC, CANARY_SVC, 443, 5, ro.Name, false) + ro := fakeRollout(STABLE_SVC, CANARY_SVC, nil, "ingress", 443) + i := ingress("ingress", STABLE_SVC, CANARY_SVC, STABLE_SVC, 443, 5, ro.Name, false) client := fake.NewSimpleClientset(i) client.ReactionChain = nil k8sI := kubeinformers.NewSharedInformerFactory(client, 0) @@ -430,8 +462,8 @@ func (f *fakeAWSClient) getAlbStatus() *v1alpha1.ALBStatus { func TestVerifyWeight(t *testing.T) { newFakeReconciler := func(status *v1alpha1.RolloutStatus) (*Reconciler, *fakeAWSClient) { - ro := fakeRollout(STABLE_SVC, CANARY_SVC, "ingress", 443) - i := ingress("ingress", STABLE_SVC, CANARY_SVC, 443, 5, ro.Name, false) + ro := fakeRollout(STABLE_SVC, CANARY_SVC, nil, "ingress", 443) + i := ingress("ingress", STABLE_SVC, CANARY_SVC, STABLE_SVC, 443, 5, ro.Name, false) i.Status.LoadBalancer = corev1.LoadBalancerStatus{ Ingress: []corev1.LoadBalancerIngress{ { @@ -549,8 +581,8 @@ func TestVerifyWeight(t *testing.T) { } func TestSetWeightWithMultipleBackends(t *testing.T) { - ro := fakeRollout(STABLE_SVC, CANARY_SVC, "ingress", 443) - i := ingress("ingress", STABLE_SVC, CANARY_SVC, 443, 0, ro.Name, false) + ro := fakeRollout(STABLE_SVC, CANARY_SVC, nil, "ingress", 443) + i := ingress("ingress", STABLE_SVC, CANARY_SVC, STABLE_SVC, 443, 0, ro.Name, false) client := fake.NewSimpleClientset(i) k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) @@ -609,8 +641,8 @@ func TestVerifyWeightWithAdditionalDestinations(t *testing.T) { }, } newFakeReconciler := func(status *v1alpha1.RolloutStatus) (*Reconciler, *fakeAWSClient) { - ro := fakeRollout(STABLE_SVC, CANARY_SVC, "ingress", 443) - i := ingress("ingress", STABLE_SVC, CANARY_SVC, 443, 0, ro.Name, false) + ro := fakeRollout(STABLE_SVC, CANARY_SVC, nil, "ingress", 443) + i := ingress("ingress", STABLE_SVC, CANARY_SVC, STABLE_SVC, 443, 0, ro.Name, false) i.Annotations["alb.ingress.kubernetes.io/actions.stable-svc"] = fmt.Sprintf(actionTemplateWithExperiments, CANARY_SVC, 443, 10, weightDestinations[0].ServiceName, 443, weightDestinations[0].Weight, weightDestinations[1].ServiceName, 443, weightDestinations[1].Weight, STABLE_SVC, 443, 85) i.Status.LoadBalancer = corev1.LoadBalancerStatus{ diff --git a/rollout/trafficrouting/service_helper.go b/rollout/trafficrouting/service_helper.go new file mode 100644 index 0000000000..15d03cad53 --- /dev/null +++ b/rollout/trafficrouting/service_helper.go @@ -0,0 +1,33 @@ +package trafficrouting + +import ( + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" +) + +// GetStableAndCanaryServices return a service names for current stable and canary services. +// If ping-pong feature enabled then the current ping or pong service will be returned. Which is a stable is defined +// based on a rollout status field Status.Canary.StablePingPong +func GetStableAndCanaryServices(ro *v1alpha1.Rollout) (string, string) { + if IsPingPongEnabled(ro) { + canary := ro.Spec.Strategy.Canary + if IsStablePing(ro) { + return canary.PingPong.PingService, canary.PingPong.PongService + } else { + return canary.PingPong.PongService, canary.PingPong.PingService + } + } else { + return ro.Spec.Strategy.Canary.StableService, ro.Spec.Strategy.Canary.CanaryService + } +} + +// IsStablePing return true if the 'ping' service is pointing to the stable replica set. +// Which of the service currently is using is stored in a status.canary.stablePingPong. +// Return true in a case if status StablePingPong value equal to 'ping'. Return false in +// case when the status value is 'pong' or empty +func IsStablePing(ro *v1alpha1.Rollout) bool { + return ro.Status.Canary.StablePingPong == v1alpha1.PPPing +} + +func IsPingPongEnabled(ro *v1alpha1.Rollout) bool { + return ro.Spec.Strategy.Canary != nil && ro.Spec.Strategy.Canary.PingPong != nil +} diff --git a/test/e2e/aws_test.go b/test/e2e/aws_test.go index 7f7ce5c4e8..5525d4650d 100644 --- a/test/e2e/aws_test.go +++ b/test/e2e/aws_test.go @@ -4,6 +4,7 @@ package e2e import ( + "encoding/json" "fmt" "os" "testing" @@ -13,6 +14,7 @@ import ( "github.com/tj/assert" "github.com/argoproj/argo-rollouts/test/fixtures" + ingress2 "github.com/argoproj/argo-rollouts/utils/ingress" ) type AWSSuite struct { @@ -23,8 +25,6 @@ func TestAWSSuite(t *testing.T) { suite.Run(t, new(AWSSuite)) } -const actionTemplate = `{"Type":"forward","ForwardConfig":{"TargetGroups":[{"ServiceName":"%s","ServicePort":"%d","Weight":%d},{"ServiceName":"%s","ServicePort":"%d","Weight":%d}]}}` - const actionTemplateWithExperiment = `{"Type":"forward","ForwardConfig":{"TargetGroups":[{"ServiceName":"%s","ServicePort":"%d","Weight":%d},{"ServiceName":"%s","ServicePort":"%d","Weight":%d},{"ServiceName":"%s","ServicePort":"%d","Weight":%d}]}}` const actionTemplateWithExperiments = `{"Type":"forward","ForwardConfig":{"TargetGroups":[{"ServiceName":"%s","ServicePort":"%d","Weight":%d},{"ServiceName":"%s","ServicePort":"%d","Weight":%d},{"ServiceName":"%s","ServicePort":"%d","Weight":%d},{"ServiceName":"%s","ServicePort":"%d","Weight":%d}]}}` @@ -56,6 +56,55 @@ func (s *AWSSuite) TestALBBlueGreenUpdate() { WaitForRolloutStatus("Healthy") } +func (s *AWSSuite) TestALBPingPongUpdate() { + s.Given(). + RolloutObjects("@functional/alb-pingpong-rollout.yaml"). + When().ApplyManifests().WaitForRolloutStatus("Healthy"). + Then(). + Assert(assertWeights(s, "ping-service", "pong-service", 100, 0)). + // Update 1. Test the weight switch from ping => pong + When().UpdateSpec(). + WaitForRolloutCanaryStepIndex(1).Sleep(1 * time.Second).Then(). + Assert(assertWeights(s, "ping-service", "pong-service", 75, 25)). + When().PromoteRollout(). + WaitForRolloutStatus("Healthy"). + Sleep(1 * time.Second). + Then(). + Assert(assertWeights(s, "ping-service", "pong-service", 0, 100)). + // Update 2. Test the weight switch from pong => ping + When().UpdateSpec(). + WaitForRolloutCanaryStepIndex(1).Sleep(1 * time.Second).Then(). + Assert(assertWeights(s, "ping-service", "pong-service", 25, 75)). + When().PromoteRollout(). + WaitForRolloutStatus("Healthy"). + Sleep(1 * time.Second). + Then(). + Assert(assertWeights(s, "ping-service", "pong-service", 100, 0)) +} + +func assertWeights(s *AWSSuite, groupA, groupB string, weightA, weightB int64) func(t *fixtures.Then) { + return func(t *fixtures.Then) { + ingress := t.GetALBIngress() + action, ok := ingress.Annotations["alb.ingress.kubernetes.io/actions.alb-rollout-root"] + assert.True(s.T(), ok) + + var albAction ingress2.ALBAction + if err := json.Unmarshal([]byte(action), &albAction); err != nil { + panic(err) + } + for _, targetGroup := range albAction.ForwardConfig.TargetGroups { + switch targetGroup.ServiceName { + case groupA: + assert.True(s.T(), *targetGroup.Weight == weightA, fmt.Sprintf("Weight doesn't match: %d and %d", *targetGroup.Weight, weightA)) + case groupB: + assert.True(s.T(), *targetGroup.Weight == weightB, fmt.Sprintf("Weight doesn't match: %d and %d", *targetGroup.Weight, weightB)) + default: + assert.True(s.T(), false, "Service is not expected in the target group: "+targetGroup.ServiceName) + } + } + } +} + func (s *AWSSuite) TestALBExperimentStep() { s.Given(). RolloutObjects("@alb/rollout-alb-experiment.yaml"). @@ -63,15 +112,7 @@ func (s *AWSSuite) TestALBExperimentStep() { ApplyManifests(). WaitForRolloutStatus("Healthy"). Then(). - Assert(func(t *fixtures.Then) { - ingress := t.GetALBIngress() - action, ok := ingress.Annotations["alb.ingress.kubernetes.io/actions.alb-rollout-root"] - assert.True(s.T(), ok) - - port := 80 - expectedAction := fmt.Sprintf(actionTemplate, "alb-rollout-canary", port, 0, "alb-rollout-stable", port, 100) - assert.Equal(s.T(), expectedAction, action) - }). + Assert(assertWeights(s, "alb-rollout-canary", "alb-rollout-stable", 0, 100)). ExpectExperimentCount(0). When(). UpdateSpec(). @@ -95,15 +136,7 @@ func (s *AWSSuite) TestALBExperimentStep() { WaitForRolloutStatus("Healthy"). Sleep(1 * time.Second). // stable is currently set first, and then changes made to VirtualServices/DestinationRules Then(). - Assert(func(t *fixtures.Then) { - ingress := t.GetALBIngress() - action, ok := ingress.Annotations["alb.ingress.kubernetes.io/actions.alb-rollout-root"] - assert.True(s.T(), ok) - - port := 80 - expectedAction := fmt.Sprintf(actionTemplate, "alb-rollout-canary", port, 0, "alb-rollout-stable", port, 100) - assert.Equal(s.T(), expectedAction, action) - }) + Assert(assertWeights(s, "alb-rollout-canary", "alb-rollout-stable", 0, 100)) } func (s *AWSSuite) TestALBExperimentStepNoSetWeight() { @@ -113,15 +146,7 @@ func (s *AWSSuite) TestALBExperimentStepNoSetWeight() { ApplyManifests(). WaitForRolloutStatus("Healthy"). Then(). - Assert(func(t *fixtures.Then) { - ingress := t.GetALBIngress() - action, ok := ingress.Annotations["alb.ingress.kubernetes.io/actions.alb-rollout-root"] - assert.True(s.T(), ok) - - port := 80 - expectedAction := fmt.Sprintf(actionTemplate, "alb-rollout-canary", port, 0, "alb-rollout-stable", port, 100) - assert.Equal(s.T(), expectedAction, action) - }). + Assert(assertWeights(s, "alb-rollout-canary", "alb-rollout-stable", 0, 100)). ExpectExperimentCount(0). When(). UpdateSpec(). @@ -144,13 +169,5 @@ func (s *AWSSuite) TestALBExperimentStepNoSetWeight() { WaitForRolloutStatus("Healthy"). Sleep(1 * time.Second). // stable is currently set first, and then changes made to VirtualServices/DestinationRules Then(). - Assert(func(t *fixtures.Then) { - ingress := t.GetALBIngress() - action, ok := ingress.Annotations["alb.ingress.kubernetes.io/actions.alb-rollout-root"] - assert.True(s.T(), ok) - - port := 80 - expectedAction := fmt.Sprintf(actionTemplate, "alb-rollout-canary", port, 0, "alb-rollout-stable", port, 100) - assert.Equal(s.T(), expectedAction, action) - }) + Assert(assertWeights(s, "alb-rollout-canary", "alb-rollout-stable", 0, 100)) } diff --git a/test/e2e/functional/alb-pingpong-rollout.yaml b/test/e2e/functional/alb-pingpong-rollout.yaml new file mode 100644 index 0000000000..ddb7904e76 --- /dev/null +++ b/test/e2e/functional/alb-pingpong-rollout.yaml @@ -0,0 +1,86 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: ping-service +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: alb-canary +--- +apiVersion: v1 +kind: Service +metadata: + name: pong-service +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: alb-canary +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: alb-canary-ingress + annotations: + kubernetes.io/ingress.class: alb +spec: + rules: + - http: + paths: + - path: /* + backend: + service: + name: alb-rollout-root + port: + name: use-annotation + pathType: ImplementationSpecific +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: alb-canary +spec: + replicas: 2 + selector: + matchLabels: + app: alb-canary + template: + metadata: + labels: + app: alb-canary + spec: + containers: + - name: alb-canary + image: "argoproj/rollouts-demo:red" + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m + strategy: + canary: + scaleDownDelaySeconds: 2 + pingPong: + pingService: ping-service + pongService: pong-service + trafficRouting: + alb: + ingress: alb-canary-ingress + rootService: alb-rollout-root + servicePort: 80 + steps: + - setWeight: 25 + - pause: {duration: 5s} diff --git a/utils/service/service.go b/utils/service/service.go index eb3be4139c..fbcfb63ad2 100644 --- a/utils/service/service.go +++ b/utils/service/service.go @@ -35,6 +35,12 @@ func GetRolloutServiceKeys(rollout *v1alpha1.Rollout) []string { if rollout.Spec.Strategy.Canary.StableService != "" { services = append(services, fmt.Sprintf("%s/%s", rollout.Namespace, rollout.Spec.Strategy.Canary.StableService)) } + if rollout.Spec.Strategy.Canary.PingPong != nil && rollout.Spec.Strategy.Canary.PingPong.PingService != "" { + services = append(services, fmt.Sprintf("%s/%s", rollout.Namespace, rollout.Spec.Strategy.Canary.PingPong.PingService)) + } + if rollout.Spec.Strategy.Canary.PingPong != nil && rollout.Spec.Strategy.Canary.PingPong.PongService != "" { + services = append(services, fmt.Sprintf("%s/%s", rollout.Namespace, rollout.Spec.Strategy.Canary.PingPong.PongService)) + } } return services } diff --git a/utils/service/service_test.go b/utils/service/service_test.go index 82cab8dbab..1b1d615dd2 100644 --- a/utils/service/service_test.go +++ b/utils/service/service_test.go @@ -63,6 +63,25 @@ func TestGetRolloutServiceKeysForCanaryWithCanaryService(t *testing.T) { assert.Equal(t, keys, []string{"default/canary-service", "default/stable-service"}) } +func TestGetRolloutServiceKeysForPingPongCanaryService(t *testing.T) { + keys := GetRolloutServiceKeys(&v1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + }, + Spec: v1alpha1.RolloutSpec{ + Strategy: v1alpha1.RolloutStrategy{ + Canary: &v1alpha1.CanaryStrategy{ + PingPong: &v1alpha1.PingPongSpec{ + PingService: "ping-service", + PongService: "pong-service", + }, + }, + }, + }, + }) + assert.Equal(t, keys, []string{"default/ping-service", "default/pong-service"}) +} + func TestGetRolloutServiceKeysForBlueGreen(t *testing.T) { keys := GetRolloutServiceKeys(&v1alpha1.Rollout{ ObjectMeta: metav1.ObjectMeta{ From 2fda86a1b1ef4a24e9d6f7baf166285d0aa1eaf6 Mon Sep 17 00:00:00 2001 From: cskh Date: Thu, 3 Feb 2022 23:06:54 -0500 Subject: [PATCH 087/175] fix(analysis): surface analysis validation failure to rollout status (#1833) Signed-off-by: Hui Kang --- .../validation/validation_references.go | 12 +++++++ .../validation/validation_references_test.go | 33 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/pkg/apis/rollouts/validation/validation_references.go b/pkg/apis/rollouts/validation/validation_references.go index a980216413..39b8107f2e 100644 --- a/pkg/apis/rollouts/validation/validation_references.go +++ b/pkg/apis/rollouts/validation/validation_references.go @@ -133,6 +133,18 @@ func ValidateAnalysisTemplatesWithType(rollout *v1alpha1.Rollout, templates Anal return allErrs } + if rollout.Spec.Strategy.Canary != nil { + for _, step := range rollout.Spec.Strategy.Canary.Steps { + if step.Analysis != nil { + _, err := analysisutil.NewAnalysisRunFromTemplates(templates.AnalysisTemplates, templates.ClusterAnalysisTemplates, buildAnalysisArgs(templates.Args, rollout), step.Analysis.DryRun, step.Analysis.MeasurementRetention, "", "", "") + if err != nil { + allErrs = append(allErrs, field.Invalid(fldPath, value, err.Error())) + return allErrs + } + } + } + } + for _, template := range templates.AnalysisTemplates { allErrs = append(allErrs, ValidateAnalysisTemplateWithType(rollout, template, nil, templates.TemplateType, fldPath)...) } diff --git a/pkg/apis/rollouts/validation/validation_references_test.go b/pkg/apis/rollouts/validation/validation_references_test.go index 15465d09a3..7b14dd7483 100644 --- a/pkg/apis/rollouts/validation/validation_references_test.go +++ b/pkg/apis/rollouts/validation/validation_references_test.go @@ -256,6 +256,39 @@ func TestValidateAnalysisTemplatesWithType(t *testing.T) { assert.Empty(t, allErrs) }) + t.Run("failure - duplicate MeasurementRetention", func(t *testing.T) { + rollout := getRollout() + rollout.Spec.Strategy.Canary.Steps = append(rollout.Spec.Strategy.Canary.Steps, v1alpha1.CanaryStep{ + Analysis: &v1alpha1.RolloutAnalysis{ + Templates: []v1alpha1.RolloutAnalysisTemplate{ + { + TemplateName: "analysis-template-name", + }, + }, + MeasurementRetention: []v1alpha1.MeasurementRetention{ + { + MetricName: "example", + Limit: 2, + }, + }, + }, + }) + templates := getAnalysisTemplatesWithType() + templates.AnalysisTemplates[0].Spec.Args = append(templates.AnalysisTemplates[0].Spec.Args, v1alpha1.Argument{Name: "valid"}) + templates.AnalysisTemplates[0].Spec.MeasurementRetention = []v1alpha1.MeasurementRetention{ + { + MetricName: "example", + Limit: 5, + }, + } + templates.Args = []v1alpha1.AnalysisRunArgument{{Name: "valid", Value: "true"}} + + allErrs := ValidateAnalysisTemplatesWithType(rollout, templates) + assert.Len(t, allErrs, 1) + msg := fmt.Sprintf("spec.strategy.canary.steps[0].analysis.templates: Invalid value: \"templateNames: [analysis-template-name cluster-analysis-template-name]\": two Measurement Retention metric rules have the same name 'example'") + assert.Equal(t, msg, allErrs[0].Error()) + }) + } func TestValidateAnalysisTemplateWithType(t *testing.T) { From 18677425dc2447a3c43683b1bdac3d031e4de6d6 Mon Sep 17 00:00:00 2001 From: Karol-Szlachta-DM <61009714+Karol-Szlachta-DM@users.noreply.github.com> Date: Fri, 4 Feb 2022 05:14:23 +0100 Subject: [PATCH 088/175] feat: Add logformat flag to rollouts-controller (#1818) Signed-off-by: Karol Szlachta --- cmd/rollouts-controller/main.go | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/cmd/rollouts-controller/main.go b/cmd/rollouts-controller/main.go index 048df53db6..401b579323 100644 --- a/cmd/rollouts-controller/main.go +++ b/cmd/rollouts-controller/main.go @@ -3,6 +3,7 @@ package main import ( "fmt" "os" + "strings" "time" smiclientset "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/clientset/versioned" @@ -36,7 +37,9 @@ import ( const ( // CLIName is the name of the CLI - cliName = "argo-rollouts" + cliName = "argo-rollouts" + jsonFormat = "json" + textFormat = "text" ) func newCommand() *cobra.Command { @@ -44,6 +47,7 @@ func newCommand() *cobra.Command { clientConfig clientcmd.ClientConfig rolloutResyncPeriod int64 logLevel string + logFormat string klogLevel int metricsPort int healthzPort int @@ -76,10 +80,9 @@ func newCommand() *cobra.Command { return nil } setLogLevel(logLevel) - formatter := &log.TextFormatter{ - FullTimestamp: true, + if logFormat != "" { + log.SetFormatter(createFormatter(logFormat)) } - log.SetFormatter(formatter) logutil.SetKLogLevel(klogLevel) log.WithField("version", version.GetVersion()).Info("Argo Rollouts starting") @@ -215,6 +218,7 @@ func newCommand() *cobra.Command { command.Flags().Int64Var(&rolloutResyncPeriod, "rollout-resync", controller.DefaultRolloutResyncPeriod, "Time period in seconds for rollouts resync.") command.Flags().BoolVar(&namespaced, "namespaced", false, "runs controller in namespaced mode (does not require cluster RBAC)") command.Flags().StringVar(&logLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error") + command.Flags().StringVar(&logFormat, "logformat", "", "Set the logging format. One of: text|json") command.Flags().IntVar(&klogLevel, "kloglevel", 0, "Set the klog logging level") command.Flags().IntVar(&metricsPort, "metricsport", controller.DefaultMetricsPort, "Set the port the metrics endpoint should be exposed over") command.Flags().IntVar(&healthzPort, "healthzPort", controller.DefaultHealthzPort, "Set the port the healthz endpoint should be exposed over") @@ -270,6 +274,25 @@ func setLogLevel(logLevel string) { log.SetLevel(level) } +func createFormatter(logFormat string) log.Formatter { + var formatType log.Formatter + switch strings.ToLower(logFormat) { + case jsonFormat: + formatType = &log.JSONFormatter{} + case textFormat: + formatType = &log.TextFormatter{ + FullTimestamp: true, + } + default: + log.Infof("Unknown format: %s. Using text logformat", logFormat) + formatType = &log.TextFormatter{ + FullTimestamp: true, + } + } + + return formatType +} + func checkError(err error) { if err != nil { log.Fatal(err) From 7cc2f0de357e91ed0bed9aca6d25d6f739d89df6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 4 Feb 2022 10:17:23 -0800 Subject: [PATCH 089/175] chore(deps): bump github.com/aws/aws-sdk-go-v2 dependencies (#1835) * chore(deps): bump github.com/aws/aws-sdk-go-v2/config Bumps [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) from 1.13.0 to 1.13.1. - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.13.0...config/v1.13.1) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go-v2/config dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * chore(deps): update github.com/aws/aws-sdk-go-v2/service/cloudwatch to v1.15.0 Signed-off-by: Jesse Suen Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jesse Suen --- go.mod | 6 +++--- go.sum | 14 ++++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 995c5a2583..f66820ea7f 100644 --- a/go.mod +++ b/go.mod @@ -6,8 +6,8 @@ require ( github.com/antonmedv/expr v1.9.0 github.com/argoproj/notifications-engine v0.3.1-0.20220129012210-32519f8f68ec github.com/argoproj/pkg v0.9.0 - github.com/aws/aws-sdk-go-v2/config v1.13.0 - github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.5.0 + github.com/aws/aws-sdk-go-v2/config v1.13.1 + github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.15.0 github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.16.0 github.com/blang/semver v3.5.1+incompatible github.com/evanphx/json-patch/v5 v5.6.0 @@ -71,7 +71,7 @@ require ( github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.10.0 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.4 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.2.0 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.4 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.5 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.9.0 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.14.0 // indirect diff --git a/go.sum b/go.sum index f2810b33c3..43bcf68ce8 100644 --- a/go.sum +++ b/go.sum @@ -127,11 +127,10 @@ github.com/auth0/go-jwt-middleware v1.0.1/go.mod h1:YSeUX3z6+TF2H+7padiEqNJ73Zy9 github.com/aws/aws-sdk-go v1.33.16/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.35.24/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k= github.com/aws/aws-sdk-go v1.38.49/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go-v2 v1.7.0/go.mod h1:tb9wi5s61kTDA5qCkcDbt3KRVV74GGslQkl/DRdX/P4= github.com/aws/aws-sdk-go-v2 v1.13.0 h1:1XIXAfxsEmbhbj5ry3D3vX+6ZcUYvIqSm4CWWEuGZCA= github.com/aws/aws-sdk-go-v2 v1.13.0/go.mod h1:L6+ZpqHaLbAaxsqV0L4cvxZY7QupWJB4fhkf8LXvC7w= -github.com/aws/aws-sdk-go-v2/config v1.13.0 h1:1ij3YPk13RrIn1h+pH+dArh3lNPD5JSAP+ifOkNhnB0= -github.com/aws/aws-sdk-go-v2/config v1.13.0/go.mod h1:Pjv2OafecIn+4miw9VFDCr06YhKyf/oKOkIcpQOgWKk= +github.com/aws/aws-sdk-go-v2/config v1.13.1 h1:yLv8bfNoT4r+UvUKQKqRtdnvuWGMK5a82l4ru9Jvnuo= +github.com/aws/aws-sdk-go-v2/config v1.13.1/go.mod h1:Ba5Z4yL/UGbjQUzsiaN378YobhFo0MLfueXGiOsYtEs= github.com/aws/aws-sdk-go-v2/credentials v1.8.0 h1:8Ow0WcyDesGNL0No11jcgb1JAtE+WtubqXjgxau+S0o= github.com/aws/aws-sdk-go-v2/credentials v1.8.0/go.mod h1:gnMo58Vwx3Mu7hj1wpcG8DI0s57c9o42UQ6wgTQT5to= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.10.0 h1:NITDuUZO34mqtOwFWZiXo7yAHj7kf+XPE+EiKuCBNUI= @@ -140,10 +139,10 @@ github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.4 h1:CRiQJ4E2RhfDdqbie1 github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.4/go.mod h1:XHgQ7Hz2WY2GAn//UXHofLfPXWh+s62MbMOijrg12Lw= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.2.0 h1:3ADoioDMOtF4uiK59vCpplpCwugEU+v4ZFD29jDL3RQ= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.2.0/go.mod h1:BsCSJHx5DnDXIrOcqB8KN1/B+hXLG/bi4Y6Vjcx/x9E= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.4 h1:0NrDHIwS1LIR750ltj6ciiu4NZLpr9rgq8vHi/4QD4s= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.4/go.mod h1:R3sWUqPcfXSiF/LSFJhjyJmpg9uV6yP2yv3YZZjldVI= -github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.5.0 h1:XO1uX7dQKWfD0WzycEfz+bL/7rl0SsQ05VJwLPWGzGM= -github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.5.0/go.mod h1:acH3+MQoiMzozT/ivU+DbRg7Ooo2298RdRaWcOv+4vM= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.5 h1:ixotxbfTCFpqbuwFv/RcZwyzhkxPSYDYEMcj4niB5Uk= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.5/go.mod h1:R3sWUqPcfXSiF/LSFJhjyJmpg9uV6yP2yv3YZZjldVI= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.15.0 h1:5WstmcviZ9X/h5nORkGT4akyLmWjrLxE9s8oKkFhkD4= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.15.0/go.mod h1:bPS4S6vXEGUVMabXYHOJRFvoWrztb38v4i84i8Hd6ZY= github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.16.0 h1:4NawSD1qP7RPEqtCoahFNwkTa4MHtoKF08mhy+Y2Kok= github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.16.0/go.mod h1:5rsn/Fxs9Rnq28KLB8n1pJcRR3UtrHY787uapxrvDRA= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0 h1:4QAOB3KrvI1ApJK14sliGr3Ie2pjyvNypn/lfzDHfUw= @@ -152,7 +151,6 @@ github.com/aws/aws-sdk-go-v2/service/sso v1.9.0 h1:1qLJeQGBmNQW3mBNzK2CFmrQNmoXW github.com/aws/aws-sdk-go-v2/service/sso v1.9.0/go.mod h1:vCV4glupK3tR7pw7ks7Y4jYRL86VvxS+g5qk04YeWrU= github.com/aws/aws-sdk-go-v2/service/sts v1.14.0 h1:ksiDXhvNYg0D2/UFkLejsaz3LqpW5yjNQ8Nx9Sn2c0E= github.com/aws/aws-sdk-go-v2/service/sts v1.14.0/go.mod h1:u0xMJKDvvfocRjiozsoZglVNXRG19043xzp3r2ivLIk= -github.com/aws/smithy-go v1.5.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.10.0 h1:gsoZQMNHnX+PaghNw4ynPsyGP7aUCqx5sY2dlPQsZ0w= github.com/aws/smithy-go v1.10.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= From a78640a3f2fed23c9855b2ac1d45e3035248e3e9 Mon Sep 17 00:00:00 2001 From: Mohit Kumar Sharma <58915694+mksha@users.noreply.github.com> Date: Fri, 4 Feb 2022 23:49:40 +0530 Subject: [PATCH 090/175] docs: Updated the case of properties according to actual property name --- docs/features/specification.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/features/specification.md b/docs/features/specification.md index 75c09fcfd6..5a4d23394b 100644 --- a/docs/features/specification.md +++ b/docs/features/specification.md @@ -197,11 +197,11 @@ spec: # in order to give time for traffic providers to re-target the new pods. # This value is ignored with basic, replica-weighted canary without # traffic routing. - ScaleDownDelaySeconds: 30 + scaleDownDelaySeconds: 30 # Limits the number of old RS that can run at one time before getting # scaled down. Defaults to nil - ScaleDownDelayRevisionLimit: 2 + scaleDownDelayRevisionLimit: 2 # Background analysis to run during a rollout update. Skipped upon # initial deploy of a rollout. +optional @@ -341,4 +341,4 @@ status: You can find examples of Rollouts at: * The [example directory](https://github.com/argoproj/argo-rollouts/tree/master/examples) - * The [Argo Rollouts Demo application](https://github.com/argoproj/rollouts-demo) \ No newline at end of file + * The [Argo Rollouts Demo application](https://github.com/argoproj/rollouts-demo) From ae4bf3353606894a0d018cabe652c3b08fbfd9e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 4 Feb 2022 12:44:11 -0800 Subject: [PATCH 091/175] chore(deps): bump github.com/newrelic/newrelic-client-go (#1836) Bumps [github.com/newrelic/newrelic-client-go](https://github.com/newrelic/newrelic-client-go) from 0.71.0 to 0.72.0. - [Release notes](https://github.com/newrelic/newrelic-client-go/releases) - [Changelog](https://github.com/newrelic/newrelic-client-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/newrelic/newrelic-client-go/compare/v0.71.0...v0.72.0) --- updated-dependencies: - dependency-name: github.com/newrelic/newrelic-client-go dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f66820ea7f..7255d19def 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a github.com/mitchellh/mapstructure v1.4.3 - github.com/newrelic/newrelic-client-go v0.71.0 + github.com/newrelic/newrelic-client-go v0.72.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.11.0 github.com/prometheus/client_model v0.2.0 diff --git a/go.sum b/go.sum index 43bcf68ce8..a8f9f0cc96 100644 --- a/go.sum +++ b/go.sum @@ -680,8 +680,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/newrelic/newrelic-client-go v0.71.0 h1:gDpryPJf1Jd/yA3BhSx67iMneTpuMNxOezISUk6j3SU= -github.com/newrelic/newrelic-client-go v0.71.0/go.mod h1:VXjhsfui0rvhM9cVwnKwlidF8NbXlHZvh63ZKi6fImA= +github.com/newrelic/newrelic-client-go v0.72.0 h1:7dv4V+Wq4cKqZ1vq2OkspF9j08Q65D9A19LB6FWn9XM= +github.com/newrelic/newrelic-client-go v0.72.0/go.mod h1:VXjhsfui0rvhM9cVwnKwlidF8NbXlHZvh63ZKi6fImA= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nlopes/slack v0.5.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM= From 00bc97c45e2c0a35c9d64679626ac535bbbecb96 Mon Sep 17 00:00:00 2001 From: Leonardo Luz Almeida Date: Fri, 4 Feb 2022 15:58:33 -0500 Subject: [PATCH 092/175] chore: Generate spdx file for the docker image (#1844) Signed-off-by: Leonardo Luz Almeida --- .github/workflows/release.yaml | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 9db56c214a..161d9c9f22 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -115,6 +115,11 @@ jobs: with: ref: ${{ github.event.inputs.tag }} + - name: Setup Golang + uses: actions/setup-go@v2 + with: + go-version: 1.17.6 + - name: Generate release artifacts run: | make release-plugins @@ -123,21 +128,33 @@ jobs: - name: Generate SBOM (spdx) id: spdx-builder env: - # defines the https://github.com/opensbom-generator/spdx-sbom-generator - # to use. + # defines the spdx/spdx-sbom-generator version to use. SPDX_GEN_VERSION: v0.0.13 + # defines the sigs.k8s.io/bom version to use. + SIGS_BOM_VERSION: v0.2.1 # comma delimited list of project relative folders to inspect for package # managers (gomod, yarn, npm). PROJECT_FOLDERS: ".,./ui" + # full qualified name of the docker image to be inspected + DOCKER_IMAGE: quay.io/argoproj/argo-rollouts:v${{ github.event.inputs.tag }} + run: | yarn install --cwd ./ui - wget -q https://github.com/opensbom-generator/spdx-sbom-generator/releases/download/$SPDX_GEN_VERSION/spdx-sbom-generator-$SPDX_GEN_VERSION-linux-386.tar.gz -O generator.tar.gz - tar -zxf generator.tar.gz + go install github.com/spdx/spdx-sbom-generator/cmd/generator@$SPDX_GEN_VERSION + go install sigs.k8s.io/bom/cmd/bom@$SIGS_BOM_VERSION + + # Generate SPDX for project dependencies analyzing package managers for folder in $(echo $PROJECT_FOLDERS | sed "s/,/ /g") do - ./spdx-sbom-generator -p $folder -o /tmp + generator -p $folder -o /tmp done - tar -zcf /tmp/sbom.tar.gz /tmp/*.spdx + + # Generate SPDX for binaries analyzing the docker image + if [[ ! -z $DOCKER_IMAGE ]]; then + bom generate -o /tmp/bom-docker-image.spdx -i $DOCKER_IMAGE + fi + + cd /tmp && tar -zcf sbom.tar.gz *.spdx - name: Draft release uses: softprops/action-gh-release@v1 From 52b4bd8f4a0650c4bb2f160abb7a06f57c88287a Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Fri, 4 Feb 2022 21:39:08 -0800 Subject: [PATCH 093/175] chore: fix spdx ci (#1848) Signed-off-by: Jesse Suen --- .github/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 161d9c9f22..aeec6ed621 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -136,7 +136,7 @@ jobs: # managers (gomod, yarn, npm). PROJECT_FOLDERS: ".,./ui" # full qualified name of the docker image to be inspected - DOCKER_IMAGE: quay.io/argoproj/argo-rollouts:v${{ github.event.inputs.tag }} + DOCKER_IMAGE: quay.io/argoproj/argo-rollouts:${{ github.event.inputs.tag }} run: | yarn install --cwd ./ui From 2deb9f0d05c52fac6a19a4e45cece7c948a13c55 Mon Sep 17 00:00:00 2001 From: Leonardo Luz Almeida Date: Sat, 5 Feb 2022 13:10:51 -0500 Subject: [PATCH 094/175] chore: fix spdx image generation (#1849) Signed-off-by: Leonardo Luz Almeida --- .github/workflows/release.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index aeec6ed621..ac5d4e06b0 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -108,6 +108,7 @@ jobs: release-artifacts: runs-on: ubuntu-latest + needs: release-images steps: - name: Checkout From 47973e49d3251fcde612f55e9936e2f926d0c3ff Mon Sep 17 00:00:00 2001 From: William Van Hevelingen Date: Fri, 4 Feb 2022 17:02:12 -0800 Subject: [PATCH 095/175] docs: Add a toggle for dark mode Signed-off-by: William Van Hevelingen --- docs/requirements.txt | 6 +++--- mkdocs.yml | 10 +++++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index f3fda1b012..fa8fc0cf4c 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,4 +1,4 @@ -mkdocs==1.1.2 -mkdocs-material==7.1.7 +mkdocs==1.2.3 +mkdocs-material==8.1.9 markdown_include==0.6.0 -pygments==2.7.4 \ No newline at end of file +pygments==2.11.2 diff --git a/mkdocs.yml b/mkdocs.yml index c94e257094..cb65594d57 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -129,4 +129,12 @@ theme: logo: assets/logo.png name: material palette: - primary: teal + - scheme: default + primary: teal + toggle: + icon: material/toggle-switch-off-outline + name: Switch to dark mode + - scheme: slate + toggle: + icon: material/toggle-switch + name: Switch to light mode \ No newline at end of file From e3344dca08a6722fb917e805034a7be52a0cfc81 Mon Sep 17 00:00:00 2001 From: William Van Hevelingen Date: Fri, 4 Feb 2022 17:05:02 -0800 Subject: [PATCH 096/175] docs: Add new line Signed-off-by: William Van Hevelingen --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index cb65594d57..7428ae2e19 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -137,4 +137,4 @@ theme: - scheme: slate toggle: icon: material/toggle-switch - name: Switch to light mode \ No newline at end of file + name: Switch to light mode From 7a9850e9be802081cd8ce54746a19362caa088c4 Mon Sep 17 00:00:00 2001 From: William Van Hevelingen Date: Fri, 4 Feb 2022 18:17:06 -0800 Subject: [PATCH 097/175] docs: Fix lint Signed-off-by: William Van Hevelingen --- mkdocs.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index 7428ae2e19..15913a7342 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -129,12 +129,12 @@ theme: logo: assets/logo.png name: material palette: - - scheme: default - primary: teal - toggle: - icon: material/toggle-switch-off-outline - name: Switch to dark mode - - scheme: slate - toggle: - icon: material/toggle-switch - name: Switch to light mode + - scheme: default + primary: teal + toggle: + icon: material/toggle-switch-off-outline + name: Switch to dark mode + - scheme: slate + toggle: + icon: material/toggle-switch + name: Switch to light mode From f37166594c224ef3ee361abe7c95c3d23d423f84 Mon Sep 17 00:00:00 2001 From: William Van Hevelingen Date: Sat, 5 Feb 2022 10:28:31 -0800 Subject: [PATCH 098/175] docs: Fix codegen of mkdocs.yaml Signed-off-by: William Van Hevelingen --- mkdocs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index 15913a7342..6af2bc52cb 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -129,8 +129,8 @@ theme: logo: assets/logo.png name: material palette: - - scheme: default - primary: teal + - primary: teal + scheme: default toggle: icon: material/toggle-switch-off-outline name: Switch to dark mode From 459112b318b4a900639fd8a514bbefe12c392393 Mon Sep 17 00:00:00 2001 From: schakrad <58915923+schakrad@users.noreply.github.com> Date: Wed, 9 Feb 2022 14:21:08 -0500 Subject: [PATCH 099/175] feat: Added delay button in the scaled down revision (#1355) (#1804) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: Added delay button in the scaled down revision (#1355) (#1804) Signed-off-by: “schakradari” --- ui/package.json | 6 ++- ui/src/app/components/pods/pods.tsx | 18 +++++++- ui/yarn.lock | 68 +++++++++++++++++------------ 3 files changed, 61 insertions(+), 31 deletions(-) diff --git a/ui/package.json b/ui/package.json index 5a27c50c0a..3aef76ec5f 100644 --- a/ui/package.json +++ b/ui/package.json @@ -6,6 +6,7 @@ "@testing-library/jest-dom": "^5.11.4", "@testing-library/react": "^11.1.0", "@testing-library/user-event": "^12.1.10", + "@types/classnames": "2.2.9", "@types/jest": "^26.0.15", "@types/node": "^12.0.0", "@types/react": "^16.9.3", @@ -13,6 +14,7 @@ "@types/react-helmet": "^6.1.0", "@types/react-router-dom": "^5.1.7", "argo-ui": "git+https://github.com/argoproj/argo-ui.git", + "classnames": "2.2.6", "moment": "^2.29.1", "moment-timezone": "^0.5.33", "portable-fetch": "^3.0.0", @@ -21,10 +23,10 @@ "react-helmet": "^6.1.0", "react-hot-loader": "^3.1.3", "react-keyhooks": "^0.2.3", - "react-router-dom": "^5.2.0", + "react-router-dom": "5.2.0", "react-scripts": "4.0.3", "rxjs": "^6.6.6", - "typescript": "^4.1.2", + "typescript": "4.3.5", "web-vitals": "^1.0.1", "webpack-dev-server": "^3.11.2" }, diff --git a/ui/src/app/components/pods/pods.tsx b/ui/src/app/components/pods/pods.tsx index 30b13ed854..ae45adfef8 100644 --- a/ui/src/app/components/pods/pods.tsx +++ b/ui/src/app/components/pods/pods.tsx @@ -1,5 +1,7 @@ -import {Menu, ThemeDiv, Tooltip, WaitFor} from 'argo-ui/v2'; +import {Menu, ThemeDiv, Tooltip, WaitFor, InfoItem} from 'argo-ui/v2'; import * as React from 'react'; +import * as moment from 'moment'; +import {Duration, Ticker} from 'argo-ui'; import {RolloutReplicaSetInfo} from '../../../models/rollout/generated'; import {Pod} from '../../../models/rollout/rollout'; import {ReplicaSetStatus, ReplicaSetStatusIcon} from '../status-icon/status-icon'; @@ -107,6 +109,20 @@ export const ReplicaSet = (props: {rs: RolloutReplicaSetInfo; showRevision?: boo {rsName} {props.showRevision &&
Revision {props.rs.revision}
} + {props.rs.scaleDownDeadline && ( +
+ + {(now) => { + const time = moment(props.rs.scaleDownDeadline).diff(now, 'second'); + return time <= 0 ? null : ( + Scaledown in }> + as any} icon='fa fa-clock'> + + ); + }} + +
+ )}
)} diff --git a/ui/yarn.lock b/ui/yarn.lock index 3551c8ca01..89c94a9f4e 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -1157,13 +1157,20 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.0.tgz#46794bc20b612c5f75e62dd071e24dfd95f1cbe6" integrity sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA== dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.12.1": + version "7.17.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.2.tgz#66f68591605e59da47523c631416b18508779941" + integrity sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/runtime@^7.4.2", "@babel/runtime@^7.8.7": version "7.15.3" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.3.tgz#2e1c2880ca118e5b2f9988322bd8a7656a32502b" @@ -1762,6 +1769,11 @@ dependencies: "@babel/types" "^7.3.0" +"@types/classnames@2.2.9": + version "2.2.9" + resolved "https://registry.yarnpkg.com/@types/classnames/-/classnames-2.2.9.tgz#d868b6febb02666330410fe7f58f3c4b8258be7b" + integrity sha512-MNl+rT5UmZeilaPxAVs6YaPC2m6aA8rofviZbhbxpPpl61uKodfdQVsBtgJGTqGizEf02oW3tsVe7FYB8kK14A== + "@types/eslint@^7.2.6": version "7.2.10" resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.2.10.tgz#4b7a9368d46c0f8cd5408c23288a59aa2394d917" @@ -1800,6 +1812,11 @@ resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.8.tgz#49348387983075705fe8f4e02fb67f7daaec4934" integrity sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA== +"@types/history@^4.7.11": + version "4.7.11" + resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64" + integrity sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA== + "@types/html-minifier-terser@^5.0.0": version "5.1.1" resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#3c9ee980f1a10d6021ae6632ca3e79ca2ec4fb50" @@ -1911,11 +1928,11 @@ "@types/react" "*" "@types/react-router-dom@^5.1.7": - version "5.1.7" - resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.1.7.tgz#a126d9ea76079ffbbdb0d9225073eb5797ab7271" - integrity sha512-D5mHD6TbdV/DNHYsnwBTv+y73ei+mMjrkGrla86HthE4/PVvL1J94Bu3qABU+COXzpL23T1EZapVVpwHuBXiUg== + version "5.3.3" + resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.3.3.tgz#e9d6b4a66fcdbd651a5f106c2656a30088cc1e83" + integrity sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw== dependencies: - "@types/history" "*" + "@types/history" "^4.7.11" "@types/react" "*" "@types/react-router" "*" @@ -3437,10 +3454,10 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -classnames@^2.2.5, classnames@^2.2.6: - version "2.3.1" - resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" - integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== +classnames@2.2.6, classnames@^2.2.5, classnames@^2.2.6: + version "2.2.6" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" + integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== clean-css@^4.2.3: version "4.2.3" @@ -9574,19 +9591,7 @@ react-refresh@^0.8.3: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f" integrity sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg== -react-router-dom@^4.2.2: - version "4.3.1" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-4.3.1.tgz#4c2619fc24c4fa87c9fd18f4fb4a43fe63fbd5c6" - integrity sha512-c/MlywfxDdCp7EnB7YfPMOfMD3tOtIjrQlj/CKfNMBxdmpJP8xcz5P/UAFn3JbnQCNUxsHyVVqllF9LhgVyFCA== - dependencies: - history "^4.7.2" - invariant "^2.2.4" - loose-envify "^1.3.1" - prop-types "^15.6.1" - react-router "^4.3.1" - warning "^4.0.1" - -react-router-dom@^5.2.0: +react-router-dom@5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662" integrity sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA== @@ -9599,6 +9604,18 @@ react-router-dom@^5.2.0: tiny-invariant "^1.0.2" tiny-warning "^1.0.0" +react-router-dom@^4.2.2: + version "4.3.1" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-4.3.1.tgz#4c2619fc24c4fa87c9fd18f4fb4a43fe63fbd5c6" + integrity sha512-c/MlywfxDdCp7EnB7YfPMOfMD3tOtIjrQlj/CKfNMBxdmpJP8xcz5P/UAFn3JbnQCNUxsHyVVqllF9LhgVyFCA== + dependencies: + history "^4.7.2" + invariant "^2.2.4" + loose-envify "^1.3.1" + prop-types "^15.6.1" + react-router "^4.3.1" + warning "^4.0.1" + react-router@5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.0.tgz#424e75641ca8747fbf76e5ecca69781aa37ea293" @@ -11464,16 +11481,11 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^4.0.3: +typescript@4.3.5, typescript@^4.0.3: version "4.3.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== -typescript@^4.1.2: - version "4.2.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" - integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== - unbox-primitive@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" From d3c305c4ff46a1ae32df9cbcce2f389b668aa4d2 Mon Sep 17 00:00:00 2001 From: Alexander Matyushentsev Date: Sat, 12 Feb 2022 14:25:52 -0800 Subject: [PATCH 100/175] fix: add workaround to fix 'stream terminated by RST_STREAM with error code: PROTOCOL_ERROR' (#1862) Signed-off-by: Alexander Matyushentsev --- server/server.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server/server.go b/server/server.go index bc9661c5b5..393cc97a08 100644 --- a/server/server.go +++ b/server/server.go @@ -8,6 +8,7 @@ import ( "net" "net/http" "os" + "strings" "time" "github.com/argoproj/pkg/errors" @@ -101,7 +102,11 @@ func (s *ArgoRolloutsServer) newHTTPServer(ctx context.Context, port int) *http. gwMuxOpts := runtime.WithMarshalerOption(runtime.MIMEWildcard, new(json.JSONMarshaler)) gwmux := runtime.NewServeMux(gwMuxOpts, - runtime.WithIncomingHeaderMatcher(func(key string) (string, bool) { return key, true }), + runtime.WithIncomingHeaderMatcher(func(key string) (string, bool) { + // Dropping "Connection" header as a workaround for https://github.com/grpc-ecosystem/grpc-gateway/issues/2447 + // The fix is part of grpc-gateway v2.x but not available in v1.x, so workaround should be removed after upgrading to grpc v2.x + return key, strings.ToLower(key) != "connection" + }), runtime.WithProtoErrorHandler(runtime.DefaultHTTPProtoErrorHandler), ) From 7b690580f69fd491f40c15b3ff4031f13bdae332 Mon Sep 17 00:00:00 2001 From: Daniel Helfand Date: Thu, 17 Feb 2022 09:48:14 -0600 Subject: [PATCH 101/175] docs: add community section to README.md Signed-off-by: Daniel Helfand --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 10da141d86..94931ac5b5 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,15 @@ For these reasons, in large scale high-volume production environments, a rolling ## Documentation To learn more about Argo Rollouts go to the [complete documentation](https://argoproj.github.io/argo-rollouts/). +## Community + +You can reach the Argo Rollouts community and developers via the following channels: + +* Q & A: [Github Discussions](https://github.com/argoproj/argo-rollouts/discussions) +* Chat: [The #argo-rollouts Slack channel](https://argoproj.github.io/community/join-slack) +* Contributors Office Hours: [Every Thursday](https://calendar.google.com/calendar/u/0/embed?src=argoproj@gmail.com) | [Agenda](https://docs.google.com/document/d/1xkoFkVviB70YBzSEa4bDnu-rUZ1sIFtwKKG1Uw8XsY8) +* User Community meeting: [First Wednesday of each month](https://calendar.google.com/calendar/u/0/embed?src=argoproj@gmail.com) | [Agenda](https://docs.google.com/document/d/1ttgw98MO45Dq7ZUHpIiOIEfbyeitKHNfMjbY5dLLMKQ) + ## Who uses Argo Rollouts? [Official Argo Rollouts User List](https://github.com/argoproj/argo-rollouts/blob/master/USERS.md) From 575a619d68fdd0e21e6dfa80aeea1c6c34009ef9 Mon Sep 17 00:00:00 2001 From: Michael Crenshaw Date: Wed, 23 Feb 2022 13:03:29 -0500 Subject: [PATCH 102/175] chore: move dependencies to dev dependencies Signed-off-by: Michael Crenshaw --- ui/package.json | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/ui/package.json b/ui/package.json index 3aef76ec5f..234376cfce 100644 --- a/ui/package.json +++ b/ui/package.json @@ -3,16 +3,6 @@ "version": "0.1.0", "private": true, "dependencies": { - "@testing-library/jest-dom": "^5.11.4", - "@testing-library/react": "^11.1.0", - "@testing-library/user-event": "^12.1.10", - "@types/classnames": "2.2.9", - "@types/jest": "^26.0.15", - "@types/node": "^12.0.0", - "@types/react": "^16.9.3", - "@types/react-dom": "^16.9.3", - "@types/react-helmet": "^6.1.0", - "@types/react-router-dom": "^5.1.7", "argo-ui": "git+https://github.com/argoproj/argo-ui.git", "classnames": "2.2.6", "moment": "^2.29.1", @@ -24,11 +14,9 @@ "react-hot-loader": "^3.1.3", "react-keyhooks": "^0.2.3", "react-router-dom": "5.2.0", - "react-scripts": "4.0.3", "rxjs": "^6.6.6", "typescript": "4.3.5", - "web-vitals": "^1.0.1", - "webpack-dev-server": "^3.11.2" + "web-vitals": "^1.0.1" }, "scripts": { "start": "webpack serve --config ./src/app/webpack.dev.js", @@ -56,13 +44,25 @@ ] }, "devDependencies": { + "@testing-library/jest-dom": "^5.11.4", + "@testing-library/react": "^11.1.0", + "@testing-library/user-event": "^12.1.10", + "@types/classnames": "2.2.9", + "@types/jest": "^26.0.15", + "@types/node": "^12.0.0", + "@types/react": "^16.9.3", + "@types/react-dom": "^16.9.3", + "@types/react-helmet": "^6.1.0", + "@types/react-router-dom": "^5.1.7", "copy-webpack-plugin": "^6.3.2", "mini-css-extract-plugin": "^1.3.9", "raw-loader": "^4.0.2", + "react-scripts": "4.0.3", "sass": "^1.32.8", "ts-loader": "^8.0.17", "webpack-bundle-analyzer": "^4.4.0", "webpack-cli": "^4.5.0", + "webpack-dev-server": "^3.11.2", "webpack-merge": "^5.7.3" }, "resolutions": { From 4d95f6a96dee36ec90c954f153d39c3058265793 Mon Sep 17 00:00:00 2001 From: Tomas Valasek <13797085+tvalasek@users.noreply.github.com> Date: Mon, 7 Mar 2022 09:24:43 -0800 Subject: [PATCH 103/175] docs: Add SAP Concur (#1878) Fixes docs: Add SAP Concur Signed-off-by: Tomas Valasek tomas.valasek@sap.com --- USERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/USERS.md b/USERS.md index 9c29b73a7f..cc59fd3382 100644 --- a/USERS.md +++ b/USERS.md @@ -24,6 +24,7 @@ Organizations below are **officially** using Argo Rollouts. Please send a PR wit 1. [Quipper](https://www.quipper.com/) 1. [Quizlet](https://quizlet.com) 1. [Salesforce](https://www.salesforce.com/) +1. [SAP Concur](https://www.concur.com/) 1. [Shipt](https://www.shipt.com/) 1. [Skillz](https://www.skillz.com) 1. [Spotify](https://www.spotify.com/) From acf805423c48f0e037e6e5686e6d164465f33c51 Mon Sep 17 00:00:00 2001 From: schakrad <58915923+schakrad@users.noreply.github.com> Date: Mon, 7 Mar 2022 15:21:10 -0500 Subject: [PATCH 104/175] feat: Dashboard now displaying name, specRef and weight in the experimental step. (#1863) feat: Dashboard now displaying name, specRef and weight in the experimental step. (#1863) Signed-off-by: Alexander Matyushentsev --- ui/src/app/components/rollout/rollout.scss | 43 +++++++++++++++++ ui/src/app/components/rollout/rollout.tsx | 56 ++++++++++++++++++++-- ui/src/models/rollout/generated/api.ts | 6 +++ 3 files changed, 102 insertions(+), 3 deletions(-) diff --git a/ui/src/app/components/rollout/rollout.scss b/ui/src/app/components/rollout/rollout.scss index 897f43e1ef..c1925bd304 100644 --- a/ui/src/app/components/rollout/rollout.scss +++ b/ui/src/app/components/rollout/rollout.scss @@ -76,6 +76,49 @@ border: 2px solid $sherbert; } + &-title { + padding-left: 16px; + padding-right: 16px; + margin: 0 -16px; + &--experiment { + padding-bottom: 8px; + border-bottom: 1px solid $argo-color-gray-6; + } + } + + &__content { + margin-left: -16px; + margin-right: -16px; + max-height: 160px; + overflow-y: auto; + + &-body { + padding: 8px 16px; + } + + &-header { + display: flex; + align-items: center; + justify-content: space-between; + } + + &-title { + padding-top: 8px; + padding-bottom: 4px; + font-size: 14px; + } + + &-value { + font-weight: 600; + padding-bottom: 4px; + border-bottom: 1px solid $argo-color-gray-4; + &:last-child { + padding-bottom: -8px; + border-bottom: none; + } + } + } + &:hover > &__background { transform: scale(1.02); } diff --git a/ui/src/app/components/rollout/rollout.tsx b/ui/src/app/components/rollout/rollout.tsx index 12a00ba6a5..5fb794c95a 100644 --- a/ui/src/app/components/rollout/rollout.tsx +++ b/ui/src/app/components/rollout/rollout.tsx @@ -3,7 +3,13 @@ import * as React from 'react'; import {Helmet} from 'react-helmet'; import {Key, KeybindingContext} from 'react-keyhooks'; import {useHistory, useParams} from 'react-router-dom'; -import {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStep, RolloutReplicaSetInfo, RolloutRolloutInfo, RolloutServiceApi} from '../../../models/rollout/generated'; +import { + GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStep, + GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutExperimentTemplate, + RolloutReplicaSetInfo, + RolloutRolloutInfo, + RolloutServiceApi, +} from '../../../models/rollout/generated'; import {RolloutInfo} from '../../../models/rollout/rollout'; import {NamespaceContext, RolloutAPIContext} from '../../shared/context/api'; import {useWatchRollout} from '../../shared/services/rollout'; @@ -12,6 +18,7 @@ import {RolloutStatus, StatusIcon} from '../status-icon/status-icon'; import {ContainersWidget} from './containers'; import {Revision, RevisionWidget} from './revision'; import './rollout.scss'; +import {Fragment} from 'react'; const RolloutActions = React.lazy(() => import('../rollout-actions/rollout-actions')); export interface ImageInfo { @@ -266,6 +273,7 @@ const parseDuration = (duration: string): string => { }; const Step = (props: {step: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStep; complete?: boolean; current?: boolean; last?: boolean}) => { + const [openedTemplate, setOpenedTemplate] = React.useState(''); let icon: string; let content = ''; let unit = ''; @@ -297,10 +305,52 @@ const Step = (props: {step: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1 return ( - {content} - {unit} +
+ {content} + {unit} +
+ {props.step.experiment?.templates && ( +
+ {props.step.experiment?.templates.map((template) => { + return ; + })} +
+ )}
{!props.last && }
); }; + +const ExperimentWidget = ({ + template, + opened, + onToggle, +}: { + template: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutExperimentTemplate; + opened: boolean; + onToggle: (name: string) => void; +}) => { + const icon = opened ? 'fa-chevron-circle-up' : 'fa-chevron-circle-down'; + return ( + + + {template.name} + onToggle(opened ? '' : template.name)}> + + + + {opened && ( + +
SPECREF
+
{template.specRef}
+ {template.weight && ( + +
WEIGHT
{template.weight}
+
+ )} +
+ )} +
+ ); +}; diff --git a/ui/src/models/rollout/generated/api.ts b/ui/src/models/rollout/generated/api.ts index 5ad4585a3b..e0e6752792 100644 --- a/ui/src/models/rollout/generated/api.ts +++ b/ui/src/models/rollout/generated/api.ts @@ -867,6 +867,12 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutExpe * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutExperimentTemplate */ replicas?: number; + /** + * + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutExperimentTemplate + */ + weight?: number; /** * * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PodTemplateMetadata} From 676c8656e1dc6c1d64641c05f8334baab5588b63 Mon Sep 17 00:00:00 2001 From: RaviHari Date: Thu, 17 Mar 2022 02:05:11 +0530 Subject: [PATCH 105/175] docs: vpa for rollouts (#1909) Signed-off-by: Ravi Hari --- docs/features/vpa-support.md | 356 +++++++++++++++++++++++++++++++++++ mkdocs.yml | 1 + 2 files changed, 357 insertions(+) create mode 100644 docs/features/vpa-support.md diff --git a/docs/features/vpa-support.md b/docs/features/vpa-support.md new file mode 100644 index 0000000000..48733cd1f8 --- /dev/null +++ b/docs/features/vpa-support.md @@ -0,0 +1,356 @@ + +# Vertical Pod Autoscaling + +Vertical Pod Autoscaling (VPA) reduces the maintenance cost and improve utilization of cluster resources by automating configuration of resource requirements. + +## VPA modes + +There are four modes in which VPAs operate + +1. "Auto": VPA assigns resource requests on pod creation as well as updates them on existing pods using the preferred update mechanism. Currently this is equivalent to "Recreate" (see below). Once restart free ("in-place") update of pod requests is available, it may be used as the preferred update mechanism by the "Auto" mode. +NOTE: This feature of VPA is experimental and may cause downtime for your applications. + +1. "Recreate": VPA assigns resource requests on pod creation as well as updates them on existing pods by evicting them when the requested resources differ significantly from the new recommendation (respecting the Pod Disruption Budget, if defined). This mode should be used rarely, only if you need to ensure that the pods are restarted whenever the resource request changes. Otherwise prefer the "Auto" mode which may take advantage of restart free updates once they are available. +NOTE: This feature of VPA is experimental and may cause downtime for your applications. + +1. "Initial": VPA only assigns resource requests on pod creation and never changes them later. + +1. "Off": VPA does not automatically change resource requirements of the pods. The recommendations are calculated and can be inspected in the VPA object. + + +## Example + +Below is an example of a Vertical Pod Autoscaler with Argo-Rollouts. + +Rollout sample app: + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: vpa-demo-rollout + namespace: test-vpa +spec: + replicas: 5 + strategy: + canary: + steps: + - setWeight: 20 + - pause: {duration: 10} + - setWeight: 40 + - pause: {duration: 10} + - setWeight: 60 + - pause: {duration: 10} + - setWeight: 80 + - pause: {duration: 10} + revisionHistoryLimit: 10 + selector: + matchLabels: + app: vpa-demo-rollout + template: + metadata: + labels: + app: vpa-demo-rollout + spec: + containers: + - name: vpa-demo-rollout + image: ravihari/nginx:v1 + ports: + - containerPort: 80 + resources: + requests: + cpu: "5m" + memory: "5Mi" +``` + +VPA configuration for Rollout sample app: + +```yaml +apiVersion: "autoscaling.k8s.io/v1beta2" +kind: VerticalPodAutoscaler +metadata: + name: vpa-rollout-example + namespace: test-vpa +spec: + targetRef: + apiVersion: "argoproj.io/v1alpha1" + kind: Rollout + name: vpa-demo-rollout + updatePolicy: + updateMode: "Auto" + resourcePolicy: + containerPolicies: + - containerName: '*' + minAllowed: + cpu: 5m + memory: 5Mi + maxAllowed: + cpu: 1 + memory: 500Mi + controlledResources: ["cpu", "memory"] +``` + +Describe VPA when initially deployed we donot see recommendations as it will take few mins. + +```yaml +Name: kubengix-vpa +Namespace: test-vpa +Labels: +Annotations: +API Version: autoscaling.k8s.io/v1 +Kind: VerticalPodAutoscaler +Metadata: + Creation Timestamp: 2022-03-14T12:54:06Z + Generation: 1 + Managed Fields: + API Version: autoscaling.k8s.io/v1beta2 + Fields Type: FieldsV1 + fieldsV1: + f:metadata: + f:annotations: + .: + f:kubectl.kubernetes.io/last-applied-configuration: + f:spec: + .: + f:resourcePolicy: + .: + f:containerPolicies: + f:targetRef: + .: + f:apiVersion: + f:kind: + f:name: + f:updatePolicy: + .: + f:updateMode: + Manager: kubectl-client-side-apply + Operation: Update + Time: 2022-03-14T12:54:06Z + Resource Version: 3886 + UID: 4ac64e4c-c84b-478e-92e4-5f072f985971 +Spec: + Resource Policy: + Container Policies: + Container Name: * + Controlled Resources: + cpu + memory + Max Allowed: + Cpu: 1 + Memory: 500Mi + Min Allowed: + Cpu: 5m + Memory: 5Mi + Target Ref: + API Version: argoproj.io/v1alpha1 + Kind: Rollout + Name: vpa-demo-rollout + Update Policy: + Update Mode: Auto +Events: +``` + +After few minutes when VPA starts to process and provide recommendation: + +```yaml +Name: kubengix-vpa +Namespace: test-vpa +Labels: +Annotations: +API Version: autoscaling.k8s.io/v1 +Kind: VerticalPodAutoscaler +Metadata: + Creation Timestamp: 2022-03-14T12:54:06Z + Generation: 2 + Managed Fields: + API Version: autoscaling.k8s.io/v1beta2 + Fields Type: FieldsV1 + fieldsV1: + f:metadata: + f:annotations: + .: + f:kubectl.kubernetes.io/last-applied-configuration: + f:spec: + .: + f:resourcePolicy: + .: + f:containerPolicies: + f:targetRef: + .: + f:apiVersion: + f:kind: + f:name: + f:updatePolicy: + .: + f:updateMode: + Manager: kubectl-client-side-apply + Operation: Update + Time: 2022-03-14T12:54:06Z + API Version: autoscaling.k8s.io/v1 + Fields Type: FieldsV1 + fieldsV1: + f:status: + .: + f:conditions: + f:recommendation: + .: + f:containerRecommendations: + Manager: recommender + Operation: Update + Time: 2022-03-14T12:54:52Z + Resource Version: 3950 + UID: 4ac64e4c-c84b-478e-92e4-5f072f985971 +Spec: + Resource Policy: + Container Policies: + Container Name: * + Controlled Resources: + cpu + memory + Max Allowed: + Cpu: 1 + Memory: 500Mi + Min Allowed: + Cpu: 5m + Memory: 5Mi + Target Ref: + API Version: argoproj.io/v1alpha1 + Kind: Rollout + Name: vpa-demo-rollout + Update Policy: + Update Mode: Auto +Status: + Conditions: + Last Transition Time: 2022-03-14T12:54:52Z + Status: True + Type: RecommendationProvided + Recommendation: + Container Recommendations: + Container Name: vpa-demo-rollout + Lower Bound: + Cpu: 25m + Memory: 262144k + Target: + Cpu: 25m + Memory: 262144k + Uncapped Target: + Cpu: 25m + Memory: 262144k + Upper Bound: + Cpu: 1 + Memory: 500Mi +Events: +``` + +Here we see the recommendation for cpu, memory with lowerbound, upper bound, Target etc., are provided. If we check the status of the pods.. the older pods with initial configuration would get terminated and newer pods get created. + +```yaml +# kubectl get po -n test-vpa -w +NAME READY STATUS RESTARTS AGE +vpa-demo-rollout-f5df6d577-65f26 1/1 Running 0 17m +vpa-demo-rollout-f5df6d577-d55cx 1/1 Running 0 17m +vpa-demo-rollout-f5df6d577-fdpn2 1/1 Running 0 17m +vpa-demo-rollout-f5df6d577-jg2pw 1/1 Running 0 17m +vpa-demo-rollout-f5df6d577-vlx5x 1/1 Running 0 17m +... + +vpa-demo-rollout-f5df6d577-jg2pw 1/1 Terminating 0 17m +vpa-demo-rollout-f5df6d577-vlx5x 1/1 Terminating 0 17m +vpa-demo-rollout-f5df6d577-jg2pw 0/1 Terminating 0 18m +vpa-demo-rollout-f5df6d577-vlx5x 0/1 Terminating 0 18m +vpa-demo-rollout-f5df6d577-w7tx4 0/1 Pending 0 0s +vpa-demo-rollout-f5df6d577-w7tx4 0/1 Pending 0 0s +vpa-demo-rollout-f5df6d577-w7tx4 0/1 ContainerCreating 0 0s +vpa-demo-rollout-f5df6d577-vdlqq 0/1 Pending 0 0s +vpa-demo-rollout-f5df6d577-vdlqq 0/1 Pending 0 1s +vpa-demo-rollout-f5df6d577-jg2pw 0/1 Terminating 0 18m +vpa-demo-rollout-f5df6d577-jg2pw 0/1 Terminating 0 18m +vpa-demo-rollout-f5df6d577-vdlqq 0/1 ContainerCreating 0 1s +vpa-demo-rollout-f5df6d577-w7tx4 1/1 Running 0 6s +vpa-demo-rollout-f5df6d577-vdlqq 1/1 Running 0 7s +vpa-demo-rollout-f5df6d577-vlx5x 0/1 Terminating 0 18m +vpa-demo-rollout-f5df6d577-vlx5x 0/1 Terminating 0 18m +``` + +If we check the new pod cpu and memory they would be updated as per VPA recommendation: + + +```yaml +# kubectl describe po vpa-demo-rollout-f5df6d577-vdlqq -n test-vpa +Name: vpa-demo-rollout-f5df6d577-vdlqq +Namespace: test-vpa +Priority: 0 +Node: argo-rollouts-control-plane/172.18.0.2 +Start Time: Mon, 14 Mar 2022 12:55:06 +0000 +Labels: app=vpa-demo-rollout + rollouts-pod-template-hash=f5df6d577 +Annotations: vpaObservedContainers: vpa-demo-rollout + vpaUpdates: Pod resources updated by kubengix-vpa: container 0: cpu request, memory request +Status: Running +IP: 10.244.0.17 +IPs: + IP: 10.244.0.17 +Controlled By: ReplicaSet/vpa-demo-rollout-f5df6d577 +Containers: + vpa-demo-rollout: + Container ID: containerd://b79bd88851fe0622d33bc90a1560ca54ef2c27405a3bc9a4fc3a333eef5f9733 + Image: ravihari/nginx:v1 + Image ID: docker.io/ravihari/nginx@sha256:205961b09a80476af4c2379841bf6abec0022101a7e6c5585a88316f7115d17a + Port: 80/TCP + Host Port: 0/TCP + State: Running + Started: Mon, 14 Mar 2022 12:55:11 +0000 + Ready: True + Restart Count: 0 + Requests: + cpu: 25m + memory: 262144k + Environment: + Mounts: + /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-mk4fz (ro) +Conditions: + Type Status + Initialized True + Ready True + ContainersReady True + PodScheduled True +Volumes: + kube-api-access-mk4fz: + Type: Projected (a volume that contains injected data from multiple sources) + TokenExpirationSeconds: 3607 + ConfigMapName: kube-root-ca.crt + ConfigMapOptional: + DownwardAPI: true +QoS Class: Burstable +Node-Selectors: +Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s + node.kubernetes.io/unreachable:NoExecute op=Exists for 300s +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal Scheduled 38s default-scheduler Successfully assigned test-vpa/vpa-demo-rollout-f5df6d577-vdlqq to argo-rollouts-control-plane + Normal Pulled 35s kubelet Container image "ravihari/nginx:v1" already present on machine + Normal Created 35s kubelet Created container vpa-demo-rollout + Normal Started 33s kubelet Started container vpa-demo-rollout +``` + +## Requirements +In order for the VPA to manipulate the rollout, the Kubernetes cluster hosting the rollout CRD needs the subresources support for CRDs. This feature was introduced as alpha in Kubernetes version 1.10 and transitioned to beta in Kubernetes version 1.11. If a user wants to use VPA on v1.10, the Kubernetes Cluster operator will need to add a custom feature flag to the API server. After 1.10, the flag is turned on by default. Check out the following [link](https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/) for more information on setting the custom feature flag. + +When installing VPA you may need to add the following in RBAC configurations for `system:vpa-target-reader` cluster role as by default VPA maynot support rollouts in all the versions. + +```yaml + - apiGroups: + - argoproj.io + resources: + - rollouts + - rollouts/scale + - rollouts/status + - replicasets + verbs: + - get + - list + - watch +``` + +Makes sure Metrics-Server is installed in the cluster and openssl is upto date for VPA latest version to apply recommendations to the pods properly. diff --git a/mkdocs.yml b/mkdocs.yml index 6af2bc52cb..50f355a1a4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -29,6 +29,7 @@ nav: - Canary: features/canary.md - Rollout Spec: features/specification.md - HPA: features/hpa-support.md + - VPA: features/vpa-support.md - Ephemeral Metadata: features/ephemeral-metadata.md - Restarting Rollouts: features/restart.md - Scaledown Aborted Rollouts: features/scaledown-aborted-rs.md From 08cf10e554fe99c24c8a37ad07fadd9318e4c8a1 Mon Sep 17 00:00:00 2001 From: Jesse Suen Date: Mon, 21 Mar 2022 13:45:35 -0700 Subject: [PATCH 106/175] chore: fix golangci-lint to 1.44 to fix build error (#1917) Signed-off-by: Jesse Suen --- Dockerfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 88e0768b16..c2ac9a90f6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,9 +12,7 @@ RUN apt-get update && apt-get install -y \ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* # Install golangci-lint -RUN wget https://install.goreleaser.com/github.com/golangci/golangci-lint.sh && \ - chmod +x ./golangci-lint.sh && \ - ./golangci-lint.sh -b $GOPATH/bin && \ +RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.44.0 && \ golangci-lint linters COPY .golangci.yml ${GOPATH}/src/dummy/.golangci.yml From 55a041a6b3d088cf9ddcfc4121ad8c97880489db Mon Sep 17 00:00:00 2001 From: RaviHari Date: Tue, 22 Mar 2022 06:50:58 +0530 Subject: [PATCH 107/175] feat: Report notification metrics for rollouts (#1856) feat: Report notification metrics for rollouts (#1856) Signed-off-by: Ravi Hari --- controller/controller.go | 2 +- controller/metrics/metrics.go | 12 +++- controller/metrics/prommetrics.go | 28 +++++++++ docs/features/notifications.md | 7 +++ go.mod | 4 +- go.sum | 6 +- metricproviders/prometheus/mock_test.go | 4 ++ utils/record/record.go | 47 +++++++++++++-- utils/record/record_test.go | 79 ++++++++++++++++++++++++- 9 files changed, 177 insertions(+), 12 deletions(-) diff --git a/controller/controller.go b/controller/controller.go index 171f62d5fc..f12b268fbf 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -199,7 +199,7 @@ func NewManager( refResolver := rollout.NewInformerBasedWorkloadRefResolver(namespace, dynamicclientset, discoveryClient, argoprojclientset, rolloutsInformer.Informer()) apiFactory := notificationapi.NewFactory(record.NewAPIFactorySettings(), defaults.Namespace(), secretInformer.Informer(), configMapInformer.Informer()) - recorder := record.NewEventRecorder(kubeclientset, metrics.MetricRolloutEventsTotal, apiFactory) + recorder := record.NewEventRecorder(kubeclientset, metrics.MetricRolloutEventsTotal, metrics.MetricNotificationFailedTotal, metrics.MetricNotificationSuccessTotal, metrics.MetricNotificationSend, apiFactory) notificationsController := notificationcontroller.NewController(dynamicclientset.Resource(v1alpha1.RolloutGVR), rolloutsInformer.Informer(), apiFactory, notificationcontroller.WithToUnstructured(func(obj metav1.Object) (*unstructured.Unstructured, error) { data, err := json.Marshal(obj) diff --git a/controller/metrics/metrics.go b/controller/metrics/metrics.go index b502ff32e6..b5940bc61f 100644 --- a/controller/metrics/metrics.go +++ b/controller/metrics/metrics.go @@ -26,8 +26,10 @@ type MetricsServer struct { reconcileAnalysisRunHistogram *prometheus.HistogramVec errorAnalysisRunCounter *prometheus.CounterVec - - k8sRequestsCounter *K8sRequestsCountProvider + successNotificationCounter *prometheus.CounterVec + errorNotificationCounter *prometheus.CounterVec + sendNotificationRunHistogram *prometheus.HistogramVec + k8sRequestsCounter *K8sRequestsCountProvider } const ( @@ -75,6 +77,9 @@ func NewMetricsServer(cfg ServerConfig, isPrimary bool) *MetricsServer { reg.MustRegister(MetricExperimentReconcileError) reg.MustRegister(MetricAnalysisRunReconcile) reg.MustRegister(MetricAnalysisRunReconcileError) + reg.MustRegister(MetricNotificationSuccessTotal) + reg.MustRegister(MetricNotificationFailedTotal) + reg.MustRegister(MetricNotificationSend) reg.MustRegister(MetricVersionGauge) mux.Handle(MetricsPath, promhttp.HandlerFor(prometheus.Gatherers{ @@ -96,6 +101,9 @@ func NewMetricsServer(cfg ServerConfig, isPrimary bool) *MetricsServer { reconcileAnalysisRunHistogram: MetricAnalysisRunReconcile, errorAnalysisRunCounter: MetricAnalysisRunReconcileError, + successNotificationCounter: MetricNotificationSuccessTotal, + errorNotificationCounter: MetricNotificationFailedTotal, + sendNotificationRunHistogram: MetricNotificationSend, k8sRequestsCounter: cfg.K8SRequestProvider, } diff --git a/controller/metrics/prommetrics.go b/controller/metrics/prommetrics.go index abf6a77312..02ed83af92 100644 --- a/controller/metrics/prommetrics.go +++ b/controller/metrics/prommetrics.go @@ -175,6 +175,34 @@ var ( ) ) +// Notification metrics +var ( + MetricNotificationSuccessTotal = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "notification_send_success", + Help: "Notification send success.", + }, + append(namespaceNameLabels, "type", "reason"), + ) + + MetricNotificationFailedTotal = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "notification_send_error", + Help: "Error sending the notification", + }, + append(namespaceNameLabels, "type", "reason"), + ) + + MetricNotificationSend = prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Name: "notification_send", + Help: "Notification send performance.", + Buckets: []float64{0.01, 0.15, .25, .5, 1}, + }, + namespaceNameLabels, + ) +) + // K8s Client metrics var ( // Custom events metric diff --git a/docs/features/notifications.md b/docs/features/notifications.md index 1556345734..3a7dfb2e4e 100644 --- a/docs/features/notifications.md +++ b/docs/features/notifications.md @@ -143,3 +143,10 @@ data: ``` Each condition might use several templates. Typically each template is responsible for generating a service-specific notification part. + +### Notification Metrics + +The following prometheus metrics are emitted when notifications are enabled in argo-rollouts. +- notification_send_success is a counter that measures how many times the notification is sent successfully. +- notification_send_error is a counter that measures how many times the notification failed to send. +- notification_send is a histogram that measures performance of sending notification. \ No newline at end of file diff --git a/go.mod b/go.mod index 7255d19def..0ac3bf0f6d 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/mitchellh/mapstructure v1.4.3 github.com/newrelic/newrelic-client-go v0.72.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.11.0 + github.com/prometheus/client_golang v1.12.1 github.com/prometheus/client_model v0.2.0 github.com/prometheus/common v0.32.1 github.com/servicemeshinterface/smi-sdk-go v0.4.1 @@ -135,7 +135,7 @@ require ( github.com/opsgenie/opsgenie-go-sdk-v2 v1.0.5 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/procfs v0.6.0 // indirect + github.com/prometheus/procfs v0.7.3 // indirect github.com/russross/blackfriday v1.5.2 // indirect github.com/slack-go/slack v0.10.1 // indirect github.com/spf13/pflag v1.0.5 // indirect diff --git a/go.sum b/go.sum index a8f9f0cc96..f45bf974f5 100644 --- a/go.sum +++ b/go.sum @@ -739,8 +739,9 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -761,8 +762,9 @@ github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7z github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/quobyte/api v0.1.8/go.mod h1:jL7lIHrmqQ7yh05OJ+eEEdHr0u/kmT1Ff9iHd+4H6VI= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= diff --git a/metricproviders/prometheus/mock_test.go b/metricproviders/prometheus/mock_test.go index a93c285244..ae833b8074 100644 --- a/metricproviders/prometheus/mock_test.go +++ b/metricproviders/prometheus/mock_test.go @@ -14,6 +14,10 @@ type mockAPI struct { warnings v1.Warnings } +func (m mockAPI) WalReplay(ctx context.Context) (v1.WalReplayStatus, error) { + panic("Not used") +} + // Query performs a query for the given time. func (m mockAPI) Query(ctx context.Context, query string, ts time.Time) (model.Value, v1.Warnings, error) { if m.err != nil { diff --git a/utils/record/record.go b/utils/record/record.go index f7e9ad7395..d6f00bd469 100644 --- a/utils/record/record.go +++ b/utils/record/record.go @@ -7,6 +7,8 @@ import ( "strings" "time" + timeutil "github.com/argoproj/argo-rollouts/utils/time" + "github.com/argoproj/notifications-engine/pkg/api" "github.com/argoproj/notifications-engine/pkg/services" "github.com/argoproj/notifications-engine/pkg/subscriptions" @@ -65,13 +67,18 @@ type EventRecorderAdapter struct { Recorder record.EventRecorder // RolloutEventCounter is a counter to increment on events RolloutEventCounter *prometheus.CounterVec + // NotificationFailCounter is a counter to increment on failing to send notifications + NotificationFailedCounter *prometheus.CounterVec + // NotificationSuccessCounter is a counter to increment on successful send notifications + NotificationSuccessCounter *prometheus.CounterVec + NotificationSendPerformance *prometheus.HistogramVec eventf func(object runtime.Object, warn bool, opts EventOptions, messageFmt string, args ...interface{}) // apiFactory is a notifications engine API factory apiFactory api.Factory } -func NewEventRecorder(kubeclientset kubernetes.Interface, rolloutEventCounter *prometheus.CounterVec, apiFactory api.Factory) EventRecorder { +func NewEventRecorder(kubeclientset kubernetes.Interface, rolloutEventCounter *prometheus.CounterVec, notificationFailedCounter *prometheus.CounterVec, notificationSuccessCounter *prometheus.CounterVec, notificationSendPerformance *prometheus.HistogramVec, apiFactory api.Factory) EventRecorder { // Create event broadcaster // Add argo-rollouts custom resources to the default Kubernetes Scheme so Events can be // logged for argo-rollouts types. @@ -80,9 +87,12 @@ func NewEventRecorder(kubeclientset kubernetes.Interface, rolloutEventCounter *p eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: kubeclientset.CoreV1().Events("")}) k8srecorder := eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: controllerAgentName}) recorder := &EventRecorderAdapter{ - Recorder: k8srecorder, - RolloutEventCounter: rolloutEventCounter, - apiFactory: apiFactory, + Recorder: k8srecorder, + RolloutEventCounter: rolloutEventCounter, + NotificationFailedCounter: notificationFailedCounter, + NotificationSuccessCounter: notificationSuccessCounter, + NotificationSendPerformance: notificationSendPerformance, + apiFactory: apiFactory, } recorder.eventf = recorder.defaultEventf return recorder @@ -137,6 +147,26 @@ func NewFakeEventRecorder() *FakeEventRecorder { }, []string{"name", "namespace", "type", "reason"}, ), + prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "notification_send_error", + }, + []string{"name", "namespace", "type", "reason"}, + ), + prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "notification_send_success", + }, + []string{"name", "namespace", "type", "reason"}, + ), + prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Name: "notification_send_performance", + Help: "Notification send performance.", + Buckets: []float64{0.01, 0.15, .25, .5, 1}, + }, + []string{"namespace", "name"}, + ), NewFakeApiFactory(), ).(*EventRecorderAdapter) recorder.Recorder = record.NewFakeRecorder(1000) @@ -178,7 +208,9 @@ func (e *EventRecorderAdapter) defaultEventf(object runtime.Object, warn bool, o err := e.sendNotifications(object, opts) if err != nil { logCtx.Errorf("Notifications failed to send for eventReason %s with error: %s", opts.EventReason, err) + e.NotificationFailedCounter.WithLabelValues(namespace, name, opts.EventType, opts.EventReason).Inc() } + e.NotificationSuccessCounter.WithLabelValues(namespace, name, opts.EventType, opts.EventReason).Inc() } logFn := logCtx.Infof @@ -207,6 +239,13 @@ func NewAPIFactorySettings() api.Settings { // Send notifications for triggered event if user is subscribed func (e *EventRecorderAdapter) sendNotifications(object runtime.Object, opts EventOptions) error { logCtx := logutil.WithObject(object) + _, namespace, name := logutil.KindNamespaceName(logCtx) + startTime := timeutil.Now() + defer func() { + duration := time.Since(startTime) + e.NotificationSendPerformance.WithLabelValues(namespace, name).Observe(duration.Seconds()) + logCtx.WithField("time_ms", duration.Seconds()*1e3).Debug("Notification sent") + }() notificationsAPI, err := e.apiFactory.GetAPI() if err != nil { // don't return error if notifications are not configured and rollout has no subscribers diff --git a/utils/record/record_test.go b/utils/record/record_test.go index c7fe164fd9..b3b34e7a3d 100644 --- a/utils/record/record_test.go +++ b/utils/record/record_test.go @@ -13,6 +13,7 @@ import ( "github.com/argoproj/notifications-engine/pkg/triggers" "github.com/golang/mock/gomock" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/testutil" dto "github.com/prometheus/client_model/go" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" @@ -100,11 +101,87 @@ func TestSendNotifications(t *testing.T) { apiFactory := &mocks.FakeFactory{Api: mockAPI} rec := NewFakeEventRecorder() rec.EventRecorderAdapter.apiFactory = apiFactory - + //ch := make(chan prometheus.HistogramVec, 1) err := rec.sendNotifications(&r, EventOptions{EventReason: "FooReason"}) assert.NoError(t, err) } +func TestNotificationFailedCounter(t *testing.T) { + r := v1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Name: "guestbook", + Namespace: "default", + Annotations: map[string]string{"notifications.argoproj.io/subscribe.on-foo-reason.console": "console"}, + }, + } + rec := NewFakeEventRecorder() + opts := EventOptions{EventType: corev1.EventTypeWarning, EventReason: "FooReason"} + rec.NotificationFailedCounter.WithLabelValues(r.Name, r.Namespace, opts.EventType, opts.EventReason).Inc() + + res := testutil.ToFloat64(rec.NotificationFailedCounter) + assert.Equal(t, float64(1), res) +} + +func TestNotificationSuccessCounter(t *testing.T) { + r := v1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Name: "guestbook", + Namespace: "default", + Annotations: map[string]string{"notifications.argoproj.io/subscribe.on-foo-reason.console": "console"}, + }, + } + rec := NewFakeEventRecorder() + opts := EventOptions{EventType: corev1.EventTypeNormal, EventReason: "FooReason"} + rec.NotificationSuccessCounter.WithLabelValues(r.Name, r.Namespace, opts.EventType, opts.EventReason).Inc() + + res := testutil.ToFloat64(rec.NotificationSuccessCounter) + assert.Equal(t, float64(1), res) +} + +func TestNotificationSendPerformance(t *testing.T) { + r := v1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Name: "guestbook", + Namespace: "default", + Annotations: map[string]string{"notifications.argoproj.io/subscribe.on-foo-reason.console": "console"}, + }, + } + rec := NewFakeEventRecorder() + rec.NotificationSendPerformance.WithLabelValues(r.Namespace, r.Name).Observe(float64(0.4)) + rec.NotificationSendPerformance.WithLabelValues(r.Namespace, r.Name).Observe(float64(1.3)) + rec.NotificationSendPerformance.WithLabelValues(r.Namespace, r.Name).Observe(float64(0.5)) + rec.NotificationSendPerformance.WithLabelValues(r.Namespace, r.Name).Observe(float64(1.4)) + rec.NotificationSendPerformance.WithLabelValues(r.Namespace, r.Name).Observe(float64(0.6)) + rec.NotificationSendPerformance.WithLabelValues(r.Namespace, r.Name).Observe(float64(0.1)) + rec.NotificationSendPerformance.WithLabelValues(r.Namespace, r.Name).Observe(float64(1.3)) + rec.NotificationSendPerformance.WithLabelValues(r.Namespace, r.Name).Observe(float64(0.25)) + rec.NotificationSendPerformance.WithLabelValues(r.Namespace, r.Name).Observe(float64(0.9)) + rec.NotificationSendPerformance.WithLabelValues(r.Namespace, r.Name).Observe(float64(0.17)) + rec.NotificationSendPerformance.WithLabelValues(r.Namespace, r.Name).Observe(float64(0.35)) + + reg := prometheus.NewRegistry() + reg.MustRegister(rec.NotificationSendPerformance) + + mfs, err := reg.Gather() + if err != nil { + t.Fatalf("error: %v", err) + } + log.Infof("mfs: %v, %v, %v, %v", *mfs[0], *mfs[0].Metric[0].Histogram.SampleCount, *mfs[0].Metric[0].Histogram.SampleSum, *mfs[0].Metric[0].Histogram.Bucket[0].CumulativeCount) + want := `# HELP notification_send_performance Notification send performance. + # TYPE notification_send_performance histogram + notification_send_performance_bucket{name="guestbook",namespace="default",le="0.01"} 0 + notification_send_performance_bucket{name="guestbook",namespace="default",le="0.15"} 1 + notification_send_performance_bucket{name="guestbook",namespace="default",le="0.25"} 3 + notification_send_performance_bucket{name="guestbook",namespace="default",le="0.5"} 6 + notification_send_performance_bucket{name="guestbook",namespace="default",le="1"} 8 + notification_send_performance_bucket{name="guestbook",namespace="default",le="+Inf"} 11 + notification_send_performance_sum{name="guestbook",namespace="default"} 7.27 + notification_send_performance_count{name="guestbook",namespace="default"} 11 + ` + err = testutil.CollectAndCompare(rec.NotificationSendPerformance, strings.NewReader(want)) + assert.Nil(t, err) +} + func TestSendNotificationsFails(t *testing.T) { r := v1alpha1.Rollout{ ObjectMeta: metav1.ObjectMeta{ From e89c97b73fbe3a69ce0979a2fc825ce6f1058faa Mon Sep 17 00:00:00 2001 From: schakrad <58915923+schakrad@users.noreply.github.com> Date: Wed, 30 Mar 2022 17:12:44 -0400 Subject: [PATCH 108/175] feature: Dashboard displaying the setCanaryScale values (#1923) feature: Dashboard displaying the setCanaryScale values (#1923) Signed-off-by: Alexander Matyushentsev --- ui/src/app/components/rollout/rollout.scss | 5 +++ ui/src/app/components/rollout/rollout.tsx | 48 ++++++++++++++-------- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/ui/src/app/components/rollout/rollout.scss b/ui/src/app/components/rollout/rollout.scss index c1925bd304..6c2e6f020c 100644 --- a/ui/src/app/components/rollout/rollout.scss +++ b/ui/src/app/components/rollout/rollout.scss @@ -80,10 +80,15 @@ padding-left: 16px; padding-right: 16px; margin: 0 -16px; + display: flex; + align-items: center; &--experiment { padding-bottom: 8px; border-bottom: 1px solid $argo-color-gray-6; } + & > i:first-child { + margin-right: 5px; + } } &__content { diff --git a/ui/src/app/components/rollout/rollout.tsx b/ui/src/app/components/rollout/rollout.tsx index 5fb794c95a..b614968780 100644 --- a/ui/src/app/components/rollout/rollout.tsx +++ b/ui/src/app/components/rollout/rollout.tsx @@ -160,9 +160,11 @@ export const RolloutWidget = (props: {rollout: RolloutRolloutInfo; interactive?: Steps
- {rollout.steps.map((step, i) => ( - - ))} + {rollout.steps + .filter((step) => Object.keys(step).length) + .map((step, i, arr) => ( + + ))}
)} @@ -274,6 +276,8 @@ const parseDuration = (duration: string): string => { const Step = (props: {step: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStep; complete?: boolean; current?: boolean; last?: boolean}) => { const [openedTemplate, setOpenedTemplate] = React.useState(''); + const [open, setOpen] = React.useState(false); + let icon: string; let content = ''; let unit = ''; @@ -305,9 +309,14 @@ const Step = (props: {step: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1 return ( -
- {content} +
+ {icon && } {content} {unit} + {props.step.setCanaryScale && ( + setOpen(!open)}> + + + )}
{props.step.experiment?.templates && (
@@ -316,6 +325,7 @@ const Step = (props: {step: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1 })}
)} + {props.step?.setCanaryScale && open && } {!props.last && } @@ -340,17 +350,23 @@ const ExperimentWidget = ({ - {opened && ( - -
SPECREF
-
{template.specRef}
- {template.weight && ( - -
WEIGHT
{template.weight}
-
- )} -
- )} + {opened && } + + ); +}; + +const WidgetItem = ({values}: {values: Record}) => { + return ( + + {Object.keys(values).map((val) => { + if (!values[val]) return null; + return ( + +
{val.toUpperCase()}
+
{String(values[val])}
+
+ ); + })}
); }; From 40c22b36790493e5bc9f0e3247ab107e5b319e3c Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Fri, 1 Apr 2022 12:44:13 -0500 Subject: [PATCH 109/175] fix: Use actual weight from status field on rollout object (#1937) fix: Use actual weight from status field on rollout object (#1937) Signed-off-by: zachaller --- pkg/kubectl-argo-rollouts/info/info_test.go | 25 +++++ .../info/rollout_info.go | 6 +- .../info/testdata/canary/canary-rollout5.yaml | 96 +++++++++++++++++++ .../info/testdata/canary/canary-rollout6.yaml | 87 +++++++++++++++++ 4 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 pkg/kubectl-argo-rollouts/info/testdata/canary/canary-rollout5.yaml create mode 100644 pkg/kubectl-argo-rollouts/info/testdata/canary/canary-rollout6.yaml diff --git a/pkg/kubectl-argo-rollouts/info/info_test.go b/pkg/kubectl-argo-rollouts/info/info_test.go index 33515e9ad4..d7bbe161fd 100644 --- a/pkg/kubectl-argo-rollouts/info/info_test.go +++ b/pkg/kubectl-argo-rollouts/info/info_test.go @@ -1,6 +1,7 @@ package info import ( + "strconv" "testing" "time" @@ -37,6 +38,30 @@ func TestCanaryRolloutInfo(t *testing.T) { }) } +func TestCanaryRolloutInfoWeights(t *testing.T) { + rolloutObjs := testdata.NewCanaryRollout() + + t.Run("TestActualWeightWithExistingWeight", func(t *testing.T) { + t.Run("will test that actual weight for info object is set from rollout status", func(t *testing.T) { + roInfo := NewRolloutInfo(rolloutObjs.Rollouts[4], rolloutObjs.ReplicaSets, rolloutObjs.Pods, rolloutObjs.Experiments, rolloutObjs.AnalysisRuns, nil) + actualWeightString := roInfo.ActualWeight + actualWeightStringInt32, err := strconv.ParseInt(actualWeightString, 10, 32) + if err != nil { + t.Error(err) + } + assert.Equal(t, rolloutObjs.Rollouts[4].Status.Canary.Weights.Canary.Weight, int32(actualWeightStringInt32)) + }) + }) + + t.Run("TestActualWeightWithoutExistingWeight", func(t *testing.T) { + t.Run("will test that actual weight is set to SetWeight when status field does not exist", func(t *testing.T) { + //This test has a no canary weight object in the status field so we fall back to using SetWeight value + roInfo := NewRolloutInfo(rolloutObjs.Rollouts[5], rolloutObjs.ReplicaSets, rolloutObjs.Pods, rolloutObjs.Experiments, rolloutObjs.AnalysisRuns, nil) + assert.Equal(t, roInfo.SetWeight, roInfo.ActualWeight) + }) + }) +} + func TestPingPongCanaryRolloutInfo(t *testing.T) { rolloutObjs := testdata.NewCanaryRollout() roInfo := NewRolloutInfo(rolloutObjs.Rollouts[3], rolloutObjs.ReplicaSets, rolloutObjs.Pods, rolloutObjs.Experiments, rolloutObjs.AnalysisRuns, nil) diff --git a/pkg/kubectl-argo-rollouts/info/rollout_info.go b/pkg/kubectl-argo-rollouts/info/rollout_info.go index f50e778ed5..98bfffb89c 100644 --- a/pkg/kubectl-argo-rollouts/info/rollout_info.go +++ b/pkg/kubectl-argo-rollouts/info/rollout_info.go @@ -65,7 +65,11 @@ func NewRolloutInfo( } } } else { - roInfo.ActualWeight = roInfo.SetWeight + if ro.Status.Canary.Weights != nil { + roInfo.ActualWeight = fmt.Sprintf("%d", ro.Status.Canary.Weights.Canary.Weight) + } else { + roInfo.ActualWeight = roInfo.SetWeight + } } } } else if ro.Spec.Strategy.BlueGreen != nil { diff --git a/pkg/kubectl-argo-rollouts/info/testdata/canary/canary-rollout5.yaml b/pkg/kubectl-argo-rollouts/info/testdata/canary/canary-rollout5.yaml new file mode 100644 index 0000000000..2ea2c4436a --- /dev/null +++ b/pkg/kubectl-argo-rollouts/info/testdata/canary/canary-rollout5.yaml @@ -0,0 +1,96 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + annotations: + rollout.argoproj.io/revision: "31" + creationTimestamp: "2019-10-25T06:07:18Z" + generation: 429 + labels: + app: canary-demo-weights + app.kubernetes.io/instance: jesse-test + name: canary-demo-weights + namespace: jesse-test + resourceVersion: "28253567" + selfLink: /apis/argoproj.io/v1alpha1/namespaces/jesse-test/rollouts/canary-demo-weights + uid: b350ba76-f6ed-11e9-a15b-42010aa80033 +spec: + progressDeadlineSeconds: 30 + replicas: 5 + revisionHistoryLimit: 3 + selector: + matchLabels: + app: canary-demo-weights + strategy: + canary: + canaryService: canary-demo-preview + stableService: canary-demo-stable + trafficRouting: + smi: + rootService: root-svc # optional + trafficSplitName: rollout-example-traffic-split # optional + steps: + - setWeight: 20 + - pause: {} + - setWeight: 40 + - pause: + duration: 10s + - setWeight: 60 + - pause: + duration: 10s + - setWeight: 80 + - pause: + duration: 10s + template: + metadata: + creationTimestamp: null + labels: + app: canary-demo-weights + spec: + containers: + - image: argoproj/rollouts-demo:does-not-exist + imagePullPolicy: Always + name: canary-demo + ports: + - containerPort: 8080 + name: http + protocol: TCP + resources: + requests: + cpu: 5m + memory: 32Mi +status: + HPAReplicas: 6 + availableReplicas: 5 + blueGreen: {} + canary: + weights: + canary: + podTemplateHash: 868d98998a + serviceName: canary-demo + weight: 20 + stable: + podTemplateHash: 877894d5b + serviceName: canary-demo + weight: 60 + stableRS: 877894d5b + conditions: + - lastTransitionTime: "2019-10-25T06:07:29Z" + lastUpdateTime: "2019-10-25T06:07:29Z" + message: Rollout has minimum availability + reason: AvailableReason + status: "True" + type: Available + - lastTransitionTime: "2019-10-28T04:52:55Z" + lastUpdateTime: "2019-10-28T04:52:55Z" + message: ReplicaSet "canary-demo-65fb5ffc84" has timed out progressing. + reason: ProgressDeadlineExceeded + status: "False" + type: Progressing + currentPodHash: 65fb5ffc84 + currentStepHash: f64cdc9d + currentStepIndex: 0 + observedGeneration: "429" + readyReplicas: 5 + replicas: 6 + selector: app=canary-demo-weights + updatedReplicas: 1 diff --git a/pkg/kubectl-argo-rollouts/info/testdata/canary/canary-rollout6.yaml b/pkg/kubectl-argo-rollouts/info/testdata/canary/canary-rollout6.yaml new file mode 100644 index 0000000000..54edf27937 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/info/testdata/canary/canary-rollout6.yaml @@ -0,0 +1,87 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + annotations: + rollout.argoproj.io/revision: "31" + creationTimestamp: "2019-10-25T06:07:18Z" + generation: 429 + labels: + app: canary-demo-weights-na + app.kubernetes.io/instance: jesse-test + name: canary-demo-weights-na + namespace: jesse-test + resourceVersion: "28253567" + selfLink: /apis/argoproj.io/v1alpha1/namespaces/jesse-test/rollouts/canary-demo-weights-na + uid: b350ba76-f6ed-11e9-a15b-42010aa80033 +spec: + progressDeadlineSeconds: 30 + replicas: 5 + revisionHistoryLimit: 3 + selector: + matchLabels: + app: canary-demo-weights-na + strategy: + canary: + canaryService: canary-demo-preview + stableService: canary-demo-stable + trafficRouting: + smi: + rootService: root-svc # optional + trafficSplitName: rollout-example-traffic-split # optional + steps: + - setWeight: 20 + - pause: {} + - setWeight: 40 + - pause: + duration: 10s + - setWeight: 60 + - pause: + duration: 10s + - setWeight: 80 + - pause: + duration: 10s + template: + metadata: + creationTimestamp: null + labels: + app: canary-demo-weights-na + spec: + containers: + - image: argoproj/rollouts-demo:does-not-exist + imagePullPolicy: Always + name: canary-demo + ports: + - containerPort: 8080 + name: http + protocol: TCP + resources: + requests: + cpu: 5m + memory: 32Mi +status: + HPAReplicas: 6 + availableReplicas: 5 + blueGreen: {} + canary: {} + stableRS: 877894d5b + conditions: + - lastTransitionTime: "2019-10-25T06:07:29Z" + lastUpdateTime: "2019-10-25T06:07:29Z" + message: Rollout has minimum availability + reason: AvailableReason + status: "True" + type: Available + - lastTransitionTime: "2019-10-28T04:52:55Z" + lastUpdateTime: "2019-10-28T04:52:55Z" + message: ReplicaSet "canary-demo-65fb5ffc84" has timed out progressing. + reason: ProgressDeadlineExceeded + status: "False" + type: Progressing + currentPodHash: 65fb5ffc84 + currentStepHash: f64cdc9d + currentStepIndex: 0 + observedGeneration: "429" + readyReplicas: 5 + replicas: 6 + selector: app=canary-demo-weights-na + updatedReplicas: 1 From beae624100a3ec899f649bca28d555c8a6bfe5d0 Mon Sep 17 00:00:00 2001 From: 34FathomBelow <34fathombelow@protonmail.com> Date: Fri, 1 Apr 2022 13:56:19 -0700 Subject: [PATCH 110/175] chore: Improve image build speed (#1919) Signed-off-by: Justin Marquis <34fathombelow@protonmail.com> --- .github/workflows/docker-publish.yml | 26 +++++++++++--------------- Dockerfile | 9 +++++---- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 1780f13348..3fb8351327 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -23,13 +23,13 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - - name: Cache Docker layers - uses: actions/cache@v2 - with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx- + # - name: Cache Docker layers + # uses: actions/cache@v2 + # with: + # path: /tmp/.buildx-cache + # key: ${{ runner.os }}-buildx-${{ github.sha }} + # restore-keys: | + # ${{ runner.os }}-buildx- - name: Docker meta (controller) id: controller-meta @@ -87,8 +87,6 @@ jobs: platforms: ${{ steps.platform-matrix.outputs.platform-matrix }} push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.controller-meta.outputs.tags }} - cache-from: type=local,src=/tmp/.buildx-cache - cache-to: type=local,dest=/tmp/.buildx-cache - name: Build and push (plugin-image) uses: docker/build-push-action@v2 @@ -97,13 +95,11 @@ jobs: platforms: ${{ steps.platform-matrix.outputs.platform-matrix }} push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.plugin-meta.outputs.tags }} - cache-from: type=local,src=/tmp/.buildx-cache - cache-to: type=local,dest=/tmp/.buildx-cache-new # Temp fix # https://github.com/docker/build-push-action/issues/252 # https://github.com/moby/buildkit/issues/1896 - - name: Move cache - run: | - rm -rf /tmp/.buildx-cache - mv /tmp/.buildx-cache-new /tmp/.buildx-cache + # - name: Move cache + # run: | + # rm -rf /tmp/.buildx-cache + # mv /tmp/.buildx-cache-new /tmp/.buildx-cache diff --git a/Dockerfile b/Dockerfile index c2ac9a90f6..be21aa3fa2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ # Initial stage which pulls prepares build dependencies and CLI tooling we need for our final image # Also used as the image in CI jobs so needs all dependencies #################################################################################################### -FROM golang:1.17.6 as builder +FROM --platform=$BUILDPLATFORM golang:1.17.6 as builder RUN apt-get update && apt-get install -y \ wget \ @@ -24,7 +24,7 @@ RUN cd ${GOPATH}/src/dummy && \ #################################################################################################### # UI build stage #################################################################################################### -FROM docker.io/library/node:12.18.4 as argo-rollouts-ui +FROM --platform=$BUILDPLATFORM docker.io/library/node:12.18.4 as argo-rollouts-ui WORKDIR /src ADD ["ui/package.json", "ui/yarn.lock", "./"] @@ -40,7 +40,7 @@ RUN NODE_ENV='production' yarn build #################################################################################################### # Rollout Controller Build stage which performs the actual build of argo-rollouts binaries #################################################################################################### -FROM golang:1.17.6 as argo-rollouts-build +FROM --platform=$BUILDPLATFORM golang:1.17.6 as argo-rollouts-build WORKDIR /go/src/github.com/argoproj/argo-rollouts @@ -61,8 +61,9 @@ RUN touch ui/dist/node_modules.marker && \ touch ui/dist/app/index.html && \ find ui/dist +ARG TARGETOS TARGETARCH ARG MAKE_TARGET="controller plugin plugin-linux plugin-darwin plugin-windows" -RUN make ${MAKE_TARGET} +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH make ${MAKE_TARGET} #################################################################################################### # Kubectl plugin image From 4333b4f08d613d881dc891170e23774df248c7ce Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Tue, 5 Apr 2022 13:52:41 -0500 Subject: [PATCH 111/175] fix: build/lint is broken due to dependencies changes (#1958) Signed-off-by: zachaller --- .github/workflows/go.yml | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index bb382359d2..9d7ba50006 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -7,26 +7,34 @@ on: pull_request: branches: - "master" +env: + # Golang version to use across CI steps + GOLANG_VERSION: '1.17' + jobs: lint-go: name: Lint Go code runs-on: ubuntu-latest steps: + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: ${{ env.GOLANG_VERSION }} - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Run golangci-lint - uses: golangci/golangci-lint-action@v2 + uses: golangci/golangci-lint-action@v3 with: - version: v1.30 + version: v1.45.2 args: --timeout 5m build: name: Build runs-on: ubuntu-latest steps: - name: Set up Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: - go-version: 1.17 + go-version: ${{ env.GOLANG_VERSION }} id: go - name: Check out code into the Go module directory @@ -70,7 +78,7 @@ jobs: - name: Setup Golang uses: actions/setup-go@v1 with: - go-version: 1.17.6 + go-version: ${{ env.GOLANG_VERSION }} # k8s codegen generates files into GOPATH location instead of the GitHub git checkout location # This symlink is necessary to ensure that `git diff` detects changes - name: Create symlink in GOPATH From 589e89647c59863a16e1d4168ac383842144d0aa Mon Sep 17 00:00:00 2001 From: Ansil H Date: Thu, 7 Apr 2022 02:56:01 -0400 Subject: [PATCH 112/175] fix: Add watch verb to clusterRole for pods Fixes https://github.com/argoproj/argo-rollouts/issues/1960 Signed-off-by: Ansil H --- manifests/install.yaml | 1 + manifests/namespace-install.yaml | 1 + manifests/role/argo-rollouts-clusterrole.yaml | 1 + 3 files changed, 3 insertions(+) diff --git a/manifests/install.yaml b/manifests/install.yaml index 31af7b4ca2..9e104720ef 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -14430,6 +14430,7 @@ rules: verbs: - list - update + - watch - apiGroups: - "" resources: diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 744aebf18b..2e5ee32b54 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -14430,6 +14430,7 @@ rules: verbs: - list - update + - watch - apiGroups: - "" resources: diff --git a/manifests/role/argo-rollouts-clusterrole.yaml b/manifests/role/argo-rollouts-clusterrole.yaml index 692299af0f..6176262e06 100644 --- a/manifests/role/argo-rollouts-clusterrole.yaml +++ b/manifests/role/argo-rollouts-clusterrole.yaml @@ -107,6 +107,7 @@ rules: verbs: - list - update + - watch # pods eviction needed for restart - apiGroups: - "" From 633892d59ae0dce271e9ddc176217331686e20a7 Mon Sep 17 00:00:00 2001 From: Benoit Duverger Date: Mon, 11 Apr 2022 15:45:27 -0400 Subject: [PATCH 113/175] chore: Pin golang to 1.17 to avoid CVEs in docker image (#1920) Signed-off-by: Benoit Duverger --- .github/workflows/release.yaml | 2 +- Dockerfile | 4 ++-- Dockerfile.dev | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index ac5d4e06b0..991453e7a7 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -119,7 +119,7 @@ jobs: - name: Setup Golang uses: actions/setup-go@v2 with: - go-version: 1.17.6 + go-version: 1.17 - name: Generate release artifacts run: | diff --git a/Dockerfile b/Dockerfile index be21aa3fa2..c51e983cd2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ # Initial stage which pulls prepares build dependencies and CLI tooling we need for our final image # Also used as the image in CI jobs so needs all dependencies #################################################################################################### -FROM --platform=$BUILDPLATFORM golang:1.17.6 as builder +FROM --platform=$BUILDPLATFORM golang:1.17 as builder RUN apt-get update && apt-get install -y \ wget \ @@ -40,7 +40,7 @@ RUN NODE_ENV='production' yarn build #################################################################################################### # Rollout Controller Build stage which performs the actual build of argo-rollouts binaries #################################################################################################### -FROM --platform=$BUILDPLATFORM golang:1.17.6 as argo-rollouts-build +FROM --platform=$BUILDPLATFORM golang:1.17 as argo-rollouts-build WORKDIR /go/src/github.com/argoproj/argo-rollouts diff --git a/Dockerfile.dev b/Dockerfile.dev index c09858ed36..4694dda836 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,7 +1,7 @@ #################################################################################################### # argo-rollouts-dev #################################################################################################### -FROM golang:1.17.6 as builder +FROM golang:1.17 as builder RUN apt-get update && apt-get install -y \ ca-certificates && \ From a8ae46a7e6cf53fa440f51d0a55f7156c1b3703c Mon Sep 17 00:00:00 2001 From: 34FathomBelow <34fathombelow@protonmail.com> Date: Mon, 11 Apr 2022 13:01:05 -0700 Subject: [PATCH 114/175] chore: Improve image build speed #1919 (#1948) * chore: Improve image build speed #2 Signed-off-by: Justin Marquis <34fathombelow@protonmail.com> * chore: Added test-arm-image test for arm64 Signed-off-by: Justin Marquis <34fathombelow@protonmail.com> * chore: enabled buildkit for docker build commands Signed-off-by: Justin Marquis <34fathombelow@protonmail.com> * chore: support for releases and further docker optimizations Signed-off-by: Justin Marquis <34fathombelow@protonmail.com> --- .github/workflows/docker-publish.yml | 23 ++++++----------------- .github/workflows/release.yaml | 19 +++---------------- Dockerfile | 5 +++-- Makefile | 8 ++++---- hack/build-release-plugins.sh | 3 ++- 5 files changed, 18 insertions(+), 40 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 3fb8351327..a7c8e55a75 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -22,14 +22,10 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - - # - name: Cache Docker layers - # uses: actions/cache@v2 - # with: - # path: /tmp/.buildx-cache - # key: ${{ runner.os }}-buildx-${{ github.sha }} - # restore-keys: | - # ${{ runner.os }}-buildx- + with: + config-inline: | + [worker.oci] + gc = false - name: Docker meta (controller) id: controller-meta @@ -76,7 +72,8 @@ jobs: id: platform-matrix run: | PLATFORM_MATRIX=linux/amd64 - if [ ${{ github.event_name != 'pull_request' }} = true ]; then + if [[ "${{ github.event_name }}" == "push" || "${{ contains(github.event.pull_request.labels.*.name, 'test-arm-image') }}" == "true" ]] + then PLATFORM_MATRIX=$PLATFORM_MATRIX,linux/arm64 fi echo "::set-output name=platform-matrix::$PLATFORM_MATRIX" @@ -95,11 +92,3 @@ jobs: platforms: ${{ steps.platform-matrix.outputs.platform-matrix }} push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.plugin-meta.outputs.tags }} - - # Temp fix - # https://github.com/docker/build-push-action/issues/252 - # https://github.com/moby/buildkit/issues/1896 - # - name: Move cache - # run: | - # rm -rf /tmp/.buildx-cache - # mv /tmp/.buildx-cache-new /tmp/.buildx-cache diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 991453e7a7..5a2336a5f7 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -25,12 +25,10 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - - - name: Cache Docker layers - uses: actions/cache@v2 with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ steps.get-sha.outputs.sha }} + config-inline: | + [worker.oci] + gc = false - name: Print Disk Usage run: | @@ -84,8 +82,6 @@ jobs: platforms: linux/amd64,linux/arm64 push: true tags: ${{ steps.controller-meta.outputs.tags }} - cache-from: type=local,src=/tmp/.buildx-cache - cache-to: type=local,dest=/tmp/.buildx-cache - name: Build and push (plugin-image) uses: docker/build-push-action@v2 @@ -95,16 +91,7 @@ jobs: platforms: linux/amd64,linux/arm64 push: true tags: ${{ steps.plugin-meta.outputs.tags }} - cache-from: type=local,src=/tmp/.buildx-cache - cache-to: type=local,dest=/tmp/.buildx-cache-new - # Temp fix - # https://github.com/docker/build-push-action/issues/252 - # https://github.com/moby/buildkit/issues/1896 - - name: Move cache - run: | - rm -rf /tmp/.buildx-cache - mv /tmp/.buildx-cache-new /tmp/.buildx-cache release-artifacts: runs-on: ubuntu-latest diff --git a/Dockerfile b/Dockerfile index c51e983cd2..9865e51415 100644 --- a/Dockerfile +++ b/Dockerfile @@ -61,8 +61,9 @@ RUN touch ui/dist/node_modules.marker && \ touch ui/dist/app/index.html && \ find ui/dist -ARG TARGETOS TARGETARCH -ARG MAKE_TARGET="controller plugin plugin-linux plugin-darwin plugin-windows" +ARG TARGETOS +ARG TARGETARCH +ARG MAKE_TARGET="controller plugin" RUN GOOS=$TARGETOS GOARCH=$TARGETARCH make ${MAKE_TARGET} #################################################################################################### diff --git a/Makefile b/Makefile index eecbc4eb00..f9956d960e 100644 --- a/Makefile +++ b/Makefile @@ -175,22 +175,22 @@ docs: .PHONY: builder-image builder-image: - docker build -t $(IMAGE_PREFIX)argo-rollouts-ci-builder:$(IMAGE_TAG) --target builder . + DOCKER_BUILDKIT=1 docker build -t $(IMAGE_PREFIX)argo-rollouts-ci-builder:$(IMAGE_TAG) --target builder . @if [ "$(DOCKER_PUSH)" = "true" ] ; then docker push $(IMAGE_PREFIX)argo-rollouts:$(IMAGE_TAG) ; fi .PHONY: image image: ifeq ($(DEV_IMAGE), true) CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -v -i -ldflags '${LDFLAGS}' -o ${DIST_DIR}/rollouts-controller-linux-amd64 ./cmd/rollouts-controller - docker build -t $(IMAGE_PREFIX)argo-rollouts:$(IMAGE_TAG) -f Dockerfile.dev ${DIST_DIR} + DOCKER_BUILDKIT=1 docker build -t $(IMAGE_PREFIX)argo-rollouts:$(IMAGE_TAG) -f Dockerfile.dev ${DIST_DIR} else - docker build -t $(IMAGE_PREFIX)argo-rollouts:$(IMAGE_TAG) . + DOCKER_BUILDKIT=1 docker build -t $(IMAGE_PREFIX)argo-rollouts:$(IMAGE_TAG) . endif @if [ "$(DOCKER_PUSH)" = "true" ] ; then docker push $(IMAGE_PREFIX)argo-rollouts:$(IMAGE_TAG) ; fi .PHONY: plugin-image plugin-image: - docker build --target kubectl-argo-rollouts -t $(IMAGE_PREFIX)kubectl-argo-rollouts:$(IMAGE_TAG) . + DOCKER_BUILDKIT=1 docker build --target kubectl-argo-rollouts -t $(IMAGE_PREFIX)kubectl-argo-rollouts:$(IMAGE_TAG) . if [ "$(DOCKER_PUSH)" = "true" ] ; then docker push $(IMAGE_PREFIX)kubectl-argo-rollouts:$(IMAGE_TAG) ; fi .PHONY: lint diff --git a/hack/build-release-plugins.sh b/hack/build-release-plugins.sh index 25c4091dd7..00f86b7b98 100755 --- a/hack/build-release-plugins.sh +++ b/hack/build-release-plugins.sh @@ -6,7 +6,8 @@ SRCROOT="$( CDPATH='' cd -- "$(dirname "$0")/.." && pwd -P )" mkdir -p ${SRCROOT}/dist rollout_iid_file=$(mktemp -d "${SRCROOT}/dist/rollout_iid.XXXXXXXXX") -docker build --iidfile ${rollout_iid_file} --target argo-rollouts-build . +DOCKER_BUILDKIT=1 docker build --iidfile ${rollout_iid_file} --build-arg MAKE_TARGET="plugin-linux plugin-darwin plugin-windows" \ +--target argo-rollouts-build . rollout_iid=$(cat ${rollout_iid_file}) container_id=$(docker create ${rollout_iid}) From 5d257f78e0a8f47ee25e511482a14ef486c6ff41 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Mon, 11 Apr 2022 13:19:46 -0700 Subject: [PATCH 115/175] chore(doc): Clarify doc for Rollout.spec.progressDeadlineAbort Signed-off-by: Vladimir Ivanov --- docs/features/specification.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/features/specification.md b/docs/features/specification.md index 5a4d23394b..c61f8d4446 100644 --- a/docs/features/specification.md +++ b/docs/features/specification.md @@ -60,8 +60,7 @@ spec: # Defaults to 600s progressDeadlineSeconds: 600 - # Whether to abort the update when ProgressDeadlineSeconds - # is exceeded if analysis or experiment is not used. + # Whether to abort the update when ProgressDeadlineSeconds is exceeded. # Optional and default is false. progressDeadlineAbort: false From b50a222e1fd27b78d70b3b2eb2a0f474a73d16cc Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Mon, 11 Apr 2022 14:07:37 -0700 Subject: [PATCH 116/175] chore(doc): Sync doc and code comments for the progressDeadlineAbort param Signed-off-by: Vladimir Ivanov --- pkg/apiclient/rollout/rollout.swagger.json | 2 +- pkg/apis/rollouts/v1alpha1/generated.proto | 2 +- pkg/apis/rollouts/v1alpha1/openapi_generated.go | 2 +- pkg/apis/rollouts/v1alpha1/types.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/apiclient/rollout/rollout.swagger.json b/pkg/apiclient/rollout/rollout.swagger.json index 10d5eb02d0..7d676a6626 100644 --- a/pkg/apiclient/rollout/rollout.swagger.json +++ b/pkg/apiclient/rollout/rollout.swagger.json @@ -1352,7 +1352,7 @@ }, "progressDeadlineAbort": { "type": "boolean", - "title": "ProgressDeadlineAbort is whether to abort the update when ProgressDeadlineSeconds\nis exceeded if analysis is not used. Default is false.\n+optional" + "title": "ProgressDeadlineAbort is whether to abort the update when ProgressDeadlineSeconds\nis exceeded.\n+optional" }, "restartAt": { "$ref": "#/definitions/k8s.io.apimachinery.pkg.apis.meta.v1.Time", diff --git a/pkg/apis/rollouts/v1alpha1/generated.proto b/pkg/apis/rollouts/v1alpha1/generated.proto index b388a99398..d7b97c4ab4 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.proto +++ b/pkg/apis/rollouts/v1alpha1/generated.proto @@ -1250,7 +1250,7 @@ message RolloutSpec { optional int32 progressDeadlineSeconds = 8; // ProgressDeadlineAbort is whether to abort the update when ProgressDeadlineSeconds - // is exceeded if analysis is not used. Default is false. + // is exceeded. // +optional optional bool progressDeadlineAbort = 12; diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index 1e32f065f5..b16dbe5ec1 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -3819,7 +3819,7 @@ func schema_pkg_apis_rollouts_v1alpha1_RolloutSpec(ref common.ReferenceCallback) }, "progressDeadlineAbort": { SchemaProps: spec.SchemaProps{ - Description: "ProgressDeadlineAbort is whether to abort the update when ProgressDeadlineSeconds is exceeded if analysis is not used. Default is false.", + Description: "ProgressDeadlineAbort is whether to abort the update when ProgressDeadlineSeconds is exceeded.", Type: []string{"boolean"}, Format: "", }, diff --git a/pkg/apis/rollouts/v1alpha1/types.go b/pkg/apis/rollouts/v1alpha1/types.go index b86c69f0e9..fca9c33eb0 100644 --- a/pkg/apis/rollouts/v1alpha1/types.go +++ b/pkg/apis/rollouts/v1alpha1/types.go @@ -71,7 +71,7 @@ type RolloutSpec struct { // Defaults to 600s. ProgressDeadlineSeconds *int32 `json:"progressDeadlineSeconds,omitempty" protobuf:"varint,8,opt,name=progressDeadlineSeconds"` // ProgressDeadlineAbort is whether to abort the update when ProgressDeadlineSeconds - // is exceeded if analysis is not used. Default is false. + // is exceeded. // +optional ProgressDeadlineAbort bool `json:"progressDeadlineAbort,omitempty" protobuf:"varint,12,opt,name=progressDeadlineAbort"` // RestartAt indicates when all the pods of a Rollout should be restarted From 3321a89aa91352df816987aa6421a474928e33ee Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Wed, 13 Apr 2022 15:22:07 -0500 Subject: [PATCH 117/175] fix: Add pagination to FindLoadBalancerByDNSName (#1971) * fix: this close issue #1963 by adding pagination to FindLoadBalancerByDNSName This adds pagination to the FindLoadBalancerByDNSName function this should allow argo rollouts to work with any number of loadbalancers. Signed-off-by: zachaller --- go.mod | 2 +- utils/aws/aws.go | 21 ++++++++++++++------- utils/defaults/defaults.go | 2 ++ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 0ac3bf0f6d..ce8e3e1388 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/antonmedv/expr v1.9.0 github.com/argoproj/notifications-engine v0.3.1-0.20220129012210-32519f8f68ec github.com/argoproj/pkg v0.9.0 + github.com/aws/aws-sdk-go-v2 v1.13.0 github.com/aws/aws-sdk-go-v2/config v1.13.1 github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.15.0 github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.16.0 @@ -66,7 +67,6 @@ require ( github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60 // indirect - github.com/aws/aws-sdk-go-v2 v1.13.0 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.8.0 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.10.0 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.4 // indirect diff --git a/utils/aws/aws.go b/utils/aws/aws.go index eba35e4f48..501e17b3ac 100644 --- a/utils/aws/aws.go +++ b/utils/aws/aws.go @@ -6,6 +6,8 @@ import ( "fmt" "strings" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/argoproj/argo-rollouts/utils/defaults" "github.com/aws/aws-sdk-go-v2/config" elbv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" @@ -128,13 +130,18 @@ func FakeNewClientFunc(elbClient ELBv2APIClient) func() (Client, error) { } func (c *ClientAdapter) FindLoadBalancerByDNSName(ctx context.Context, dnsName string) (*elbv2types.LoadBalancer, error) { - lbOutput, err := c.ELBV2.DescribeLoadBalancers(ctx, &elbv2.DescribeLoadBalancersInput{}) - if err != nil { - return nil, err - } - for _, lb := range lbOutput.LoadBalancers { - if lb.DNSName != nil && *lb.DNSName == dnsName { - return &lb, nil + paginator := elbv2.NewDescribeLoadBalancersPaginator(c.ELBV2, &elbv2.DescribeLoadBalancersInput{ + PageSize: aws.Int32(defaults.DefaultAwsLoadBalancerPageSize), + }) + for paginator.HasMorePages() { + output, err := paginator.NextPage(ctx) + if err != nil { + return nil, err + } + for _, lb := range output.LoadBalancers { + if lb.DNSName != nil && *lb.DNSName == dnsName { + return &lb, nil + } } } return nil, nil diff --git a/utils/defaults/defaults.go b/utils/defaults/defaults.go index 8a9a000675..5570f65481 100644 --- a/utils/defaults/defaults.go +++ b/utils/defaults/defaults.go @@ -40,6 +40,8 @@ const ( DefaultQPS float32 = 40.0 // DefaultBurst is the default value for Burst for client side throttling to the K8s API server DefaultBurst int = 80 + // DefaultAwsLoadBalancerPageSize is the default page size used when calling aws to get load balancers by DNS name + DefaultAwsLoadBalancerPageSize = int32(300) ) const ( From e42b4d4b9d5a5b8f2334745aeb9b9692d09bf60c Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Wed, 20 Apr 2022 19:34:04 -0500 Subject: [PATCH 118/175] fix: Change behavior of rollout to not check for availability during rollout and fix flakey e2e tests (#1957) This change make it so that we do not care about available pods in the stable replicaset while checking for step completness during canary rollout instead we only care that the controller has the desired replica count set for the stable release ignoring availability. Signed-off-by: zachaller --- Makefile | 1 + test/e2e/functional_test.go | 10 +-- test/fixtures/e2e_suite.go | 4 +- utils/replicaset/canary.go | 6 +- utils/replicaset/canary_test.go | 124 ++++++++++++++++++++++++++++++++ 5 files changed, 138 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index f9956d960e..5b67005c74 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,7 @@ DEV_IMAGE=false E2E_INSTANCE_ID ?= argo-rollouts-e2e E2E_TEST_OPTIONS ?= E2E_PARALLEL ?= 4 +E2E_WAIT_TIMEOUT ?= 90 override LDFLAGS += \ -X ${PACKAGE}/utils/version.version=${VERSION} \ diff --git a/test/e2e/functional_test.go b/test/e2e/functional_test.go index 277a19c7f9..f4380c3562 100644 --- a/test/e2e/functional_test.go +++ b/test/e2e/functional_test.go @@ -644,7 +644,8 @@ spec: maxUnavailable: 0 steps: - setWeight: 50 - - pause: {} + - pause: + duration: 5s selector: matchLabels: app: bad2good-setweight @@ -671,10 +672,10 @@ spec: containers: - name: bad2good-setweight command: null`). - WaitForRolloutStatus("Progressing"). - WaitForRolloutStatus("Degraded"). + WaitForRolloutStatus("Healthy"). Then(). - ExpectCanaryStablePodCount(2, 2) + ExpectRevisionPodCount("2", 4). + ExpectRevisionPodCount("1", 0) } // TestBlueGreenUpdate @@ -757,6 +758,7 @@ spec: - pause: {} `). WaitForRolloutStatus("Paused"). + WaitForRolloutAvailableReplicas(2). Then(). ExpectReplicaCounts(2, 2, 1, 2, 2). // desired, current, updated, ready, available ExpectServiceSelector("bluegreen-to-canary", map[string]string{"app": "bluegreen-to-canary"}, false) diff --git a/test/fixtures/e2e_suite.go b/test/fixtures/e2e_suite.go index 0b4267c9db..fdac7fcd3f 100644 --- a/test/fixtures/e2e_suite.go +++ b/test/fixtures/e2e_suite.go @@ -36,7 +36,7 @@ import ( const ( // E2E_INSTANCE_ID is the instance id label attached to objects created by the e2e tests EnvVarE2EInstanceID = "E2E_INSTANCE_ID" - // E2E_WAIT_TIMEOUT is a timeout in seconds when waiting for a test condition (default: 60) + // E2E_WAIT_TIMEOUT is a timeout in seconds when waiting for a test condition (default: 90) EnvVarE2EWaitTimeout = "E2E_WAIT_TIMEOUT" // E2E_POD_DELAY slows down pod startup and shutdown by the value in seconds (default: 0) // Used humans slow down rollout activity during a test @@ -52,7 +52,7 @@ const ( ) var ( - E2EWaitTimeout time.Duration = time.Second * 60 + E2EWaitTimeout time.Duration = time.Second * 90 E2EPodDelay = 0 E2EALBIngressAnnotations map[string]string diff --git a/utils/replicaset/canary.go b/utils/replicaset/canary.go index 157d90f916..88e78f86c6 100644 --- a/utils/replicaset/canary.go +++ b/utils/replicaset/canary.go @@ -21,6 +21,10 @@ func allDesiredAreAvailable(rs *appsv1.ReplicaSet, desired int32) bool { return rs != nil && desired == *rs.Spec.Replicas && desired == rs.Status.AvailableReplicas } +func allDesiredAreCreated(rs *appsv1.ReplicaSet, desired int32) bool { + return rs != nil && desired == *rs.Spec.Replicas && desired == rs.Status.Replicas +} + func AtDesiredReplicaCountsForCanary(ro *v1alpha1.Rollout, newRS, stableRS *appsv1.ReplicaSet, olderRSs []*appsv1.ReplicaSet, weights *v1alpha1.TrafficWeights) bool { var desiredNewRSReplicaCount, desiredStableRSReplicaCount int32 if ro.Spec.Strategy.Canary.TrafficRouting == nil { @@ -32,7 +36,7 @@ func AtDesiredReplicaCountsForCanary(ro *v1alpha1.Rollout, newRS, stableRS *apps return false } if ro.Spec.Strategy.Canary.TrafficRouting == nil || !ro.Spec.Strategy.Canary.DynamicStableScale { - if !allDesiredAreAvailable(stableRS, desiredStableRSReplicaCount) { + if !allDesiredAreCreated(stableRS, desiredStableRSReplicaCount) { // only check stable RS if we are not using dynamic stable scaling return false } diff --git a/utils/replicaset/canary_test.go b/utils/replicaset/canary_test.go index 66631fe9f3..b341bb06e6 100644 --- a/utils/replicaset/canary_test.go +++ b/utils/replicaset/canary_test.go @@ -1014,6 +1014,130 @@ func TestGetCurrentSetWeight(t *testing.T) { } +func TestAtDesiredReplicaCountsForCanary(t *testing.T) { + + t.Run("we are at desired replica counts and availability", func(t *testing.T) { + rollout := newRollout(4, 50, intstr.FromInt(1), intstr.FromInt(1), "current", "stable", &v1alpha1.SetCanaryScale{ + Weight: pointer.Int32Ptr(2), + Replicas: pointer.Int32Ptr(2), + MatchTrafficWeight: false, + }, nil) + + newReplicaSet := newRS("", 2, 2) + newReplicaSet.Name = "newRS" + newReplicaSet.Status.Replicas = 2 + + stableReplicaSet := newRS("", 2, 2) + stableReplicaSet.Name = "stableRS" + stableReplicaSet.Status.Replicas = 2 + + atDesiredReplicaCounts := AtDesiredReplicaCountsForCanary(rollout, newReplicaSet, stableReplicaSet, nil, &v1alpha1.TrafficWeights{ + Canary: v1alpha1.WeightDestination{ + Weight: 50, + }, + Stable: v1alpha1.WeightDestination{ + Weight: 50, + }, + }) + assert.Equal(t, true, atDesiredReplicaCounts) + }) + + t.Run("new replicaset is not at desired counts or availability", func(t *testing.T) { + rollout := newRollout(4, 50, intstr.FromInt(1), intstr.FromInt(1), "current", "stable", &v1alpha1.SetCanaryScale{ + Weight: pointer.Int32Ptr(2), + Replicas: pointer.Int32Ptr(2), + MatchTrafficWeight: false, + }, nil) + + newReplicaSet := newRS("", 2, 1) + newReplicaSet.Name = "newRS" + newReplicaSet.Status.Replicas = 2 + + stableReplicaSet := newRS("", 2, 2) + stableReplicaSet.Name = "stableRS" + stableReplicaSet.Status.Replicas = 2 + + atDesiredReplicaCounts := AtDesiredReplicaCountsForCanary(rollout, newReplicaSet, stableReplicaSet, nil, &v1alpha1.TrafficWeights{ + Canary: v1alpha1.WeightDestination{ + Weight: 50, + }, + Stable: v1alpha1.WeightDestination{ + Weight: 50, + }, + }) + assert.Equal(t, false, atDesiredReplicaCounts) + }) + + t.Run("stable replicaset is not at desired counts or availability", func(t *testing.T) { + rollout := newRollout(4, 75, intstr.FromInt(1), intstr.FromInt(1), "current", "stable", &v1alpha1.SetCanaryScale{}, nil) + newReplicaSet := newRS("", 3, 3) + newReplicaSet.Name = "newRS" + newReplicaSet.Status.Replicas = 3 + + stableReplicaSet := newRS("", 2, 2) + stableReplicaSet.Name = "stableRS" + stableReplicaSet.Status.Replicas = 2 + + atDesiredReplicaCounts := AtDesiredReplicaCountsForCanary(rollout, newReplicaSet, stableReplicaSet, nil, &v1alpha1.TrafficWeights{ + Canary: v1alpha1.WeightDestination{ + Weight: 75, + }, + Stable: v1alpha1.WeightDestination{ + Weight: 25, + }, + }) + assert.Equal(t, false, atDesiredReplicaCounts) + }) + + t.Run("stable replicaset is not at desired availability but is at correct count", func(t *testing.T) { + // This test returns true because for stable replicasets we only check the count of the pods but not availability + rollout := newRollout(4, 75, intstr.FromInt(1), intstr.FromInt(1), "current", "stable", &v1alpha1.SetCanaryScale{}, nil) + newReplicaSet := newRS("", 3, 3) + newReplicaSet.Name = "newRS" + newReplicaSet.Status.Replicas = 1 + + stableReplicaSet := newRS("", 1, 0) + stableReplicaSet.Name = "stableRS" + stableReplicaSet.Status.Replicas = 1 + + atDesiredReplicaCounts := AtDesiredReplicaCountsForCanary(rollout, newReplicaSet, stableReplicaSet, nil, &v1alpha1.TrafficWeights{ + Canary: v1alpha1.WeightDestination{ + Weight: 75, + }, + Stable: v1alpha1.WeightDestination{ + Weight: 25, + }, + }) + assert.Equal(t, true, atDesiredReplicaCounts) + }) + + t.Run("test that when status field lags behind spec.replicas we fail", func(t *testing.T) { + rollout := newRollout(4, 50, intstr.FromInt(1), intstr.FromInt(1), "current", "stable", &v1alpha1.SetCanaryScale{ + Weight: pointer.Int32Ptr(2), + Replicas: pointer.Int32Ptr(2), + MatchTrafficWeight: false, + }, nil) + + newReplicaSet := newRS("", 2, 2) + newReplicaSet.Name = "newRS" + newReplicaSet.Status.Replicas = 2 + + stableReplicaSet := newRS("", 2, 2) + stableReplicaSet.Name = "stableRS" + stableReplicaSet.Status.Replicas = 3 + + atDesiredReplicaCounts := AtDesiredReplicaCountsForCanary(rollout, newReplicaSet, stableReplicaSet, nil, &v1alpha1.TrafficWeights{ + Canary: v1alpha1.WeightDestination{ + Weight: 50, + }, + Stable: v1alpha1.WeightDestination{ + Weight: 50, + }, + }) + assert.Equal(t, false, atDesiredReplicaCounts) + }) +} + func TestGetCurrentExperiment(t *testing.T) { rollout := &v1alpha1.Rollout{ Spec: v1alpha1.RolloutSpec{ From f91e3ba067581f11e7f3aab2f3906c76a2f84fc1 Mon Sep 17 00:00:00 2001 From: RaviHari Date: Thu, 28 Apr 2022 12:22:28 +0530 Subject: [PATCH 119/175] feat: Allow prometheus server address to be centrally configured (#1956) Signed-off-by: Ravi Hari --- analysis/analysis.go | 8 +- metricproviders/prometheus/prometheus.go | 35 ++++++- metricproviders/prometheus/prometheus_test.go | 99 ++++++++++++++++++- 3 files changed, 133 insertions(+), 9 deletions(-) diff --git a/analysis/analysis.go b/analysis/analysis.go index 1ebee1ec2c..5bae4a8892 100644 --- a/analysis/analysis.go +++ b/analysis/analysis.go @@ -316,7 +316,7 @@ func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTa for _, task := range tasks { wg.Add(1) - go func(t metricTask) { + go func(t metricTask) error { defer wg.Done() //redact secret values from logs logger := logutil.WithRedactor(*logutil.WithAnalysisRun(run).WithField("metric", t.metric.Name), secrets) @@ -326,6 +326,10 @@ func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTa resultsLock.Unlock() provider, err := c.newProvider(*logger, t.metric) + if err != nil { + log.Errorf("Error in getting provider :%v", err) + return err + } if metricResult == nil { metricResult = &v1alpha1.MetricResult{ Name: t.metric.Name, @@ -404,7 +408,7 @@ func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTa resultsLock.Lock() analysisutil.SetResult(run, *metricResult) resultsLock.Unlock() - + return nil }(task) } wg.Wait() diff --git a/metricproviders/prometheus/prometheus.go b/metricproviders/prometheus/prometheus.go index 6646086eec..2dadaf8aa2 100644 --- a/metricproviders/prometheus/prometheus.go +++ b/metricproviders/prometheus/prometheus.go @@ -2,7 +2,10 @@ package prometheus import ( "context" + "errors" "fmt" + "net/url" + "os" "time" "github.com/prometheus/client_golang/api" @@ -21,7 +24,8 @@ const ( ProviderType = "Prometheus" // ResolvedPrometheusQuery is used as the key for storing the resolved prometheus query in the metrics result // metadata object. - ResolvedPrometheusQuery = "ResolvedPrometheusQuery" + ResolvedPrometheusQuery = "ResolvedPrometheusQuery" + EnvVarArgoRolloutsPrometheusAddress = "ARGO_ROLLOUTS_PROMETHEUS_ADDRESS" ) // Provider contains all the required components to run a prometheus query @@ -140,12 +144,39 @@ func NewPrometheusProvider(api v1.API, logCtx log.Entry) *Provider { // NewPrometheusAPI generates a prometheus API from the metric configuration func NewPrometheusAPI(metric v1alpha1.Metric) (v1.API, error) { + envValuesByKey := make(map[string]string) + if value, ok := os.LookupEnv(fmt.Sprintf("%s", EnvVarArgoRolloutsPrometheusAddress)); ok { + envValuesByKey[EnvVarArgoRolloutsPrometheusAddress] = value + log.Debugf("ARGO_ROLLOUTS_PROMETHEUS_ADDRESS: %v", envValuesByKey[EnvVarArgoRolloutsPrometheusAddress]) + } + if len(metric.Provider.Prometheus.Address) != 0 { + if !IsUrl(metric.Provider.Prometheus.Address) { + return nil, errors.New("prometheus address is not is url format") + } + } else if envValuesByKey[EnvVarArgoRolloutsPrometheusAddress] != "" { + if IsUrl(envValuesByKey[EnvVarArgoRolloutsPrometheusAddress]) { + metric.Provider.Prometheus.Address = envValuesByKey[EnvVarArgoRolloutsPrometheusAddress] + } else { + return nil, errors.New("prometheus address is not is url format") + } + } else { + return nil, errors.New("prometheus address is not configured") + } client, err := api.NewClient(api.Config{ Address: metric.Provider.Prometheus.Address, }) if err != nil { + log.Errorf("Error in getting prometheus client: %v", err) return nil, err } - return v1.NewAPI(client), nil } + +func IsUrl(str string) bool { + u, err := url.Parse(str) + if err != nil { + log.Errorf("Error in parsing url: %v", err) + } + log.Debugf("Parsed url: %v", u) + return err == nil && u.Scheme != "" && u.Host != "" +} diff --git a/metricproviders/prometheus/prometheus_test.go b/metricproviders/prometheus/prometheus_test.go index 4268fd92c2..d62f080bcd 100644 --- a/metricproviders/prometheus/prometheus_test.go +++ b/metricproviders/prometheus/prometheus_test.go @@ -3,16 +3,15 @@ package prometheus import ( "fmt" "math" + "os" "testing" + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" v1 "github.com/prometheus/client_golang/api/prometheus/v1" - "github.com/prometheus/common/model" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" ) func newScalar(f float64) model.Value { @@ -58,6 +57,31 @@ func TestRunSuccessfully(t *testing.T) { assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, measurement.Phase) } +func TestRunSuccessfullyWithEnv(t *testing.T) { + e := log.Entry{} + mock := mockAPI{ + value: newScalar(10), + } + address := "http://127.0.0.1:9090" + os.Setenv(EnvVarArgoRolloutsPrometheusAddress, address) + p := NewPrometheusProvider(mock, e) + metric := v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result == 10", + FailureCondition: "result != 10", + Provider: v1alpha1.MetricProvider{ + Prometheus: &v1alpha1.PrometheusMetric{ + Query: "test", + }, + }, + } + measurement := p.Run(newAnalysisRun(), metric) + assert.NotNil(t, measurement.StartedAt) + assert.Equal(t, "10", measurement.Value) + assert.NotNil(t, measurement.FinishedAt) + assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, measurement.Phase) +} + func TestRunSuccessfullyWithWarning(t *testing.T) { e := log.NewEntry(log.New()) mock := mockAPI{ @@ -83,6 +107,31 @@ func TestRunSuccessfullyWithWarning(t *testing.T) { assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, measurement.Phase) } +func TestRunSuccessfullyWithWarningWithEnv(t *testing.T) { + e := log.NewEntry(log.New()) + mock := mockAPI{ + value: newScalar(10), + warnings: v1.Warnings([]string{"warning", "warning2"}), + } + p := NewPrometheusProvider(mock, *e) + metric := v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result == 10", + FailureCondition: "result != 10", + Provider: v1alpha1.MetricProvider{ + Prometheus: &v1alpha1.PrometheusMetric{ + Query: "test", + }, + }, + } + measurement := p.Run(newAnalysisRun(), metric) + assert.NotNil(t, measurement.StartedAt) + assert.Equal(t, "10", measurement.Value) + assert.NotNil(t, measurement.FinishedAt) + assert.Equal(t, `"warning", "warning2"`, measurement.Metadata["warnings"]) + assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, measurement.Phase) +} + func TestRunWithQueryError(t *testing.T) { e := log.NewEntry(log.New()) expectedErr := fmt.Errorf("bad big bug :(") @@ -362,17 +411,57 @@ func TestProcessInvalidResponse(t *testing.T) { } func TestNewPrometheusAPI(t *testing.T) { + os.Unsetenv(EnvVarArgoRolloutsPrometheusAddress) + address := ":invalid::url" metric := v1alpha1.Metric{ Provider: v1alpha1.MetricProvider{ Prometheus: &v1alpha1.PrometheusMetric{ - Address: ":invalid::url", + Address: address, }, }, } - _, err := NewPrometheusAPI(metric) + api, err := NewPrometheusAPI(metric) assert.NotNil(t, err) + log.Infof("api:%v", api) metric.Provider.Prometheus.Address = "https://www.example.com" _, err = NewPrometheusAPI(metric) assert.Nil(t, err) } + +func TestNewPrometheusAPIWithEnv(t *testing.T) { + os.Unsetenv(EnvVarArgoRolloutsPrometheusAddress) + os.Setenv(EnvVarArgoRolloutsPrometheusAddress, ":invalid::url") + address := "" + metric := v1alpha1.Metric{ + Provider: v1alpha1.MetricProvider{ + Prometheus: &v1alpha1.PrometheusMetric{ + Address: address, + }, + }, + } + api, err := NewPrometheusAPI(metric) + assert.NotNil(t, err) + log.Infof("api:%v", api) + + os.Unsetenv(EnvVarArgoRolloutsPrometheusAddress) + os.Setenv(EnvVarArgoRolloutsPrometheusAddress, "https://www.example.com") + _, err = NewPrometheusAPI(metric) + assert.Nil(t, err) +} + +func TestNewPrometheusAddressNotConfigured(t *testing.T) { + os.Unsetenv(EnvVarArgoRolloutsPrometheusAddress) + os.Setenv(EnvVarArgoRolloutsPrometheusAddress, "") + address := "" + metric := v1alpha1.Metric{ + Provider: v1alpha1.MetricProvider{ + Prometheus: &v1alpha1.PrometheusMetric{ + Address: address, + }, + }, + } + api, err := NewPrometheusAPI(metric) + assert.NotNil(t, err) + log.Infof("api:%v", api) +} From b115ea844a76862ab525e22591628edbaf283c13 Mon Sep 17 00:00:00 2001 From: Philipp Plotnikov Date: Fri, 29 Apr 2022 23:11:11 +0500 Subject: [PATCH 120/175] feat: Traefik support. Fixes #516 (#1907) * Make Traefik suppurt Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Make Traefik suppurt Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Make Traefik suppurt Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Traefik support Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Traefik support Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Update traefik Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Implement traefil support Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * make codegen Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Refactor Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Add traefik tests Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Goimports Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Refactor Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Add test to trafiicrouting_test.go Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Remove added test to trafficrouting_test.go Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Refactor Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Refactor Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Generate new files Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Make codegen Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Add tests Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Add tests Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Add tests Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Add test Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Change tests Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Add mocks Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Add tests Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Add tests Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Change go.yml Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Refactor Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Back apimachinery package version Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Revert "Back apimachinery package version" This reverts commit 34c61b8cd774ccccae9644c888b13aa3cd6841d2. Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Fix Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Bump Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Refactor Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Add field doc Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Make codegen Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Removew verifyWeight and add permissions Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Back go.yml Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Back go.yml Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Change manifests Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Refactor Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Fix tests Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Add tests Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Add test Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Bump Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Add documentation Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Refactor Signed-off-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> * Refactor Signed-off-by: PhilippPlotnikov * Bump Signed-off-by: PhilippPlotnikov * Refactor Signed-off-by: PhilippPlotnikov * Bump Signed-off-by: PhilippPlotnikov * Bump Signed-off-by: PhilippPlotnikov Co-authored-by: PhilippPlotnikov <70917163+PhilippDeveloper@users.noreply.github.com> --- docs/features/traffic-management/traefik.md | 101 ++ manifests/crds/rollout-crd.yaml | 7 + manifests/install.yaml | 15 + manifests/namespace-install.yaml | 15 + manifests/role/argo-rollouts-clusterrole.yaml | 11 +- pkg/apiclient/rollout/rollout.swagger.json | 14 + pkg/apis/rollouts/v1alpha1/generated.pb.go | 1118 ++++++++++------- pkg/apis/rollouts/v1alpha1/generated.proto | 9 + .../rollouts/v1alpha1/openapi_generated.go | 31 +- pkg/apis/rollouts/v1alpha1/types.go | 8 + .../v1alpha1/zz_generated.deepcopy.go | 21 + rollout/trafficrouting.go | 9 + .../trafficrouting/traefik/mocks/traefik.go | 99 ++ rollout/trafficrouting/traefik/traefik.go | 165 +++ .../trafficrouting/traefik/traefik_test.go | 329 +++++ rollout/trafficrouting_test.go | 25 + utils/defaults/defaults.go | 2 + 17 files changed, 1524 insertions(+), 455 deletions(-) create mode 100644 docs/features/traffic-management/traefik.md create mode 100644 rollout/trafficrouting/traefik/mocks/traefik.go create mode 100644 rollout/trafficrouting/traefik/traefik.go create mode 100644 rollout/trafficrouting/traefik/traefik_test.go diff --git a/docs/features/traffic-management/traefik.md b/docs/features/traffic-management/traefik.md new file mode 100644 index 0000000000..01a4409d64 --- /dev/null +++ b/docs/features/traffic-management/traefik.md @@ -0,0 +1,101 @@ +# Traefik + +The [TraefikService](https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/#kind-traefikservice) is the object supports the ability for [weighted round robin load balancing](https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/#weighted-round-robin) and (traffic mirroring)[https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/#mirroring] when using Traefik as ingress. + +## How to integrate TraefikService with Argo Rollouts using it as weighted round robin load balancer + +Firstly, we need to create the TraefikService object using its ability for weighted round robin load balancing. + +```yaml +apiVersion: traefik.containo.us/v1alpha1 +kind: TraefikService +metadata: + name: traefik-service +spec: + weighted: + services: + - name: stable-rollout # k8s service name that you need to create for stable application version + port: 80 + - name: canary-rollout # k8s service name that you need to create for new application version + port: 80 +``` + +Notice, we don't specify the `weight` field. It is necessary to be synced with ArgoCD. If we specify this field and Argo Rollouts controller will change it, ArgoCD controller will notice it and will show that this resource is out of sync. + +Secondly, we need to create the Argo Rollouts controller. + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollouts-demo +spec: + replicas: 5 + strategy: + canary: + canaryService: canary-rollout + stableService: stable-rollout + trafficRouting: + traefik: + weightedTraefikServiceName: traefik-service # specify traefikService resource name that we have created before + steps: + - setWeight: 30 + - pause: {} + - setWeight: 40 + - pause: {duration: 10} + - setWeight: 60 + - pause: {duration: 10} + - setWeight: 80 + - pause: {duration: 10} + ... +``` + +## How to integrate TraefikService with Argo Rollouts using it as traffic mirror + +Firstly, we also need to create the TraefikService object but using its ability for traffic mirroring. + +```yaml +apiVersion: traefik.containo.us/v1alpha1 +kind: TraefikService +metadata: + name: traefik-service +spec: + mirroring: + name: some-service + port: 80 + mirrors: + - name: stable-rollout # k8s service name that you need to create for stable application version + port: 80 + - name: canary-rollout # k8s service name that you need to create for new application version + port: 80 +``` + +Notice, we don't specify the `percent` field. It is necessary to be synced with ArgoCD. If we specify this field and Argo Rollouts controller will change it, ArgoCD controller will notice it and will show that this resource is out of sync. + +Secondly, we need to create the Argo Rollouts controller. + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollouts-demo +spec: + replicas: 5 + strategy: + canary: + canaryService: canary-rollout + stableService: stable-rollout + trafficRouting: + traefik: + mirrorTraefikServiceName: traefik-service # specify traefikService resource name that we have created before + steps: + - setWeight: 30 + - pause: {} + - setWeight: 40 + - pause: {duration: 10} + - setWeight: 60 + - pause: {duration: 10} + - setWeight: 80 + - pause: {duration: 10} + ... +``` diff --git a/manifests/crds/rollout-crd.yaml b/manifests/crds/rollout-crd.yaml index 0d1fa09528..3e1f1ec350 100644 --- a/manifests/crds/rollout-crd.yaml +++ b/manifests/crds/rollout-crd.yaml @@ -753,6 +753,13 @@ spec: trafficSplitName: type: string type: object + traefik: + properties: + weightedTraefikServiceName: + type: string + required: + - weightedTraefikServiceName + type: object type: object type: object type: object diff --git a/manifests/install.yaml b/manifests/install.yaml index 9e104720ef..c24d2dbc35 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -11721,6 +11721,13 @@ spec: trafficSplitName: type: string type: object + traefik: + properties: + weightedTraefikServiceName: + type: string + required: + - weightedTraefikServiceName + type: object type: object type: object type: object @@ -14534,6 +14541,14 @@ rules: - list - update - patch +- apiGroups: + - traefik.containo.us + resources: + - traefikservices + verbs: + - watch + - get + - update --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 2e5ee32b54..5a9e72162c 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -11721,6 +11721,13 @@ spec: trafficSplitName: type: string type: object + traefik: + properties: + weightedTraefikServiceName: + type: string + required: + - weightedTraefikServiceName + type: object type: object type: object type: object @@ -14534,6 +14541,14 @@ rules: - list - update - patch +- apiGroups: + - traefik.containo.us + resources: + - traefikservices + verbs: + - watch + - get + - update --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole diff --git a/manifests/role/argo-rollouts-clusterrole.yaml b/manifests/role/argo-rollouts-clusterrole.yaml index 6176262e06..db1a97f875 100644 --- a/manifests/role/argo-rollouts-clusterrole.yaml +++ b/manifests/role/argo-rollouts-clusterrole.yaml @@ -221,6 +221,11 @@ rules: - list - update - patch - - - +- apiGroups: + - traefik.containo.us + resources: + - traefikservices + verbs: + - watch + - get + - update diff --git a/pkg/apiclient/rollout/rollout.swagger.json b/pkg/apiclient/rollout/rollout.swagger.json index 7d676a6626..031aa5ff65 100644 --- a/pkg/apiclient/rollout/rollout.swagger.json +++ b/pkg/apiclient/rollout/rollout.swagger.json @@ -1524,6 +1524,10 @@ "appMesh": { "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.AppMeshTrafficRouting", "title": "AppMesh holds specific configuration to use AppMesh to route traffic" + }, + "traefik": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.TraefikTrafficRouting", + "title": "Traefik holds specific configuration to use Traefik to route traffic" } }, "title": "RolloutTrafficRouting hosts all the different configuration for supported service meshes to enable more fine-grained traffic routing" @@ -1592,6 +1596,16 @@ }, "description": "TLSRoute holds the information on the virtual service's TLS/HTTPS routes that are desired to be matched for changing weights." }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.TraefikTrafficRouting": { + "type": "object", + "properties": { + "weightedTraefikServiceName": { + "type": "string", + "title": "TraefikServiceName refer to the name of the Traefik service used to route traffic to the service" + } + }, + "title": "TraefikTrafficRouting defines the configuration required to use Traefik as traffic router" + }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.TrafficWeights": { "type": "object", "properties": { diff --git a/pkg/apis/rollouts/v1alpha1/generated.pb.go b/pkg/apis/rollouts/v1alpha1/generated.pb.go index 72a7752573..3e023b49b7 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.pb.go +++ b/pkg/apis/rollouts/v1alpha1/generated.pb.go @@ -2546,10 +2546,38 @@ func (m *TemplateStatus) XXX_DiscardUnknown() { var xxx_messageInfo_TemplateStatus proto.InternalMessageInfo +func (m *TraefikTrafficRouting) Reset() { *m = TraefikTrafficRouting{} } +func (*TraefikTrafficRouting) ProtoMessage() {} +func (*TraefikTrafficRouting) Descriptor() ([]byte, []int) { + return fileDescriptor_e0e705f843545fab, []int{89} +} +func (m *TraefikTrafficRouting) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TraefikTrafficRouting) 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 *TraefikTrafficRouting) XXX_Merge(src proto.Message) { + xxx_messageInfo_TraefikTrafficRouting.Merge(m, src) +} +func (m *TraefikTrafficRouting) XXX_Size() int { + return m.Size() +} +func (m *TraefikTrafficRouting) XXX_DiscardUnknown() { + xxx_messageInfo_TraefikTrafficRouting.DiscardUnknown(m) +} + +var xxx_messageInfo_TraefikTrafficRouting proto.InternalMessageInfo + func (m *TrafficWeights) Reset() { *m = TrafficWeights{} } func (*TrafficWeights) ProtoMessage() {} func (*TrafficWeights) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{89} + return fileDescriptor_e0e705f843545fab, []int{90} } func (m *TrafficWeights) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2577,7 +2605,7 @@ var xxx_messageInfo_TrafficWeights proto.InternalMessageInfo func (m *ValueFrom) Reset() { *m = ValueFrom{} } func (*ValueFrom) ProtoMessage() {} func (*ValueFrom) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{90} + return fileDescriptor_e0e705f843545fab, []int{91} } func (m *ValueFrom) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2605,7 +2633,7 @@ var xxx_messageInfo_ValueFrom proto.InternalMessageInfo func (m *WavefrontMetric) Reset() { *m = WavefrontMetric{} } func (*WavefrontMetric) ProtoMessage() {} func (*WavefrontMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{91} + return fileDescriptor_e0e705f843545fab, []int{92} } func (m *WavefrontMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2633,7 +2661,7 @@ var xxx_messageInfo_WavefrontMetric proto.InternalMessageInfo func (m *WebMetric) Reset() { *m = WebMetric{} } func (*WebMetric) ProtoMessage() {} func (*WebMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{92} + return fileDescriptor_e0e705f843545fab, []int{93} } func (m *WebMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2661,7 +2689,7 @@ var xxx_messageInfo_WebMetric proto.InternalMessageInfo func (m *WebMetricHeader) Reset() { *m = WebMetricHeader{} } func (*WebMetricHeader) ProtoMessage() {} func (*WebMetricHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{93} + return fileDescriptor_e0e705f843545fab, []int{94} } func (m *WebMetricHeader) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2689,7 +2717,7 @@ var xxx_messageInfo_WebMetricHeader proto.InternalMessageInfo func (m *WeightDestination) Reset() { *m = WeightDestination{} } func (*WeightDestination) ProtoMessage() {} func (*WeightDestination) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{94} + return fileDescriptor_e0e705f843545fab, []int{95} } func (m *WeightDestination) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2809,6 +2837,7 @@ func init() { proto.RegisterType((*TemplateService)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.TemplateService") proto.RegisterType((*TemplateSpec)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.TemplateSpec") proto.RegisterType((*TemplateStatus)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.TemplateStatus") + proto.RegisterType((*TraefikTrafficRouting)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.TraefikTrafficRouting") proto.RegisterType((*TrafficWeights)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.TrafficWeights") proto.RegisterType((*ValueFrom)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ValueFrom") proto.RegisterType((*WavefrontMetric)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.WavefrontMetric") @@ -2822,452 +2851,455 @@ func init() { } var fileDescriptor_e0e705f843545fab = []byte{ - // 7118 bytes of a gzipped FileDescriptorProto + // 7167 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x5d, 0x8c, 0x24, 0xd7, - 0x55, 0xb0, 0xab, 0x7b, 0x7a, 0xa6, 0xfb, 0xcc, 0xff, 0xdd, 0xd9, 0xec, 0x78, 0xed, 0xdd, 0x76, - 0xca, 0x91, 0x3f, 0xe7, 0xfb, 0x92, 0xd9, 0xc4, 0x3f, 0x1f, 0x4e, 0x1c, 0x19, 0xba, 0x67, 0x76, - 0xbd, 0xb3, 0x9e, 0x99, 0x9d, 0xbd, 0x3d, 0xbb, 0x9b, 0x38, 0x71, 0x48, 0x4d, 0xf7, 0x9d, 0x9e, - 0xda, 0xed, 0xae, 0xea, 0x54, 0x55, 0xcf, 0xee, 0x38, 0x56, 0x62, 0x13, 0xd9, 0x04, 0x94, 0x28, - 0x86, 0x24, 0x42, 0x08, 0x05, 0x45, 0x28, 0x12, 0x88, 0xe4, 0x01, 0x45, 0x20, 0x5e, 0x22, 0x81, - 0x48, 0x22, 0xc2, 0x03, 0x28, 0x20, 0x20, 0x09, 0x22, 0x0d, 0x9e, 0xf0, 0x02, 0x02, 0x21, 0xa4, - 0x20, 0x94, 0x7d, 0x42, 0xf7, 0xb7, 0x6e, 0xfd, 0xf4, 0x6c, 0xf7, 0x74, 0xcd, 0xc6, 0x82, 0xbc, - 0x75, 0xdf, 0x73, 0xee, 0x39, 0xf7, 0xf7, 0x9c, 0x73, 0xcf, 0x3d, 0xf7, 0x14, 0xac, 0x35, 0xed, - 0x60, 0xb7, 0xbb, 0xbd, 0x54, 0x77, 0xdb, 0xe7, 0x2c, 0xaf, 0xe9, 0x76, 0x3c, 0xf7, 0x06, 0xfb, - 0xf1, 0x4e, 0xcf, 0x6d, 0xb5, 0xdc, 0x6e, 0xe0, 0x9f, 0xeb, 0xdc, 0x6c, 0x9e, 0xb3, 0x3a, 0xb6, - 0x7f, 0x4e, 0x95, 0xec, 0xbd, 0xdb, 0x6a, 0x75, 0x76, 0xad, 0x77, 0x9f, 0x6b, 0x12, 0x87, 0x78, - 0x56, 0x40, 0x1a, 0x4b, 0x1d, 0xcf, 0x0d, 0x5c, 0xf4, 0xbe, 0x90, 0xda, 0x92, 0xa4, 0xc6, 0x7e, - 0xfc, 0xbc, 0xac, 0xbb, 0xd4, 0xb9, 0xd9, 0x5c, 0xa2, 0xd4, 0x96, 0x54, 0x89, 0xa4, 0x76, 0xfa, - 0x9d, 0x5a, 0x5b, 0x9a, 0x6e, 0xd3, 0x3d, 0xc7, 0x88, 0x6e, 0x77, 0x77, 0xd8, 0x3f, 0xf6, 0x87, - 0xfd, 0xe2, 0xcc, 0x4e, 0x3f, 0x7c, 0xf3, 0x29, 0x7f, 0xc9, 0x76, 0x69, 0xdb, 0xce, 0x6d, 0x5b, - 0x41, 0x7d, 0xf7, 0xdc, 0x5e, 0xa2, 0x45, 0xa7, 0x4d, 0x0d, 0xa9, 0xee, 0x7a, 0x24, 0x0d, 0xe7, - 0x89, 0x10, 0xa7, 0x6d, 0xd5, 0x77, 0x6d, 0x87, 0x78, 0xfb, 0x61, 0xaf, 0xdb, 0x24, 0xb0, 0xd2, - 0x6a, 0x9d, 0xeb, 0x57, 0xcb, 0xeb, 0x3a, 0x81, 0xdd, 0x26, 0x89, 0x0a, 0xff, 0xff, 0x6e, 0x15, - 0xfc, 0xfa, 0x2e, 0x69, 0x5b, 0x89, 0x7a, 0x8f, 0xf7, 0xab, 0xd7, 0x0d, 0xec, 0xd6, 0x39, 0xdb, - 0x09, 0xfc, 0xc0, 0x8b, 0x57, 0x32, 0xbf, 0x99, 0x87, 0x52, 0x65, 0xad, 0x5a, 0x0b, 0xac, 0xa0, - 0xeb, 0xa3, 0xd7, 0x0c, 0x98, 0x6a, 0xb9, 0x56, 0xa3, 0x6a, 0xb5, 0x2c, 0xa7, 0x4e, 0xbc, 0x45, - 0xe3, 0x21, 0xe3, 0xd1, 0xc9, 0xc7, 0xd6, 0x96, 0x46, 0x99, 0xaf, 0xa5, 0xca, 0x2d, 0x1f, 0x13, - 0xdf, 0xed, 0x7a, 0x75, 0x82, 0xc9, 0x4e, 0x75, 0xe1, 0xdb, 0xbd, 0xf2, 0x7d, 0x07, 0xbd, 0xf2, - 0xd4, 0x9a, 0xc6, 0x09, 0x47, 0xf8, 0xa2, 0x2f, 0x18, 0x30, 0x5f, 0xb7, 0x1c, 0xcb, 0xdb, 0xdf, - 0xb2, 0xbc, 0x26, 0x09, 0x9e, 0xf5, 0xdc, 0x6e, 0x67, 0x31, 0x77, 0x0c, 0xad, 0xb9, 0x5f, 0xb4, - 0x66, 0x7e, 0x39, 0xce, 0x0e, 0x27, 0x5b, 0xc0, 0xda, 0xe5, 0x07, 0xd6, 0x76, 0x8b, 0xe8, 0xed, - 0xca, 0x1f, 0x67, 0xbb, 0x6a, 0x71, 0x76, 0x38, 0xd9, 0x02, 0xf3, 0xd5, 0x3c, 0xcc, 0x57, 0xd6, - 0xaa, 0x5b, 0x9e, 0xb5, 0xb3, 0x63, 0xd7, 0xb1, 0xdb, 0x0d, 0x6c, 0xa7, 0x89, 0xde, 0x0e, 0x13, - 0xb6, 0xd3, 0xf4, 0x88, 0xef, 0xb3, 0x89, 0x2c, 0x55, 0x67, 0x05, 0xd1, 0x89, 0x55, 0x5e, 0x8c, - 0x25, 0x1c, 0x3d, 0x09, 0x93, 0x3e, 0xf1, 0xf6, 0xec, 0x3a, 0xd9, 0x74, 0xbd, 0x80, 0x8d, 0x74, - 0xa1, 0x7a, 0x42, 0xa0, 0x4f, 0xd6, 0x42, 0x10, 0xd6, 0xf1, 0x68, 0x35, 0xcf, 0x75, 0x03, 0x01, - 0x67, 0x03, 0x51, 0x0a, 0xab, 0xe1, 0x10, 0x84, 0x75, 0x3c, 0xf4, 0xba, 0x01, 0x73, 0x7e, 0x60, - 0xd7, 0x6f, 0xda, 0x0e, 0xf1, 0xfd, 0x65, 0xd7, 0xd9, 0xb1, 0x9b, 0x8b, 0x05, 0x36, 0x8a, 0x1b, - 0xa3, 0x8d, 0x62, 0x2d, 0x46, 0xb5, 0xba, 0x70, 0xd0, 0x2b, 0xcf, 0xc5, 0x4b, 0x71, 0x82, 0x3b, - 0x5a, 0x81, 0x39, 0xcb, 0x71, 0xdc, 0xc0, 0x0a, 0x6c, 0xd7, 0xd9, 0xf4, 0xc8, 0x8e, 0x7d, 0x7b, - 0x71, 0x8c, 0x75, 0x67, 0x51, 0x74, 0x67, 0xae, 0x12, 0x83, 0xe3, 0x44, 0x0d, 0x73, 0x05, 0x16, - 0x2b, 0xed, 0x6d, 0xcb, 0xf7, 0xad, 0x86, 0xeb, 0xc5, 0x66, 0xe3, 0x51, 0x28, 0xb6, 0xad, 0x4e, - 0xc7, 0x76, 0x9a, 0x74, 0x3a, 0xf2, 0x8f, 0x96, 0xaa, 0x53, 0x07, 0xbd, 0x72, 0x71, 0x5d, 0x94, - 0x61, 0x05, 0x35, 0xbf, 0x9f, 0x83, 0xc9, 0x8a, 0x63, 0xb5, 0xf6, 0x7d, 0xdb, 0xc7, 0x5d, 0x07, - 0x7d, 0x04, 0x8a, 0x54, 0xba, 0x34, 0xac, 0xc0, 0x12, 0x3b, 0xf2, 0x5d, 0x4b, 0x7c, 0xb3, 0x2f, - 0xe9, 0x9b, 0x3d, 0x1c, 0x17, 0x8a, 0xbd, 0xb4, 0xf7, 0xee, 0xa5, 0xcb, 0xdb, 0x37, 0x48, 0x3d, - 0x58, 0x27, 0x81, 0x55, 0x45, 0xa2, 0x17, 0x10, 0x96, 0x61, 0x45, 0x15, 0xb9, 0x30, 0xe6, 0x77, - 0x48, 0x5d, 0xec, 0xb0, 0xf5, 0x11, 0x57, 0x72, 0xd8, 0xf4, 0x5a, 0x87, 0xd4, 0xab, 0x53, 0x82, - 0xf5, 0x18, 0xfd, 0x87, 0x19, 0x23, 0x74, 0x0b, 0xc6, 0x7d, 0x26, 0x73, 0xc4, 0xe6, 0xb9, 0x9c, - 0x1d, 0x4b, 0x46, 0xb6, 0x3a, 0x23, 0x98, 0x8e, 0xf3, 0xff, 0x58, 0xb0, 0x33, 0xff, 0xce, 0x80, - 0x13, 0x1a, 0x76, 0xc5, 0x6b, 0x76, 0xdb, 0xc4, 0x09, 0xd0, 0x43, 0x30, 0xe6, 0x58, 0x6d, 0x22, - 0x36, 0x8a, 0x6a, 0xf2, 0x86, 0xd5, 0x26, 0x98, 0x41, 0xd0, 0xc3, 0x50, 0xd8, 0xb3, 0x5a, 0x5d, - 0xc2, 0x06, 0xa9, 0x54, 0x9d, 0x16, 0x28, 0x85, 0x6b, 0xb4, 0x10, 0x73, 0x18, 0x7a, 0x09, 0x4a, - 0xec, 0xc7, 0x05, 0xcf, 0x6d, 0x67, 0xd4, 0x35, 0xd1, 0xc2, 0x6b, 0x92, 0x6c, 0x75, 0xfa, 0xa0, - 0x57, 0x2e, 0xa9, 0xbf, 0x38, 0x64, 0x68, 0xfe, 0x83, 0x01, 0xb3, 0x5a, 0xe7, 0xd6, 0x6c, 0x3f, - 0x40, 0x1f, 0x4a, 0x2c, 0x9e, 0xa5, 0xc1, 0x16, 0x0f, 0xad, 0xcd, 0x96, 0xce, 0x9c, 0xe8, 0x69, - 0x51, 0x96, 0x68, 0x0b, 0xc7, 0x81, 0x82, 0x1d, 0x90, 0xb6, 0xbf, 0x98, 0x7b, 0x28, 0xff, 0xe8, - 0xe4, 0x63, 0xab, 0x99, 0x4d, 0x63, 0x38, 0xbe, 0xab, 0x94, 0x3e, 0xe6, 0x6c, 0xcc, 0xaf, 0x8d, - 0x45, 0x7a, 0x48, 0x57, 0x14, 0x72, 0x61, 0xa2, 0x4d, 0x02, 0xcf, 0xae, 0xf3, 0x7d, 0x35, 0xf9, - 0xd8, 0xca, 0x68, 0xad, 0x58, 0x67, 0xc4, 0x42, 0x61, 0xc9, 0xff, 0xfb, 0x58, 0x72, 0x41, 0xbb, - 0x30, 0x66, 0x79, 0x4d, 0xd9, 0xe7, 0x0b, 0xd9, 0xcc, 0x6f, 0xb8, 0xe6, 0x2a, 0x5e, 0xd3, 0xc7, - 0x8c, 0x03, 0x3a, 0x07, 0xa5, 0x80, 0x78, 0x6d, 0xdb, 0xb1, 0x02, 0x2e, 0x5d, 0x8b, 0xd5, 0x79, - 0x81, 0x56, 0xda, 0x92, 0x00, 0x1c, 0xe2, 0xa0, 0x16, 0x8c, 0x37, 0xbc, 0x7d, 0xdc, 0x75, 0x16, - 0xc7, 0xb2, 0x18, 0x8a, 0x15, 0x46, 0x2b, 0xdc, 0x4c, 0xfc, 0x3f, 0x16, 0x3c, 0xd0, 0x97, 0x0d, - 0x58, 0x68, 0x13, 0xcb, 0xef, 0x7a, 0x84, 0x76, 0x01, 0x93, 0x80, 0x38, 0x54, 0x1a, 0x2e, 0x16, - 0x18, 0x73, 0x3c, 0xea, 0x3c, 0x24, 0x29, 0x57, 0x1f, 0x14, 0x4d, 0x59, 0x48, 0x83, 0xe2, 0xd4, - 0xd6, 0x98, 0xdf, 0x1f, 0x83, 0xf9, 0x84, 0x84, 0x40, 0x4f, 0x40, 0xa1, 0xb3, 0x6b, 0xf9, 0x72, - 0xcb, 0x9f, 0x95, 0xeb, 0x6d, 0x93, 0x16, 0xde, 0xe9, 0x95, 0xa7, 0x65, 0x15, 0x56, 0x80, 0x39, - 0x32, 0xd5, 0xa9, 0x6d, 0xe2, 0xfb, 0x56, 0x53, 0xca, 0x01, 0x6d, 0x99, 0xb0, 0x62, 0x2c, 0xe1, - 0xe8, 0x17, 0x0d, 0x98, 0xe6, 0x4b, 0x06, 0x13, 0xbf, 0xdb, 0x0a, 0xa8, 0xac, 0xa3, 0xc3, 0x72, - 0x29, 0x8b, 0xe5, 0xc9, 0x49, 0x56, 0x4f, 0x0a, 0xee, 0xd3, 0x7a, 0xa9, 0x8f, 0xa3, 0x7c, 0xd1, - 0x75, 0x28, 0xf9, 0x81, 0xe5, 0x05, 0xa4, 0x51, 0x09, 0x98, 0x56, 0x9b, 0x7c, 0xec, 0xff, 0x0e, - 0x26, 0x04, 0xb6, 0xec, 0x36, 0xe1, 0x02, 0xa7, 0x26, 0x09, 0xe0, 0x90, 0x16, 0x7a, 0x09, 0xc0, - 0xeb, 0x3a, 0xb5, 0x6e, 0xbb, 0x6d, 0x79, 0xfb, 0x42, 0x83, 0x5f, 0x1c, 0xad, 0x7b, 0x58, 0xd1, - 0x0b, 0x75, 0x56, 0x58, 0x86, 0x35, 0x7e, 0xe8, 0x15, 0x03, 0xa6, 0xf9, 0x4a, 0x94, 0x2d, 0x18, - 0xcf, 0xb8, 0x05, 0xf3, 0x74, 0x68, 0x57, 0x74, 0x16, 0x38, 0xca, 0xd1, 0xfc, 0x9b, 0xa8, 0x3e, - 0xa9, 0x05, 0xd4, 0xba, 0x6e, 0xee, 0xa3, 0x0f, 0xc2, 0xfd, 0x7e, 0xb7, 0x5e, 0x27, 0xbe, 0xbf, - 0xd3, 0x6d, 0xe1, 0xae, 0x73, 0xd1, 0xf6, 0x03, 0xd7, 0xdb, 0x5f, 0xb3, 0xdb, 0x76, 0xc0, 0x56, - 0x5c, 0xa1, 0x7a, 0xe6, 0xa0, 0x57, 0xbe, 0xbf, 0xd6, 0x0f, 0x09, 0xf7, 0xaf, 0x8f, 0x2c, 0x78, - 0xa0, 0xeb, 0xf4, 0x27, 0xcf, 0xad, 0xb7, 0xf2, 0x41, 0xaf, 0xfc, 0xc0, 0xd5, 0xfe, 0x68, 0xf8, - 0x30, 0x1a, 0xe6, 0xbf, 0x18, 0x30, 0x27, 0xfb, 0xb5, 0x45, 0xda, 0x9d, 0x16, 0x95, 0x2e, 0xc7, - 0x6f, 0x88, 0x04, 0x11, 0x43, 0x04, 0x67, 0xa3, 0x4e, 0x64, 0xfb, 0xfb, 0x59, 0x23, 0xe6, 0x3f, - 0x1b, 0xb0, 0x10, 0x47, 0xbe, 0x07, 0xca, 0xd3, 0x8f, 0x2a, 0xcf, 0x8d, 0x6c, 0x7b, 0xdb, 0x47, - 0x83, 0xbe, 0x36, 0x96, 0xec, 0xeb, 0xff, 0x74, 0x35, 0x1a, 0x6a, 0xc5, 0xfc, 0x4f, 0x52, 0x2b, - 0x8e, 0xbd, 0xa9, 0xb4, 0xe2, 0xef, 0x8c, 0xc1, 0x54, 0xc5, 0x09, 0xec, 0xca, 0xce, 0x8e, 0xed, - 0xd8, 0xc1, 0x3e, 0xfa, 0x74, 0x0e, 0xce, 0x75, 0x3c, 0xb2, 0x43, 0x3c, 0x8f, 0x34, 0x56, 0xba, - 0x9e, 0xed, 0x34, 0x6b, 0xf5, 0x5d, 0xd2, 0xe8, 0xb6, 0x6c, 0xa7, 0xb9, 0xda, 0x74, 0x5c, 0x55, - 0x7c, 0xfe, 0x36, 0xa9, 0x77, 0x59, 0x97, 0xf8, 0xa6, 0x68, 0x8f, 0xd6, 0xa5, 0xcd, 0xe1, 0x98, - 0x56, 0x1f, 0x3f, 0xe8, 0x95, 0xcf, 0x0d, 0x59, 0x09, 0x0f, 0xdb, 0x35, 0xf4, 0xa9, 0x1c, 0x2c, - 0x79, 0xe4, 0xa3, 0x5d, 0x7b, 0xf0, 0xd1, 0xe0, 0x52, 0xab, 0x35, 0xa2, 0xfa, 0x19, 0x8a, 0x67, - 0xf5, 0xb1, 0x83, 0x5e, 0x79, 0xc8, 0x3a, 0x78, 0xc8, 0x7e, 0x99, 0xdf, 0xc8, 0xc1, 0xc9, 0x4a, - 0xa7, 0xb3, 0x4e, 0xfc, 0xdd, 0xd8, 0xa1, 0xf6, 0xb3, 0x06, 0xcc, 0xec, 0xd9, 0x5e, 0xd0, 0xb5, - 0x5a, 0xd2, 0x09, 0xc0, 0x97, 0x44, 0x6d, 0xc4, 0xed, 0xcc, 0xb9, 0x5d, 0x8b, 0x90, 0xae, 0xa2, - 0x83, 0x5e, 0x79, 0x26, 0x5a, 0x86, 0x63, 0xec, 0xd1, 0xaf, 0x19, 0x30, 0x27, 0x8a, 0x36, 0xdc, - 0x06, 0xd1, 0x3d, 0x47, 0x57, 0xb3, 0x6c, 0x93, 0x22, 0xce, 0x5d, 0x0c, 0xf1, 0x52, 0x9c, 0x68, - 0x84, 0xf9, 0x6f, 0x39, 0x38, 0xd5, 0x87, 0x06, 0xfa, 0x6d, 0x03, 0x16, 0xb8, 0xbb, 0x49, 0x03, - 0x61, 0xb2, 0x23, 0x46, 0xf3, 0x03, 0x59, 0xb7, 0x1c, 0xd3, 0xbd, 0x40, 0x9c, 0x3a, 0xa9, 0x2e, - 0x52, 0xb1, 0xb1, 0x9c, 0xc2, 0x1a, 0xa7, 0x36, 0x88, 0xb5, 0x94, 0x3b, 0xa0, 0x62, 0x2d, 0xcd, - 0xdd, 0x93, 0x96, 0xd6, 0x52, 0x58, 0xe3, 0xd4, 0x06, 0x99, 0x3f, 0x0b, 0x0f, 0x1c, 0x42, 0xee, - 0xee, 0x27, 0x7e, 0xf3, 0x05, 0xb5, 0xea, 0xa3, 0x6b, 0x6e, 0x00, 0x67, 0x81, 0x09, 0xe3, 0x9e, - 0xdb, 0x0d, 0x08, 0xd7, 0x6e, 0xa5, 0x2a, 0x50, 0x3d, 0x81, 0x59, 0x09, 0x16, 0x10, 0xf3, 0x1b, - 0x06, 0x14, 0x87, 0xf0, 0x3f, 0x94, 0xa3, 0xfe, 0x87, 0x52, 0xc2, 0xf7, 0x10, 0x24, 0x7d, 0x0f, - 0xcf, 0x8e, 0x36, 0x1b, 0x83, 0xf8, 0x1c, 0xfe, 0xdd, 0x80, 0xf9, 0x84, 0x8f, 0x02, 0xed, 0xc2, - 0x42, 0xc7, 0x6d, 0x48, 0xfb, 0xe2, 0xa2, 0xe5, 0xef, 0x32, 0x98, 0xe8, 0xde, 0x13, 0x74, 0x26, - 0x37, 0x53, 0xe0, 0x77, 0x7a, 0xe5, 0x45, 0x45, 0x24, 0x86, 0x80, 0x53, 0x29, 0xa2, 0x0e, 0x14, - 0x77, 0x6c, 0xd2, 0x6a, 0x84, 0x4b, 0x70, 0x44, 0x4b, 0xe2, 0x82, 0xa0, 0xc6, 0xdd, 0x73, 0xf2, - 0x1f, 0x56, 0x5c, 0xcc, 0x2b, 0x30, 0x13, 0x75, 0xd6, 0x0e, 0x30, 0x79, 0x67, 0x20, 0x6f, 0x79, - 0x8e, 0x98, 0xba, 0x49, 0x81, 0x90, 0xaf, 0xe0, 0x0d, 0x4c, 0xcb, 0xcd, 0x1f, 0x8f, 0xc1, 0x6c, - 0xb5, 0xd5, 0x25, 0xcf, 0x7a, 0x84, 0xc8, 0xf3, 0x69, 0x05, 0x66, 0x3b, 0x1e, 0xd9, 0xb3, 0xc9, - 0xad, 0x1a, 0x69, 0x91, 0x7a, 0xe0, 0x7a, 0x82, 0xfe, 0x29, 0x51, 0x7d, 0x76, 0x33, 0x0a, 0xc6, - 0x71, 0x7c, 0xf4, 0x0c, 0xcc, 0x58, 0xf5, 0xc0, 0xde, 0x23, 0x8a, 0x02, 0x6f, 0xc0, 0x5b, 0x04, - 0x85, 0x99, 0x4a, 0x04, 0x8a, 0x63, 0xd8, 0xe8, 0x43, 0xb0, 0xe8, 0xd7, 0xad, 0x16, 0xb9, 0xda, - 0x11, 0xac, 0x96, 0x77, 0x49, 0xfd, 0xe6, 0xa6, 0x6b, 0x3b, 0x81, 0xf0, 0x46, 0x3c, 0x24, 0x28, - 0x2d, 0xd6, 0xfa, 0xe0, 0xe1, 0xbe, 0x14, 0xd0, 0x1f, 0x19, 0x70, 0xa6, 0xe3, 0x91, 0x4d, 0xcf, - 0x6d, 0xbb, 0x54, 0xcd, 0x24, 0x8e, 0xe8, 0xe2, 0xa8, 0x7a, 0x6d, 0x44, 0x7d, 0xca, 0x4b, 0x92, - 0x2e, 0xc2, 0xb7, 0x1e, 0xf4, 0xca, 0x67, 0x36, 0x0f, 0x6b, 0x00, 0x3e, 0xbc, 0x7d, 0xe8, 0x4f, - 0x0c, 0x38, 0xdb, 0x71, 0xfd, 0xe0, 0x90, 0x2e, 0x14, 0x8e, 0xb5, 0x0b, 0xe6, 0x41, 0xaf, 0x7c, - 0x76, 0xf3, 0xd0, 0x16, 0xe0, 0xbb, 0xb4, 0xd0, 0x3c, 0x98, 0x84, 0x79, 0x6d, 0xed, 0x89, 0xf3, - 0xeb, 0xd3, 0x30, 0x2d, 0x17, 0x43, 0xa8, 0xd6, 0x4b, 0xa1, 0xbf, 0xa1, 0xa2, 0x03, 0x71, 0x14, - 0x97, 0xae, 0x3b, 0xb5, 0x14, 0x79, 0xed, 0xd8, 0xba, 0xdb, 0x8c, 0x40, 0x71, 0x0c, 0x1b, 0xad, - 0xc2, 0x09, 0x51, 0x82, 0x49, 0xa7, 0x65, 0xd7, 0xad, 0x65, 0xb7, 0x2b, 0x96, 0x5c, 0xa1, 0x7a, - 0xea, 0xa0, 0x57, 0x3e, 0xb1, 0x99, 0x04, 0xe3, 0xb4, 0x3a, 0x68, 0x0d, 0x16, 0xac, 0x6e, 0xe0, - 0xaa, 0xfe, 0x9f, 0x77, 0xa8, 0xa6, 0x68, 0xb0, 0xa5, 0x55, 0xe4, 0x2a, 0xa5, 0x92, 0x02, 0xc7, - 0xa9, 0xb5, 0xd0, 0x66, 0x8c, 0x5a, 0x8d, 0xd4, 0x5d, 0xa7, 0xc1, 0x67, 0xb9, 0x10, 0x5a, 0xe1, - 0x95, 0x14, 0x1c, 0x9c, 0x5a, 0x13, 0xb5, 0x60, 0xa6, 0x6d, 0xdd, 0xbe, 0xea, 0x58, 0x7b, 0x96, - 0xdd, 0xa2, 0x4c, 0x84, 0x0f, 0xa3, 0xff, 0xc1, 0xba, 0x1b, 0xd8, 0xad, 0x25, 0x7e, 0x9d, 0xb7, - 0xb4, 0xea, 0x04, 0x97, 0xbd, 0x5a, 0x40, 0xad, 0x35, 0x6e, 0x1c, 0xad, 0x47, 0x68, 0xe1, 0x18, - 0x6d, 0x74, 0x19, 0x4e, 0xb2, 0xed, 0xb8, 0xe2, 0xde, 0x72, 0x56, 0x48, 0xcb, 0xda, 0x97, 0x1d, - 0x98, 0x60, 0x1d, 0xb8, 0xff, 0xa0, 0x57, 0x3e, 0x59, 0x4b, 0x43, 0xc0, 0xe9, 0xf5, 0x90, 0x05, - 0x0f, 0x44, 0x01, 0x98, 0xec, 0xd9, 0xbe, 0xed, 0x3a, 0xdc, 0x13, 0x51, 0x0c, 0x3d, 0x11, 0xb5, - 0xfe, 0x68, 0xf8, 0x30, 0x1a, 0xe8, 0x37, 0x0c, 0x58, 0x48, 0xdb, 0x86, 0x8b, 0xa5, 0x2c, 0x2e, - 0x2b, 0x62, 0x5b, 0x8b, 0xaf, 0x88, 0x54, 0xa1, 0x90, 0xda, 0x08, 0xf4, 0xb2, 0x01, 0x53, 0x96, - 0x76, 0x8a, 0x5a, 0x04, 0xd6, 0xaa, 0x4b, 0xa3, 0x9e, 0xe5, 0x43, 0x8a, 0xd5, 0xb9, 0x83, 0x5e, - 0x39, 0x72, 0x52, 0xc3, 0x11, 0x8e, 0xe8, 0x37, 0x0d, 0x38, 0x99, 0xba, 0xc7, 0x17, 0x27, 0x8f, - 0x63, 0x84, 0xd8, 0x22, 0x49, 0x97, 0x39, 0xe9, 0xcd, 0x40, 0xaf, 0x1b, 0x4a, 0x95, 0xad, 0x4b, - 0x6f, 0xca, 0x14, 0x6b, 0xda, 0x95, 0x11, 0x0f, 0x8e, 0xa1, 0x41, 0x20, 0x09, 0x57, 0x4f, 0x68, - 0x9a, 0x51, 0x16, 0xe2, 0x38, 0x7b, 0xf4, 0x19, 0x43, 0xaa, 0x46, 0xd5, 0xa2, 0xe9, 0xe3, 0x6a, - 0x11, 0x0a, 0x35, 0xad, 0x6a, 0x50, 0x8c, 0x39, 0xfa, 0x30, 0x9c, 0xb6, 0xb6, 0x5d, 0x2f, 0x48, - 0xdd, 0x7c, 0x8b, 0x33, 0x6c, 0x1b, 0x9d, 0x3d, 0xe8, 0x95, 0x4f, 0x57, 0xfa, 0x62, 0xe1, 0x43, - 0x28, 0x98, 0x5f, 0x2d, 0xc0, 0x14, 0x37, 0xf2, 0x85, 0xea, 0xfa, 0xba, 0x01, 0x0f, 0xd6, 0xbb, - 0x9e, 0x47, 0x9c, 0xa0, 0x16, 0x90, 0x4e, 0x52, 0x71, 0x19, 0xc7, 0xaa, 0xb8, 0x1e, 0x3a, 0xe8, - 0x95, 0x1f, 0x5c, 0x3e, 0x84, 0x3f, 0x3e, 0xb4, 0x75, 0xe8, 0x2f, 0x0c, 0x30, 0x05, 0x42, 0xd5, - 0xaa, 0xdf, 0x6c, 0x7a, 0x6e, 0xd7, 0x69, 0x24, 0x3b, 0x91, 0x3b, 0xd6, 0x4e, 0x3c, 0x72, 0xd0, - 0x2b, 0x9b, 0xcb, 0x77, 0x6d, 0x05, 0x1e, 0xa0, 0xa5, 0xe8, 0x59, 0x98, 0x17, 0x58, 0xe7, 0x6f, - 0x77, 0x88, 0x67, 0x53, 0x73, 0x5a, 0xdc, 0xa7, 0x87, 0x21, 0x0a, 0x71, 0x04, 0x9c, 0xac, 0x83, - 0x7c, 0x98, 0xb8, 0x45, 0xec, 0xe6, 0x6e, 0x20, 0xcd, 0xa7, 0x11, 0xe3, 0x12, 0xc4, 0x81, 0xff, - 0x3a, 0xa7, 0x59, 0x9d, 0x3c, 0xe8, 0x95, 0x27, 0xc4, 0x1f, 0x2c, 0x39, 0xa1, 0x0d, 0x98, 0xe1, - 0x47, 0xb0, 0x4d, 0xdb, 0x69, 0x6e, 0xba, 0x0e, 0xbf, 0xcd, 0x2f, 0x55, 0x1f, 0x91, 0x0a, 0xbf, - 0x16, 0x81, 0xde, 0xe9, 0x95, 0xa7, 0xe4, 0xef, 0xad, 0xfd, 0x0e, 0xc1, 0xb1, 0xda, 0xe6, 0xef, - 0x8d, 0x01, 0xc8, 0xe5, 0x4a, 0x3a, 0xe8, 0xff, 0x41, 0xc9, 0x27, 0x01, 0xe7, 0x2a, 0x9c, 0xe7, - 0xfc, 0x4e, 0x42, 0x16, 0xe2, 0x10, 0x8e, 0x6e, 0x42, 0xa1, 0x63, 0x75, 0x7d, 0x22, 0x26, 0xff, - 0x52, 0x26, 0x93, 0xbf, 0x49, 0x29, 0xf2, 0x33, 0x17, 0xfb, 0x89, 0x39, 0x0f, 0xf4, 0x49, 0x03, - 0x80, 0x44, 0x27, 0x6c, 0x64, 0xdf, 0x87, 0x60, 0x19, 0xce, 0x29, 0x1d, 0x83, 0xea, 0xcc, 0x41, - 0xaf, 0x0c, 0xda, 0xd4, 0x6b, 0x6c, 0xd1, 0x2d, 0x28, 0x5a, 0x52, 0xe6, 0x8f, 0x1d, 0x87, 0xcc, - 0x67, 0x47, 0x21, 0xb5, 0x68, 0x15, 0x33, 0xf4, 0x29, 0x03, 0x66, 0x7c, 0x12, 0x88, 0xa9, 0xa2, - 0x92, 0x47, 0x18, 0xbc, 0x23, 0x2e, 0xba, 0x5a, 0x84, 0x26, 0x97, 0xa0, 0xd1, 0x32, 0x1c, 0xe3, - 0x6b, 0xfe, 0xd5, 0x14, 0xcc, 0xc8, 0x25, 0x13, 0xda, 0xb0, 0xdc, 0x85, 0xd1, 0xc7, 0x86, 0x5d, - 0xd6, 0x81, 0x38, 0x8a, 0x4b, 0x2b, 0xf3, 0x45, 0x19, 0x35, 0x61, 0x55, 0xe5, 0x9a, 0x0e, 0xc4, - 0x51, 0x5c, 0xd4, 0x86, 0x82, 0x1f, 0x90, 0x8e, 0xbc, 0xf1, 0x1b, 0xf1, 0x42, 0x2a, 0xdc, 0x09, - 0xa1, 0x4f, 0x9f, 0xfe, 0xf3, 0x31, 0xe7, 0xc2, 0xbc, 0x70, 0x41, 0xc4, 0x31, 0x27, 0x96, 0x41, - 0x36, 0x2b, 0x31, 0xea, 0xf3, 0xe3, 0xb3, 0x11, 0x2d, 0xc3, 0x31, 0xf6, 0x29, 0x66, 0x6d, 0xe1, - 0x18, 0xcd, 0xda, 0xe7, 0xa1, 0xd8, 0xb6, 0x6e, 0xd7, 0xba, 0x5e, 0xf3, 0xe8, 0xe6, 0xb3, 0x08, - 0xc6, 0xe1, 0x54, 0xb0, 0xa2, 0x87, 0x5e, 0x31, 0xb4, 0xcd, 0x35, 0xc1, 0x88, 0x5f, 0xcf, 0x76, - 0x73, 0x29, 0xad, 0xd0, 0x77, 0x9b, 0x25, 0x8c, 0xcc, 0xe2, 0x3d, 0x37, 0x32, 0xa9, 0xc1, 0xc4, - 0x37, 0x88, 0x32, 0x98, 0x4a, 0xc7, 0x6a, 0x30, 0x2d, 0x47, 0x98, 0xe1, 0x18, 0x73, 0xd6, 0x1e, - 0xbe, 0xe7, 0x54, 0x7b, 0xe0, 0x58, 0xdb, 0x53, 0x8b, 0x30, 0xc3, 0x31, 0xe6, 0xfd, 0x4f, 0x56, - 0x93, 0xc7, 0x73, 0xb2, 0x9a, 0xca, 0xe0, 0x64, 0x75, 0xb8, 0xd1, 0x39, 0x3d, 0xaa, 0xd1, 0x89, - 0x2e, 0x01, 0x6a, 0xec, 0x3b, 0x56, 0xdb, 0xae, 0x0b, 0x61, 0xc9, 0x14, 0xc4, 0x0c, 0x3b, 0x79, - 0x9f, 0x16, 0x82, 0x0c, 0xad, 0x24, 0x30, 0x70, 0x4a, 0x2d, 0x14, 0x40, 0xb1, 0x23, 0x6d, 0x8b, - 0xd9, 0x2c, 0x56, 0xbf, 0xb4, 0x35, 0xf8, 0xa5, 0x30, 0xdd, 0x78, 0xb2, 0x04, 0x2b, 0x4e, 0xe6, - 0x7f, 0x1a, 0x30, 0xb7, 0xdc, 0x72, 0xbb, 0x8d, 0xeb, 0x56, 0x50, 0xdf, 0xe5, 0x37, 0x98, 0xe8, - 0x19, 0x28, 0xda, 0x4e, 0x40, 0xbc, 0x3d, 0xab, 0x25, 0x34, 0x8a, 0x29, 0x2f, 0x79, 0x57, 0x45, - 0xf9, 0x9d, 0x5e, 0x79, 0x66, 0xa5, 0xeb, 0xb1, 0xd0, 0x40, 0x2e, 0x5f, 0xb0, 0xaa, 0x83, 0xbe, - 0x64, 0xc0, 0x3c, 0xbf, 0x03, 0x5d, 0xb1, 0x02, 0xeb, 0x4a, 0x97, 0x78, 0x36, 0x91, 0xb7, 0xa0, - 0x23, 0x8a, 0x96, 0x78, 0x5b, 0x25, 0x83, 0xfd, 0xd0, 0x88, 0x5c, 0x8f, 0x73, 0xc6, 0xc9, 0xc6, - 0x98, 0x9f, 0xcb, 0xc3, 0xfd, 0x7d, 0x69, 0xa1, 0xd3, 0x90, 0xb3, 0x1b, 0xa2, 0xeb, 0x20, 0xe8, - 0xe6, 0x56, 0x1b, 0x38, 0x67, 0x37, 0xd0, 0x12, 0xb3, 0x87, 0x3c, 0xe2, 0xfb, 0xf2, 0x42, 0xac, - 0xa4, 0x4c, 0x17, 0x51, 0x8a, 0x35, 0x0c, 0x54, 0x86, 0x42, 0xcb, 0xda, 0x26, 0x2d, 0x61, 0xeb, - 0x32, 0x0b, 0x6b, 0x8d, 0x16, 0x60, 0x5e, 0x8e, 0x7e, 0xc1, 0x00, 0xe0, 0x0d, 0xa4, 0x96, 0xb2, - 0xd0, 0x6b, 0x38, 0xdb, 0x61, 0xa2, 0x94, 0x79, 0x2b, 0xc3, 0xff, 0x58, 0xe3, 0x8a, 0xb6, 0x60, - 0x9c, 0x1a, 0x5b, 0x6e, 0xe3, 0xc8, 0x6a, 0x8c, 0x5d, 0x00, 0x6c, 0x32, 0x1a, 0x58, 0xd0, 0xa2, - 0x63, 0xe5, 0x91, 0xa0, 0xeb, 0x39, 0x74, 0x68, 0x99, 0xe2, 0x2a, 0xf2, 0x56, 0x60, 0x55, 0x8a, - 0x35, 0x0c, 0xf3, 0x0f, 0x73, 0xb0, 0x90, 0xd6, 0x74, 0xaa, 0x1f, 0xc6, 0x79, 0x6b, 0xc5, 0xb1, - 0xed, 0xfd, 0xd9, 0x8f, 0x8f, 0xb8, 0xce, 0x57, 0x97, 0xde, 0x22, 0xe0, 0x48, 0xf0, 0x45, 0xef, - 0x57, 0x23, 0x94, 0x3b, 0xe2, 0x08, 0x29, 0xca, 0xb1, 0x51, 0x7a, 0x08, 0xc6, 0x7c, 0x3a, 0xf3, - 0xf9, 0xa8, 0x73, 0x9d, 0xcd, 0x11, 0x83, 0x50, 0x8c, 0xae, 0x63, 0x07, 0x22, 0x5e, 0x57, 0x61, - 0x5c, 0x75, 0xec, 0x00, 0x33, 0x88, 0xf9, 0x85, 0x1c, 0x9c, 0xee, 0xdf, 0x29, 0xf4, 0x05, 0x03, - 0xa0, 0x41, 0x4d, 0x69, 0xba, 0x24, 0x65, 0xf8, 0x83, 0x75, 0x5c, 0x63, 0xb8, 0x22, 0x39, 0x85, - 0xb1, 0x30, 0xaa, 0xc8, 0xc7, 0x5a, 0x43, 0xd0, 0x63, 0x72, 0xe9, 0x6f, 0x58, 0x6d, 0x69, 0x80, - 0xaa, 0x3a, 0xeb, 0x0a, 0x82, 0x35, 0x2c, 0x7a, 0x56, 0x72, 0xac, 0x36, 0xf1, 0x3b, 0x96, 0x0a, - 0xc8, 0x66, 0x67, 0xa5, 0x0d, 0x59, 0x88, 0x43, 0xb8, 0xd9, 0x82, 0x87, 0x07, 0x68, 0x67, 0x46, - 0xc1, 0xb1, 0xe6, 0x7f, 0x18, 0x70, 0x6a, 0xb9, 0xd5, 0xf5, 0x03, 0xe2, 0xfd, 0xaf, 0x09, 0x2d, - 0xfa, 0x2f, 0x03, 0x1e, 0xe8, 0xd3, 0xe7, 0x7b, 0x10, 0x61, 0xf4, 0x62, 0x34, 0xc2, 0xe8, 0xea, - 0xa8, 0x4b, 0x3a, 0xb5, 0x1f, 0x7d, 0x02, 0x8d, 0x02, 0x98, 0xa6, 0x52, 0xab, 0xe1, 0x36, 0x33, - 0xd2, 0x9b, 0x0f, 0x43, 0xe1, 0xa3, 0x54, 0xff, 0xc4, 0xd7, 0x18, 0x53, 0x4a, 0x98, 0xc3, 0xcc, - 0xf7, 0x81, 0x08, 0xc7, 0x89, 0x6d, 0x1e, 0x63, 0x90, 0xcd, 0x63, 0xfe, 0x6d, 0x0e, 0xb4, 0x33, - 0xf6, 0x3d, 0x58, 0x94, 0x4e, 0x64, 0x51, 0x8e, 0x78, 0x6a, 0xd6, 0x3c, 0x06, 0xfd, 0xe2, 0xee, - 0xf7, 0x62, 0x71, 0xf7, 0x1b, 0x99, 0x71, 0x3c, 0x3c, 0xec, 0xfe, 0xbb, 0x06, 0x3c, 0x10, 0x22, - 0x27, 0xdd, 0x5f, 0x77, 0x97, 0x30, 0x4f, 0xc2, 0xa4, 0x15, 0x56, 0x13, 0x6b, 0x40, 0x3d, 0x35, - 0xd1, 0x28, 0x62, 0x1d, 0x2f, 0x8c, 0xf2, 0xcd, 0x1f, 0x31, 0xca, 0x77, 0xec, 0xf0, 0x28, 0x5f, - 0xf3, 0x47, 0x39, 0x38, 0x93, 0xec, 0x99, 0xdc, 0x1b, 0x83, 0xdd, 0x0e, 0x3f, 0x05, 0x53, 0x81, - 0xa8, 0xa0, 0x49, 0x7a, 0xf5, 0x50, 0x6a, 0x4b, 0x83, 0xe1, 0x08, 0x26, 0xad, 0x59, 0xe7, 0xbb, - 0xb2, 0x56, 0x77, 0x3b, 0x32, 0x46, 0x5c, 0xd5, 0x5c, 0xd6, 0x60, 0x38, 0x82, 0xa9, 0xa2, 0xef, - 0xc6, 0x8e, 0x3d, 0xfa, 0xae, 0x06, 0x27, 0x65, 0xbc, 0xd1, 0x05, 0xd7, 0x5b, 0x76, 0xdb, 0x9d, - 0x16, 0x11, 0x51, 0xe2, 0xb4, 0xb1, 0x67, 0x44, 0x95, 0x93, 0x38, 0x0d, 0x09, 0xa7, 0xd7, 0x35, - 0xbf, 0x9b, 0x87, 0x13, 0xe1, 0xb0, 0x2f, 0xbb, 0x4e, 0xc3, 0x66, 0x51, 0x5b, 0x4f, 0xc3, 0x58, - 0xb0, 0xdf, 0x91, 0x83, 0xfd, 0x7f, 0x64, 0x73, 0xb6, 0xf6, 0x3b, 0x74, 0xb6, 0x4f, 0xa5, 0x54, - 0x61, 0x0e, 0x48, 0x56, 0x09, 0xad, 0xa9, 0xdd, 0xc1, 0x67, 0xe0, 0x89, 0xe8, 0x6a, 0xbe, 0xd3, - 0x2b, 0xa7, 0xbc, 0x13, 0x5c, 0x52, 0x94, 0xa2, 0x6b, 0x1e, 0xdd, 0x80, 0x99, 0x96, 0xe5, 0x07, - 0x57, 0x3b, 0x0d, 0x2b, 0x20, 0x5b, 0x76, 0x9b, 0x88, 0x3d, 0x37, 0x4c, 0xe8, 0xb5, 0xba, 0x31, - 0x5d, 0x8b, 0x50, 0xc2, 0x31, 0xca, 0x68, 0x0f, 0x10, 0x2d, 0xd9, 0xf2, 0x2c, 0xc7, 0xe7, 0xbd, - 0xa2, 0xfc, 0x86, 0x0f, 0xf5, 0x56, 0xc7, 0xb2, 0xb5, 0x04, 0x35, 0x9c, 0xc2, 0x01, 0x3d, 0x02, - 0xe3, 0x1e, 0xb1, 0x7c, 0x31, 0x99, 0xa5, 0x70, 0xff, 0x63, 0x56, 0x8a, 0x05, 0x54, 0xdf, 0x50, - 0xe3, 0x77, 0xd9, 0x50, 0x3f, 0x30, 0x60, 0x26, 0x9c, 0xa6, 0x7b, 0xa0, 0x24, 0xdb, 0x51, 0x25, - 0x79, 0x31, 0x2b, 0x91, 0xd8, 0x47, 0x2f, 0xfe, 0xe9, 0xb8, 0xde, 0x3f, 0x16, 0x7a, 0xfb, 0x31, - 0x28, 0xc9, 0x5d, 0x2d, 0xad, 0xcf, 0x11, 0x4f, 0xb7, 0x11, 0xbb, 0x44, 0x7b, 0x32, 0x22, 0x98, - 0xe0, 0x90, 0x1f, 0x55, 0xcb, 0x0d, 0xa1, 0x72, 0xc5, 0xb2, 0x57, 0x6a, 0x59, 0xaa, 0xe2, 0x34, - 0xb5, 0x2c, 0xeb, 0xa0, 0xab, 0x70, 0xaa, 0xe3, 0xb9, 0xec, 0x19, 0xe1, 0x0a, 0xb1, 0x1a, 0x2d, - 0xdb, 0x21, 0xd2, 0x85, 0xc0, 0x2f, 0xec, 0x1f, 0x38, 0xe8, 0x95, 0x4f, 0x6d, 0xa6, 0xa3, 0xe0, - 0x7e, 0x75, 0xa3, 0x4f, 0x5f, 0xc6, 0x06, 0x78, 0xfa, 0xf2, 0x4b, 0xca, 0x51, 0x47, 0x7c, 0xf1, - 0x00, 0xe5, 0x83, 0x59, 0x4d, 0x65, 0x8a, 0x58, 0x0f, 0x97, 0x54, 0x45, 0x30, 0xc5, 0x8a, 0x7d, - 0x7f, 0x6f, 0xd0, 0xf8, 0x11, 0xbd, 0x41, 0x61, 0x04, 0xf3, 0xc4, 0x4f, 0x32, 0x82, 0xb9, 0xf8, - 0xa6, 0x8a, 0x60, 0x7e, 0xb5, 0x00, 0x73, 0x71, 0x0b, 0xe4, 0xf8, 0x9f, 0xf5, 0xfc, 0xaa, 0x01, - 0x73, 0x72, 0xf7, 0x70, 0x9e, 0x44, 0xfa, 0xf9, 0xd7, 0x32, 0xda, 0xb4, 0xdc, 0x96, 0x52, 0x0f, - 0x4f, 0xb7, 0x62, 0xdc, 0x70, 0x82, 0x3f, 0x7a, 0x01, 0x26, 0x95, 0x3b, 0xfc, 0x48, 0x6f, 0x7c, - 0x66, 0x99, 0x15, 0x15, 0x92, 0xc0, 0x3a, 0x3d, 0xf4, 0xaa, 0x01, 0x50, 0x97, 0x6a, 0x4e, 0xee, - 0xae, 0x2b, 0x59, 0xed, 0x2e, 0xa5, 0x40, 0x43, 0x63, 0x59, 0x15, 0xf9, 0x58, 0x63, 0x8c, 0x3e, - 0xc7, 0x1c, 0xe1, 0xca, 0xba, 0xa3, 0xfb, 0x29, 0x3f, 0x7a, 0xd0, 0xe9, 0x21, 0x86, 0x69, 0x68, - 0x4a, 0x69, 0x20, 0x1f, 0x47, 0x1a, 0x61, 0x3e, 0x0d, 0x2a, 0x4c, 0x90, 0x8a, 0x2d, 0x16, 0x28, - 0xb8, 0x69, 0x05, 0xbb, 0x62, 0x09, 0x2a, 0xb1, 0x75, 0x41, 0x02, 0x70, 0x88, 0x63, 0x7e, 0x04, - 0x66, 0x9e, 0xf5, 0xac, 0xce, 0xae, 0xcd, 0x1c, 0xce, 0xf4, 0x9c, 0xf4, 0x76, 0x98, 0xb0, 0x1a, - 0x8d, 0xb4, 0x67, 0xdb, 0x15, 0x5e, 0x8c, 0x25, 0x7c, 0xb0, 0x23, 0xd1, 0x37, 0x0d, 0x58, 0x58, - 0xf5, 0x03, 0xdb, 0x5d, 0x21, 0x7e, 0x40, 0x65, 0x25, 0xdd, 0x51, 0xdd, 0xd6, 0x20, 0x61, 0xac, - 0x2b, 0x30, 0x27, 0x6e, 0xc5, 0xba, 0xdb, 0x3e, 0x09, 0x34, 0xe3, 0x54, 0x2d, 0xce, 0xe5, 0x18, - 0x1c, 0x27, 0x6a, 0x50, 0x2a, 0xe2, 0x7a, 0x2c, 0xa4, 0x92, 0x8f, 0x52, 0xa9, 0xc5, 0xe0, 0x38, - 0x51, 0xc3, 0xfc, 0x4e, 0x1e, 0x4e, 0xb0, 0x6e, 0xc4, 0x42, 0xd0, 0x3f, 0xd3, 0x2f, 0x04, 0x7d, - 0xc4, 0xf5, 0xc9, 0x78, 0x1d, 0x21, 0x00, 0xfd, 0x57, 0x0c, 0x98, 0x6d, 0x44, 0x47, 0x3a, 0x1b, - 0x9f, 0x43, 0xda, 0x1c, 0xf2, 0x70, 0x97, 0x58, 0x21, 0x8e, 0xf3, 0x47, 0x9f, 0x37, 0x60, 0x36, - 0xda, 0x4c, 0x29, 0xb2, 0x8e, 0x61, 0x90, 0x54, 0x7c, 0x6a, 0xb4, 0xdc, 0xc7, 0xf1, 0x26, 0x98, - 0x7f, 0x6d, 0x88, 0x29, 0x3d, 0x8e, 0xf8, 0x6a, 0x74, 0x0b, 0x4a, 0x41, 0xcb, 0xe7, 0x85, 0xa2, - 0xb7, 0x23, 0x1e, 0x73, 0xb6, 0xd6, 0x6a, 0x8c, 0x9c, 0x66, 0x89, 0x88, 0x12, 0x6a, 0x51, 0x49, - 0x5e, 0xe6, 0x57, 0x0c, 0x28, 0x5d, 0x72, 0xb7, 0xc5, 0x76, 0xfe, 0x70, 0x06, 0x4e, 0x04, 0x65, - 0x6b, 0xa8, 0xfb, 0xa7, 0xd0, 0x7c, 0x7d, 0x26, 0xe2, 0x42, 0x78, 0x50, 0xa3, 0xbd, 0xc4, 0xd2, - 0x9d, 0x50, 0x52, 0x97, 0xdc, 0xed, 0xbe, 0x1e, 0xaa, 0xdf, 0x2a, 0xc0, 0xf4, 0x73, 0xd6, 0x3e, - 0x71, 0x02, 0x6b, 0x78, 0x01, 0x44, 0x4f, 0xe5, 0x1d, 0x16, 0x6e, 0xa9, 0xd9, 0x8f, 0xe1, 0xa9, - 0x3c, 0x04, 0x61, 0x1d, 0x2f, 0x94, 0x2b, 0x3c, 0xfb, 0x42, 0x9a, 0x44, 0x58, 0x8e, 0xc1, 0x71, - 0xa2, 0x06, 0xba, 0x04, 0x48, 0xbc, 0x25, 0xab, 0xd4, 0xeb, 0x6e, 0xd7, 0xe1, 0x92, 0x85, 0x1f, - 0xd8, 0xd5, 0x41, 0x66, 0x3d, 0x81, 0x81, 0x53, 0x6a, 0xa1, 0x0f, 0xc1, 0x62, 0x9d, 0x51, 0x16, - 0x66, 0xad, 0x4e, 0x91, 0x1f, 0x6d, 0x54, 0xa8, 0xf3, 0x72, 0x1f, 0x3c, 0xdc, 0x97, 0x02, 0x6d, - 0xa9, 0x1f, 0xb8, 0x9e, 0xd5, 0x24, 0x3a, 0xdd, 0xf1, 0x68, 0x4b, 0x6b, 0x09, 0x0c, 0x9c, 0x52, - 0x0b, 0x7d, 0x02, 0x4a, 0xc1, 0xae, 0x47, 0xfc, 0x5d, 0xb7, 0xd5, 0x10, 0x17, 0xd2, 0x23, 0x7a, - 0x71, 0xc4, 0xec, 0x6f, 0x49, 0xaa, 0xda, 0xf2, 0x96, 0x45, 0x38, 0xe4, 0x89, 0x3c, 0x18, 0xf7, - 0xeb, 0x6e, 0x87, 0xf8, 0xc2, 0x1c, 0xbc, 0x94, 0x09, 0x77, 0xe6, 0x95, 0xd0, 0xfc, 0x47, 0x8c, - 0x03, 0x16, 0x9c, 0xcc, 0x6f, 0xe5, 0x60, 0x4a, 0x47, 0x1c, 0x40, 0x44, 0x7c, 0xd2, 0x80, 0xa9, - 0xba, 0xeb, 0x04, 0x9e, 0xdb, 0xe2, 0xbe, 0x11, 0xbe, 0x41, 0x46, 0x4c, 0x51, 0xc0, 0x48, 0xad, - 0x90, 0xc0, 0xb2, 0x5b, 0x9a, 0x9b, 0x45, 0x63, 0x83, 0x23, 0x4c, 0xd1, 0xa7, 0x0d, 0x98, 0x0d, - 0x23, 0x75, 0x42, 0x27, 0x4d, 0xa6, 0x0d, 0x51, 0x12, 0xf7, 0x7c, 0x94, 0x13, 0x8e, 0xb3, 0x36, - 0xb7, 0x61, 0x2e, 0x3e, 0xdb, 0x74, 0x28, 0x3b, 0x96, 0xd8, 0xeb, 0xf9, 0x70, 0x28, 0x37, 0x2d, - 0xdf, 0xc7, 0x0c, 0x82, 0xde, 0x01, 0xc5, 0xb6, 0xe5, 0x35, 0x6d, 0xc7, 0x6a, 0xb1, 0x51, 0xcc, - 0x6b, 0x02, 0x49, 0x94, 0x63, 0x85, 0x61, 0xfe, 0x70, 0x0c, 0x26, 0x35, 0x2b, 0xfe, 0xf8, 0x2d, - 0xf2, 0xc8, 0xf3, 0xf6, 0x7c, 0x86, 0xcf, 0xdb, 0x9f, 0x07, 0xd8, 0xb1, 0x1d, 0xdb, 0xdf, 0x3d, - 0xe2, 0xc3, 0x79, 0x76, 0x99, 0x77, 0x41, 0x51, 0xc0, 0x1a, 0xb5, 0xf0, 0xc6, 0xa4, 0x70, 0x48, - 0x3a, 0x91, 0x57, 0x0d, 0x4d, 0x79, 0x8c, 0x67, 0x71, 0x43, 0xac, 0x4d, 0xcc, 0x92, 0x54, 0x26, - 0xe7, 0x9d, 0xc0, 0xdb, 0x3f, 0x54, 0xc7, 0x6c, 0x41, 0xd1, 0x23, 0x7e, 0xb7, 0x4d, 0xcf, 0x16, - 0x13, 0x43, 0x0f, 0x03, 0xbb, 0x5d, 0xc7, 0xa2, 0x3e, 0x56, 0x94, 0x4e, 0x3f, 0x0d, 0xd3, 0x91, - 0x26, 0xa0, 0x39, 0xc8, 0xdf, 0x24, 0xfb, 0x7c, 0x9d, 0x60, 0xfa, 0x13, 0x2d, 0x44, 0xee, 0x95, - 0xc4, 0xb0, 0xbc, 0x37, 0xf7, 0x94, 0x61, 0xba, 0x90, 0x7a, 0x54, 0x3c, 0x8a, 0xdb, 0x9f, 0xce, - 0x45, 0x4b, 0x7b, 0x39, 0xaf, 0xe6, 0x82, 0xc7, 0x50, 0x70, 0x98, 0xf9, 0xa3, 0x71, 0x10, 0x97, - 0x9e, 0x03, 0x08, 0x1f, 0xfd, 0xae, 0x23, 0x77, 0x84, 0xbb, 0x8e, 0x4b, 0x30, 0x65, 0x3b, 0x76, - 0x60, 0x5b, 0x2d, 0xe6, 0x06, 0x10, 0xca, 0x51, 0x86, 0x53, 0x4e, 0xad, 0x6a, 0xb0, 0x14, 0x3a, - 0x91, 0xba, 0xe8, 0x0a, 0x14, 0x98, 0xf6, 0x10, 0x0b, 0x78, 0xf8, 0x9b, 0x59, 0x76, 0x29, 0xcf, - 0xdf, 0x58, 0x70, 0x4a, 0xcc, 0xa2, 0xe7, 0xa9, 0x03, 0xd4, 0x41, 0x4d, 0xac, 0xe3, 0xd0, 0xa2, - 0x8f, 0xc1, 0x71, 0xa2, 0x06, 0xa5, 0xb2, 0x63, 0xd9, 0xad, 0xae, 0x47, 0x42, 0x2a, 0xe3, 0x51, - 0x2a, 0x17, 0x62, 0x70, 0x9c, 0xa8, 0x81, 0x76, 0x60, 0x4a, 0x94, 0xf1, 0xc8, 0x98, 0x89, 0x23, - 0xf6, 0x92, 0x45, 0x40, 0x5d, 0xd0, 0x28, 0xe1, 0x08, 0x5d, 0xd4, 0x85, 0x79, 0xdb, 0xa9, 0xbb, - 0x4e, 0xbd, 0xd5, 0xf5, 0xed, 0x3d, 0x12, 0x3e, 0x70, 0x38, 0x0a, 0xb3, 0x93, 0x07, 0xbd, 0xf2, - 0xfc, 0x6a, 0x9c, 0x1c, 0x4e, 0x72, 0x40, 0xaf, 0x18, 0x70, 0xb2, 0xee, 0x3a, 0x3e, 0x7b, 0x8b, - 0xbb, 0x47, 0xce, 0x7b, 0x9e, 0xeb, 0x71, 0xde, 0xa5, 0x23, 0xf2, 0x66, 0xde, 0xa7, 0xe5, 0x34, - 0x92, 0x38, 0x9d, 0x13, 0x7a, 0x11, 0x8a, 0x1d, 0xcf, 0xdd, 0xb3, 0x1b, 0xc4, 0x13, 0x51, 0x56, - 0x6b, 0x59, 0xe4, 0x06, 0xd8, 0x14, 0x34, 0x43, 0xd1, 0x23, 0x4b, 0xb0, 0xe2, 0x67, 0x7e, 0xb5, - 0x08, 0x33, 0x51, 0x74, 0xf4, 0x71, 0x80, 0x8e, 0xe7, 0xb6, 0x49, 0xb0, 0x4b, 0x54, 0xa0, 0xfa, - 0xc6, 0xa8, 0x4f, 0xd0, 0x25, 0x3d, 0x19, 0xe7, 0x40, 0xc5, 0x45, 0x58, 0x8a, 0x35, 0x8e, 0xc8, - 0x83, 0x89, 0x9b, 0x5c, 0x89, 0x0a, 0x9b, 0xe2, 0xb9, 0x4c, 0x2c, 0x20, 0xc1, 0x99, 0x45, 0x58, - 0x8b, 0x22, 0x2c, 0x19, 0xa1, 0x6d, 0xc8, 0xdf, 0x22, 0xdb, 0xd9, 0x3c, 0xeb, 0xbc, 0x4e, 0xc4, - 0xd9, 0xa4, 0x3a, 0x71, 0xd0, 0x2b, 0xe7, 0xaf, 0x93, 0x6d, 0x4c, 0x89, 0xd3, 0x7e, 0x35, 0xf8, - 0x8d, 0xad, 0x10, 0x15, 0x23, 0xf6, 0x2b, 0x72, 0xfd, 0xcb, 0xfb, 0x25, 0x8a, 0xb0, 0x64, 0x84, - 0x5e, 0x84, 0xd2, 0x2d, 0x6b, 0x8f, 0xec, 0x78, 0xae, 0x13, 0x88, 0xe0, 0x9a, 0x11, 0x63, 0x97, - 0xaf, 0x4b, 0x72, 0x82, 0x2f, 0x53, 0xef, 0xaa, 0x10, 0x87, 0xec, 0xd0, 0x1e, 0x14, 0x1d, 0x72, - 0x0b, 0x93, 0x96, 0x5d, 0x17, 0x61, 0xa3, 0x23, 0x2e, 0xeb, 0x0d, 0x41, 0x4d, 0x70, 0x66, 0x7a, - 0x4f, 0x96, 0x61, 0xc5, 0x8b, 0xce, 0xe5, 0x0d, 0x77, 0x5b, 0x08, 0xaa, 0x11, 0xe7, 0x52, 0x9d, - 0x33, 0xf9, 0x5c, 0x5e, 0x72, 0xb7, 0x31, 0x25, 0x4e, 0xf7, 0x48, 0x5d, 0x45, 0x76, 0x08, 0x31, - 0xb5, 0x91, 0x6d, 0x44, 0x0b, 0xdf, 0x23, 0x61, 0x29, 0xd6, 0x38, 0xd2, 0xb1, 0x6d, 0x0a, 0xb7, - 0x96, 0x10, 0x54, 0x23, 0x8e, 0x6d, 0xd4, 0x49, 0xc6, 0xc7, 0x56, 0x96, 0x61, 0xc5, 0xcb, 0xfc, - 0xca, 0x38, 0x4c, 0xe9, 0xb9, 0x90, 0x06, 0xd0, 0xd5, 0xca, 0x3e, 0xcd, 0x0d, 0x63, 0x9f, 0xd2, - 0xe3, 0x85, 0xe6, 0x95, 0x96, 0x1e, 0x86, 0xd5, 0xcc, 0xcc, 0xb3, 0xf0, 0x78, 0xa1, 0x15, 0xfa, - 0x38, 0xc2, 0x74, 0x88, 0x8b, 0x6a, 0x6a, 0xe4, 0x70, 0x33, 0xa0, 0x10, 0x35, 0x72, 0x22, 0x8a, - 0xfd, 0x31, 0x80, 0x30, 0x27, 0x90, 0xb8, 0xad, 0x50, 0xd6, 0x93, 0x96, 0xab, 0x48, 0xc3, 0x42, - 0x8f, 0xc0, 0x38, 0x55, 0x94, 0xa4, 0x21, 0x5e, 0x11, 0xaa, 0x33, 0xdc, 0x05, 0x56, 0x8a, 0x05, - 0x14, 0x3d, 0x45, 0x6d, 0x9a, 0x50, 0xbd, 0x89, 0xc7, 0x81, 0x0b, 0xa1, 0x4d, 0x13, 0xc2, 0x70, - 0x04, 0x93, 0x36, 0x9d, 0x50, 0x6d, 0xc4, 0x56, 0x92, 0xd6, 0x74, 0xa6, 0xa2, 0x30, 0x87, 0x31, - 0x9f, 0x42, 0x4c, 0x7b, 0x31, 0x65, 0x55, 0xd0, 0x7c, 0x0a, 0x31, 0x38, 0x4e, 0xd4, 0xa0, 0x9d, - 0x11, 0x17, 0x2d, 0x93, 0x3c, 0x1e, 0xaf, 0xcf, 0x15, 0xc9, 0x6b, 0xba, 0x65, 0x3e, 0xc5, 0xa6, - 0xfe, 0xfd, 0xd9, 0xe5, 0xf5, 0x1a, 0xdc, 0x34, 0x1f, 0xcd, 0x88, 0xfe, 0x08, 0xcc, 0x44, 0x65, - 0x16, 0x5d, 0x50, 0x1d, 0xcf, 0xdd, 0xb1, 0x5b, 0x24, 0xee, 0xfb, 0xd9, 0xe4, 0xc5, 0x58, 0xc2, - 0x07, 0x73, 0x3e, 0xff, 0x59, 0x1e, 0x4e, 0x6c, 0x34, 0x6d, 0xe7, 0x76, 0xcc, 0x6b, 0x9b, 0x96, - 0x6f, 0xd3, 0x18, 0x36, 0xdf, 0x66, 0xf8, 0x48, 0x43, 0x24, 0x34, 0x4d, 0x7f, 0xa4, 0x21, 0xb3, - 0x9d, 0x46, 0x71, 0xd1, 0x0f, 0x0c, 0x78, 0xd0, 0x6a, 0x70, 0x2b, 0xd2, 0x6a, 0x89, 0xd2, 0x90, - 0xa9, 0xdc, 0xd1, 0xfe, 0x88, 0x3a, 0x21, 0xd9, 0xf9, 0xa5, 0xca, 0x21, 0x5c, 0xf9, 0x8c, 0xbf, - 0x4d, 0xf4, 0xe0, 0xc1, 0xc3, 0x50, 0xf1, 0xa1, 0xcd, 0x3f, 0x7d, 0x19, 0xde, 0x7a, 0x57, 0x46, - 0x43, 0xad, 0x96, 0x4f, 0x1a, 0x50, 0xe2, 0x4e, 0x49, 0x4c, 0x76, 0xa8, 0xa8, 0xb0, 0x3a, 0xf6, - 0x35, 0xe2, 0xf9, 0x32, 0x11, 0x90, 0x76, 0xd0, 0xaa, 0x6c, 0xae, 0x0a, 0x08, 0xd6, 0xb0, 0xa8, - 0x30, 0xbe, 0x69, 0x3b, 0x0d, 0x31, 0x4d, 0x4a, 0x18, 0x3f, 0x67, 0x3b, 0x0d, 0xcc, 0x20, 0x4a, - 0x5c, 0xe7, 0xfb, 0x66, 0xe5, 0xf8, 0xb2, 0x01, 0x33, 0xec, 0x0d, 0x56, 0x78, 0x04, 0x78, 0x52, - 0x45, 0x21, 0xf0, 0x66, 0x9c, 0x89, 0x46, 0x21, 0xdc, 0xe9, 0x95, 0x27, 0xf9, 0xab, 0xad, 0x68, - 0x50, 0xc2, 0x07, 0x85, 0xdf, 0x80, 0xc5, 0x4a, 0xe4, 0x86, 0x3e, 0xd6, 0x2a, 0x2f, 0x59, 0x4d, - 0x12, 0xc1, 0x21, 0x3d, 0xf3, 0x25, 0x98, 0xd2, 0x43, 0xcc, 0xd1, 0x93, 0x30, 0xd9, 0xb1, 0x9d, - 0x66, 0xf4, 0x29, 0x92, 0xf2, 0x94, 0x6e, 0x86, 0x20, 0xac, 0xe3, 0xb1, 0x6a, 0x6e, 0x58, 0x2d, - 0xe6, 0x60, 0xdd, 0x74, 0xf5, 0x6a, 0xe1, 0x1f, 0xf3, 0xf7, 0xf3, 0x70, 0x22, 0xe5, 0x29, 0x03, - 0x7a, 0xd5, 0x80, 0x71, 0x16, 0x57, 0x2d, 0xe3, 0x0c, 0x5e, 0xc8, 0xfc, 0xb9, 0xc4, 0x12, 0x0b, - 0xdf, 0x16, 0xeb, 0x58, 0x89, 0x4f, 0x5e, 0x88, 0x05, 0x73, 0xf4, 0xeb, 0x06, 0x4c, 0x5a, 0xda, - 0x56, 0xe3, 0xa1, 0x17, 0xdb, 0xd9, 0x37, 0x26, 0xb1, 0xb3, 0xb4, 0x90, 0xb1, 0x70, 0x23, 0xe9, - 0x6d, 0x39, 0xfd, 0x1e, 0x98, 0xd4, 0xba, 0x30, 0xcc, 0x0e, 0x39, 0xfd, 0x0c, 0xcc, 0x8d, 0xb4, - 0xc3, 0x3e, 0x00, 0xc3, 0xe6, 0xb5, 0xa2, 0x0a, 0xeb, 0x96, 0xfe, 0x30, 0x52, 0x8d, 0xb8, 0x78, - 0x19, 0x29, 0xa0, 0xe6, 0x36, 0xcc, 0xc5, 0x0f, 0x39, 0x99, 0xdf, 0x34, 0xbe, 0x0b, 0x86, 0xcc, - 0x44, 0x65, 0xfe, 0x79, 0x0e, 0x26, 0xc4, 0x7b, 0xa8, 0x7b, 0x10, 0x6d, 0x79, 0x33, 0x72, 0x55, - 0xb2, 0x9a, 0xc9, 0x33, 0xae, 0xbe, 0xa1, 0x96, 0x7e, 0x2c, 0xd4, 0xf2, 0xb9, 0x6c, 0xd8, 0x1d, - 0x1e, 0x67, 0xf9, 0xe5, 0x31, 0x98, 0x8d, 0xbd, 0x2f, 0xa3, 0xa6, 0x4a, 0x22, 0xbc, 0xe8, 0x6a, - 0xa6, 0x4f, 0xd8, 0x54, 0x24, 0xf0, 0xe1, 0x91, 0x46, 0x7e, 0x24, 0xe1, 0xdf, 0x95, 0xcc, 0x72, - 0x05, 0xff, 0x34, 0xf7, 0xdf, 0xb0, 0x91, 0x33, 0xff, 0x64, 0xc0, 0xfd, 0x7d, 0x9f, 0x21, 0xb2, - 0x7c, 0x0d, 0x5e, 0x14, 0x2a, 0x36, 0x64, 0xc6, 0xcf, 0x8a, 0xd5, 0xbd, 0x45, 0xfc, 0x89, 0x7d, - 0x9c, 0x3d, 0x7a, 0x02, 0xa6, 0x98, 0x6a, 0xa5, 0x32, 0x25, 0x20, 0x1d, 0xe1, 0xa8, 0x65, 0x2e, - 0xbb, 0x9a, 0x56, 0x8e, 0x23, 0x58, 0xe6, 0x97, 0x0c, 0x58, 0xec, 0xf7, 0x7a, 0x7f, 0x80, 0x83, - 0xe1, 0xcf, 0xc4, 0xc2, 0x41, 0xcb, 0x89, 0x70, 0xd0, 0xd8, 0xd1, 0x50, 0x46, 0x7e, 0x6a, 0xa7, - 0xb2, 0xfc, 0x5d, 0xa2, 0x1d, 0x3f, 0x63, 0xc0, 0xa9, 0x3e, 0xbb, 0x29, 0x11, 0x16, 0x6c, 0x1c, - 0x39, 0x2c, 0x38, 0x37, 0x68, 0x58, 0xb0, 0xf9, 0x97, 0x79, 0x98, 0x13, 0xed, 0x09, 0xed, 0xab, - 0xa7, 0x22, 0x41, 0xb5, 0x6f, 0x8b, 0x05, 0xd5, 0x2e, 0xc4, 0xf1, 0x7f, 0x1a, 0x51, 0xfb, 0xe6, - 0x8a, 0xa8, 0xfd, 0x71, 0x0e, 0x4e, 0xa6, 0x26, 0x15, 0x40, 0x9f, 0x4a, 0x51, 0x0d, 0xd7, 0x33, - 0xce, 0x5e, 0x30, 0xa0, 0x72, 0x18, 0x35, 0x0c, 0xf5, 0xf3, 0x7a, 0xf8, 0x27, 0x17, 0xf5, 0x3b, - 0xc7, 0x90, 0x87, 0x61, 0xc8, 0x48, 0x50, 0xf3, 0x97, 0xf3, 0xf0, 0xe8, 0xa0, 0x84, 0xde, 0xa4, - 0x2f, 0x05, 0xfc, 0xc8, 0x4b, 0x81, 0x7b, 0xa4, 0xb6, 0x8f, 0xe5, 0xd1, 0xc0, 0x57, 0xf2, 0x4a, - 0xed, 0x25, 0xd7, 0xe7, 0x40, 0xb7, 0x7a, 0x13, 0xd4, 0xb4, 0x93, 0xa9, 0x06, 0x43, 0x51, 0x38, - 0x51, 0xe3, 0xc5, 0x77, 0x7a, 0xe5, 0x79, 0x91, 0x7e, 0xac, 0x46, 0x02, 0x51, 0x88, 0x65, 0x25, - 0xf4, 0x28, 0x14, 0x3d, 0x0e, 0x95, 0xb1, 0xd1, 0xe2, 0x6a, 0x94, 0x97, 0x61, 0x05, 0x45, 0x9f, - 0xd0, 0x6c, 0xe1, 0xb1, 0xe3, 0x7a, 0xd7, 0x7e, 0xd8, 0x8d, 0xef, 0x0b, 0x50, 0xf4, 0x65, 0xd2, - 0x40, 0xee, 0x96, 0x7f, 0x7c, 0xc0, 0x90, 0x7b, 0x7a, 0x74, 0x92, 0x19, 0x04, 0x79, 0xff, 0x54, - 0x7e, 0x41, 0x45, 0x12, 0x99, 0xea, 0xd4, 0xc2, 0x7d, 0x8c, 0x90, 0x72, 0x62, 0xf9, 0xae, 0x01, - 0x93, 0x62, 0xb6, 0xee, 0xc1, 0x2b, 0x80, 0x1b, 0xd1, 0x57, 0x00, 0xe7, 0x33, 0x91, 0x1d, 0x7d, - 0x9e, 0x00, 0xdc, 0x80, 0x29, 0x3d, 0xaf, 0x0c, 0x7a, 0x5e, 0x93, 0x7d, 0xc6, 0x28, 0xf9, 0x2b, - 0xa4, 0x74, 0x0c, 0xe5, 0xa2, 0xf9, 0xc5, 0xa2, 0x1a, 0x45, 0xe6, 0x87, 0xd0, 0xd7, 0xa0, 0x71, - 0xe8, 0x1a, 0xd4, 0x97, 0x40, 0x2e, 0xfb, 0x25, 0x70, 0x05, 0x8a, 0x52, 0x40, 0x09, 0x35, 0xfe, - 0xb0, 0x1e, 0xbb, 0x46, 0x6d, 0x01, 0x4a, 0x4c, 0x5b, 0xb8, 0xec, 0xa8, 0xa5, 0xe6, 0x50, 0x09, - 0x4e, 0x45, 0x06, 0xbd, 0x08, 0x93, 0xb7, 0x5c, 0xef, 0x66, 0xcb, 0xb5, 0x58, 0x3a, 0x50, 0xc8, - 0xe2, 0x82, 0x45, 0x39, 0xbc, 0x78, 0x88, 0xf4, 0xf5, 0x90, 0x3e, 0xd6, 0x99, 0xa1, 0x0a, 0xcc, - 0xb6, 0x6d, 0x07, 0x13, 0xab, 0xa1, 0x82, 0xfd, 0xc7, 0x78, 0xbe, 0x42, 0x69, 0xe4, 0xae, 0x47, - 0xc1, 0x38, 0x8e, 0x8f, 0x3e, 0x06, 0x45, 0x5f, 0xe4, 0xae, 0xc9, 0xe6, 0x2a, 0x4c, 0x9d, 0x19, - 0x39, 0xd1, 0x70, 0xec, 0x64, 0x09, 0x56, 0x0c, 0xd1, 0x1a, 0x2c, 0x78, 0x22, 0x3b, 0x44, 0xe4, - 0x63, 0x02, 0x7c, 0x7f, 0xb2, 0xb4, 0x78, 0x38, 0x05, 0x8e, 0x53, 0x6b, 0x51, 0x2b, 0x86, 0x25, - 0x48, 0xe2, 0x77, 0x02, 0x9a, 0x1b, 0x9d, 0x2d, 0xf8, 0x06, 0x16, 0xd0, 0xc3, 0x1e, 0x8f, 0x14, - 0x47, 0x78, 0x3c, 0x52, 0x83, 0x93, 0x71, 0x10, 0xcb, 0x61, 0xc1, 0xd2, 0x66, 0x68, 0xda, 0x63, - 0x33, 0x0d, 0x09, 0xa7, 0xd7, 0x45, 0xd7, 0xa1, 0xe4, 0x11, 0x76, 0xbe, 0xa8, 0xc8, 0xcb, 0xf7, - 0xa1, 0xc3, 0x8c, 0xb0, 0x24, 0x80, 0x43, 0x5a, 0x74, 0xde, 0xad, 0x68, 0xca, 0xbe, 0x2b, 0x19, - 0x7e, 0x0e, 0x49, 0xcc, 0x7d, 0x9f, 0xdc, 0x32, 0xe6, 0x1b, 0x33, 0x30, 0x1d, 0xf1, 0x2d, 0xa0, - 0x87, 0xa1, 0xc0, 0x92, 0x7a, 0x30, 0xf1, 0x50, 0x0c, 0x45, 0x18, 0x1f, 0x1c, 0x0e, 0x43, 0x9f, - 0x35, 0x60, 0xb6, 0x13, 0xf1, 0xc2, 0x4a, 0xc9, 0x39, 0xe2, 0x3d, 0x5f, 0xd4, 0xb5, 0xab, 0x25, - 0xbb, 0x8d, 0x32, 0xc3, 0x71, 0xee, 0x74, 0x03, 0x8a, 0xc8, 0xbb, 0x16, 0xf1, 0x18, 0xb6, 0xb0, - 0x71, 0x14, 0x89, 0xe5, 0x28, 0x18, 0xc7, 0xf1, 0xe9, 0x0c, 0xb3, 0xde, 0x8d, 0xf2, 0x9d, 0x94, - 0x8a, 0x24, 0x80, 0x43, 0x5a, 0xe8, 0x19, 0x98, 0x11, 0x99, 0xda, 0x36, 0xdd, 0xc6, 0x45, 0xcb, - 0xdf, 0x15, 0xc6, 0xbd, 0x3a, 0x8c, 0x2c, 0x47, 0xa0, 0x38, 0x86, 0xcd, 0xfa, 0x16, 0xa6, 0xc3, - 0x63, 0x04, 0xc6, 0xa3, 0xb9, 0x80, 0x97, 0xa3, 0x60, 0x1c, 0xc7, 0x47, 0xef, 0xd0, 0xe4, 0x3e, - 0xbf, 0xa7, 0x53, 0xd2, 0x20, 0x45, 0xf6, 0x57, 0x60, 0xb6, 0xcb, 0xce, 0x42, 0x0d, 0x09, 0x14, - 0xfb, 0x51, 0x31, 0xbc, 0x1a, 0x05, 0xe3, 0x38, 0x3e, 0x7a, 0x1a, 0xa6, 0x3d, 0x2a, 0xdd, 0x14, - 0x01, 0x7e, 0x79, 0xa7, 0xee, 0x66, 0xb0, 0x0e, 0xc4, 0x51, 0x5c, 0xf4, 0x2c, 0xcc, 0x87, 0xe9, - 0x9e, 0x24, 0x01, 0x7e, 0x9b, 0xa7, 0x32, 0x99, 0x54, 0xe2, 0x08, 0x38, 0x59, 0x07, 0xfd, 0x1c, - 0xcc, 0x69, 0x23, 0xb1, 0xea, 0x34, 0xc8, 0x6d, 0x91, 0x92, 0x87, 0xa5, 0x6d, 0x5f, 0x8e, 0xc1, - 0x70, 0x02, 0x1b, 0xbd, 0x17, 0x66, 0xea, 0x6e, 0xab, 0xc5, 0x64, 0x1c, 0xcf, 0x43, 0xcb, 0x73, - 0xef, 0xf0, 0x2c, 0x45, 0x11, 0x08, 0x8e, 0x61, 0xa2, 0x4b, 0x80, 0xdc, 0x6d, 0x9f, 0x78, 0x7b, - 0xa4, 0xf1, 0x2c, 0xff, 0xf2, 0x22, 0x55, 0xf1, 0xd3, 0xd1, 0xb8, 0xdf, 0xcb, 0x09, 0x0c, 0x9c, - 0x52, 0x8b, 0x25, 0x42, 0xd1, 0xde, 0xe0, 0xcc, 0x64, 0xf1, 0xcd, 0x90, 0xf8, 0xc9, 0xfd, 0xae, - 0x0f, 0x70, 0x3c, 0x18, 0xe7, 0x61, 0xd8, 0xd9, 0x24, 0xe1, 0xd1, 0x53, 0x52, 0x86, 0x3a, 0x82, - 0x97, 0x62, 0xc1, 0x09, 0x7d, 0x1c, 0x4a, 0xdb, 0x32, 0x3f, 0xf1, 0xe2, 0x5c, 0x16, 0x7a, 0x31, - 0x96, 0x6a, 0x3b, 0x3c, 0x99, 0x2a, 0x00, 0x0e, 0x59, 0xa2, 0x47, 0x60, 0xf2, 0xe2, 0x66, 0x45, - 0xad, 0xc2, 0x79, 0x36, 0xfb, 0x63, 0xb4, 0x0a, 0xd6, 0x01, 0x74, 0x87, 0x29, 0x7b, 0x09, 0xb1, - 0x29, 0x0e, 0xf5, 0x6d, 0xd2, 0xfc, 0xa1, 0xd8, 0xec, 0x3a, 0x12, 0xd7, 0x16, 0x4f, 0xc4, 0xb0, - 0x45, 0x39, 0x56, 0x18, 0xe8, 0x05, 0x98, 0x14, 0xfa, 0x82, 0xc9, 0xa6, 0x85, 0xa3, 0xbd, 0xef, - 0xc2, 0x21, 0x09, 0xac, 0xd3, 0x63, 0xb7, 0x4c, 0x2c, 0x6d, 0x2b, 0xb9, 0xd0, 0x6d, 0xb5, 0x16, - 0x4f, 0x32, 0xb9, 0x19, 0xde, 0x32, 0x85, 0x20, 0xac, 0xe3, 0xa1, 0xc7, 0x65, 0xe4, 0xc4, 0x5b, - 0x22, 0xd7, 0x6e, 0x2a, 0x72, 0x42, 0x59, 0xb9, 0x7d, 0x02, 0x7b, 0x4f, 0xdd, 0x25, 0x64, 0x61, - 0x1b, 0x4e, 0x4b, 0x13, 0x2b, 0xb9, 0x49, 0x16, 0x17, 0x23, 0x5e, 0x82, 0xd3, 0xd7, 0xfb, 0x62, - 0xe2, 0x43, 0xa8, 0xa0, 0x6d, 0xc8, 0x5b, 0xad, 0xed, 0xc5, 0xfb, 0xb3, 0xb0, 0x15, 0xd5, 0x97, - 0x54, 0x79, 0x30, 0x4e, 0x65, 0xad, 0x8a, 0x29, 0x71, 0xf3, 0x95, 0x9c, 0xf2, 0xca, 0xab, 0xe4, - 0x84, 0x2f, 0xe9, 0xab, 0xda, 0xc8, 0xe2, 0x4b, 0x81, 0x89, 0x24, 0xde, 0x5c, 0x21, 0xa5, 0xae, - 0xe9, 0x8e, 0xda, 0xc7, 0x99, 0x64, 0x9e, 0x88, 0x26, 0x5e, 0xe4, 0xa7, 0xb9, 0xe8, 0x2e, 0x36, - 0xff, 0xbe, 0xa0, 0x9c, 0x50, 0xb1, 0x50, 0x00, 0x0f, 0x0a, 0xb6, 0x1f, 0xd8, 0x6e, 0x86, 0xcf, - 0xb6, 0x62, 0x19, 0x0b, 0x59, 0x00, 0x2b, 0x03, 0x60, 0xce, 0x8a, 0xf2, 0x74, 0x9a, 0xb6, 0x73, - 0x5b, 0x74, 0xff, 0x4a, 0xe6, 0x77, 0xfc, 0x9c, 0x27, 0x03, 0x60, 0xce, 0x0a, 0xdd, 0xe0, 0x2b, - 0x2d, 0x9b, 0xaf, 0x42, 0xc6, 0x3f, 0xf6, 0x1a, 0x5d, 0x71, 0x94, 0x97, 0xdf, 0xb6, 0x85, 0x0d, - 0x33, 0x22, 0xaf, 0xda, 0xfa, 0x6a, 0x1a, 0xaf, 0xda, 0xfa, 0x2a, 0xa6, 0x4c, 0xd0, 0x6b, 0x06, - 0x80, 0xa5, 0xbe, 0x7a, 0x9a, 0x4d, 0xc6, 0xfb, 0x7e, 0x5f, 0x51, 0xe5, 0x31, 0x67, 0x21, 0x14, - 0x6b, 0x9c, 0xd1, 0x8b, 0x30, 0x61, 0xf1, 0xef, 0x75, 0x88, 0x70, 0xbe, 0x6c, 0x3e, 0x42, 0x13, - 0x6b, 0x01, 0x8b, 0x63, 0x14, 0x20, 0x2c, 0x19, 0x9a, 0xff, 0x6a, 0x80, 0xf6, 0x99, 0xba, 0x30, - 0xd8, 0xca, 0x18, 0x38, 0xd8, 0x2a, 0x37, 0x64, 0xb0, 0x55, 0x7e, 0xa8, 0x60, 0xab, 0xb1, 0xe1, - 0x83, 0xad, 0x0a, 0xfd, 0x83, 0xad, 0xcc, 0xd7, 0x0d, 0x98, 0x4f, 0xac, 0x8b, 0xf8, 0xe7, 0x80, - 0x8d, 0x01, 0x3f, 0x07, 0xbc, 0x02, 0x73, 0x22, 0x7d, 0x68, 0xad, 0xd3, 0xb2, 0x53, 0x5f, 0x99, - 0x6e, 0xc5, 0xe0, 0x38, 0x51, 0xc3, 0xfc, 0x63, 0x03, 0x26, 0xb5, 0x47, 0x31, 0xb4, 0x1f, 0xec, - 0xf1, 0x90, 0x68, 0x46, 0x98, 0x39, 0x95, 0xb9, 0x38, 0x39, 0x8c, 0x7b, 0xdb, 0x9b, 0x5a, 0xaa, - 0xba, 0xd0, 0xdb, 0x4e, 0x4b, 0xb1, 0x80, 0xf2, 0x24, 0x64, 0x84, 0x7f, 0xea, 0x39, 0xaf, 0x27, - 0x21, 0x23, 0x1d, 0xcc, 0x20, 0x8c, 0x1d, 0xd5, 0xa7, 0x22, 0x0e, 0x4f, 0x4b, 0xd4, 0x6a, 0xd1, - 0x53, 0x13, 0x83, 0xa1, 0x33, 0x90, 0x27, 0x4e, 0x43, 0x18, 0xff, 0xea, 0x33, 0x20, 0xe7, 0x9d, - 0x06, 0xa6, 0xe5, 0xe6, 0x65, 0x98, 0xaa, 0x91, 0xba, 0x47, 0x82, 0xe7, 0xc8, 0xfe, 0xc0, 0xdf, - 0x15, 0xb9, 0x49, 0xf6, 0xe3, 0xdf, 0x15, 0xa1, 0xd5, 0x69, 0xb9, 0xf9, 0xbb, 0x06, 0xc4, 0xf2, - 0xe6, 0x6a, 0x9e, 0x37, 0xa3, 0x9f, 0xe7, 0x2d, 0xe2, 0x23, 0xca, 0x1d, 0xea, 0x23, 0xba, 0x04, - 0xa8, 0x6d, 0x05, 0xf5, 0xdd, 0x48, 0x96, 0x68, 0x71, 0xee, 0x0a, 0x9f, 0xe0, 0x25, 0x30, 0x70, - 0x4a, 0x2d, 0xf3, 0x65, 0x03, 0x12, 0x5f, 0x6a, 0xa6, 0xd6, 0x02, 0x11, 0x9f, 0x6c, 0xe0, 0xc7, - 0x51, 0x65, 0x2d, 0xc8, 0x2f, 0x35, 0x48, 0x38, 0x3d, 0xb3, 0x48, 0xaf, 0x97, 0xf4, 0x21, 0xf0, - 0xc7, 0x4a, 0xea, 0xcc, 0xb2, 0x12, 0x05, 0xe3, 0x38, 0xbe, 0x79, 0x0d, 0x8a, 0xf2, 0x45, 0x27, - 0x7b, 0x16, 0x25, 0x4f, 0xc1, 0xfa, 0xb3, 0x28, 0x7a, 0x08, 0x66, 0x10, 0x3a, 0x4c, 0xbe, 0x63, - 0x5f, 0x74, 0xfd, 0x40, 0x3e, 0x43, 0xe5, 0xbe, 0xae, 0x8d, 0x55, 0x56, 0x86, 0x15, 0xd4, 0x9c, - 0x87, 0x59, 0xe5, 0xc4, 0x12, 0x11, 0x3a, 0xdf, 0xca, 0xc3, 0x54, 0xe4, 0xfb, 0x7b, 0x77, 0x9f, - 0xec, 0xc1, 0xa7, 0x25, 0xc5, 0x19, 0x95, 0x1f, 0xd2, 0x19, 0xa5, 0x7b, 0xff, 0xc6, 0x8e, 0xd7, - 0xfb, 0x57, 0xc8, 0xc6, 0xfb, 0x17, 0xc0, 0x84, 0xf8, 0x36, 0xb9, 0x10, 0xff, 0xeb, 0x19, 0xa5, - 0x63, 0x10, 0xef, 0x9a, 0x99, 0xe0, 0x97, 0x02, 0x4c, 0xb2, 0x32, 0xbf, 0x5e, 0x80, 0x99, 0x68, - 0x82, 0x86, 0x01, 0x66, 0xf2, 0x1d, 0x89, 0x99, 0x1c, 0xf2, 0x30, 0x9e, 0x1f, 0xf5, 0x30, 0x3e, - 0x36, 0xea, 0x61, 0xbc, 0x70, 0x84, 0xc3, 0x78, 0xf2, 0x28, 0x3d, 0x3e, 0xf0, 0x51, 0xfa, 0x7d, - 0xea, 0x26, 0x79, 0x22, 0x72, 0xf5, 0x12, 0xde, 0x24, 0xa3, 0xe8, 0x34, 0x2c, 0xbb, 0x8d, 0xd4, - 0x1b, 0xf9, 0xe2, 0x5d, 0x0e, 0x1d, 0x5e, 0xea, 0xc5, 0xef, 0xf0, 0xfe, 0xbe, 0xb7, 0x0c, 0x71, - 0xe9, 0x1b, 0x7e, 0x7e, 0x9f, 0x29, 0x3f, 0x88, 0x2a, 0xce, 0x5a, 0x08, 0xc2, 0x3a, 0x1e, 0xfb, - 0x44, 0x54, 0xf4, 0x9b, 0x58, 0xcc, 0xb7, 0xa1, 0x7f, 0x22, 0x2a, 0xf6, 0x0d, 0xad, 0x38, 0xbe, - 0xf9, 0xb5, 0x3c, 0xcc, 0x44, 0x53, 0xfc, 0xa3, 0x5b, 0xea, 0x6c, 0x90, 0xc9, 0xb1, 0x84, 0x93, - 0xd5, 0x52, 0x14, 0xf4, 0x3d, 0xe8, 0xf3, 0x8f, 0xc2, 0x6f, 0xab, 0x7c, 0x09, 0xc7, 0xc7, 0x58, - 0x9c, 0xb0, 0x05, 0x3b, 0x96, 0xc5, 0x3f, 0x0c, 0xa5, 0x15, 0xb7, 0xc7, 0x99, 0x73, 0x0f, 0x83, - 0x63, 0x15, 0x2b, 0xac, 0xb1, 0xa5, 0xe2, 0x7d, 0x8f, 0x78, 0xf6, 0x8e, 0xad, 0x3e, 0x4f, 0xc4, - 0x84, 0xe7, 0x35, 0x51, 0x86, 0x15, 0xd4, 0x7c, 0x39, 0x07, 0xe1, 0xc7, 0xd8, 0x58, 0x76, 0x70, - 0x5f, 0x33, 0x1b, 0xc4, 0xb4, 0x5d, 0x1a, 0x35, 0x05, 0x7f, 0x48, 0x51, 0x04, 0xda, 0x68, 0x25, - 0x38, 0xc2, 0xf1, 0x27, 0xf0, 0x11, 0x36, 0x0b, 0x66, 0x63, 0x0f, 0x7d, 0x32, 0x8f, 0x66, 0xfc, - 0x62, 0x1e, 0x4a, 0xea, 0xa9, 0x14, 0x7a, 0x0f, 0x4b, 0xb1, 0xbb, 0xeb, 0xca, 0xc4, 0xc7, 0x6f, - 0xd5, 0x12, 0xe1, 0xee, 0xba, 0x8d, 0x3b, 0xbd, 0xf2, 0xac, 0x42, 0xe6, 0x45, 0x58, 0x54, 0xa0, - 0x46, 0x5a, 0xd7, 0x6b, 0xc5, 0x8d, 0xb4, 0xab, 0x78, 0x0d, 0xd3, 0x72, 0x74, 0x1b, 0x26, 0x76, - 0x89, 0xd5, 0x20, 0x9e, 0x8c, 0x5b, 0x58, 0xcf, 0xe8, 0x79, 0xd7, 0x45, 0x46, 0x35, 0x1c, 0x06, - 0xfe, 0xdf, 0xc7, 0x92, 0x1d, 0x55, 0x54, 0xdb, 0x6e, 0x63, 0x3f, 0x9e, 0x38, 0xb7, 0xea, 0x36, - 0xf6, 0x31, 0x83, 0xa0, 0x67, 0x60, 0x26, 0xb0, 0xdb, 0xc4, 0xed, 0x06, 0xfa, 0xa7, 0xae, 0xf2, - 0xa1, 0xe3, 0x7a, 0x2b, 0x02, 0xc5, 0x31, 0x6c, 0xaa, 0xe8, 0x6e, 0xf8, 0xae, 0xc3, 0xb2, 0xe1, - 0x8c, 0x47, 0xbd, 0x5c, 0x97, 0x6a, 0x97, 0x37, 0x58, 0x32, 0x1c, 0x85, 0x41, 0xb1, 0x6d, 0xf6, - 0x1e, 0xc3, 0x23, 0xe2, 0xde, 0x68, 0x2e, 0x7c, 0x35, 0xcb, 0xcb, 0xb1, 0xc2, 0x30, 0xaf, 0xc2, - 0x6c, 0xac, 0xab, 0xd2, 0x1c, 0x36, 0xd2, 0xcd, 0xe1, 0xc1, 0xb2, 0xd4, 0xfe, 0x81, 0x01, 0xf3, - 0x89, 0xcd, 0x3b, 0x68, 0x98, 0x6d, 0x5c, 0x92, 0xe7, 0x8e, 0x2e, 0xc9, 0xf3, 0xc3, 0x49, 0xf2, - 0xea, 0xd2, 0xb7, 0xdf, 0x38, 0x7b, 0xdf, 0x77, 0xde, 0x38, 0x7b, 0xdf, 0xf7, 0xde, 0x38, 0x7b, - 0xdf, 0xcb, 0x07, 0x67, 0x8d, 0x6f, 0x1f, 0x9c, 0x35, 0xbe, 0x73, 0x70, 0xd6, 0xf8, 0xde, 0xc1, - 0x59, 0xe3, 0x1f, 0x0f, 0xce, 0x1a, 0xaf, 0xff, 0xf0, 0xec, 0x7d, 0xcf, 0x17, 0xe5, 0x32, 0xf9, - 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x08, 0xc1, 0x61, 0x7b, 0xd3, 0x89, 0x00, 0x00, + 0x55, 0xb0, 0xab, 0x7b, 0x7a, 0xa6, 0xfb, 0xcc, 0xff, 0xdd, 0xd9, 0xec, 0x78, 0xec, 0xdd, 0x76, + 0xca, 0x91, 0x3f, 0xe7, 0x23, 0x99, 0x4d, 0xfc, 0x03, 0x4e, 0x1c, 0x19, 0xba, 0x67, 0x76, 0xbd, + 0xb3, 0x9e, 0x99, 0x9d, 0xbd, 0x3d, 0xbb, 0x9b, 0x38, 0x71, 0x48, 0x4d, 0xf7, 0x9d, 0x9e, 0xda, + 0xe9, 0xae, 0xea, 0x54, 0x55, 0xcf, 0xee, 0x38, 0x56, 0x62, 0x13, 0xd9, 0x04, 0x94, 0x28, 0x86, + 0x24, 0x42, 0x08, 0x05, 0x45, 0x28, 0x12, 0x88, 0xe4, 0x01, 0x45, 0x20, 0x5e, 0x22, 0x81, 0x48, + 0x22, 0xc2, 0x03, 0x28, 0x20, 0x20, 0x09, 0x52, 0x1a, 0xdc, 0xe1, 0x05, 0x04, 0x42, 0x48, 0x41, + 0x28, 0xfb, 0x84, 0xee, 0x6f, 0xdd, 0xaa, 0xae, 0x9e, 0xed, 0x9e, 0xae, 0xd9, 0x58, 0x90, 0xb7, + 0xee, 0x7b, 0xce, 0x3d, 0xe7, 0xfe, 0x9e, 0x73, 0xee, 0xb9, 0xe7, 0x9e, 0x82, 0xf5, 0xba, 0x1d, + 0xec, 0xb5, 0x77, 0x96, 0xab, 0x6e, 0xf3, 0xbc, 0xe5, 0xd5, 0xdd, 0x96, 0xe7, 0xde, 0x64, 0x3f, + 0xde, 0xe9, 0xb9, 0x8d, 0x86, 0xdb, 0x0e, 0xfc, 0xf3, 0xad, 0xfd, 0xfa, 0x79, 0xab, 0x65, 0xfb, + 0xe7, 0x55, 0xc9, 0xc1, 0xbb, 0xad, 0x46, 0x6b, 0xcf, 0x7a, 0xf7, 0xf9, 0x3a, 0x71, 0x88, 0x67, + 0x05, 0xa4, 0xb6, 0xdc, 0xf2, 0xdc, 0xc0, 0x45, 0xef, 0x0b, 0xa9, 0x2d, 0x4b, 0x6a, 0xec, 0xc7, + 0x2f, 0xca, 0xba, 0xcb, 0xad, 0xfd, 0xfa, 0x32, 0xa5, 0xb6, 0xac, 0x4a, 0x24, 0xb5, 0xa5, 0x77, + 0x6a, 0x6d, 0xa9, 0xbb, 0x75, 0xf7, 0x3c, 0x23, 0xba, 0xd3, 0xde, 0x65, 0xff, 0xd8, 0x1f, 0xf6, + 0x8b, 0x33, 0x5b, 0x7a, 0x78, 0xff, 0x29, 0x7f, 0xd9, 0x76, 0x69, 0xdb, 0xce, 0xef, 0x58, 0x41, + 0x75, 0xef, 0xfc, 0x41, 0x4f, 0x8b, 0x96, 0x4c, 0x0d, 0xa9, 0xea, 0x7a, 0x24, 0x09, 0xe7, 0x89, + 0x10, 0xa7, 0x69, 0x55, 0xf7, 0x6c, 0x87, 0x78, 0x87, 0x61, 0xaf, 0x9b, 0x24, 0xb0, 0x92, 0x6a, + 0x9d, 0xef, 0x57, 0xcb, 0x6b, 0x3b, 0x81, 0xdd, 0x24, 0x3d, 0x15, 0x7e, 0xf6, 0x6e, 0x15, 0xfc, + 0xea, 0x1e, 0x69, 0x5a, 0x3d, 0xf5, 0x1e, 0xef, 0x57, 0xaf, 0x1d, 0xd8, 0x8d, 0xf3, 0xb6, 0x13, + 0xf8, 0x81, 0x17, 0xaf, 0x64, 0x7e, 0x33, 0x0b, 0x85, 0xd2, 0x7a, 0xb9, 0x12, 0x58, 0x41, 0xdb, + 0x47, 0xaf, 0x19, 0x30, 0xd5, 0x70, 0xad, 0x5a, 0xd9, 0x6a, 0x58, 0x4e, 0x95, 0x78, 0x8b, 0xc6, + 0x43, 0xc6, 0xa3, 0x93, 0x8f, 0xad, 0x2f, 0x8f, 0x32, 0x5f, 0xcb, 0xa5, 0x5b, 0x3e, 0x26, 0xbe, + 0xdb, 0xf6, 0xaa, 0x04, 0x93, 0xdd, 0xf2, 0xc2, 0xb7, 0x3b, 0xc5, 0xfb, 0xba, 0x9d, 0xe2, 0xd4, + 0xba, 0xc6, 0x09, 0x47, 0xf8, 0xa2, 0x2f, 0x18, 0x30, 0x5f, 0xb5, 0x1c, 0xcb, 0x3b, 0xdc, 0xb6, + 0xbc, 0x3a, 0x09, 0x9e, 0xf5, 0xdc, 0x76, 0x6b, 0x31, 0x73, 0x02, 0xad, 0xb9, 0x5f, 0xb4, 0x66, + 0x7e, 0x25, 0xce, 0x0e, 0xf7, 0xb6, 0x80, 0xb5, 0xcb, 0x0f, 0xac, 0x9d, 0x06, 0xd1, 0xdb, 0x95, + 0x3d, 0xc9, 0x76, 0x55, 0xe2, 0xec, 0x70, 0x6f, 0x0b, 0xcc, 0x57, 0xb3, 0x30, 0x5f, 0x5a, 0x2f, + 0x6f, 0x7b, 0xd6, 0xee, 0xae, 0x5d, 0xc5, 0x6e, 0x3b, 0xb0, 0x9d, 0x3a, 0x7a, 0x3b, 0x4c, 0xd8, + 0x4e, 0xdd, 0x23, 0xbe, 0xcf, 0x26, 0xb2, 0x50, 0x9e, 0x15, 0x44, 0x27, 0xd6, 0x78, 0x31, 0x96, + 0x70, 0xf4, 0x24, 0x4c, 0xfa, 0xc4, 0x3b, 0xb0, 0xab, 0x64, 0xcb, 0xf5, 0x02, 0x36, 0xd2, 0xb9, + 0xf2, 0x29, 0x81, 0x3e, 0x59, 0x09, 0x41, 0x58, 0xc7, 0xa3, 0xd5, 0x3c, 0xd7, 0x0d, 0x04, 0x9c, + 0x0d, 0x44, 0x21, 0xac, 0x86, 0x43, 0x10, 0xd6, 0xf1, 0xd0, 0xeb, 0x06, 0xcc, 0xf9, 0x81, 0x5d, + 0xdd, 0xb7, 0x1d, 0xe2, 0xfb, 0x2b, 0xae, 0xb3, 0x6b, 0xd7, 0x17, 0x73, 0x6c, 0x14, 0x37, 0x47, + 0x1b, 0xc5, 0x4a, 0x8c, 0x6a, 0x79, 0xa1, 0xdb, 0x29, 0xce, 0xc5, 0x4b, 0x71, 0x0f, 0x77, 0xb4, + 0x0a, 0x73, 0x96, 0xe3, 0xb8, 0x81, 0x15, 0xd8, 0xae, 0xb3, 0xe5, 0x91, 0x5d, 0xfb, 0xf6, 0xe2, + 0x18, 0xeb, 0xce, 0xa2, 0xe8, 0xce, 0x5c, 0x29, 0x06, 0xc7, 0x3d, 0x35, 0xcc, 0x55, 0x58, 0x2c, + 0x35, 0x77, 0x2c, 0xdf, 0xb7, 0x6a, 0xae, 0x17, 0x9b, 0x8d, 0x47, 0x21, 0xdf, 0xb4, 0x5a, 0x2d, + 0xdb, 0xa9, 0xd3, 0xe9, 0xc8, 0x3e, 0x5a, 0x28, 0x4f, 0x75, 0x3b, 0xc5, 0xfc, 0x86, 0x28, 0xc3, + 0x0a, 0x6a, 0x7e, 0x3f, 0x03, 0x93, 0x25, 0xc7, 0x6a, 0x1c, 0xfa, 0xb6, 0x8f, 0xdb, 0x0e, 0xfa, + 0x08, 0xe4, 0xa9, 0x74, 0xa9, 0x59, 0x81, 0x25, 0x76, 0xe4, 0xbb, 0x96, 0xf9, 0x66, 0x5f, 0xd6, + 0x37, 0x7b, 0x38, 0x2e, 0x14, 0x7b, 0xf9, 0xe0, 0xdd, 0xcb, 0x57, 0x76, 0x6e, 0x92, 0x6a, 0xb0, + 0x41, 0x02, 0xab, 0x8c, 0x44, 0x2f, 0x20, 0x2c, 0xc3, 0x8a, 0x2a, 0x72, 0x61, 0xcc, 0x6f, 0x91, + 0xaa, 0xd8, 0x61, 0x1b, 0x23, 0xae, 0xe4, 0xb0, 0xe9, 0x95, 0x16, 0xa9, 0x96, 0xa7, 0x04, 0xeb, + 0x31, 0xfa, 0x0f, 0x33, 0x46, 0xe8, 0x16, 0x8c, 0xfb, 0x4c, 0xe6, 0x88, 0xcd, 0x73, 0x25, 0x3d, + 0x96, 0x8c, 0x6c, 0x79, 0x46, 0x30, 0x1d, 0xe7, 0xff, 0xb1, 0x60, 0x67, 0xfe, 0x83, 0x01, 0xa7, + 0x34, 0xec, 0x92, 0x57, 0x6f, 0x37, 0x89, 0x13, 0xa0, 0x87, 0x60, 0xcc, 0xb1, 0x9a, 0x44, 0x6c, + 0x14, 0xd5, 0xe4, 0x4d, 0xab, 0x49, 0x30, 0x83, 0xa0, 0x87, 0x21, 0x77, 0x60, 0x35, 0xda, 0x84, + 0x0d, 0x52, 0xa1, 0x3c, 0x2d, 0x50, 0x72, 0xd7, 0x69, 0x21, 0xe6, 0x30, 0xf4, 0x12, 0x14, 0xd8, + 0x8f, 0x8b, 0x9e, 0xdb, 0x4c, 0xa9, 0x6b, 0xa2, 0x85, 0xd7, 0x25, 0xd9, 0xf2, 0x74, 0xb7, 0x53, + 0x2c, 0xa8, 0xbf, 0x38, 0x64, 0x68, 0xfe, 0xa3, 0x01, 0xb3, 0x5a, 0xe7, 0xd6, 0x6d, 0x3f, 0x40, + 0x1f, 0xea, 0x59, 0x3c, 0xcb, 0x83, 0x2d, 0x1e, 0x5a, 0x9b, 0x2d, 0x9d, 0x39, 0xd1, 0xd3, 0xbc, + 0x2c, 0xd1, 0x16, 0x8e, 0x03, 0x39, 0x3b, 0x20, 0x4d, 0x7f, 0x31, 0xf3, 0x50, 0xf6, 0xd1, 0xc9, + 0xc7, 0xd6, 0x52, 0x9b, 0xc6, 0x70, 0x7c, 0xd7, 0x28, 0x7d, 0xcc, 0xd9, 0x98, 0x5f, 0x1b, 0x8b, + 0xf4, 0x90, 0xae, 0x28, 0xe4, 0xc2, 0x44, 0x93, 0x04, 0x9e, 0x5d, 0xe5, 0xfb, 0x6a, 0xf2, 0xb1, + 0xd5, 0xd1, 0x5a, 0xb1, 0xc1, 0x88, 0x85, 0xc2, 0x92, 0xff, 0xf7, 0xb1, 0xe4, 0x82, 0xf6, 0x60, + 0xcc, 0xf2, 0xea, 0xb2, 0xcf, 0x17, 0xd3, 0x99, 0xdf, 0x70, 0xcd, 0x95, 0xbc, 0xba, 0x8f, 0x19, + 0x07, 0x74, 0x1e, 0x0a, 0x01, 0xf1, 0x9a, 0xb6, 0x63, 0x05, 0x5c, 0xba, 0xe6, 0xcb, 0xf3, 0x02, + 0xad, 0xb0, 0x2d, 0x01, 0x38, 0xc4, 0x41, 0x0d, 0x18, 0xaf, 0x79, 0x87, 0xb8, 0xed, 0x2c, 0x8e, + 0xa5, 0x31, 0x14, 0xab, 0x8c, 0x56, 0xb8, 0x99, 0xf8, 0x7f, 0x2c, 0x78, 0xa0, 0x2f, 0x1b, 0xb0, + 0xd0, 0x24, 0x96, 0xdf, 0xf6, 0x08, 0xed, 0x02, 0x26, 0x01, 0x71, 0xa8, 0x34, 0x5c, 0xcc, 0x31, + 0xe6, 0x78, 0xd4, 0x79, 0xe8, 0xa5, 0x5c, 0x7e, 0x50, 0x34, 0x65, 0x21, 0x09, 0x8a, 0x13, 0x5b, + 0x63, 0x7e, 0x7f, 0x0c, 0xe6, 0x7b, 0x24, 0x04, 0x7a, 0x02, 0x72, 0xad, 0x3d, 0xcb, 0x97, 0x5b, + 0xfe, 0x9c, 0x5c, 0x6f, 0x5b, 0xb4, 0xf0, 0x4e, 0xa7, 0x38, 0x2d, 0xab, 0xb0, 0x02, 0xcc, 0x91, + 0xa9, 0x4e, 0x6d, 0x12, 0xdf, 0xb7, 0xea, 0x52, 0x0e, 0x68, 0xcb, 0x84, 0x15, 0x63, 0x09, 0x47, + 0xbf, 0x6c, 0xc0, 0x34, 0x5f, 0x32, 0x98, 0xf8, 0xed, 0x46, 0x40, 0x65, 0x1d, 0x1d, 0x96, 0xcb, + 0x69, 0x2c, 0x4f, 0x4e, 0xb2, 0x7c, 0x5a, 0x70, 0x9f, 0xd6, 0x4b, 0x7d, 0x1c, 0xe5, 0x8b, 0x6e, + 0x40, 0xc1, 0x0f, 0x2c, 0x2f, 0x20, 0xb5, 0x52, 0xc0, 0xb4, 0xda, 0xe4, 0x63, 0xff, 0x7f, 0x30, + 0x21, 0xb0, 0x6d, 0x37, 0x09, 0x17, 0x38, 0x15, 0x49, 0x00, 0x87, 0xb4, 0xd0, 0x4b, 0x00, 0x5e, + 0xdb, 0xa9, 0xb4, 0x9b, 0x4d, 0xcb, 0x3b, 0x14, 0x1a, 0xfc, 0xd2, 0x68, 0xdd, 0xc3, 0x8a, 0x5e, + 0xa8, 0xb3, 0xc2, 0x32, 0xac, 0xf1, 0x43, 0xaf, 0x18, 0x30, 0xcd, 0x57, 0xa2, 0x6c, 0xc1, 0x78, + 0xca, 0x2d, 0x98, 0xa7, 0x43, 0xbb, 0xaa, 0xb3, 0xc0, 0x51, 0x8e, 0xe6, 0xdf, 0x45, 0xf5, 0x49, + 0x25, 0xa0, 0xd6, 0x75, 0xfd, 0x10, 0x7d, 0x10, 0xee, 0xf7, 0xdb, 0xd5, 0x2a, 0xf1, 0xfd, 0xdd, + 0x76, 0x03, 0xb7, 0x9d, 0x4b, 0xb6, 0x1f, 0xb8, 0xde, 0xe1, 0xba, 0xdd, 0xb4, 0x03, 0xb6, 0xe2, + 0x72, 0xe5, 0xb3, 0xdd, 0x4e, 0xf1, 0xfe, 0x4a, 0x3f, 0x24, 0xdc, 0xbf, 0x3e, 0xb2, 0xe0, 0x81, + 0xb6, 0xd3, 0x9f, 0x3c, 0xb7, 0xde, 0x8a, 0xdd, 0x4e, 0xf1, 0x81, 0x6b, 0xfd, 0xd1, 0xf0, 0x51, + 0x34, 0xcc, 0x7f, 0x35, 0x60, 0x4e, 0xf6, 0x6b, 0x9b, 0x34, 0x5b, 0x0d, 0x2a, 0x5d, 0x4e, 0xde, + 0x10, 0x09, 0x22, 0x86, 0x08, 0x4e, 0x47, 0x9d, 0xc8, 0xf6, 0xf7, 0xb3, 0x46, 0xcc, 0x7f, 0x31, + 0x60, 0x21, 0x8e, 0x7c, 0x0f, 0x94, 0xa7, 0x1f, 0x55, 0x9e, 0x9b, 0xe9, 0xf6, 0xb6, 0x8f, 0x06, + 0x7d, 0x6d, 0xac, 0xb7, 0xaf, 0xff, 0xdb, 0xd5, 0x68, 0xa8, 0x15, 0xb3, 0x3f, 0x49, 0xad, 0x38, + 0xf6, 0xa6, 0xd2, 0x8a, 0xbf, 0x37, 0x06, 0x53, 0x25, 0x27, 0xb0, 0x4b, 0xbb, 0xbb, 0xb6, 0x63, + 0x07, 0x87, 0xe8, 0xd3, 0x19, 0x38, 0xdf, 0xf2, 0xc8, 0x2e, 0xf1, 0x3c, 0x52, 0x5b, 0x6d, 0x7b, + 0xb6, 0x53, 0xaf, 0x54, 0xf7, 0x48, 0xad, 0xdd, 0xb0, 0x9d, 0xfa, 0x5a, 0xdd, 0x71, 0x55, 0xf1, + 0x85, 0xdb, 0xa4, 0xda, 0x66, 0x5d, 0xe2, 0x9b, 0xa2, 0x39, 0x5a, 0x97, 0xb6, 0x86, 0x63, 0x5a, + 0x7e, 0xbc, 0xdb, 0x29, 0x9e, 0x1f, 0xb2, 0x12, 0x1e, 0xb6, 0x6b, 0xe8, 0x53, 0x19, 0x58, 0xf6, + 0xc8, 0x47, 0xdb, 0xf6, 0xe0, 0xa3, 0xc1, 0xa5, 0x56, 0x63, 0x44, 0xf5, 0x33, 0x14, 0xcf, 0xf2, + 0x63, 0xdd, 0x4e, 0x71, 0xc8, 0x3a, 0x78, 0xc8, 0x7e, 0x99, 0xdf, 0xc8, 0xc0, 0xe9, 0x52, 0xab, + 0xb5, 0x41, 0xfc, 0xbd, 0xd8, 0xa1, 0xf6, 0xb3, 0x06, 0xcc, 0x1c, 0xd8, 0x5e, 0xd0, 0xb6, 0x1a, + 0xd2, 0x09, 0xc0, 0x97, 0x44, 0x65, 0xc4, 0xed, 0xcc, 0xb9, 0x5d, 0x8f, 0x90, 0x2e, 0xa3, 0x6e, + 0xa7, 0x38, 0x13, 0x2d, 0xc3, 0x31, 0xf6, 0xe8, 0x37, 0x0c, 0x98, 0x13, 0x45, 0x9b, 0x6e, 0x8d, + 0xe8, 0x9e, 0xa3, 0x6b, 0x69, 0xb6, 0x49, 0x11, 0xe7, 0x2e, 0x86, 0x78, 0x29, 0xee, 0x69, 0x84, + 0xf9, 0xef, 0x19, 0x38, 0xd3, 0x87, 0x06, 0xfa, 0x5d, 0x03, 0x16, 0xb8, 0xbb, 0x49, 0x03, 0x61, + 0xb2, 0x2b, 0x46, 0xf3, 0x03, 0x69, 0xb7, 0x1c, 0xd3, 0xbd, 0x40, 0x9c, 0x2a, 0x29, 0x2f, 0x52, + 0xb1, 0xb1, 0x92, 0xc0, 0x1a, 0x27, 0x36, 0x88, 0xb5, 0x94, 0x3b, 0xa0, 0x62, 0x2d, 0xcd, 0xdc, + 0x93, 0x96, 0x56, 0x12, 0x58, 0xe3, 0xc4, 0x06, 0x99, 0x3f, 0x0f, 0x0f, 0x1c, 0x41, 0xee, 0xee, + 0x27, 0x7e, 0xf3, 0x05, 0xb5, 0xea, 0xa3, 0x6b, 0x6e, 0x00, 0x67, 0x81, 0x09, 0xe3, 0x9e, 0xdb, + 0x0e, 0x08, 0xd7, 0x6e, 0x85, 0x32, 0x50, 0x3d, 0x81, 0x59, 0x09, 0x16, 0x10, 0xf3, 0x1b, 0x06, + 0xe4, 0x87, 0xf0, 0x3f, 0x14, 0xa3, 0xfe, 0x87, 0x42, 0x8f, 0xef, 0x21, 0xe8, 0xf5, 0x3d, 0x3c, + 0x3b, 0xda, 0x6c, 0x0c, 0xe2, 0x73, 0xf8, 0x0f, 0x03, 0xe6, 0x7b, 0x7c, 0x14, 0x68, 0x0f, 0x16, + 0x5a, 0x6e, 0x4d, 0xda, 0x17, 0x97, 0x2c, 0x7f, 0x8f, 0xc1, 0x44, 0xf7, 0x9e, 0xa0, 0x33, 0xb9, + 0x95, 0x00, 0xbf, 0xd3, 0x29, 0x2e, 0x2a, 0x22, 0x31, 0x04, 0x9c, 0x48, 0x11, 0xb5, 0x20, 0xbf, + 0x6b, 0x93, 0x46, 0x2d, 0x5c, 0x82, 0x23, 0x5a, 0x12, 0x17, 0x05, 0x35, 0xee, 0x9e, 0x93, 0xff, + 0xb0, 0xe2, 0x62, 0x5e, 0x85, 0x99, 0xa8, 0xb3, 0x76, 0x80, 0xc9, 0x3b, 0x0b, 0x59, 0xcb, 0x73, + 0xc4, 0xd4, 0x4d, 0x0a, 0x84, 0x6c, 0x09, 0x6f, 0x62, 0x5a, 0x6e, 0xfe, 0x78, 0x0c, 0x66, 0xcb, + 0x8d, 0x36, 0x79, 0xd6, 0x23, 0x44, 0x9e, 0x4f, 0x4b, 0x30, 0xdb, 0xf2, 0xc8, 0x81, 0x4d, 0x6e, + 0x55, 0x48, 0x83, 0x54, 0x03, 0xd7, 0x13, 0xf4, 0xcf, 0x88, 0xea, 0xb3, 0x5b, 0x51, 0x30, 0x8e, + 0xe3, 0xa3, 0x67, 0x60, 0xc6, 0xaa, 0x06, 0xf6, 0x01, 0x51, 0x14, 0x78, 0x03, 0xde, 0x22, 0x28, + 0xcc, 0x94, 0x22, 0x50, 0x1c, 0xc3, 0x46, 0x1f, 0x82, 0x45, 0xbf, 0x6a, 0x35, 0xc8, 0xb5, 0x96, + 0x60, 0xb5, 0xb2, 0x47, 0xaa, 0xfb, 0x5b, 0xae, 0xed, 0x04, 0xc2, 0x1b, 0xf1, 0x90, 0xa0, 0xb4, + 0x58, 0xe9, 0x83, 0x87, 0xfb, 0x52, 0x40, 0x7f, 0x62, 0xc0, 0xd9, 0x96, 0x47, 0xb6, 0x3c, 0xb7, + 0xe9, 0x52, 0x35, 0xd3, 0x73, 0x44, 0x17, 0x47, 0xd5, 0xeb, 0x23, 0xea, 0x53, 0x5e, 0xd2, 0xeb, + 0x22, 0x7c, 0x6b, 0xb7, 0x53, 0x3c, 0xbb, 0x75, 0x54, 0x03, 0xf0, 0xd1, 0xed, 0x43, 0x7f, 0x66, + 0xc0, 0xb9, 0x96, 0xeb, 0x07, 0x47, 0x74, 0x21, 0x77, 0xa2, 0x5d, 0x30, 0xbb, 0x9d, 0xe2, 0xb9, + 0xad, 0x23, 0x5b, 0x80, 0xef, 0xd2, 0x42, 0xb3, 0x3b, 0x09, 0xf3, 0xda, 0xda, 0x13, 0xe7, 0xd7, + 0xa7, 0x61, 0x5a, 0x2e, 0x86, 0x50, 0xad, 0x17, 0x42, 0x7f, 0x43, 0x49, 0x07, 0xe2, 0x28, 0x2e, + 0x5d, 0x77, 0x6a, 0x29, 0xf2, 0xda, 0xb1, 0x75, 0xb7, 0x15, 0x81, 0xe2, 0x18, 0x36, 0x5a, 0x83, + 0x53, 0xa2, 0x04, 0x93, 0x56, 0xc3, 0xae, 0x5a, 0x2b, 0x6e, 0x5b, 0x2c, 0xb9, 0x5c, 0xf9, 0x4c, + 0xb7, 0x53, 0x3c, 0xb5, 0xd5, 0x0b, 0xc6, 0x49, 0x75, 0xd0, 0x3a, 0x2c, 0x58, 0xed, 0xc0, 0x55, + 0xfd, 0xbf, 0xe0, 0x50, 0x4d, 0x51, 0x63, 0x4b, 0x2b, 0xcf, 0x55, 0x4a, 0x29, 0x01, 0x8e, 0x13, + 0x6b, 0xa1, 0xad, 0x18, 0xb5, 0x0a, 0xa9, 0xba, 0x4e, 0x8d, 0xcf, 0x72, 0x2e, 0xb4, 0xc2, 0x4b, + 0x09, 0x38, 0x38, 0xb1, 0x26, 0x6a, 0xc0, 0x4c, 0xd3, 0xba, 0x7d, 0xcd, 0xb1, 0x0e, 0x2c, 0xbb, + 0x41, 0x99, 0x08, 0x1f, 0x46, 0xff, 0x83, 0x75, 0x3b, 0xb0, 0x1b, 0xcb, 0xfc, 0x3a, 0x6f, 0x79, + 0xcd, 0x09, 0xae, 0x78, 0x95, 0x80, 0x5a, 0x6b, 0xdc, 0x38, 0xda, 0x88, 0xd0, 0xc2, 0x31, 0xda, + 0xe8, 0x0a, 0x9c, 0x66, 0xdb, 0x71, 0xd5, 0xbd, 0xe5, 0xac, 0x92, 0x86, 0x75, 0x28, 0x3b, 0x30, + 0xc1, 0x3a, 0x70, 0x7f, 0xb7, 0x53, 0x3c, 0x5d, 0x49, 0x42, 0xc0, 0xc9, 0xf5, 0x90, 0x05, 0x0f, + 0x44, 0x01, 0x98, 0x1c, 0xd8, 0xbe, 0xed, 0x3a, 0xdc, 0x13, 0x91, 0x0f, 0x3d, 0x11, 0x95, 0xfe, + 0x68, 0xf8, 0x28, 0x1a, 0xe8, 0xb7, 0x0c, 0x58, 0x48, 0xda, 0x86, 0x8b, 0x85, 0x34, 0x2e, 0x2b, + 0x62, 0x5b, 0x8b, 0xaf, 0x88, 0x44, 0xa1, 0x90, 0xd8, 0x08, 0xf4, 0xb2, 0x01, 0x53, 0x96, 0x76, + 0x8a, 0x5a, 0x04, 0xd6, 0xaa, 0xcb, 0xa3, 0x9e, 0xe5, 0x43, 0x8a, 0xe5, 0xb9, 0x6e, 0xa7, 0x18, + 0x39, 0xa9, 0xe1, 0x08, 0x47, 0xf4, 0xdb, 0x06, 0x9c, 0x4e, 0xdc, 0xe3, 0x8b, 0x93, 0x27, 0x31, + 0x42, 0x6c, 0x91, 0x24, 0xcb, 0x9c, 0xe4, 0x66, 0xa0, 0xd7, 0x0d, 0xa5, 0xca, 0x36, 0xa4, 0x37, + 0x65, 0x8a, 0x35, 0xed, 0xea, 0x88, 0x07, 0xc7, 0xd0, 0x20, 0x90, 0x84, 0xcb, 0xa7, 0x34, 0xcd, + 0x28, 0x0b, 0x71, 0x9c, 0x3d, 0xfa, 0x8c, 0x21, 0x55, 0xa3, 0x6a, 0xd1, 0xf4, 0x49, 0xb5, 0x08, + 0x85, 0x9a, 0x56, 0x35, 0x28, 0xc6, 0x1c, 0x7d, 0x18, 0x96, 0xac, 0x1d, 0xd7, 0x0b, 0x12, 0x37, + 0xdf, 0xe2, 0x0c, 0xdb, 0x46, 0xe7, 0xba, 0x9d, 0xe2, 0x52, 0xa9, 0x2f, 0x16, 0x3e, 0x82, 0x82, + 0xf9, 0xd5, 0x1c, 0x4c, 0x71, 0x23, 0x5f, 0xa8, 0xae, 0xaf, 0x1b, 0xf0, 0x60, 0xb5, 0xed, 0x79, + 0xc4, 0x09, 0x2a, 0x01, 0x69, 0xf5, 0x2a, 0x2e, 0xe3, 0x44, 0x15, 0xd7, 0x43, 0xdd, 0x4e, 0xf1, + 0xc1, 0x95, 0x23, 0xf8, 0xe3, 0x23, 0x5b, 0x87, 0xfe, 0xca, 0x00, 0x53, 0x20, 0x94, 0xad, 0xea, + 0x7e, 0xdd, 0x73, 0xdb, 0x4e, 0xad, 0xb7, 0x13, 0x99, 0x13, 0xed, 0xc4, 0x23, 0xdd, 0x4e, 0xd1, + 0x5c, 0xb9, 0x6b, 0x2b, 0xf0, 0x00, 0x2d, 0x45, 0xcf, 0xc2, 0xbc, 0xc0, 0xba, 0x70, 0xbb, 0x45, + 0x3c, 0x9b, 0x9a, 0xd3, 0xe2, 0x3e, 0x3d, 0x0c, 0x51, 0x88, 0x23, 0xe0, 0xde, 0x3a, 0xc8, 0x87, + 0x89, 0x5b, 0xc4, 0xae, 0xef, 0x05, 0xd2, 0x7c, 0x1a, 0x31, 0x2e, 0x41, 0x1c, 0xf8, 0x6f, 0x70, + 0x9a, 0xe5, 0xc9, 0x6e, 0xa7, 0x38, 0x21, 0xfe, 0x60, 0xc9, 0x09, 0x6d, 0xc2, 0x0c, 0x3f, 0x82, + 0x6d, 0xd9, 0x4e, 0x7d, 0xcb, 0x75, 0xf8, 0x6d, 0x7e, 0xa1, 0xfc, 0x88, 0x54, 0xf8, 0x95, 0x08, + 0xf4, 0x4e, 0xa7, 0x38, 0x25, 0x7f, 0x6f, 0x1f, 0xb6, 0x08, 0x8e, 0xd5, 0x36, 0xff, 0x60, 0x0c, + 0x40, 0x2e, 0x57, 0xd2, 0x42, 0x3f, 0x03, 0x05, 0x9f, 0x04, 0x9c, 0xab, 0x70, 0x9e, 0xf3, 0x3b, + 0x09, 0x59, 0x88, 0x43, 0x38, 0xda, 0x87, 0x5c, 0xcb, 0x6a, 0xfb, 0x44, 0x4c, 0xfe, 0xe5, 0x54, + 0x26, 0x7f, 0x8b, 0x52, 0xe4, 0x67, 0x2e, 0xf6, 0x13, 0x73, 0x1e, 0xe8, 0x93, 0x06, 0x00, 0x89, + 0x4e, 0xd8, 0xc8, 0xbe, 0x0f, 0xc1, 0x32, 0x9c, 0x53, 0x3a, 0x06, 0xe5, 0x99, 0x6e, 0xa7, 0x08, + 0xda, 0xd4, 0x6b, 0x6c, 0xd1, 0x2d, 0xc8, 0x5b, 0x52, 0xe6, 0x8f, 0x9d, 0x84, 0xcc, 0x67, 0x47, + 0x21, 0xb5, 0x68, 0x15, 0x33, 0xf4, 0x29, 0x03, 0x66, 0x7c, 0x12, 0x88, 0xa9, 0xa2, 0x92, 0x47, + 0x18, 0xbc, 0x23, 0x2e, 0xba, 0x4a, 0x84, 0x26, 0x97, 0xa0, 0xd1, 0x32, 0x1c, 0xe3, 0x6b, 0xfe, + 0xcd, 0x14, 0xcc, 0xc8, 0x25, 0x13, 0xda, 0xb0, 0xdc, 0x85, 0xd1, 0xc7, 0x86, 0x5d, 0xd1, 0x81, + 0x38, 0x8a, 0x4b, 0x2b, 0xf3, 0x45, 0x19, 0x35, 0x61, 0x55, 0xe5, 0x8a, 0x0e, 0xc4, 0x51, 0x5c, + 0xd4, 0x84, 0x9c, 0x1f, 0x90, 0x96, 0xbc, 0xf1, 0x1b, 0xf1, 0x42, 0x2a, 0xdc, 0x09, 0xa1, 0x4f, + 0x9f, 0xfe, 0xf3, 0x31, 0xe7, 0xc2, 0xbc, 0x70, 0x41, 0xc4, 0x31, 0x27, 0x96, 0x41, 0x3a, 0x2b, + 0x31, 0xea, 0xf3, 0xe3, 0xb3, 0x11, 0x2d, 0xc3, 0x31, 0xf6, 0x09, 0x66, 0x6d, 0xee, 0x04, 0xcd, + 0xda, 0xe7, 0x21, 0xdf, 0xb4, 0x6e, 0x57, 0xda, 0x5e, 0xfd, 0xf8, 0xe6, 0xb3, 0x08, 0xc6, 0xe1, + 0x54, 0xb0, 0xa2, 0x87, 0x5e, 0x31, 0xb4, 0xcd, 0x35, 0xc1, 0x88, 0xdf, 0x48, 0x77, 0x73, 0x29, + 0xad, 0xd0, 0x77, 0x9b, 0xf5, 0x18, 0x99, 0xf9, 0x7b, 0x6e, 0x64, 0x52, 0x83, 0x89, 0x6f, 0x10, + 0x65, 0x30, 0x15, 0x4e, 0xd4, 0x60, 0x5a, 0x89, 0x30, 0xc3, 0x31, 0xe6, 0xac, 0x3d, 0x7c, 0xcf, + 0xa9, 0xf6, 0xc0, 0x89, 0xb6, 0xa7, 0x12, 0x61, 0x86, 0x63, 0xcc, 0xfb, 0x9f, 0xac, 0x26, 0x4f, + 0xe6, 0x64, 0x35, 0x95, 0xc2, 0xc9, 0xea, 0x68, 0xa3, 0x73, 0x7a, 0x54, 0xa3, 0x13, 0x5d, 0x06, + 0x54, 0x3b, 0x74, 0xac, 0xa6, 0x5d, 0x15, 0xc2, 0x92, 0x29, 0x88, 0x19, 0x76, 0xf2, 0x5e, 0x12, + 0x82, 0x0c, 0xad, 0xf6, 0x60, 0xe0, 0x84, 0x5a, 0x28, 0x80, 0x7c, 0x4b, 0xda, 0x16, 0xb3, 0x69, + 0xac, 0x7e, 0x69, 0x6b, 0xf0, 0x4b, 0x61, 0xba, 0xf1, 0x64, 0x09, 0x56, 0x9c, 0xcc, 0xff, 0x32, + 0x60, 0x6e, 0xa5, 0xe1, 0xb6, 0x6b, 0x37, 0xac, 0xa0, 0xba, 0xc7, 0x6f, 0x30, 0xd1, 0x33, 0x90, + 0xb7, 0x9d, 0x80, 0x78, 0x07, 0x56, 0x43, 0x68, 0x14, 0x53, 0x5e, 0xf2, 0xae, 0x89, 0xf2, 0x3b, + 0x9d, 0xe2, 0xcc, 0x6a, 0xdb, 0x63, 0xa1, 0x81, 0x5c, 0xbe, 0x60, 0x55, 0x07, 0x7d, 0xc9, 0x80, + 0x79, 0x7e, 0x07, 0xba, 0x6a, 0x05, 0xd6, 0xd5, 0x36, 0xf1, 0x6c, 0x22, 0x6f, 0x41, 0x47, 0x14, + 0x2d, 0xf1, 0xb6, 0x4a, 0x06, 0x87, 0xa1, 0x11, 0xb9, 0x11, 0xe7, 0x8c, 0x7b, 0x1b, 0x63, 0x7e, + 0x2e, 0x0b, 0xf7, 0xf7, 0xa5, 0x85, 0x96, 0x20, 0x63, 0xd7, 0x44, 0xd7, 0x41, 0xd0, 0xcd, 0xac, + 0xd5, 0x70, 0xc6, 0xae, 0xa1, 0x65, 0x66, 0x0f, 0x79, 0xc4, 0xf7, 0xe5, 0x85, 0x58, 0x41, 0x99, + 0x2e, 0xa2, 0x14, 0x6b, 0x18, 0xa8, 0x08, 0xb9, 0x86, 0xb5, 0x43, 0x1a, 0xc2, 0xd6, 0x65, 0x16, + 0xd6, 0x3a, 0x2d, 0xc0, 0xbc, 0x1c, 0xfd, 0x92, 0x01, 0xc0, 0x1b, 0x48, 0x2d, 0x65, 0xa1, 0xd7, + 0x70, 0xba, 0xc3, 0x44, 0x29, 0xf3, 0x56, 0x86, 0xff, 0xb1, 0xc6, 0x15, 0x6d, 0xc3, 0x38, 0x35, + 0xb6, 0xdc, 0xda, 0xb1, 0xd5, 0x18, 0xbb, 0x00, 0xd8, 0x62, 0x34, 0xb0, 0xa0, 0x45, 0xc7, 0xca, + 0x23, 0x41, 0xdb, 0x73, 0xe8, 0xd0, 0x32, 0xc5, 0x95, 0xe7, 0xad, 0xc0, 0xaa, 0x14, 0x6b, 0x18, + 0xe6, 0x1f, 0x67, 0x60, 0x21, 0xa9, 0xe9, 0x54, 0x3f, 0x8c, 0xf3, 0xd6, 0x8a, 0x63, 0xdb, 0xfb, + 0xd3, 0x1f, 0x1f, 0x71, 0x9d, 0xaf, 0x2e, 0xbd, 0x45, 0xc0, 0x91, 0xe0, 0x8b, 0xde, 0xaf, 0x46, + 0x28, 0x73, 0xcc, 0x11, 0x52, 0x94, 0x63, 0xa3, 0xf4, 0x10, 0x8c, 0xf9, 0x74, 0xe6, 0xb3, 0x51, + 0xe7, 0x3a, 0x9b, 0x23, 0x06, 0xa1, 0x18, 0x6d, 0xc7, 0x0e, 0x44, 0xbc, 0xae, 0xc2, 0xb8, 0xe6, + 0xd8, 0x01, 0x66, 0x10, 0xf3, 0x0b, 0x19, 0x58, 0xea, 0xdf, 0x29, 0xf4, 0x05, 0x03, 0xa0, 0x46, + 0x4d, 0x69, 0xba, 0x24, 0x65, 0xf8, 0x83, 0x75, 0x52, 0x63, 0xb8, 0x2a, 0x39, 0x85, 0xb1, 0x30, + 0xaa, 0xc8, 0xc7, 0x5a, 0x43, 0xd0, 0x63, 0x72, 0xe9, 0x6f, 0x5a, 0x4d, 0x69, 0x80, 0xaa, 0x3a, + 0x1b, 0x0a, 0x82, 0x35, 0x2c, 0x7a, 0x56, 0x72, 0xac, 0x26, 0xf1, 0x5b, 0x96, 0x0a, 0xc8, 0x66, + 0x67, 0xa5, 0x4d, 0x59, 0x88, 0x43, 0xb8, 0xd9, 0x80, 0x87, 0x07, 0x68, 0x67, 0x4a, 0xc1, 0xb1, + 0xe6, 0x7f, 0x1a, 0x70, 0x66, 0xa5, 0xd1, 0xf6, 0x03, 0xe2, 0xfd, 0x9f, 0x09, 0x2d, 0xfa, 0x6f, + 0x03, 0x1e, 0xe8, 0xd3, 0xe7, 0x7b, 0x10, 0x61, 0xf4, 0x62, 0x34, 0xc2, 0xe8, 0xda, 0xa8, 0x4b, + 0x3a, 0xb1, 0x1f, 0x7d, 0x02, 0x8d, 0x02, 0x98, 0xa6, 0x52, 0xab, 0xe6, 0xd6, 0x53, 0xd2, 0x9b, + 0x0f, 0x43, 0xee, 0xa3, 0x54, 0xff, 0xc4, 0xd7, 0x18, 0x53, 0x4a, 0x98, 0xc3, 0xcc, 0xf7, 0x81, + 0x08, 0xc7, 0x89, 0x6d, 0x1e, 0x63, 0x90, 0xcd, 0x63, 0xfe, 0x7d, 0x06, 0xb4, 0x33, 0xf6, 0x3d, + 0x58, 0x94, 0x4e, 0x64, 0x51, 0x8e, 0x78, 0x6a, 0xd6, 0x3c, 0x06, 0xfd, 0xe2, 0xee, 0x0f, 0x62, + 0x71, 0xf7, 0x9b, 0xa9, 0x71, 0x3c, 0x3a, 0xec, 0xfe, 0xbb, 0x06, 0x3c, 0x10, 0x22, 0xf7, 0xba, + 0xbf, 0xee, 0x2e, 0x61, 0x9e, 0x84, 0x49, 0x2b, 0xac, 0x26, 0xd6, 0x80, 0x7a, 0x6a, 0xa2, 0x51, + 0xc4, 0x3a, 0x5e, 0x18, 0xe5, 0x9b, 0x3d, 0x66, 0x94, 0xef, 0xd8, 0xd1, 0x51, 0xbe, 0xe6, 0x8f, + 0x32, 0x70, 0xb6, 0xb7, 0x67, 0x72, 0x6f, 0x0c, 0x76, 0x3b, 0xfc, 0x14, 0x4c, 0x05, 0xa2, 0x82, + 0x26, 0xe9, 0xd5, 0x43, 0xa9, 0x6d, 0x0d, 0x86, 0x23, 0x98, 0xb4, 0x66, 0x95, 0xef, 0xca, 0x4a, + 0xd5, 0x6d, 0xc9, 0x18, 0x71, 0x55, 0x73, 0x45, 0x83, 0xe1, 0x08, 0xa6, 0x8a, 0xbe, 0x1b, 0x3b, + 0xf1, 0xe8, 0xbb, 0x0a, 0x9c, 0x96, 0xf1, 0x46, 0x17, 0x5d, 0x6f, 0xc5, 0x6d, 0xb6, 0x1a, 0x44, + 0x44, 0x89, 0xd3, 0xc6, 0x9e, 0x15, 0x55, 0x4e, 0xe3, 0x24, 0x24, 0x9c, 0x5c, 0xd7, 0xfc, 0x6e, + 0x16, 0x4e, 0x85, 0xc3, 0xbe, 0xe2, 0x3a, 0x35, 0x9b, 0x45, 0x6d, 0x3d, 0x0d, 0x63, 0xc1, 0x61, + 0x4b, 0x0e, 0xf6, 0xff, 0x93, 0xcd, 0xd9, 0x3e, 0x6c, 0xd1, 0xd9, 0x3e, 0x93, 0x50, 0x85, 0x39, + 0x20, 0x59, 0x25, 0xb4, 0xae, 0x76, 0x07, 0x9f, 0x81, 0x27, 0xa2, 0xab, 0xf9, 0x4e, 0xa7, 0x98, + 0xf0, 0x4e, 0x70, 0x59, 0x51, 0x8a, 0xae, 0x79, 0x74, 0x13, 0x66, 0x1a, 0x96, 0x1f, 0x5c, 0x6b, + 0xd5, 0xac, 0x80, 0x6c, 0xdb, 0x4d, 0x22, 0xf6, 0xdc, 0x30, 0xa1, 0xd7, 0xea, 0xc6, 0x74, 0x3d, + 0x42, 0x09, 0xc7, 0x28, 0xa3, 0x03, 0x40, 0xb4, 0x64, 0xdb, 0xb3, 0x1c, 0x9f, 0xf7, 0x8a, 0xf2, + 0x1b, 0x3e, 0xd4, 0x5b, 0x1d, 0xcb, 0xd6, 0x7b, 0xa8, 0xe1, 0x04, 0x0e, 0xe8, 0x11, 0x18, 0xf7, + 0x88, 0xe5, 0x8b, 0xc9, 0x2c, 0x84, 0xfb, 0x1f, 0xb3, 0x52, 0x2c, 0xa0, 0xfa, 0x86, 0x1a, 0xbf, + 0xcb, 0x86, 0xfa, 0x81, 0x01, 0x33, 0xe1, 0x34, 0xdd, 0x03, 0x25, 0xd9, 0x8c, 0x2a, 0xc9, 0x4b, + 0x69, 0x89, 0xc4, 0x3e, 0x7a, 0xf1, 0xcf, 0xc7, 0xf5, 0xfe, 0xb1, 0xd0, 0xdb, 0x8f, 0x41, 0x41, + 0xee, 0x6a, 0x69, 0x7d, 0x8e, 0x78, 0xba, 0x8d, 0xd8, 0x25, 0xda, 0x93, 0x11, 0xc1, 0x04, 0x87, + 0xfc, 0xa8, 0x5a, 0xae, 0x09, 0x95, 0x2b, 0x96, 0xbd, 0x52, 0xcb, 0x52, 0x15, 0x27, 0xa9, 0x65, + 0x59, 0x07, 0x5d, 0x83, 0x33, 0x2d, 0xcf, 0x65, 0xcf, 0x08, 0x57, 0x89, 0x55, 0x6b, 0xd8, 0x0e, + 0x91, 0x2e, 0x04, 0x7e, 0x61, 0xff, 0x40, 0xb7, 0x53, 0x3c, 0xb3, 0x95, 0x8c, 0x82, 0xfb, 0xd5, + 0x8d, 0x3e, 0x7d, 0x19, 0x1b, 0xe0, 0xe9, 0xcb, 0xaf, 0x28, 0x47, 0x1d, 0xf1, 0xc5, 0x03, 0x94, + 0x0f, 0xa6, 0x35, 0x95, 0x09, 0x62, 0x3d, 0x5c, 0x52, 0x25, 0xc1, 0x14, 0x2b, 0xf6, 0xfd, 0xbd, + 0x41, 0xe3, 0xc7, 0xf4, 0x06, 0x85, 0x11, 0xcc, 0x13, 0x3f, 0xc9, 0x08, 0xe6, 0xfc, 0x9b, 0x2a, + 0x82, 0xf9, 0xd5, 0x1c, 0xcc, 0xc5, 0x2d, 0x90, 0x93, 0x7f, 0xd6, 0xf3, 0xeb, 0x06, 0xcc, 0xc9, + 0xdd, 0xc3, 0x79, 0x12, 0xe9, 0xe7, 0x5f, 0x4f, 0x69, 0xd3, 0x72, 0x5b, 0x4a, 0x3d, 0x3c, 0xdd, + 0x8e, 0x71, 0xc3, 0x3d, 0xfc, 0xd1, 0x0b, 0x30, 0xa9, 0xdc, 0xe1, 0xc7, 0x7a, 0xe3, 0x33, 0xcb, + 0xac, 0xa8, 0x90, 0x04, 0xd6, 0xe9, 0xa1, 0x57, 0x0d, 0x80, 0xaa, 0x54, 0x73, 0x72, 0x77, 0x5d, + 0x4d, 0x6b, 0x77, 0x29, 0x05, 0x1a, 0x1a, 0xcb, 0xaa, 0xc8, 0xc7, 0x1a, 0x63, 0xf4, 0x39, 0xe6, + 0x08, 0x57, 0xd6, 0x1d, 0xdd, 0x4f, 0xd9, 0xd1, 0x83, 0x4e, 0x8f, 0x30, 0x4c, 0x43, 0x53, 0x4a, + 0x03, 0xf9, 0x38, 0xd2, 0x08, 0xf3, 0x69, 0x50, 0x61, 0x82, 0x54, 0x6c, 0xb1, 0x40, 0xc1, 0x2d, + 0x2b, 0xd8, 0x13, 0x4b, 0x50, 0x89, 0xad, 0x8b, 0x12, 0x80, 0x43, 0x1c, 0xf3, 0x23, 0x30, 0xf3, + 0xac, 0x67, 0xb5, 0xf6, 0x6c, 0xe6, 0x70, 0xa6, 0xe7, 0xa4, 0xb7, 0xc3, 0x84, 0x55, 0xab, 0x25, + 0x3d, 0xdb, 0x2e, 0xf1, 0x62, 0x2c, 0xe1, 0x83, 0x1d, 0x89, 0xbe, 0x69, 0xc0, 0xc2, 0x9a, 0x1f, + 0xd8, 0xee, 0x2a, 0xf1, 0x03, 0x2a, 0x2b, 0xe9, 0x8e, 0x6a, 0x37, 0x06, 0x09, 0x63, 0x5d, 0x85, + 0x39, 0x71, 0x2b, 0xd6, 0xde, 0xf1, 0x49, 0xa0, 0x19, 0xa7, 0x6a, 0x71, 0xae, 0xc4, 0xe0, 0xb8, + 0xa7, 0x06, 0xa5, 0x22, 0xae, 0xc7, 0x42, 0x2a, 0xd9, 0x28, 0x95, 0x4a, 0x0c, 0x8e, 0x7b, 0x6a, + 0x98, 0xdf, 0xc9, 0xc2, 0x29, 0xd6, 0x8d, 0x58, 0x08, 0xfa, 0x67, 0xfa, 0x85, 0xa0, 0x8f, 0xb8, + 0x3e, 0x19, 0xaf, 0x63, 0x04, 0xa0, 0xff, 0x9a, 0x01, 0xb3, 0xb5, 0xe8, 0x48, 0xa7, 0xe3, 0x73, + 0x48, 0x9a, 0x43, 0x1e, 0xee, 0x12, 0x2b, 0xc4, 0x71, 0xfe, 0xe8, 0xf3, 0x06, 0xcc, 0x46, 0x9b, + 0x29, 0x45, 0xd6, 0x09, 0x0c, 0x92, 0x8a, 0x4f, 0x8d, 0x96, 0xfb, 0x38, 0xde, 0x04, 0xf3, 0x6f, + 0x0d, 0x31, 0xa5, 0x27, 0x11, 0x5f, 0x8d, 0x6e, 0x41, 0x21, 0x68, 0xf8, 0xbc, 0x50, 0xf4, 0x76, + 0xc4, 0x63, 0xce, 0xf6, 0x7a, 0x85, 0x91, 0xd3, 0x2c, 0x11, 0x51, 0x42, 0x2d, 0x2a, 0xc9, 0xcb, + 0xfc, 0x8a, 0x01, 0x85, 0xcb, 0xee, 0x8e, 0xd8, 0xce, 0x1f, 0x4e, 0xc1, 0x89, 0xa0, 0x6c, 0x0d, + 0x75, 0xff, 0x14, 0x9a, 0xaf, 0xcf, 0x44, 0x5c, 0x08, 0x0f, 0x6a, 0xb4, 0x97, 0x59, 0xba, 0x13, + 0x4a, 0xea, 0xb2, 0xbb, 0xd3, 0xd7, 0x43, 0xf5, 0x3b, 0x39, 0x98, 0x7e, 0xce, 0x3a, 0x24, 0x4e, + 0x60, 0x0d, 0x2f, 0x80, 0xe8, 0xa9, 0xbc, 0xc5, 0xc2, 0x2d, 0x35, 0xfb, 0x31, 0x3c, 0x95, 0x87, + 0x20, 0xac, 0xe3, 0x85, 0x72, 0x85, 0x67, 0x5f, 0x48, 0x92, 0x08, 0x2b, 0x31, 0x38, 0xee, 0xa9, + 0x81, 0x2e, 0x03, 0x12, 0x6f, 0xc9, 0x4a, 0xd5, 0xaa, 0xdb, 0x76, 0xb8, 0x64, 0xe1, 0x07, 0x76, + 0x75, 0x90, 0xd9, 0xe8, 0xc1, 0xc0, 0x09, 0xb5, 0xd0, 0x87, 0x60, 0xb1, 0xca, 0x28, 0x0b, 0xb3, + 0x56, 0xa7, 0xc8, 0x8f, 0x36, 0x2a, 0xd4, 0x79, 0xa5, 0x0f, 0x1e, 0xee, 0x4b, 0x81, 0xb6, 0xd4, + 0x0f, 0x5c, 0xcf, 0xaa, 0x13, 0x9d, 0xee, 0x78, 0xb4, 0xa5, 0x95, 0x1e, 0x0c, 0x9c, 0x50, 0x0b, + 0x7d, 0x02, 0x0a, 0xc1, 0x9e, 0x47, 0xfc, 0x3d, 0xb7, 0x51, 0x13, 0x17, 0xd2, 0x23, 0x7a, 0x71, + 0xc4, 0xec, 0x6f, 0x4b, 0xaa, 0xda, 0xf2, 0x96, 0x45, 0x38, 0xe4, 0x89, 0x3c, 0x18, 0xf7, 0xab, + 0x6e, 0x8b, 0xf8, 0xc2, 0x1c, 0xbc, 0x9c, 0x0a, 0x77, 0xe6, 0x95, 0xd0, 0xfc, 0x47, 0x8c, 0x03, + 0x16, 0x9c, 0xcc, 0x6f, 0x65, 0x60, 0x4a, 0x47, 0x1c, 0x40, 0x44, 0x7c, 0xd2, 0x80, 0xa9, 0xaa, + 0xeb, 0x04, 0x9e, 0xdb, 0xe0, 0xbe, 0x11, 0xbe, 0x41, 0x46, 0x4c, 0x51, 0xc0, 0x48, 0xad, 0x92, + 0xc0, 0xb2, 0x1b, 0x9a, 0x9b, 0x45, 0x63, 0x83, 0x23, 0x4c, 0xd1, 0xa7, 0x0d, 0x98, 0x0d, 0x23, + 0x75, 0x42, 0x27, 0x4d, 0xaa, 0x0d, 0x51, 0x12, 0xf7, 0x42, 0x94, 0x13, 0x8e, 0xb3, 0x36, 0x77, + 0x60, 0x2e, 0x3e, 0xdb, 0x74, 0x28, 0x5b, 0x96, 0xd8, 0xeb, 0xd9, 0x70, 0x28, 0xb7, 0x2c, 0xdf, + 0xc7, 0x0c, 0x82, 0xde, 0x01, 0xf9, 0xa6, 0xe5, 0xd5, 0x6d, 0xc7, 0x6a, 0xb0, 0x51, 0xcc, 0x6a, + 0x02, 0x49, 0x94, 0x63, 0x85, 0x61, 0xfe, 0x70, 0x0c, 0x26, 0x35, 0x2b, 0xfe, 0xe4, 0x2d, 0xf2, + 0xc8, 0xf3, 0xf6, 0x6c, 0x8a, 0xcf, 0xdb, 0x9f, 0x07, 0xd8, 0xb5, 0x1d, 0xdb, 0xdf, 0x3b, 0xe6, + 0xc3, 0x79, 0x76, 0x99, 0x77, 0x51, 0x51, 0xc0, 0x1a, 0xb5, 0xf0, 0xc6, 0x24, 0x77, 0x44, 0x3a, + 0x91, 0x57, 0x0d, 0x4d, 0x79, 0x8c, 0xa7, 0x71, 0x43, 0xac, 0x4d, 0xcc, 0xb2, 0x54, 0x26, 0x17, + 0x9c, 0xc0, 0x3b, 0x3c, 0x52, 0xc7, 0x6c, 0x43, 0xde, 0x23, 0x7e, 0xbb, 0x49, 0xcf, 0x16, 0x13, + 0x43, 0x0f, 0x03, 0xbb, 0x5d, 0xc7, 0xa2, 0x3e, 0x56, 0x94, 0x96, 0x9e, 0x86, 0xe9, 0x48, 0x13, + 0xd0, 0x1c, 0x64, 0xf7, 0xc9, 0x21, 0x5f, 0x27, 0x98, 0xfe, 0x44, 0x0b, 0x91, 0x7b, 0x25, 0x31, + 0x2c, 0xef, 0xcd, 0x3c, 0x65, 0x98, 0x2e, 0x24, 0x1e, 0x15, 0x8f, 0xe3, 0xf6, 0xa7, 0x73, 0xd1, + 0xd0, 0x5e, 0xce, 0xab, 0xb9, 0xe0, 0x31, 0x14, 0x1c, 0x66, 0xfe, 0x68, 0x1c, 0xc4, 0xa5, 0xe7, + 0x00, 0xc2, 0x47, 0xbf, 0xeb, 0xc8, 0x1c, 0xe3, 0xae, 0xe3, 0x32, 0x4c, 0xd9, 0x8e, 0x1d, 0xd8, + 0x56, 0x83, 0xb9, 0x01, 0x84, 0x72, 0x94, 0xe1, 0x94, 0x53, 0x6b, 0x1a, 0x2c, 0x81, 0x4e, 0xa4, + 0x2e, 0xba, 0x0a, 0x39, 0xa6, 0x3d, 0xc4, 0x02, 0x1e, 0xfe, 0x66, 0x96, 0x5d, 0xca, 0xf3, 0x37, + 0x16, 0x9c, 0x12, 0xb3, 0xe8, 0x79, 0xea, 0x00, 0x75, 0x50, 0x13, 0xeb, 0x38, 0xb4, 0xe8, 0x63, + 0x70, 0xdc, 0x53, 0x83, 0x52, 0xd9, 0xb5, 0xec, 0x46, 0xdb, 0x23, 0x21, 0x95, 0xf1, 0x28, 0x95, + 0x8b, 0x31, 0x38, 0xee, 0xa9, 0x81, 0x76, 0x61, 0x4a, 0x94, 0xf1, 0xc8, 0x98, 0x89, 0x63, 0xf6, + 0x92, 0x45, 0x40, 0x5d, 0xd4, 0x28, 0xe1, 0x08, 0x5d, 0xd4, 0x86, 0x79, 0xdb, 0xa9, 0xba, 0x4e, + 0xb5, 0xd1, 0xf6, 0xed, 0x03, 0x12, 0x3e, 0x70, 0x38, 0x0e, 0xb3, 0xd3, 0xdd, 0x4e, 0x71, 0x7e, + 0x2d, 0x4e, 0x0e, 0xf7, 0x72, 0x40, 0xaf, 0x18, 0x70, 0xba, 0xea, 0x3a, 0x3e, 0x7b, 0x8b, 0x7b, + 0x40, 0x2e, 0x78, 0x9e, 0xeb, 0x71, 0xde, 0x85, 0x63, 0xf2, 0x66, 0xde, 0xa7, 0x95, 0x24, 0x92, + 0x38, 0x99, 0x13, 0x7a, 0x11, 0xf2, 0x2d, 0xcf, 0x3d, 0xb0, 0x6b, 0xc4, 0x13, 0x51, 0x56, 0xeb, + 0x69, 0xe4, 0x06, 0xd8, 0x12, 0x34, 0x43, 0xd1, 0x23, 0x4b, 0xb0, 0xe2, 0x67, 0x7e, 0x35, 0x0f, + 0x33, 0x51, 0x74, 0xf4, 0x71, 0x80, 0x96, 0xe7, 0x36, 0x49, 0xb0, 0x47, 0x54, 0xa0, 0xfa, 0xe6, + 0xa8, 0x4f, 0xd0, 0x25, 0x3d, 0x19, 0xe7, 0x40, 0xc5, 0x45, 0x58, 0x8a, 0x35, 0x8e, 0xc8, 0x83, + 0x89, 0x7d, 0xae, 0x44, 0x85, 0x4d, 0xf1, 0x5c, 0x2a, 0x16, 0x90, 0xe0, 0xcc, 0x22, 0xac, 0x45, + 0x11, 0x96, 0x8c, 0xd0, 0x0e, 0x64, 0x6f, 0x91, 0x9d, 0x74, 0x9e, 0x75, 0xde, 0x20, 0xe2, 0x6c, + 0x52, 0x9e, 0xe8, 0x76, 0x8a, 0xd9, 0x1b, 0x64, 0x07, 0x53, 0xe2, 0xb4, 0x5f, 0x35, 0x7e, 0x63, + 0x2b, 0x44, 0xc5, 0x88, 0xfd, 0x8a, 0x5c, 0xff, 0xf2, 0x7e, 0x89, 0x22, 0x2c, 0x19, 0xa1, 0x17, + 0xa1, 0x70, 0xcb, 0x3a, 0x20, 0xbb, 0x9e, 0xeb, 0x04, 0x22, 0xb8, 0x66, 0xc4, 0xd8, 0xe5, 0x1b, + 0x92, 0x9c, 0xe0, 0xcb, 0xd4, 0xbb, 0x2a, 0xc4, 0x21, 0x3b, 0x74, 0x00, 0x79, 0x87, 0xdc, 0xc2, + 0xa4, 0x61, 0x57, 0x45, 0xd8, 0xe8, 0x88, 0xcb, 0x7a, 0x53, 0x50, 0x13, 0x9c, 0x99, 0xde, 0x93, + 0x65, 0x58, 0xf1, 0xa2, 0x73, 0x79, 0xd3, 0xdd, 0x11, 0x82, 0x6a, 0xc4, 0xb9, 0x54, 0xe7, 0x4c, + 0x3e, 0x97, 0x97, 0xdd, 0x1d, 0x4c, 0x89, 0xd3, 0x3d, 0x52, 0x55, 0x91, 0x1d, 0x42, 0x4c, 0x6d, + 0xa6, 0x1b, 0xd1, 0xc2, 0xf7, 0x48, 0x58, 0x8a, 0x35, 0x8e, 0x74, 0x6c, 0xeb, 0xc2, 0xad, 0x25, + 0x04, 0xd5, 0x88, 0x63, 0x1b, 0x75, 0x92, 0xf1, 0xb1, 0x95, 0x65, 0x58, 0xf1, 0x32, 0xbf, 0x32, + 0x0e, 0x53, 0x7a, 0x2e, 0xa4, 0x01, 0x74, 0xb5, 0xb2, 0x4f, 0x33, 0xc3, 0xd8, 0xa7, 0xf4, 0x78, + 0xa1, 0x79, 0xa5, 0xa5, 0x87, 0x61, 0x2d, 0x35, 0xf3, 0x2c, 0x3c, 0x5e, 0x68, 0x85, 0x3e, 0x8e, + 0x30, 0x1d, 0xe2, 0xa2, 0x9a, 0x1a, 0x39, 0xdc, 0x0c, 0xc8, 0x45, 0x8d, 0x9c, 0x88, 0x62, 0x7f, + 0x0c, 0x20, 0xcc, 0x09, 0x24, 0x6e, 0x2b, 0x94, 0xf5, 0xa4, 0xe5, 0x2a, 0xd2, 0xb0, 0xd0, 0x23, + 0x30, 0x4e, 0x15, 0x25, 0xa9, 0x89, 0x57, 0x84, 0xea, 0x0c, 0x77, 0x91, 0x95, 0x62, 0x01, 0x45, + 0x4f, 0x51, 0x9b, 0x26, 0x54, 0x6f, 0xe2, 0x71, 0xe0, 0x42, 0x68, 0xd3, 0x84, 0x30, 0x1c, 0xc1, + 0xa4, 0x4d, 0x27, 0x54, 0x1b, 0xb1, 0x95, 0xa4, 0x35, 0x9d, 0xa9, 0x28, 0xcc, 0x61, 0xcc, 0xa7, + 0x10, 0xd3, 0x5e, 0x4c, 0x59, 0xe5, 0x34, 0x9f, 0x42, 0x0c, 0x8e, 0x7b, 0x6a, 0xd0, 0xce, 0x88, + 0x8b, 0x96, 0x49, 0x1e, 0x8f, 0xd7, 0xe7, 0x8a, 0xe4, 0x35, 0xdd, 0x32, 0x9f, 0x62, 0x53, 0xff, + 0xfe, 0xf4, 0xf2, 0x7a, 0x0d, 0x6e, 0x9a, 0x8f, 0x66, 0x44, 0x7f, 0x04, 0x66, 0xa2, 0x32, 0x8b, + 0x2e, 0xa8, 0x96, 0xe7, 0xee, 0xda, 0x0d, 0x12, 0xf7, 0xfd, 0x6c, 0xf1, 0x62, 0x2c, 0xe1, 0x83, + 0x39, 0x9f, 0xff, 0x22, 0x0b, 0xa7, 0x36, 0xeb, 0xb6, 0x73, 0x3b, 0xe6, 0xb5, 0x4d, 0xca, 0xb7, + 0x69, 0x0c, 0x9b, 0x6f, 0x33, 0x7c, 0xa4, 0x21, 0x12, 0x9a, 0x26, 0x3f, 0xd2, 0x90, 0xd9, 0x4e, + 0xa3, 0xb8, 0xe8, 0x07, 0x06, 0x3c, 0x68, 0xd5, 0xb8, 0x15, 0x69, 0x35, 0x44, 0x69, 0xc8, 0x54, + 0xee, 0x68, 0x7f, 0x44, 0x9d, 0xd0, 0xdb, 0xf9, 0xe5, 0xd2, 0x11, 0x5c, 0xf9, 0x8c, 0xbf, 0x4d, + 0xf4, 0xe0, 0xc1, 0xa3, 0x50, 0xf1, 0x91, 0xcd, 0x5f, 0xba, 0x02, 0x6f, 0xbd, 0x2b, 0xa3, 0xa1, + 0x56, 0xcb, 0x27, 0x0d, 0x28, 0x70, 0xa7, 0x24, 0x26, 0xbb, 0x54, 0x54, 0x58, 0x2d, 0xfb, 0x3a, + 0xf1, 0x7c, 0x99, 0x08, 0x48, 0x3b, 0x68, 0x95, 0xb6, 0xd6, 0x04, 0x04, 0x6b, 0x58, 0x54, 0x18, + 0xef, 0xdb, 0x4e, 0x4d, 0x4c, 0x93, 0x12, 0xc6, 0xcf, 0xd9, 0x4e, 0x0d, 0x33, 0x88, 0x12, 0xd7, + 0xd9, 0xbe, 0x59, 0x39, 0xbe, 0x6c, 0xc0, 0x0c, 0x7b, 0x83, 0x15, 0x1e, 0x01, 0x9e, 0x54, 0x51, + 0x08, 0xbc, 0x19, 0x67, 0xa3, 0x51, 0x08, 0x77, 0x3a, 0xc5, 0x49, 0xfe, 0x6a, 0x2b, 0x1a, 0x94, + 0xf0, 0x41, 0xe1, 0x37, 0x60, 0xb1, 0x12, 0x99, 0xa1, 0x8f, 0xb5, 0xca, 0x4b, 0x56, 0x91, 0x44, + 0x70, 0x48, 0xcf, 0x7c, 0x09, 0xa6, 0xf4, 0x10, 0x73, 0xf4, 0x24, 0x4c, 0xb6, 0x6c, 0xa7, 0x1e, + 0x7d, 0x8a, 0xa4, 0x3c, 0xa5, 0x5b, 0x21, 0x08, 0xeb, 0x78, 0xac, 0x9a, 0x1b, 0x56, 0x8b, 0x39, + 0x58, 0xb7, 0x5c, 0xbd, 0x5a, 0xf8, 0xc7, 0xfc, 0xc3, 0x2c, 0x9c, 0x4a, 0x78, 0xca, 0x80, 0x5e, + 0x35, 0x60, 0x9c, 0xc5, 0x55, 0xcb, 0x38, 0x83, 0x17, 0x52, 0x7f, 0x2e, 0xb1, 0xcc, 0xc2, 0xb7, + 0xc5, 0x3a, 0x56, 0xe2, 0x93, 0x17, 0x62, 0xc1, 0x1c, 0xfd, 0xa6, 0x01, 0x93, 0x96, 0xb6, 0xd5, + 0x78, 0xe8, 0xc5, 0x4e, 0xfa, 0x8d, 0xe9, 0xd9, 0x59, 0x5a, 0xc8, 0x58, 0xb8, 0x91, 0xf4, 0xb6, + 0x2c, 0xbd, 0x07, 0x26, 0xb5, 0x2e, 0x0c, 0xb3, 0x43, 0x96, 0x9e, 0x81, 0xb9, 0x91, 0x76, 0xd8, + 0x07, 0x60, 0xd8, 0xbc, 0x56, 0x54, 0x61, 0xdd, 0xd2, 0x1f, 0x46, 0xaa, 0x11, 0x17, 0x2f, 0x23, + 0x05, 0xd4, 0xdc, 0x81, 0xb9, 0xf8, 0x21, 0x27, 0xf5, 0x9b, 0xc6, 0x77, 0xc1, 0x90, 0x99, 0xa8, + 0xcc, 0xbf, 0xcc, 0xc0, 0x84, 0x78, 0x0f, 0x75, 0x0f, 0xa2, 0x2d, 0xf7, 0x23, 0x57, 0x25, 0x6b, + 0xa9, 0x3c, 0xe3, 0xea, 0x1b, 0x6a, 0xe9, 0xc7, 0x42, 0x2d, 0x9f, 0x4b, 0x87, 0xdd, 0xd1, 0x71, + 0x96, 0x5f, 0x1e, 0x83, 0xd9, 0xd8, 0xfb, 0x32, 0x6a, 0xaa, 0xf4, 0x84, 0x17, 0x5d, 0x4b, 0xf5, + 0x09, 0x9b, 0x8a, 0x04, 0x3e, 0x3a, 0xd2, 0xc8, 0x8f, 0x24, 0xfc, 0xbb, 0x9a, 0x5a, 0xae, 0xe0, + 0x9f, 0xe6, 0xfe, 0x1b, 0x36, 0x72, 0xe6, 0x9f, 0x0d, 0xb8, 0xbf, 0xef, 0x33, 0x44, 0x96, 0xaf, + 0xc1, 0x8b, 0x42, 0xc5, 0x86, 0x4c, 0xf9, 0x59, 0xb1, 0xba, 0xb7, 0x88, 0x3f, 0xb1, 0x8f, 0xb3, + 0x47, 0x4f, 0xc0, 0x14, 0x53, 0xad, 0x54, 0xa6, 0x04, 0xa4, 0x25, 0x1c, 0xb5, 0xcc, 0x65, 0x57, + 0xd1, 0xca, 0x71, 0x04, 0xcb, 0xfc, 0x92, 0x01, 0x8b, 0xfd, 0x5e, 0xef, 0x0f, 0x70, 0x30, 0xfc, + 0xb9, 0x58, 0x38, 0x68, 0xb1, 0x27, 0x1c, 0x34, 0x76, 0x34, 0x94, 0x91, 0x9f, 0xda, 0xa9, 0x2c, + 0x7b, 0x97, 0x68, 0xc7, 0xcf, 0x18, 0x70, 0xa6, 0xcf, 0x6e, 0xea, 0x09, 0x0b, 0x36, 0x8e, 0x1d, + 0x16, 0x9c, 0x19, 0x34, 0x2c, 0xd8, 0xfc, 0xeb, 0x2c, 0xcc, 0x89, 0xf6, 0x84, 0xf6, 0xd5, 0x53, + 0x91, 0xa0, 0xda, 0xb7, 0xc5, 0x82, 0x6a, 0x17, 0xe2, 0xf8, 0x3f, 0x8d, 0xa8, 0x7d, 0x73, 0x45, + 0xd4, 0xfe, 0x38, 0x03, 0xa7, 0x13, 0x93, 0x0a, 0xa0, 0x4f, 0x25, 0xa8, 0x86, 0x1b, 0x29, 0x67, + 0x2f, 0x18, 0x50, 0x39, 0x8c, 0x1a, 0x86, 0xfa, 0x79, 0x3d, 0xfc, 0x93, 0x8b, 0xfa, 0xdd, 0x13, + 0xc8, 0xc3, 0x30, 0x64, 0x24, 0xa8, 0xf9, 0xab, 0x59, 0x78, 0x74, 0x50, 0x42, 0x6f, 0xd2, 0x97, + 0x02, 0x7e, 0xe4, 0xa5, 0xc0, 0x3d, 0x52, 0xdb, 0x27, 0xf2, 0x68, 0xe0, 0x2b, 0x59, 0xa5, 0xf6, + 0x7a, 0xd7, 0xe7, 0x40, 0xb7, 0x7a, 0x13, 0xd4, 0xb4, 0x93, 0xa9, 0x06, 0x43, 0x51, 0x38, 0x51, + 0xe1, 0xc5, 0x77, 0x3a, 0xc5, 0x79, 0x91, 0x7e, 0xac, 0x42, 0x02, 0x51, 0x88, 0x65, 0x25, 0xf4, + 0x28, 0xe4, 0x3d, 0x0e, 0x95, 0xb1, 0xd1, 0xe2, 0x6a, 0x94, 0x97, 0x61, 0x05, 0x45, 0x9f, 0xd0, + 0x6c, 0xe1, 0xb1, 0x93, 0x7a, 0xd7, 0x7e, 0xd4, 0x8d, 0xef, 0x0b, 0x90, 0xf7, 0x65, 0xd2, 0x40, + 0xee, 0x96, 0x7f, 0x7c, 0xc0, 0x90, 0x7b, 0x7a, 0x74, 0x92, 0x19, 0x04, 0x79, 0xff, 0x54, 0x7e, + 0x41, 0x45, 0x12, 0x99, 0xea, 0xd4, 0xc2, 0x7d, 0x8c, 0x90, 0x70, 0x62, 0xf9, 0xae, 0x01, 0x93, + 0x62, 0xb6, 0xee, 0xc1, 0x2b, 0x80, 0x9b, 0xd1, 0x57, 0x00, 0x17, 0x52, 0x91, 0x1d, 0x7d, 0x9e, + 0x00, 0xdc, 0x84, 0x29, 0x3d, 0xaf, 0x0c, 0x7a, 0x5e, 0x93, 0x7d, 0xc6, 0x28, 0xf9, 0x2b, 0xa4, + 0x74, 0x0c, 0xe5, 0xa2, 0xf9, 0xc5, 0xbc, 0x1a, 0x45, 0xe6, 0x87, 0xd0, 0xd7, 0xa0, 0x71, 0xe4, + 0x1a, 0xd4, 0x97, 0x40, 0x26, 0xfd, 0x25, 0x70, 0x15, 0xf2, 0x52, 0x40, 0x09, 0x35, 0xfe, 0xb0, + 0x1e, 0xbb, 0x46, 0x6d, 0x01, 0x4a, 0x4c, 0x5b, 0xb8, 0xec, 0xa8, 0xa5, 0xe6, 0x50, 0x09, 0x4e, + 0x45, 0x06, 0xbd, 0x08, 0x93, 0xb7, 0x5c, 0x6f, 0xbf, 0xe1, 0x5a, 0x2c, 0x1d, 0x28, 0xa4, 0x71, + 0xc1, 0xa2, 0x1c, 0x5e, 0x3c, 0x44, 0xfa, 0x46, 0x48, 0x1f, 0xeb, 0xcc, 0x50, 0x09, 0x66, 0x9b, + 0xb6, 0x83, 0x89, 0x55, 0x53, 0xc1, 0xfe, 0x63, 0x3c, 0x5f, 0xa1, 0x34, 0x72, 0x37, 0xa2, 0x60, + 0x1c, 0xc7, 0x47, 0x1f, 0x83, 0xbc, 0x2f, 0x72, 0xd7, 0xa4, 0x73, 0x15, 0xa6, 0xce, 0x8c, 0x9c, + 0x68, 0x38, 0x76, 0xb2, 0x04, 0x2b, 0x86, 0x68, 0x1d, 0x16, 0x3c, 0x91, 0x1d, 0x22, 0xf2, 0x31, + 0x01, 0xbe, 0x3f, 0x59, 0x5a, 0x3c, 0x9c, 0x00, 0xc7, 0x89, 0xb5, 0xa8, 0x15, 0xc3, 0x12, 0x24, + 0xf1, 0x3b, 0x01, 0xcd, 0x8d, 0xce, 0x16, 0x7c, 0x0d, 0x0b, 0xe8, 0x51, 0x8f, 0x47, 0xf2, 0x23, + 0x3c, 0x1e, 0xa9, 0xc0, 0xe9, 0x38, 0x88, 0xe5, 0xb0, 0x60, 0x69, 0x33, 0x34, 0xed, 0xb1, 0x95, + 0x84, 0x84, 0x93, 0xeb, 0xa2, 0x1b, 0x50, 0xf0, 0x08, 0x3b, 0x5f, 0x94, 0xe4, 0xe5, 0xfb, 0xd0, + 0x61, 0x46, 0x58, 0x12, 0xc0, 0x21, 0x2d, 0x3a, 0xef, 0x56, 0x34, 0x65, 0xdf, 0xd5, 0x14, 0x3f, + 0x87, 0x24, 0xe6, 0xbe, 0x4f, 0x6e, 0x19, 0xf3, 0x8d, 0x19, 0x98, 0x8e, 0xf8, 0x16, 0xd0, 0xc3, + 0x90, 0x63, 0x49, 0x3d, 0x98, 0x78, 0xc8, 0x87, 0x22, 0x8c, 0x0f, 0x0e, 0x87, 0xa1, 0xcf, 0x1a, + 0x30, 0xdb, 0x8a, 0x78, 0x61, 0xa5, 0xe4, 0x1c, 0xf1, 0x9e, 0x2f, 0xea, 0xda, 0xd5, 0x92, 0xdd, + 0x46, 0x99, 0xe1, 0x38, 0x77, 0xba, 0x01, 0x45, 0xe4, 0x5d, 0x83, 0x78, 0x0c, 0x5b, 0xd8, 0x38, + 0x8a, 0xc4, 0x4a, 0x14, 0x8c, 0xe3, 0xf8, 0x74, 0x86, 0x59, 0xef, 0x46, 0xf9, 0x4e, 0x4a, 0x49, + 0x12, 0xc0, 0x21, 0x2d, 0xf4, 0x0c, 0xcc, 0x88, 0x4c, 0x6d, 0x5b, 0x6e, 0xed, 0x92, 0xe5, 0xef, + 0x09, 0xe3, 0x5e, 0x1d, 0x46, 0x56, 0x22, 0x50, 0x1c, 0xc3, 0x66, 0x7d, 0x0b, 0xd3, 0xe1, 0x31, + 0x02, 0xe3, 0xd1, 0x5c, 0xc0, 0x2b, 0x51, 0x30, 0x8e, 0xe3, 0xa3, 0x77, 0x68, 0x72, 0x9f, 0xdf, + 0xd3, 0x29, 0x69, 0x90, 0x20, 0xfb, 0x4b, 0x30, 0xdb, 0x66, 0x67, 0xa1, 0x9a, 0x04, 0x8a, 0xfd, + 0xa8, 0x18, 0x5e, 0x8b, 0x82, 0x71, 0x1c, 0x1f, 0x3d, 0x0d, 0xd3, 0x1e, 0x95, 0x6e, 0x8a, 0x00, + 0xbf, 0xbc, 0x53, 0x77, 0x33, 0x58, 0x07, 0xe2, 0x28, 0x2e, 0x7a, 0x16, 0xe6, 0xc3, 0x74, 0x4f, + 0x92, 0x00, 0xbf, 0xcd, 0x53, 0x99, 0x4c, 0x4a, 0x71, 0x04, 0xdc, 0x5b, 0x07, 0xfd, 0x02, 0xcc, + 0x69, 0x23, 0xb1, 0xe6, 0xd4, 0xc8, 0x6d, 0x91, 0x92, 0x87, 0xa5, 0x6d, 0x5f, 0x89, 0xc1, 0x70, + 0x0f, 0x36, 0x7a, 0x2f, 0xcc, 0x54, 0xdd, 0x46, 0x83, 0xc9, 0x38, 0x9e, 0x87, 0x96, 0xe7, 0xde, + 0xe1, 0x59, 0x8a, 0x22, 0x10, 0x1c, 0xc3, 0x44, 0x97, 0x01, 0xb9, 0x3b, 0x3e, 0xf1, 0x0e, 0x48, + 0xed, 0x59, 0xfe, 0xe5, 0x45, 0xaa, 0xe2, 0xa7, 0xa3, 0x71, 0xbf, 0x57, 0x7a, 0x30, 0x70, 0x42, + 0x2d, 0x96, 0x08, 0x45, 0x7b, 0x83, 0x33, 0x93, 0xc6, 0x37, 0x43, 0xe2, 0x27, 0xf7, 0xbb, 0x3e, + 0xc0, 0xf1, 0x60, 0x9c, 0x87, 0x61, 0xa7, 0x93, 0x84, 0x47, 0x4f, 0x49, 0x19, 0xea, 0x08, 0x5e, + 0x8a, 0x05, 0x27, 0xf4, 0x71, 0x28, 0xec, 0xc8, 0xfc, 0xc4, 0x8b, 0x73, 0x69, 0xe8, 0xc5, 0x58, + 0xaa, 0xed, 0xf0, 0x64, 0xaa, 0x00, 0x38, 0x64, 0x89, 0x1e, 0x81, 0xc9, 0x4b, 0x5b, 0x25, 0xb5, + 0x0a, 0xe7, 0xd9, 0xec, 0x8f, 0xd1, 0x2a, 0x58, 0x07, 0xd0, 0x1d, 0xa6, 0xec, 0x25, 0xc4, 0xa6, + 0x38, 0xd4, 0xb7, 0xbd, 0xe6, 0x0f, 0xc5, 0x66, 0xd7, 0x91, 0xb8, 0xb2, 0x78, 0x2a, 0x86, 0x2d, + 0xca, 0xb1, 0xc2, 0x40, 0x2f, 0xc0, 0xa4, 0xd0, 0x17, 0x4c, 0x36, 0x2d, 0x1c, 0xef, 0x7d, 0x17, + 0x0e, 0x49, 0x60, 0x9d, 0x1e, 0xbb, 0x65, 0x62, 0x69, 0x5b, 0xc9, 0xc5, 0x76, 0xa3, 0xb1, 0x78, + 0x9a, 0xc9, 0xcd, 0xf0, 0x96, 0x29, 0x04, 0x61, 0x1d, 0x0f, 0x3d, 0x2e, 0x23, 0x27, 0xde, 0x12, + 0xb9, 0x76, 0x53, 0x91, 0x13, 0xca, 0xca, 0xed, 0x13, 0xd8, 0x7b, 0xe6, 0x2e, 0x21, 0x0b, 0x3b, + 0xb0, 0x24, 0x4d, 0xac, 0xde, 0x4d, 0xb2, 0xb8, 0x18, 0xf1, 0x12, 0x2c, 0xdd, 0xe8, 0x8b, 0x89, + 0x8f, 0xa0, 0x82, 0x76, 0x20, 0x6b, 0x35, 0x76, 0x16, 0xef, 0x4f, 0xc3, 0x56, 0x54, 0x5f, 0x52, + 0xe5, 0xc1, 0x38, 0xa5, 0xf5, 0x32, 0xa6, 0xc4, 0xcd, 0x57, 0x32, 0xca, 0x2b, 0xaf, 0x92, 0x13, + 0xbe, 0xa4, 0xaf, 0x6a, 0x23, 0x8d, 0x2f, 0x05, 0xf6, 0x24, 0xf1, 0xe6, 0x0a, 0x29, 0x71, 0x4d, + 0xb7, 0xd4, 0x3e, 0x4e, 0x25, 0xf3, 0x44, 0x34, 0xf1, 0x22, 0x3f, 0xcd, 0x45, 0x77, 0xb1, 0xf9, + 0xbd, 0x71, 0xe5, 0x84, 0x8a, 0x85, 0x02, 0x78, 0x90, 0xb3, 0xfd, 0xc0, 0x76, 0x53, 0x7c, 0xb6, + 0x15, 0xcb, 0x58, 0xc8, 0x02, 0x58, 0x19, 0x00, 0x73, 0x56, 0x94, 0xa7, 0x53, 0xb7, 0x9d, 0xdb, + 0xa2, 0xfb, 0x57, 0x53, 0xbf, 0xe3, 0xe7, 0x3c, 0x19, 0x00, 0x73, 0x56, 0xe8, 0x26, 0x5f, 0x69, + 0xe9, 0x7c, 0x15, 0x32, 0xfe, 0xb1, 0xd7, 0xe8, 0x8a, 0xa3, 0xbc, 0xfc, 0xa6, 0x2d, 0x6c, 0x98, + 0x11, 0x79, 0x55, 0x36, 0xd6, 0x92, 0x78, 0x55, 0x36, 0xd6, 0x30, 0x65, 0x82, 0x5e, 0x33, 0x00, + 0x2c, 0xf5, 0xd5, 0xd3, 0x74, 0x32, 0xde, 0xf7, 0xfb, 0x8a, 0x2a, 0x8f, 0x39, 0x0b, 0xa1, 0x58, + 0xe3, 0x8c, 0x5e, 0x84, 0x09, 0x8b, 0x7f, 0xaf, 0x43, 0x84, 0xf3, 0xa5, 0xf3, 0x11, 0x9a, 0x58, + 0x0b, 0x58, 0x1c, 0xa3, 0x00, 0x61, 0xc9, 0x90, 0xf2, 0x0e, 0x3c, 0x8b, 0xec, 0xda, 0xfb, 0x22, + 0xae, 0xaf, 0x32, 0x72, 0xda, 0x5d, 0x4a, 0x2c, 0x89, 0xb7, 0x00, 0x61, 0xc9, 0xd0, 0xfc, 0x37, + 0x03, 0xb4, 0x4f, 0xe4, 0x85, 0x81, 0x5e, 0xc6, 0xc0, 0x81, 0x5e, 0x99, 0x21, 0x03, 0xbd, 0xb2, + 0x43, 0x05, 0x7a, 0x8d, 0x0d, 0x1f, 0xe8, 0x95, 0xeb, 0x1f, 0xe8, 0x65, 0xbe, 0x6e, 0xc0, 0x7c, + 0xcf, 0x9a, 0x8c, 0x7f, 0x8a, 0xd8, 0x18, 0xf0, 0x53, 0xc4, 0xab, 0x30, 0x27, 0x52, 0x97, 0x56, + 0x5a, 0x0d, 0x3b, 0xf1, 0x85, 0xeb, 0x76, 0x0c, 0x8e, 0x7b, 0x6a, 0x98, 0x7f, 0x6a, 0xc0, 0xa4, + 0xf6, 0x20, 0x87, 0xf6, 0x83, 0x3d, 0x5c, 0x12, 0xcd, 0x08, 0xb3, 0xb6, 0x32, 0xf7, 0x2a, 0x87, + 0x71, 0x4f, 0x7f, 0x5d, 0x4b, 0x93, 0x17, 0x7a, 0xfa, 0x69, 0x29, 0x16, 0x50, 0x9e, 0x00, 0x8d, + 0xf0, 0xcf, 0x4c, 0x67, 0xf5, 0x04, 0x68, 0xa4, 0x85, 0x19, 0x84, 0xb1, 0xa3, 0xba, 0x5c, 0xc4, + 0x00, 0x6a, 0x49, 0x62, 0x2d, 0x7a, 0x62, 0x63, 0x30, 0x74, 0x16, 0xb2, 0xc4, 0xa9, 0x89, 0x83, + 0x87, 0xfa, 0x04, 0xc9, 0x05, 0xa7, 0x86, 0x69, 0xb9, 0x79, 0x05, 0xa6, 0x2a, 0xa4, 0xea, 0x91, + 0xe0, 0x39, 0x72, 0x38, 0xf0, 0x37, 0x4d, 0xf6, 0xc9, 0x61, 0xfc, 0x9b, 0x26, 0xb4, 0x3a, 0x2d, + 0x37, 0x7f, 0xdf, 0x80, 0x58, 0xce, 0x5e, 0xcd, 0xeb, 0x67, 0xf4, 0xf3, 0xfa, 0x45, 0xfc, 0x53, + 0x99, 0x23, 0xfd, 0x53, 0x97, 0x01, 0x35, 0xad, 0xa0, 0xba, 0x17, 0xc9, 0x50, 0x2d, 0xce, 0x7c, + 0xe1, 0xf3, 0xbf, 0x1e, 0x0c, 0x9c, 0x50, 0xcb, 0x7c, 0xd9, 0x80, 0x9e, 0xaf, 0x44, 0x53, 0x4b, + 0x85, 0x88, 0xcf, 0x45, 0xf0, 0xa3, 0xb0, 0xb2, 0x54, 0xe4, 0x57, 0x22, 0x24, 0x9c, 0x9e, 0x97, + 0xa4, 0xc7, 0x4d, 0xfa, 0x2f, 0xf8, 0x43, 0x29, 0x75, 0x5e, 0x5a, 0x8d, 0x82, 0x71, 0x1c, 0xdf, + 0xbc, 0x0e, 0x79, 0xf9, 0x9a, 0x94, 0x3d, 0xc9, 0x92, 0x27, 0x70, 0xfd, 0x49, 0x16, 0x3d, 0x80, + 0x33, 0x08, 0x1d, 0x26, 0xdf, 0xb1, 0x2f, 0xb9, 0x7e, 0x20, 0x9f, 0xc0, 0x72, 0x3f, 0xdb, 0xe6, + 0x1a, 0x2b, 0xc3, 0x0a, 0x6a, 0xce, 0xc3, 0xac, 0x72, 0xa0, 0x89, 0xe8, 0xa0, 0x6f, 0x65, 0x61, + 0x2a, 0xf2, 0xed, 0xbf, 0xbb, 0x4f, 0xf6, 0xe0, 0xd3, 0x92, 0xe0, 0x08, 0xcb, 0x0e, 0xe9, 0x08, + 0xd3, 0x3d, 0x8f, 0x63, 0x27, 0xeb, 0x79, 0xcc, 0xa5, 0xe3, 0x79, 0x0c, 0x60, 0x42, 0x7c, 0x17, + 0x5d, 0xa8, 0x9e, 0x8d, 0x94, 0x52, 0x41, 0x88, 0x37, 0xd5, 0x4c, 0xf0, 0x4b, 0x01, 0x26, 0x59, + 0x99, 0x5f, 0xcf, 0xc1, 0x4c, 0x34, 0x39, 0xc4, 0x00, 0x33, 0xf9, 0x8e, 0x9e, 0x99, 0x1c, 0xd2, + 0x11, 0x90, 0x1d, 0xd5, 0x11, 0x30, 0x36, 0xaa, 0x23, 0x20, 0x77, 0x0c, 0x47, 0x40, 0xef, 0x31, + 0x7e, 0x7c, 0xe0, 0x63, 0xfc, 0xfb, 0xd4, 0x2d, 0xf6, 0x44, 0xe4, 0xda, 0x27, 0xbc, 0xc5, 0x46, + 0xd1, 0x69, 0x58, 0x71, 0x6b, 0x89, 0xd1, 0x00, 0xf9, 0xbb, 0x1c, 0x78, 0xbc, 0xc4, 0x4b, 0xe7, + 0xe1, 0x7d, 0x8d, 0x6f, 0x19, 0xe2, 0xc2, 0x39, 0xfc, 0xf4, 0x3f, 0x53, 0x7e, 0x10, 0x55, 0x9c, + 0x95, 0x10, 0x84, 0x75, 0x3c, 0xf6, 0x79, 0xaa, 0xe8, 0xf7, 0xb8, 0x98, 0x5f, 0x45, 0xff, 0x3c, + 0x55, 0xec, 0xfb, 0x5d, 0x71, 0x7c, 0xf3, 0x63, 0x70, 0x3a, 0xd1, 0xcc, 0x61, 0xe7, 0x3e, 0x26, + 0x97, 0x49, 0x4d, 0x20, 0x68, 0xcd, 0x88, 0xe5, 0x0e, 0x5c, 0xba, 0xd1, 0x17, 0x13, 0x1f, 0x41, + 0xc5, 0xfc, 0x5a, 0x16, 0x66, 0xa2, 0xdf, 0x36, 0x40, 0xb7, 0xd4, 0xa1, 0x28, 0x95, 0xf3, 0x18, + 0x27, 0xab, 0xe5, 0x66, 0xe8, 0xeb, 0xe1, 0xe0, 0x5f, 0xc3, 0xdf, 0x51, 0x89, 0x22, 0x4e, 0x8e, + 0xb1, 0x70, 0x2d, 0x08, 0x76, 0xec, 0xf3, 0x05, 0x61, 0x0c, 0xb1, 0xb8, 0x36, 0x4f, 0x9d, 0x7b, + 0x18, 0x15, 0xac, 0x58, 0x61, 0x8d, 0x2d, 0xd5, 0x2d, 0x07, 0xc4, 0xb3, 0x77, 0x6d, 0xf5, 0x5d, + 0x26, 0x26, 0xb9, 0xaf, 0x8b, 0x32, 0xac, 0xa0, 0xe6, 0xcb, 0x19, 0x08, 0xbf, 0x42, 0xc7, 0xd2, + 0xa2, 0xfb, 0x9a, 0xcd, 0x22, 0xa6, 0xed, 0xf2, 0xa8, 0xdf, 0x1e, 0x08, 0x29, 0x8a, 0x08, 0x23, + 0xad, 0x04, 0x47, 0x38, 0xfe, 0x04, 0xbe, 0x3e, 0x67, 0xc1, 0x6c, 0xec, 0x85, 0x53, 0xea, 0x61, + 0x9c, 0x5f, 0xcc, 0x42, 0x41, 0xbd, 0x11, 0x43, 0xef, 0x61, 0xb9, 0x85, 0xf7, 0x5c, 0x99, 0xf1, + 0xf9, 0xad, 0x5a, 0x06, 0xe0, 0x3d, 0xb7, 0x76, 0xa7, 0x53, 0x9c, 0x55, 0xc8, 0xbc, 0x08, 0x8b, + 0x0a, 0xd4, 0x42, 0x6c, 0x7b, 0x8d, 0xb8, 0x85, 0x78, 0x0d, 0xaf, 0x63, 0x5a, 0x8e, 0x6e, 0xc3, + 0xc4, 0x1e, 0xb1, 0x6a, 0xc4, 0x93, 0x01, 0x1b, 0x1b, 0x29, 0xbd, 0x6b, 0xbb, 0xc4, 0xa8, 0x86, + 0xc3, 0xc0, 0xff, 0xfb, 0x58, 0xb2, 0xa3, 0x5a, 0x72, 0xc7, 0xad, 0x1d, 0xc6, 0x33, 0x06, 0x97, + 0xdd, 0xda, 0x21, 0x66, 0x10, 0xf4, 0x0c, 0xcc, 0x04, 0x76, 0x93, 0xb8, 0xed, 0x40, 0xff, 0xc6, + 0x57, 0x36, 0xf4, 0xd8, 0x6f, 0x47, 0xa0, 0x38, 0x86, 0x4d, 0xb5, 0xec, 0x4d, 0xdf, 0x75, 0x58, + 0x1a, 0xa0, 0xf1, 0xa8, 0x7b, 0xef, 0x72, 0xe5, 0xca, 0x26, 0xcb, 0x02, 0xa4, 0x30, 0x28, 0xb6, + 0xcd, 0x1e, 0xa2, 0x78, 0x44, 0x5c, 0x98, 0xcd, 0x85, 0xcf, 0x85, 0x79, 0x39, 0x56, 0x18, 0xe6, + 0x35, 0x98, 0x8d, 0x75, 0x55, 0xda, 0xe2, 0x46, 0xb2, 0x2d, 0x3e, 0x58, 0x7a, 0xde, 0x3f, 0x32, + 0x60, 0xbe, 0x67, 0xf3, 0x0e, 0x1a, 0x5f, 0x1c, 0x57, 0x23, 0x99, 0xe3, 0xab, 0x91, 0xec, 0x70, + 0x6a, 0xa4, 0xbc, 0xfc, 0xed, 0x37, 0xce, 0xdd, 0xf7, 0x9d, 0x37, 0xce, 0xdd, 0xf7, 0xbd, 0x37, + 0xce, 0xdd, 0xf7, 0x72, 0xf7, 0x9c, 0xf1, 0xed, 0xee, 0x39, 0xe3, 0x3b, 0xdd, 0x73, 0xc6, 0xf7, + 0xba, 0xe7, 0x8c, 0x7f, 0xea, 0x9e, 0x33, 0x5e, 0xff, 0xe1, 0xb9, 0xfb, 0x9e, 0xcf, 0xcb, 0x65, + 0xf2, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xcc, 0x41, 0xfc, 0x5a, 0xcc, 0x8a, 0x00, 0x00, } func (m *ALBStatus) Marshal() (dAtA []byte, err error) { @@ -7836,6 +7868,18 @@ func (m *RolloutTrafficRouting) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.Traefik != nil { + { + size, err := m.Traefik.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } if m.AppMesh != nil { { size, err := m.AppMesh.MarshalToSizedBuffer(dAtA[:i]) @@ -8341,6 +8385,34 @@ func (m *TemplateStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *TraefikTrafficRouting) 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 *TraefikTrafficRouting) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TraefikTrafficRouting) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.WeightedTraefikServiceName) + copy(dAtA[i:], m.WeightedTraefikServiceName) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.WeightedTraefikServiceName))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *TrafficWeights) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -10327,6 +10399,10 @@ func (m *RolloutTrafficRouting) Size() (n int) { l = m.AppMesh.Size() n += 1 + l + sovGenerated(uint64(l)) } + if m.Traefik != nil { + l = m.Traefik.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -10495,6 +10571,17 @@ func (m *TemplateStatus) Size() (n int) { return n } +func (m *TraefikTrafficRouting) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.WeightedTraefikServiceName) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + func (m *TrafficWeights) Size() (n int) { if m == nil { return 0 @@ -11874,6 +11961,7 @@ func (this *RolloutTrafficRouting) String() string { `SMI:` + strings.Replace(this.SMI.String(), "SMITrafficRouting", "SMITrafficRouting", 1) + `,`, `Ambassador:` + strings.Replace(this.Ambassador.String(), "AmbassadorTrafficRouting", "AmbassadorTrafficRouting", 1) + `,`, `AppMesh:` + strings.Replace(this.AppMesh.String(), "AppMeshTrafficRouting", "AppMeshTrafficRouting", 1) + `,`, + `Traefik:` + strings.Replace(this.Traefik.String(), "TraefikTrafficRouting", "TraefikTrafficRouting", 1) + `,`, `}`, }, "") return s @@ -12006,6 +12094,16 @@ func (this *TemplateStatus) String() string { }, "") return s } +func (this *TraefikTrafficRouting) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&TraefikTrafficRouting{`, + `WeightedTraefikServiceName:` + fmt.Sprintf("%v", this.WeightedTraefikServiceName) + `,`, + `}`, + }, "") + return s +} func (this *TrafficWeights) String() string { if this == nil { return "nil" @@ -26544,6 +26642,42 @@ func (m *RolloutTrafficRouting) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Traefik", 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.Traefik == nil { + m.Traefik = &TraefikTrafficRouting{} + } + if err := m.Traefik.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -28053,6 +28187,88 @@ func (m *TemplateStatus) Unmarshal(dAtA []byte) error { } return nil } +func (m *TraefikTrafficRouting) 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: TraefikTrafficRouting: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TraefikTrafficRouting: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WeightedTraefikServiceName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.WeightedTraefikServiceName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *TrafficWeights) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/pkg/apis/rollouts/v1alpha1/generated.proto b/pkg/apis/rollouts/v1alpha1/generated.proto index d7b97c4ab4..f8520bf966 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.proto +++ b/pkg/apis/rollouts/v1alpha1/generated.proto @@ -1398,6 +1398,9 @@ message RolloutTrafficRouting { // AppMesh holds specific configuration to use AppMesh to route traffic optional AppMeshTrafficRouting appMesh = 6; + + // Traefik holds specific configuration to use Traefik to route traffic + optional TraefikTrafficRouting traefik = 7; } // RunSummary contains the final results from the metric executions @@ -1549,6 +1552,12 @@ message TemplateStatus { optional string podTemplateHash = 11; } +// TraefikTrafficRouting defines the configuration required to use Traefik as traffic router +message TraefikTrafficRouting { + // TraefikServiceName refer to the name of the Traefik service used to route traffic to the service + optional string weightedTraefikServiceName = 1; +} + // TrafficWeights describes the current status of how traffic has been split message TrafficWeights { // Canary is the current traffic weight split to canary ReplicaSet diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index b16dbe5ec1..747fee6e31 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -119,6 +119,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TemplateService": schema_pkg_apis_rollouts_v1alpha1_TemplateService(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TemplateSpec": schema_pkg_apis_rollouts_v1alpha1_TemplateSpec(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TemplateStatus": schema_pkg_apis_rollouts_v1alpha1_TemplateStatus(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TraefikTrafficRouting": schema_pkg_apis_rollouts_v1alpha1_TraefikTrafficRouting(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TrafficWeights": schema_pkg_apis_rollouts_v1alpha1_TrafficWeights(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ValueFrom": schema_pkg_apis_rollouts_v1alpha1_ValueFrom(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.WavefrontMetric": schema_pkg_apis_rollouts_v1alpha1_WavefrontMetric(ref), @@ -4113,11 +4114,17 @@ func schema_pkg_apis_rollouts_v1alpha1_RolloutTrafficRouting(ref common.Referenc Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AppMeshTrafficRouting"), }, }, + "traefik": { + SchemaProps: spec.SchemaProps{ + Description: "Traefik holds specific configuration to use Traefik to route traffic", + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TraefikTrafficRouting"), + }, + }, }, }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ALBTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AmbassadorTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AppMeshTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.IstioTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.NginxTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SMITrafficRouting"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ALBTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AmbassadorTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AppMeshTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.IstioTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.NginxTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SMITrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TraefikTrafficRouting"}, } } @@ -4532,6 +4539,28 @@ func schema_pkg_apis_rollouts_v1alpha1_TemplateStatus(ref common.ReferenceCallba } } +func schema_pkg_apis_rollouts_v1alpha1_TraefikTrafficRouting(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TraefikTrafficRouting defines the configuration required to use Traefik as traffic router", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "weightedTraefikServiceName": { + SchemaProps: spec.SchemaProps{ + Description: "TraefikServiceName refer to the name of the Traefik service used to route traffic to the service", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"weightedTraefikServiceName"}, + }, + }, + } +} + func schema_pkg_apis_rollouts_v1alpha1_TrafficWeights(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/pkg/apis/rollouts/v1alpha1/types.go b/pkg/apis/rollouts/v1alpha1/types.go index fca9c33eb0..3e3ad07532 100644 --- a/pkg/apis/rollouts/v1alpha1/types.go +++ b/pkg/apis/rollouts/v1alpha1/types.go @@ -361,6 +361,14 @@ type RolloutTrafficRouting struct { Ambassador *AmbassadorTrafficRouting `json:"ambassador,omitempty" protobuf:"bytes,5,opt,name=ambassador"` // AppMesh holds specific configuration to use AppMesh to route traffic AppMesh *AppMeshTrafficRouting `json:"appMesh,omitempty" protobuf:"bytes,6,opt,name=appMesh"` + // Traefik holds specific configuration to use Traefik to route traffic + Traefik *TraefikTrafficRouting `json:"traefik,omitempty" protobuf:"bytes,7,opt,name=traefik"` +} + +// TraefikTrafficRouting defines the configuration required to use Traefik as traffic router +type TraefikTrafficRouting struct { + // TraefikServiceName refer to the name of the Traefik service used to route traffic to the service + WeightedTraefikServiceName string `json:"weightedTraefikServiceName" protobuf:"bytes,1,name=weightedTraefikServiceName"` } // AmbassadorTrafficRouting defines the configuration required to use Ambassador as traffic diff --git a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go index 9eed7b6376..23c49d6c09 100644 --- a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go @@ -2193,6 +2193,11 @@ func (in *RolloutTrafficRouting) DeepCopyInto(out *RolloutTrafficRouting) { *out = new(AppMeshTrafficRouting) (*in).DeepCopyInto(*out) } + if in.Traefik != nil { + in, out := &in.Traefik, &out.Traefik + *out = new(TraefikTrafficRouting) + **out = **in + } return } @@ -2406,6 +2411,22 @@ func (in *TemplateStatus) DeepCopy() *TemplateStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TraefikTrafficRouting) DeepCopyInto(out *TraefikTrafficRouting) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TraefikTrafficRouting. +func (in *TraefikTrafficRouting) DeepCopy() *TraefikTrafficRouting { + if in == nil { + return nil + } + out := new(TraefikTrafficRouting) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TrafficWeights) DeepCopyInto(out *TrafficWeights) { *out = *in diff --git a/rollout/trafficrouting.go b/rollout/trafficrouting.go index a037f3700d..2cc0a87c25 100644 --- a/rollout/trafficrouting.go +++ b/rollout/trafficrouting.go @@ -13,6 +13,7 @@ import ( "github.com/argoproj/argo-rollouts/rollout/trafficrouting/istio" "github.com/argoproj/argo-rollouts/rollout/trafficrouting/nginx" "github.com/argoproj/argo-rollouts/rollout/trafficrouting/smi" + "github.com/argoproj/argo-rollouts/rollout/trafficrouting/traefik" "github.com/argoproj/argo-rollouts/utils/conditions" "github.com/argoproj/argo-rollouts/utils/defaults" "github.com/argoproj/argo-rollouts/utils/record" @@ -83,6 +84,14 @@ func (c *Controller) NewTrafficRoutingReconciler(roCtx *rolloutContext) ([]traff Recorder: c.recorder, })) } + if rollout.Spec.Strategy.Canary.TrafficRouting.Traefik != nil { + dynamicClient := traefik.NewDynamicClient(c.dynamicclientset, rollout.GetNamespace()) + trafficReconcilers = append(trafficReconcilers, traefik.NewReconciler(&traefik.ReconcilerConfig{ + Rollout: rollout, + Client: dynamicClient, + Recorder: c.recorder, + })) + } // ensure that the trafficReconcilers is a healthy list and its not empty if len(trafficReconcilers) > 0 { diff --git a/rollout/trafficrouting/traefik/mocks/traefik.go b/rollout/trafficrouting/traefik/mocks/traefik.go new file mode 100644 index 0000000000..e1ce30a648 --- /dev/null +++ b/rollout/trafficrouting/traefik/mocks/traefik.go @@ -0,0 +1,99 @@ +package mocks + +import ( + "context" + + "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/runtime" + + argoRecord "github.com/argoproj/argo-rollouts/utils/record" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/tools/record" +) + +type FakeDynamicClient struct{} + +type FakeClient struct { + IsGetError bool + IsGetErrorManifest bool + UpdateError bool +} + +type FakeService struct { + Weight int +} + +type FakeRecorder struct{} + +var ( + TraefikServiceObj *unstructured.Unstructured + ErrorTraefikServiceObj *unstructured.Unstructured +) + +func (f *FakeRecorder) Eventf(object runtime.Object, opts argoRecord.EventOptions, messageFmt string, args ...interface{}) { +} + +func (f *FakeRecorder) Warnf(object runtime.Object, opts argoRecord.EventOptions, messageFmt string, args ...interface{}) { +} + +func (f *FakeRecorder) K8sRecorder() record.EventRecorder { + return nil +} + +func (f *FakeClient) Create(ctx context.Context, obj *unstructured.Unstructured, options metav1.CreateOptions, subresources ...string) (*unstructured.Unstructured, error) { + return nil, nil +} + +func (f *FakeClient) Get(ctx context.Context, name string, options metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error) { + if f.IsGetError { + return TraefikServiceObj, errors.New("Traefik get error") + } + if f.IsGetErrorManifest { + return ErrorTraefikServiceObj, nil + } + return TraefikServiceObj, nil +} + +func (f *FakeClient) Update(ctx context.Context, obj *unstructured.Unstructured, options metav1.UpdateOptions, subresources ...string) (*unstructured.Unstructured, error) { + if f.UpdateError { + return obj, errors.New("Traefik update error") + } + return obj, nil +} + +func (f *FakeClient) UpdateStatus(ctx context.Context, obj *unstructured.Unstructured, options metav1.UpdateOptions) (*unstructured.Unstructured, error) { + return nil, nil +} + +func (f *FakeClient) Delete(ctx context.Context, name string, options metav1.DeleteOptions, subresources ...string) error { + return nil +} + +func (f *FakeClient) DeleteCollection(ctx context.Context, options metav1.DeleteOptions, listOptions metav1.ListOptions) error { + return nil +} + +func (f *FakeClient) List(ctx context.Context, opts metav1.ListOptions) (*unstructured.UnstructuredList, error) { + return nil, nil +} + +func (f *FakeClient) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return nil, nil +} + +func (f *FakeClient) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, options metav1.PatchOptions, subresources ...string) (*unstructured.Unstructured, error) { + return nil, nil +} + +func (f *FakeClient) Namespace(string) dynamic.ResourceInterface { + return f +} + +func (f *FakeDynamicClient) Resource(schema.GroupVersionResource) dynamic.NamespaceableResourceInterface { + return &FakeClient{} +} diff --git a/rollout/trafficrouting/traefik/traefik.go b/rollout/trafficrouting/traefik/traefik.go new file mode 100644 index 0000000000..a2f9703726 --- /dev/null +++ b/rollout/trafficrouting/traefik/traefik.go @@ -0,0 +1,165 @@ +package traefik + +import ( + "context" + "fmt" + "strings" + + "github.com/pkg/errors" + + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + "github.com/argoproj/argo-rollouts/utils/defaults" + "github.com/argoproj/argo-rollouts/utils/record" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/dynamic" +) + +// Type holds this controller type +const Type = "Traefik" + +const traefikServices = "traefikservices" +const TraefikServiceUpdateError = "TraefikServiceUpdateError" + +var ( + apiGroupToResource = map[string]string{ + defaults.DefaultTraefikAPIGroup: traefikServices, + } +) + +type ReconcilerConfig struct { + Rollout *v1alpha1.Rollout + Client ClientInterface + Recorder record.EventRecorder +} + +type Reconciler struct { + Rollout *v1alpha1.Rollout + Client ClientInterface + Recorder record.EventRecorder +} + +func (r *Reconciler) sendWarningEvent(id, msg string) { + r.sendEvent(corev1.EventTypeWarning, id, msg) +} + +func (r *Reconciler) sendEvent(eventType, id, msg string) { + r.Recorder.Eventf(r.Rollout, record.EventOptions{EventType: eventType, EventReason: id}, msg) +} + +type ClientInterface interface { + Get(ctx context.Context, name string, options metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error) + Update(ctx context.Context, obj *unstructured.Unstructured, options metav1.UpdateOptions, subresources ...string) (*unstructured.Unstructured, error) +} + +func NewReconciler(cfg *ReconcilerConfig) *Reconciler { + reconciler := &Reconciler{ + Rollout: cfg.Rollout, + Client: cfg.Client, + Recorder: cfg.Recorder, + } + return reconciler +} + +func NewDynamicClient(di dynamic.Interface, namespace string) dynamic.ResourceInterface { + return di.Resource(GetMappingGVR()).Namespace(namespace) +} + +func GetMappingGVR() schema.GroupVersionResource { + group := defaults.DefaultTraefikAPIGroup + parts := strings.Split(defaults.DefaultTraefikVersion, "/") + version := parts[len(parts)-1] + resourceName := apiGroupToResource[group] + return schema.GroupVersionResource{ + Group: group, + Version: version, + Resource: resourceName, + } +} + +func (r *Reconciler) UpdateHash(canaryHash, stableHash string, additionalDestinations ...v1alpha1.WeightDestination) error { + return nil +} + +func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { + ctx := context.TODO() + rollout := r.Rollout + traefikServiceName := rollout.Spec.Strategy.Canary.TrafficRouting.Traefik.WeightedTraefikServiceName + traefikService, err := r.Client.Get(ctx, traefikServiceName, metav1.GetOptions{}) + if err != nil { + return err + } + canaryServiceName := rollout.Spec.Strategy.Canary.CanaryService + stableServiceName := rollout.Spec.Strategy.Canary.StableService + services, isFound, err := unstructured.NestedSlice(traefikService.Object, "spec", "weighted", "services") + if err != nil { + return err + } + if !isFound { + return errors.New("spec.weighted.services was not found in traefik service manifest") + } + canaryService, err := getService(canaryServiceName, services) + if err != nil { + return err + } + if canaryService == nil { + return errors.New("traefik canary service was not found") + } + err = unstructured.SetNestedField(canaryService, int64(desiredWeight), "weight") + if err != nil { + return err + } + stableService, err := getService(stableServiceName, services) + if err != nil { + return err + } + if stableService == nil { + return errors.New("traefik stable service was not found") + } + err = unstructured.SetNestedField(stableService, int64(100-desiredWeight), "weight") + if err != nil { + return err + } + err = unstructured.SetNestedSlice(traefikService.Object, services, "spec", "weighted", "services") + if err != nil { + return err + } + _, err = r.Client.Update(ctx, traefikService, metav1.UpdateOptions{}) + if err != nil { + msg := fmt.Sprintf("Error updating traefik service %q: %s", traefikService.GetName(), err) + r.sendWarningEvent(TraefikServiceUpdateError, msg) + } + return err +} + +func getService(serviceName string, services []interface{}) (map[string]interface{}, error) { + var selectedService map[string]interface{} + for _, service := range services { + typedService, ok := service.(map[string]interface{}) + if !ok { + return nil, errors.New("Failed type assertion setting weight for traefik service") + } + nameOfCurrentService, isFound, err := unstructured.NestedString(typedService, "name") + if err != nil { + return nil, err + } + if !isFound { + return nil, errors.New("name field was not found in service") + } + if nameOfCurrentService == serviceName { + selectedService = typedService + break + } + } + return selectedService, nil +} + +func (r *Reconciler) VerifyWeight(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) (*bool, error) { + return nil, nil +} + +func (r *Reconciler) Type() string { + return Type +} diff --git a/rollout/trafficrouting/traefik/traefik_test.go b/rollout/trafficrouting/traefik/traefik_test.go new file mode 100644 index 0000000000..e3c0b5e774 --- /dev/null +++ b/rollout/trafficrouting/traefik/traefik_test.go @@ -0,0 +1,329 @@ +package traefik + +import ( + "testing" + + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + "github.com/argoproj/argo-rollouts/rollout/trafficrouting/traefik/mocks" + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/serializer/yaml" +) + +const traefikService = ` +apiVersion: mocks.containo.us/v1alpha1 +kind: TraefikService +metadata: + labels: + service: argo-mocks + name: mocks-service +spec: + weighted: + services: + - name: stable-rollout + weight: 100 + port: 80 + - name: canary-rollout + weight: 0 + port: 80 +` + +const errorTraefikService = ` +apiVersion: mocks.containo.us/v1alpha1 +kind: TraefikService +metadata: + labels: + service: argo-mocks + name: mocks-service +` + +var ( + client *mocks.FakeClient = &mocks.FakeClient{} +) + +const ( + stableServiceName string = "stable-rollout" + fakeStableServiceName string = "fake-stable-rollout" + canaryServiceName string = "canary-rollout" + fakeCanaryServiceName string = "fake-canary-rollout" + traefikServiceName string = "mocks-service" +) + +func TestNewDynamicClient(t *testing.T) { + t.Run("NewDynamicClient", func(t *testing.T) { + // Given + t.Parallel() + fakeDynamicClient := &mocks.FakeDynamicClient{} + + // When + NewDynamicClient(fakeDynamicClient, "default") + }) +} + +func TestUpdateHash(t *testing.T) { + t.Run("UpdateHash", func(t *testing.T) { + // Given + t.Parallel() + cfg := ReconcilerConfig{ + Rollout: newRollout(stableServiceName, canaryServiceName, traefikServiceName), + Client: client, + } + r := NewReconciler(&cfg) + + // When + err := r.UpdateHash("", "") + + // Then + assert.NoError(t, err) + }) +} + +func TestSetWeight(t *testing.T) { + mocks.TraefikServiceObj = toUnstructured(t, traefikService) + mocks.ErrorTraefikServiceObj = toUnstructured(t, errorTraefikService) + t.Run("SetWeight", func(t *testing.T) { + // Given + t.Parallel() + cfg := ReconcilerConfig{ + Rollout: newRollout(stableServiceName, canaryServiceName, traefikServiceName), + Client: client, + } + r := NewReconciler(&cfg) + + // When + err := r.SetWeight(30) + + // Then + assert.NoError(t, err) + services, isFound, err := unstructured.NestedSlice(mocks.TraefikServiceObj.Object, "spec", "weighted", "services") + assert.NoError(t, err) + assert.Equal(t, isFound, true) + stableService, err := getService(stableServiceName, services) + assert.NoError(t, err) + stableServiceWeight, isFound, err := unstructured.NestedInt64(stableService, "weight") + assert.NoError(t, err) + assert.Equal(t, isFound, true) + canaryService, err := getService(canaryServiceName, services) + assert.NoError(t, err) + canaryServiceWeight, isFound, err := unstructured.NestedInt64(canaryService, "weight") + assert.Equal(t, isFound, true) + assert.NoError(t, err) + assert.Equal(t, int64(70), stableServiceWeight) + assert.Equal(t, int64(30), canaryServiceWeight) + }) + t.Run("SetWeightWithError", func(t *testing.T) { + // Given + t.Parallel() + cfg := ReconcilerConfig{ + Rollout: newRollout(stableServiceName, canaryServiceName, traefikServiceName), + Client: &mocks.FakeClient{ + IsGetError: true, + }, + } + r := NewReconciler(&cfg) + + // When + err := r.SetWeight(30) + + // Then + assert.Error(t, err) + }) + t.Run("SetWeightWithErrorManifest", func(t *testing.T) { + // Given + t.Parallel() + cfg := ReconcilerConfig{ + Rollout: newRollout(stableServiceName, canaryServiceName, traefikServiceName), + Client: &mocks.FakeClient{ + IsGetErrorManifest: true, + }, + } + r := NewReconciler(&cfg) + + // When + err := r.SetWeight(30) + + // Then + assert.Error(t, err) + }) + t.Run("SetWeightWithErrorStableName", func(t *testing.T) { + // Given + t.Parallel() + cfg := ReconcilerConfig{ + Rollout: newRollout(fakeStableServiceName, canaryServiceName, traefikServiceName), + Client: client, + } + r := NewReconciler(&cfg) + + // When + err := r.SetWeight(30) + + // Then + assert.Error(t, err) + }) + t.Run("SetWeightWithErrorCanaryName", func(t *testing.T) { + // Given + t.Parallel() + cfg := ReconcilerConfig{ + Rollout: newRollout(stableServiceName, fakeCanaryServiceName, traefikServiceName), + Client: client, + } + r := NewReconciler(&cfg) + + // When + err := r.SetWeight(30) + + // Then + assert.Error(t, err) + }) + t.Run("TraefikUpdateError", func(t *testing.T) { + // Given + t.Parallel() + cfg := ReconcilerConfig{ + Rollout: newRollout(stableServiceName, canaryServiceName, traefikServiceName), + Client: &mocks.FakeClient{ + UpdateError: true, + }, + Recorder: &mocks.FakeRecorder{}, + } + r := NewReconciler(&cfg) + + // When + err := r.SetWeight(30) + + // Then + assert.Error(t, err) + }) +} + +func toUnstructured(t *testing.T, manifest string) *unstructured.Unstructured { + t.Helper() + obj := &unstructured.Unstructured{} + + dec := yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme) + _, _, err := dec.Decode([]byte(manifest), nil, obj) + if err != nil { + t.Fatal(err) + } + return obj +} + +func TestVerifyWeight(t *testing.T) { + t.Run("VerifyWeight", func(t *testing.T) { + // Given + t.Parallel() + cfg := ReconcilerConfig{ + Rollout: newRollout(stableServiceName, canaryServiceName, traefikServiceName), + Client: client, + } + r := NewReconciler(&cfg) + + // When + isSynced, err := r.VerifyWeight(32) + + // Then + assert.Nil(t, isSynced) + assert.Nil(t, err) + }) +} + +func TestType(t *testing.T) { + mocks.TraefikServiceObj = toUnstructured(t, traefikService) + t.Run("Type", func(t *testing.T) { + // Given + t.Parallel() + cfg := ReconcilerConfig{ + Rollout: newRollout(stableServiceName, canaryServiceName, traefikServiceName), + Client: client, + } + r := NewReconciler(&cfg) + + // When + reconcilerType := r.Type() + + // Then + assert.Equal(t, Type, reconcilerType) + }) +} + +func TestGetService(t *testing.T) { + t.Run("ErrorGetServiceFromStruct ", func(t *testing.T) { + // Given + t.Parallel() + services := []interface{}{ + mocks.FakeService{Weight: 12}, + } + + // When + selectedServices, err := getService("default", services) + + // Then + assert.Nil(t, selectedServices) + assert.Error(t, err) + }) + t.Run("ErrorGetServiceFromMap", func(t *testing.T) { + // Given + t.Parallel() + services := map[string]interface{}{ + "weight": 100, + } + + // When + selectedServices, err := getService("default", []interface{}{services}) + + // Then + assert.Nil(t, selectedServices) + assert.Error(t, err) + }) + t.Run("GetServiceFromMap", func(t *testing.T) { + // Given + t.Parallel() + const serviceName string = "default" + services := map[string]interface{}{ + "name": serviceName, + } + + // When + selectedServices, err := getService(serviceName, []interface{}{services}) + + // Then + assert.NotNil(t, selectedServices) + assert.NoError(t, err) + }) + t.Run("ErrorGetServiceFromNil", func(t *testing.T) { + // Given + t.Parallel() + services := map[string]interface{}{ + "name": nil, + } + + // When + selectedServices, err := getService("default", []interface{}{services}) + + // Then + assert.Nil(t, selectedServices) + assert.Error(t, err) + }) +} + +func newRollout(stableSvc, canarySvc, traefikServiceName string) *v1alpha1.Rollout { + return &v1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rollout", + Namespace: "default", + }, + Spec: v1alpha1.RolloutSpec{ + Strategy: v1alpha1.RolloutStrategy{ + Canary: &v1alpha1.CanaryStrategy{ + StableService: stableSvc, + CanaryService: canarySvc, + TrafficRouting: &v1alpha1.RolloutTrafficRouting{ + Traefik: &v1alpha1.TraefikTrafficRouting{ + WeightedTraefikServiceName: traefikServiceName, + }, + }, + }, + }, + }, + } +} diff --git a/rollout/trafficrouting_test.go b/rollout/trafficrouting_test.go index bff4858866..aff8b09060 100644 --- a/rollout/trafficrouting_test.go +++ b/rollout/trafficrouting_test.go @@ -21,6 +21,8 @@ import ( "github.com/argoproj/argo-rollouts/rollout/trafficrouting/istio" "github.com/argoproj/argo-rollouts/rollout/trafficrouting/nginx" "github.com/argoproj/argo-rollouts/rollout/trafficrouting/smi" + "github.com/argoproj/argo-rollouts/rollout/trafficrouting/traefik" + traefikMocks "github.com/argoproj/argo-rollouts/rollout/trafficrouting/traefik/mocks" testutil "github.com/argoproj/argo-rollouts/test/util" "github.com/argoproj/argo-rollouts/utils/conditions" istioutil "github.com/argoproj/argo-rollouts/utils/istio" @@ -623,6 +625,29 @@ func TestNewTrafficRoutingReconciler(t *testing.T) { assert.Equal(t, appmesh.Type, networkReconciler.Type()) } } + { + tsController := Controller{ + reconcilerBase: reconcilerBase{ + dynamicclientset: &traefikMocks.FakeDynamicClient{}, + }, + } + r := newCanaryRollout("foo", 10, nil, steps, pointer.Int32Ptr(1), intstr.FromInt(1), intstr.FromInt(0)) + r.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{ + Traefik: &v1alpha1.TraefikTrafficRouting{ + WeightedTraefikServiceName: "traefik-service", + }, + } + roCtx := &rolloutContext{ + rollout: r, + log: logutil.WithRollout(r), + } + networkReconcilerList, err := tsController.NewTrafficRoutingReconciler(roCtx) + for _, networkReconciler := range networkReconcilerList { + assert.Nil(t, err) + assert.NotNil(t, networkReconciler) + assert.Equal(t, traefik.Type, networkReconciler.Type()) + } + } { // (2) Multiple Reconcilers (Nginx + SMI) tsController := Controller{} diff --git a/utils/defaults/defaults.go b/utils/defaults/defaults.go index 5570f65481..79e208671f 100644 --- a/utils/defaults/defaults.go +++ b/utils/defaults/defaults.go @@ -51,6 +51,8 @@ const ( DefaultSMITrafficSplitVersion = "v1alpha1" DefaultTargetGroupBindingAPIVersion = "elbv2.k8s.aws/v1beta1" DefaultAppMeshCRDVersion = "v1beta2" + DefaultTraefikAPIGroup = "traefik.containo.us" + DefaultTraefikVersion = "traefik.containo.us/v1alpha1" ) var ( From b3647826d5dc740775f1def6ed27fe6e4fa9ff43 Mon Sep 17 00:00:00 2001 From: Daniel Helfand Date: Tue, 3 May 2022 21:05:05 -0500 Subject: [PATCH 121/175] docs: add WorkloadRef to Rollout spec (#2019) Signed-off-by: Daniel Helfand --- docs/features/specification.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/features/specification.md b/docs/features/specification.md index c61f8d4446..eecbe266b6 100644 --- a/docs/features/specification.md +++ b/docs/features/specification.md @@ -27,7 +27,15 @@ spec: matchLabels: app: guestbook - # Template describes the pods that will be created. Same as deployment + # WorkloadRef holds a references to a workload that provides Pod template + # (e.g. Deployment). If used, then do not use Rollout template property. + workloadRef: + apiVersion: apps/v1 + kind: Deployment + name: rollout-ref-deployment + + # Template describes the pods that will be created. Same as deployment. + # If used, then do not use Rollout workloadRef property. template: spec: containers: From 03636ab13003bcf487e8db83b6cde394c8237c23 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Thu, 5 May 2022 00:01:34 -0500 Subject: [PATCH 122/175] fix: missing lb event (#2021) * fix: turn missing load balancer log into an event Signed-off-by: zachaller * consistent naming Signed-off-by: zachaller --- rollout/trafficrouting/alb/alb.go | 2 +- utils/conditions/conditions.go | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/rollout/trafficrouting/alb/alb.go b/rollout/trafficrouting/alb/alb.go index 861df37e06..d88fd993e8 100644 --- a/rollout/trafficrouting/alb/alb.go +++ b/rollout/trafficrouting/alb/alb.go @@ -162,7 +162,7 @@ func (r *Reconciler) VerifyWeight(desiredWeight int32, additionalDestinations .. return pointer.BoolPtr(false), err } if lb == nil || lb.LoadBalancerArn == nil { - r.log.Infof("LoadBalancer %s not found", lbIngress.Hostname) + r.cfg.Recorder.Warnf(rollout, record.EventOptions{EventReason: conditions.LoadBalancerNotFoundReason}, conditions.LoadBalancerNotFoundMessage, lbIngress.Hostname) return pointer.BoolPtr(false), nil } diff --git a/utils/conditions/conditions.go b/utils/conditions/conditions.go index cddbf68db4..03341742f5 100644 --- a/utils/conditions/conditions.go +++ b/utils/conditions/conditions.go @@ -157,6 +157,9 @@ const ( // WeightVerifyErrorReason is emitted when there is an error verifying the set weight WeightVerifyErrorReason = "WeightVerifyError" WeightVerifyErrorMessage = "Failed to verify weight: %s" + // LoadBalancerNotFoundReason is emitted when load balancer can not be found + LoadBalancerNotFoundReason = "LoadBalancerNotFound" + LoadBalancerNotFoundMessage = "Failed to find load balancer: %s" ) // NewRolloutCondition creates a new rollout condition. From a21b7e5decea2ad7024a1106a30261e3ec5b94df Mon Sep 17 00:00:00 2001 From: Alex Collins Date: Thu, 5 May 2022 17:51:51 -0700 Subject: [PATCH 123/175] ci: Auto-cancel redundant builds. (#2002) Signed-off-by: Alex Collins --- .github/workflows/codeql.yml | 4 ++++ .github/workflows/e2e.yaml | 4 ++++ .github/workflows/gh-pages.yaml | 5 +++++ .github/workflows/go.yml | 4 ++++ 4 files changed, 17 insertions(+) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 0d1440d942..9b709c2364 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -8,6 +8,10 @@ on: paths-ignore: - '**/*.md' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: CodeQL-Build: diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 06e20a4749..43620453b6 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -16,6 +16,10 @@ on: required: false default: false +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: test-e2e: name: Run end-to-end tests diff --git a/.github/workflows/gh-pages.yaml b/.github/workflows/gh-pages.yaml index e3e6183d8b..00dd5adaac 100644 --- a/.github/workflows/gh-pages.yaml +++ b/.github/workflows/gh-pages.yaml @@ -4,6 +4,11 @@ on: push: branches: - master + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: deploy: runs-on: ubuntu-latest diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 9d7ba50006..1e064f306f 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -11,6 +11,10 @@ env: # Golang version to use across CI steps GOLANG_VERSION: '1.17' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: lint-go: name: Lint Go code From 97e807e8198529380bec4fdb0ff4da0deb014d39 Mon Sep 17 00:00:00 2001 From: cskh Date: Fri, 6 May 2022 01:42:23 -0700 Subject: [PATCH 124/175] chore: update version file to 1.2.0 (#2013) Signed-off-by: Hui Kang --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 9084fa2f71..26aaba0e86 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.0 +1.2.0 From a5c623a9d2f998e46a7fb3135368f1eadbbdfeae Mon Sep 17 00:00:00 2001 From: cskh Date: Fri, 6 May 2022 01:42:32 -0700 Subject: [PATCH 125/175] docs: steps to rollback to deployment kinds (#2014) Signed-off-by: Hui Kang --- docs/migrating.md | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/docs/migrating.md b/docs/migrating.md index 47a2861e3e..e0d9754df0 100644 --- a/docs/migrating.md +++ b/docs/migrating.md @@ -102,7 +102,7 @@ spec: Consider following if your Deployment runs in production: -**Running Rollout and Deployment side-by-side** +### Running Rollout and Deployment side-by-side After creation Rollout will spinup required number of Pods side-by-side with the Deployment Pods. Rollout won't try to manage existing Deployment Pods. That means you can safely update add Rollout @@ -110,7 +110,7 @@ to the production environment without any interruption but you are going to run Argo-rollouts controller patches the spec of rollout object with an annotation of `rollout.argoproj.io/workload-generation`, which equals the generation of referenced deployment. Users can detect if the rollout matches desired generation of deployment by checking the `workloadObservedGeneration` in the rollout status. -**Traffic Management During Migration** +### Traffic Management During Migration The Rollout offers traffic management functionality that manages routing rules and flows the traffic to different versions of an application. For example [Blue-Green](features/bluegreen.md) deployment strategy manipulates @@ -119,4 +119,35 @@ Kubernetes Service selector and direct production traffic to "green" instances o If you are using this feature then Rollout switches production traffic to Pods that it manages. The switch happens only when the required number of Pod is running and healthy so it is safe in production as well. However, if you want to be extra careful then consider creating a temporal Service or Ingress object to validate Rollout behavior. -Once testing is done delete temporal Service/Ingress and switch rollout to production one. \ No newline at end of file +Once testing is done delete temporal Service/Ingress and switch rollout to production one. + +# Migrating to Deployments + +In case users want to rollback to the deployment kinds from rollouts, there are two scenarios aligned with those in [Migrating to Rollouts](#migrating-to-rollouts). + +* Convert a Rollout resource to a Deployment resource. +* Reference an existing Deployment from a Rollout using `workloadRef` field. + +## Convert Rollout to Deployment + +When converting a Rollout to a Deployment, it involves changing three fields: + +1. Changing the apiVersion from argoproj.io/v1alpha1 to apps/v1 +1. Changing the kind from Rollout to Deployment +1. Remove the rollout strategy in `spec.strategy.canary` or ``spec.strategy.blueGreen`` + + +!!! warning + When migrating a Rollout which is already serving live production traffic, a Deployment should + run next to the rollout before deleting the rollout or scaling down the rollout. + **Not following this approach might result in downtime**. It also allows for the Deployment to be + tested before deleting the original Rollout. + +## Reference Deployment From Rollout + +When a rollout is referencing to a deployment: + +1. Scale-up the Deployment by changing `replicas` field of an existing Rollout to zero. +1. Scale-down existing Rollout by changing `replicas` field of an existing Rollout to zero. + +Please refer to [Running Rollout and Deployment side-by-side](#running-rollout-and-deployment-side-by-side) and [Traffic Management During Migration](#traffic-management-during-migration) for caveats. \ No newline at end of file From 85878e63e8754d88248cf8ddfb1b69d6a42f0452 Mon Sep 17 00:00:00 2001 From: Thomas Riccardi Date: Fri, 6 May 2022 15:48:01 +0200 Subject: [PATCH 126/175] fix important block typo in canary doc (#2016) Signed-off-by: Thomas Riccardi --- docs/features/canary.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/features/canary.md b/docs/features/canary.md index de1053a101..5770673b68 100644 --- a/docs/features/canary.md +++ b/docs/features/canary.md @@ -83,8 +83,7 @@ match the traffic weight. Some use cases for this: !!! important - Setting canary scale is only available when using the canary strategy with a traffic router, since - the basic canary needs to control canary scale in order to approximate canary weight. + Setting canary scale is only available when using the canary strategy with a traffic router, since the basic canary needs to control canary scale in order to approximate canary weight. To control canary scales and weights during steps, use the `setCanaryScale` step and indicate which scale the the canary should use: From 59f949c7bb8b9f1a7d0f06674cc556a3325f225f Mon Sep 17 00:00:00 2001 From: "Kostis (Codefresh)" <39800303+kostis-codefresh@users.noreply.github.com> Date: Fri, 6 May 2022 14:48:28 +0100 Subject: [PATCH 127/175] docs: expose/fix Traefik docs (#2017) Signed-off-by: Kostis Kapelonis --- docs/features/traffic-management/index.md | 1 + docs/features/traffic-management/traefik.md | 16 +++++++++------- mkdocs.yml | 1 + 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/features/traffic-management/index.md b/docs/features/traffic-management/index.md index 0c3aecca63..921546d921 100644 --- a/docs/features/traffic-management/index.md +++ b/docs/features/traffic-management/index.md @@ -23,6 +23,7 @@ Argo Rollouts enables traffic management by manipulating the Service Mesh resour - [Istio](istio.md) - [Nginx Ingress Controller](nginx.md) - [Service Mesh Interface (SMI)](smi.md) +- [Traefik Proxy](traefik.md) - [Multiple Providers](mixed.md) - File a ticket [here](https://github.com/argoproj/argo-rollouts/issues) if you would like another implementation (or thumbs up it if that issue already exists) diff --git a/docs/features/traffic-management/traefik.md b/docs/features/traffic-management/traefik.md index 01a4409d64..dfba805c4f 100644 --- a/docs/features/traffic-management/traefik.md +++ b/docs/features/traffic-management/traefik.md @@ -1,10 +1,12 @@ # Traefik -The [TraefikService](https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/#kind-traefikservice) is the object supports the ability for [weighted round robin load balancing](https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/#weighted-round-robin) and (traffic mirroring)[https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/#mirroring] when using Traefik as ingress. +You can use the [Traefik Proxy](https://traefik.io/traefik/) for traffic management with Argo Rollouts. + +The [TraefikService](https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/#kind-traefikservice) is the object that supports the ability for [weighted round robin load balancing](https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/#weighted-round-robin) and [traffic mirroring](https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/#mirroring) when using Traefik as ingress. ## How to integrate TraefikService with Argo Rollouts using it as weighted round robin load balancer -Firstly, we need to create the TraefikService object using its ability for weighted round robin load balancing. +First, we need to create the TraefikService object using its ability for weighted round robin load balancing. ```yaml apiVersion: traefik.containo.us/v1alpha1 @@ -20,9 +22,9 @@ spec: port: 80 ``` -Notice, we don't specify the `weight` field. It is necessary to be synced with ArgoCD. If we specify this field and Argo Rollouts controller will change it, ArgoCD controller will notice it and will show that this resource is out of sync. +Notice, we don't specify the `weight` field. It is necessary to be synced with ArgoCD. If we specify this field and Argo Rollouts controller changes it, then the ArgoCD controller will notice it and will show that this resource is out of sync (if you are using Argo CD to manage your Rollout). -Secondly, we need to create the Argo Rollouts controller. +Secondly, we need to create the Argo Rollouts object. ```yaml apiVersion: argoproj.io/v1alpha1 @@ -52,7 +54,7 @@ spec: ## How to integrate TraefikService with Argo Rollouts using it as traffic mirror -Firstly, we also need to create the TraefikService object but using its ability for traffic mirroring. +First, we also need to create the TraefikService object but using its ability for traffic mirroring. ```yaml apiVersion: traefik.containo.us/v1alpha1 @@ -70,9 +72,9 @@ spec: port: 80 ``` -Notice, we don't specify the `percent` field. It is necessary to be synced with ArgoCD. If we specify this field and Argo Rollouts controller will change it, ArgoCD controller will notice it and will show that this resource is out of sync. +Notice, we don't specify the `percent` field. It is necessary to be synced with ArgoCD. If we specify this field and Argo Rollouts controller changes it, then the ArgoCD controller will notice it and will show that this resource is out of sync (if you are using Argo CD to manage your Rollout). -Secondly, we need to create the Argo Rollouts controller. +Secondly, we need to create the Argo Rollouts object. ```yaml apiVersion: argoproj.io/v1alpha1 diff --git a/mkdocs.yml b/mkdocs.yml index 50f355a1a4..2e32bd682d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -44,6 +44,7 @@ nav: - Istio: features/traffic-management/istio.md - NGINX: features/traffic-management/nginx.md - SMI: features/traffic-management/smi.md + - Traefik: features/traffic-management/traefik.md - Analysis: - Overview: features/analysis.md - Prometheus: analysis/prometheus.md From c757147893aeb15dc5d6fb0aa946fdb84e7b8d5c Mon Sep 17 00:00:00 2001 From: Andrii Perenesenko Date: Wed, 25 May 2022 12:51:23 -0700 Subject: [PATCH 128/175] feat: Allow Traffic shaping through header based routing. Fixes #474 (#1990) Signed-off-by: Andrii Perenesenko Co-authored-by: zachaller --- docs/features/specification.md | 18 + docs/features/traffic-management/index.md | 41 + go.mod | 2 +- manifests/crds/rollout-crd.yaml | 22 + manifests/install.yaml | 22 + manifests/namespace-install.yaml | 22 + pkg/apiclient/rollout/rollout.swagger.json | 47 + pkg/apis/api-rules/violation_exceptions.list | 1 + pkg/apis/rollouts/v1alpha1/generated.pb.go | 1743 ++++++++++++----- pkg/apis/rollouts/v1alpha1/generated.proto | 28 + .../rollouts/v1alpha1/openapi_generated.go | 103 +- pkg/apis/rollouts/v1alpha1/types.go | 24 + .../v1alpha1/zz_generated.deepcopy.go | 59 + pkg/apis/rollouts/validation/validation.go | 49 +- .../validation/validation_references.go | 2 +- .../rollouts/validation/validation_test.go | 64 + rollout/canary.go | 2 + rollout/mocks/TrafficRoutingReconciler.go | 14 + rollout/trafficrouting.go | 7 + rollout/trafficrouting/alb/alb.go | 4 + .../trafficrouting/ambassador/ambassador.go | 4 + rollout/trafficrouting/appmesh/appmesh.go | 11 +- .../trafficrouting/appmesh/appmesh_test.go | 9 +- rollout/trafficrouting/istio/istio.go | 284 ++- rollout/trafficrouting/istio/istio_test.go | 110 +- rollout/trafficrouting/istio/istio_types.go | 1 + rollout/trafficrouting/nginx/nginx.go | 4 + rollout/trafficrouting/smi/smi.go | 4 + rollout/trafficrouting/traefik/traefik.go | 12 +- rollout/trafficrouting/trafficroutingutil.go | 2 + rollout/trafficrouting_test.go | 13 + test/e2e/header-routing/istio-hr-host.yaml | 115 ++ test/e2e/header_routing_test.go | 91 + utils/replicaset/canary.go | 15 +- utils/replicaset/canary_test.go | 36 + 35 files changed, 2404 insertions(+), 581 deletions(-) create mode 100644 test/e2e/header-routing/istio-hr-host.yaml create mode 100644 test/e2e/header_routing_test.go diff --git a/docs/features/specification.md b/docs/features/specification.md index eecbe266b6..dbea102893 100644 --- a/docs/features/specification.md +++ b/docs/features/specification.md @@ -264,6 +264,24 @@ spec: - setCanaryScale: matchTrafficWeight: true + # Sets header based route with specified header values + # Setting header based route will send all 100 traffic to the canary for the requests + # O with a specified header, in this case request header "version":"2" + # (supported only with trafficRouting, for Istio only at the moment) + - setHeaderRouting: + match: + - headerName: "version" + headerValue: + exact: "2" + + # Sets header based route with specified header values using regex as a value + # Could be used 'headerValue' or 'headerRegex' one of that values + - setHeaderRouting: + match: + - headerName: "version" + headerValue: + regex: "2.0.(.*)" + # an inline analysis step - analysis: templates: diff --git a/docs/features/traffic-management/index.md b/docs/features/traffic-management/index.md index 921546d921..78561992ca 100644 --- a/docs/features/traffic-management/index.md +++ b/docs/features/traffic-management/index.md @@ -48,3 +48,44 @@ Additionally, the Argo Rollouts controller needs to treat the Rollout object dif Since the traffic is controlled independently by the Service Mesh resources, the controller needs to make a best effort to ensure that the Stable and New ReplicaSets are not overwhelmed by the traffic sent to them. By leaving the Stable ReplicaSet scaled up, the controller is ensuring that the Stable ReplicaSet can handle 100% of the traffic at any time[^1]. The New ReplicaSet follows the same behavior as without traffic management. The new ReplicaSet's replica count is equal to the latest SetWeight step percentage multiple by the total replica count of the Rollout. This calculation ensures that the canary version does not receive more traffic than it can handle. [^1]: The Rollout has to assume that the application can handle 100% of traffic if it is fully scaled up. It should outsource to the HPA to detect if the Rollout needs to more replicas if 100% isn't enough. + +## Traffic routing based on a header values for Canary + +Argo Rollouts has ability to send all traffic to the canary-service based on a http request header value. Right now it's implemented for the Istio only. +The step for the header based traffic routing `setHeaderRouting` has a list of matchers for the header. +Should be specified the `headerName` - name of the header and a value. +The value could be one of 3 `exact` - specify the exact header value, `regex` - value in a regex format, `prefix` - the prefix of the value could be provided. + +To disable header based traffic routing just need to specify empty `setHeaderRouting`. + +Example: + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +spec: + ... + strategy: + canary: + canaryService: canary-service + stableService: stable-service + trafficRouting: + istio: + virtualService: + name: rollouts-demo-vsvc + steps: + - setWeight: 20 + - setHeaderRouting: # enable header based traffic routing where + match: + - headerName: Custom-Header1 # Custom-Header1=Mozilla + headerValue: + exact: Mozilla + - headerName: Custom-Header2 # or Custom-Header2 has a prefix Mozilla + headerValue: + prefix: Mozilla + - headerName: Custom-Header3 # or Custom-Header3 value match regex: Mozilla(.*) + headerValue: + regex: Mozilla(.*) + - pause: {} + - setHeaderRouting: {} # disable header based traffic routing +``` \ No newline at end of file diff --git a/go.mod b/go.mod index ce8e3e1388..0a0e391e9b 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/aws/aws-sdk-go-v2/config v1.13.1 github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.15.0 github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.16.0 + github.com/aws/smithy-go v1.10.0 github.com/blang/semver v3.5.1+incompatible github.com/evanphx/json-patch/v5 v5.6.0 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 @@ -75,7 +76,6 @@ require ( github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.9.0 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.14.0 // indirect - github.com/aws/smithy-go v1.10.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bradleyfalzon/ghinstallation/v2 v2.0.4 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect diff --git a/manifests/crds/rollout-crd.yaml b/manifests/crds/rollout-crd.yaml index 3e1f1ec350..bda1fdd4fc 100644 --- a/manifests/crds/rollout-crd.yaml +++ b/manifests/crds/rollout-crd.yaml @@ -593,6 +593,28 @@ spec: format: int32 type: integer type: object + setHeaderRouting: + properties: + match: + items: + properties: + headerName: + type: string + headerValue: + properties: + exact: + type: string + prefix: + type: string + regex: + type: string + type: object + required: + - headerName + - headerValue + type: object + type: array + type: object setWeight: format: int32 type: integer diff --git a/manifests/install.yaml b/manifests/install.yaml index c24d2dbc35..00ff531b5c 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -11561,6 +11561,28 @@ spec: format: int32 type: integer type: object + setHeaderRouting: + properties: + match: + items: + properties: + headerName: + type: string + headerValue: + properties: + exact: + type: string + prefix: + type: string + regex: + type: string + type: object + required: + - headerName + - headerValue + type: object + type: array + type: object setWeight: format: int32 type: integer diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 5a9e72162c..3edf1348e4 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -11561,6 +11561,28 @@ spec: format: int32 type: integer type: object + setHeaderRouting: + properties: + match: + items: + properties: + headerName: + type: string + headerValue: + properties: + exact: + type: string + prefix: + type: string + regex: + type: string + type: object + required: + - headerName + - headerValue + type: object + type: array + type: object setWeight: format: int32 type: integer diff --git a/pkg/apiclient/rollout/rollout.swagger.json b/pkg/apiclient/rollout/rollout.swagger.json index 031aa5ff65..140fb92856 100644 --- a/pkg/apiclient/rollout/rollout.swagger.json +++ b/pkg/apiclient/rollout/rollout.swagger.json @@ -820,6 +820,10 @@ "setCanaryScale": { "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SetCanaryScale", "title": "SetCanaryScale defines how to scale the newRS without changing traffic weight\n+optional" + }, + "setHeaderRouting": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SetHeaderRouting", + "title": "SetHeaderRouting defines the route with specified header name to send 100% of traffic to the canary service" } }, "description": "CanaryStep defines a step of a canary deployment." @@ -915,6 +919,19 @@ } } }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.HeaderRoutingMatch": { + "type": "object", + "properties": { + "headerName": { + "type": "string", + "title": "HeaderName the name of the request header" + }, + "headerValue": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.StringMatch", + "title": "HeaderValue the value of the header" + } + } + }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.IstioDestinationRule": { "type": "object", "properties": { @@ -1566,6 +1583,18 @@ }, "title": "SetCanaryScale defines how to scale the newRS without changing traffic weight" }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SetHeaderRouting": { + "type": "object", + "properties": { + "match": { + "type": "array", + "items": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.HeaderRoutingMatch" + } + } + }, + "title": "SetHeaderRouting defines the route with specified header name to send 100% of traffic to the canary service" + }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.StickinessConfig": { "type": "object", "properties": { @@ -1578,6 +1607,24 @@ } } }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.StringMatch": { + "type": "object", + "properties": { + "exact": { + "type": "string", + "title": "Exact The string must match exactly" + }, + "prefix": { + "type": "string", + "title": "Prefix The string will be prefixed matched" + }, + "regex": { + "type": "string", + "title": "Regex The string will be regular expression matched" + } + }, + "title": "StringMatch Used to define what type of matching we will use exact, prefix, or regular expression" + }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.TLSRoute": { "type": "object", "properties": { diff --git a/pkg/apis/api-rules/violation_exceptions.list b/pkg/apis/api-rules/violation_exceptions.list index 5c7b1d8311..d9cc556c27 100644 --- a/pkg/apis/api-rules/violation_exceptions.list +++ b/pkg/apis/api-rules/violation_exceptions.list @@ -34,6 +34,7 @@ API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutExperimentStepAnalysisTemplateRef,Args API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutStatus,Conditions API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutStatus,PauseConditions +API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,SetHeaderRouting,Match API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,TLSRoute,SNIHosts API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,TrafficWeights,Additional API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,WebMetric,Headers diff --git a/pkg/apis/rollouts/v1alpha1/generated.pb.go b/pkg/apis/rollouts/v1alpha1/generated.pb.go index 3e023b49b7..ae221882a7 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.pb.go +++ b/pkg/apis/rollouts/v1alpha1/generated.pb.go @@ -1252,10 +1252,38 @@ func (m *GraphiteMetric) XXX_DiscardUnknown() { var xxx_messageInfo_GraphiteMetric proto.InternalMessageInfo +func (m *HeaderRoutingMatch) Reset() { *m = HeaderRoutingMatch{} } +func (*HeaderRoutingMatch) ProtoMessage() {} +func (*HeaderRoutingMatch) Descriptor() ([]byte, []int) { + return fileDescriptor_e0e705f843545fab, []int{43} +} +func (m *HeaderRoutingMatch) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *HeaderRoutingMatch) 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 *HeaderRoutingMatch) XXX_Merge(src proto.Message) { + xxx_messageInfo_HeaderRoutingMatch.Merge(m, src) +} +func (m *HeaderRoutingMatch) XXX_Size() int { + return m.Size() +} +func (m *HeaderRoutingMatch) XXX_DiscardUnknown() { + xxx_messageInfo_HeaderRoutingMatch.DiscardUnknown(m) +} + +var xxx_messageInfo_HeaderRoutingMatch proto.InternalMessageInfo + func (m *IstioDestinationRule) Reset() { *m = IstioDestinationRule{} } func (*IstioDestinationRule) ProtoMessage() {} func (*IstioDestinationRule) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{43} + return fileDescriptor_e0e705f843545fab, []int{44} } func (m *IstioDestinationRule) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1283,7 +1311,7 @@ var xxx_messageInfo_IstioDestinationRule proto.InternalMessageInfo func (m *IstioTrafficRouting) Reset() { *m = IstioTrafficRouting{} } func (*IstioTrafficRouting) ProtoMessage() {} func (*IstioTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{44} + return fileDescriptor_e0e705f843545fab, []int{45} } func (m *IstioTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1311,7 +1339,7 @@ var xxx_messageInfo_IstioTrafficRouting proto.InternalMessageInfo func (m *IstioVirtualService) Reset() { *m = IstioVirtualService{} } func (*IstioVirtualService) ProtoMessage() {} func (*IstioVirtualService) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{45} + return fileDescriptor_e0e705f843545fab, []int{46} } func (m *IstioVirtualService) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1339,7 +1367,7 @@ var xxx_messageInfo_IstioVirtualService proto.InternalMessageInfo func (m *JobMetric) Reset() { *m = JobMetric{} } func (*JobMetric) ProtoMessage() {} func (*JobMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{46} + return fileDescriptor_e0e705f843545fab, []int{47} } func (m *JobMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1367,7 +1395,7 @@ var xxx_messageInfo_JobMetric proto.InternalMessageInfo func (m *KayentaMetric) Reset() { *m = KayentaMetric{} } func (*KayentaMetric) ProtoMessage() {} func (*KayentaMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{47} + return fileDescriptor_e0e705f843545fab, []int{48} } func (m *KayentaMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1395,7 +1423,7 @@ var xxx_messageInfo_KayentaMetric proto.InternalMessageInfo func (m *KayentaScope) Reset() { *m = KayentaScope{} } func (*KayentaScope) ProtoMessage() {} func (*KayentaScope) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{48} + return fileDescriptor_e0e705f843545fab, []int{49} } func (m *KayentaScope) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1423,7 +1451,7 @@ var xxx_messageInfo_KayentaScope proto.InternalMessageInfo func (m *KayentaThreshold) Reset() { *m = KayentaThreshold{} } func (*KayentaThreshold) ProtoMessage() {} func (*KayentaThreshold) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{49} + return fileDescriptor_e0e705f843545fab, []int{50} } func (m *KayentaThreshold) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1451,7 +1479,7 @@ var xxx_messageInfo_KayentaThreshold proto.InternalMessageInfo func (m *Measurement) Reset() { *m = Measurement{} } func (*Measurement) ProtoMessage() {} func (*Measurement) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{50} + return fileDescriptor_e0e705f843545fab, []int{51} } func (m *Measurement) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1479,7 +1507,7 @@ var xxx_messageInfo_Measurement proto.InternalMessageInfo func (m *MeasurementRetention) Reset() { *m = MeasurementRetention{} } func (*MeasurementRetention) ProtoMessage() {} func (*MeasurementRetention) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{51} + return fileDescriptor_e0e705f843545fab, []int{52} } func (m *MeasurementRetention) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1507,7 +1535,7 @@ var xxx_messageInfo_MeasurementRetention proto.InternalMessageInfo func (m *Metric) Reset() { *m = Metric{} } func (*Metric) ProtoMessage() {} func (*Metric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{52} + return fileDescriptor_e0e705f843545fab, []int{53} } func (m *Metric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1535,7 +1563,7 @@ var xxx_messageInfo_Metric proto.InternalMessageInfo func (m *MetricProvider) Reset() { *m = MetricProvider{} } func (*MetricProvider) ProtoMessage() {} func (*MetricProvider) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{53} + return fileDescriptor_e0e705f843545fab, []int{54} } func (m *MetricProvider) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1563,7 +1591,7 @@ var xxx_messageInfo_MetricProvider proto.InternalMessageInfo func (m *MetricResult) Reset() { *m = MetricResult{} } func (*MetricResult) ProtoMessage() {} func (*MetricResult) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{54} + return fileDescriptor_e0e705f843545fab, []int{55} } func (m *MetricResult) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1591,7 +1619,7 @@ var xxx_messageInfo_MetricResult proto.InternalMessageInfo func (m *NewRelicMetric) Reset() { *m = NewRelicMetric{} } func (*NewRelicMetric) ProtoMessage() {} func (*NewRelicMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{55} + return fileDescriptor_e0e705f843545fab, []int{56} } func (m *NewRelicMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1619,7 +1647,7 @@ var xxx_messageInfo_NewRelicMetric proto.InternalMessageInfo func (m *NginxTrafficRouting) Reset() { *m = NginxTrafficRouting{} } func (*NginxTrafficRouting) ProtoMessage() {} func (*NginxTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{56} + return fileDescriptor_e0e705f843545fab, []int{57} } func (m *NginxTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1647,7 +1675,7 @@ var xxx_messageInfo_NginxTrafficRouting proto.InternalMessageInfo func (m *ObjectRef) Reset() { *m = ObjectRef{} } func (*ObjectRef) ProtoMessage() {} func (*ObjectRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{57} + return fileDescriptor_e0e705f843545fab, []int{58} } func (m *ObjectRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1675,7 +1703,7 @@ var xxx_messageInfo_ObjectRef proto.InternalMessageInfo func (m *PauseCondition) Reset() { *m = PauseCondition{} } func (*PauseCondition) ProtoMessage() {} func (*PauseCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{58} + return fileDescriptor_e0e705f843545fab, []int{59} } func (m *PauseCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1703,7 +1731,7 @@ var xxx_messageInfo_PauseCondition proto.InternalMessageInfo func (m *PingPongSpec) Reset() { *m = PingPongSpec{} } func (*PingPongSpec) ProtoMessage() {} func (*PingPongSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{59} + return fileDescriptor_e0e705f843545fab, []int{60} } func (m *PingPongSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1731,7 +1759,7 @@ var xxx_messageInfo_PingPongSpec proto.InternalMessageInfo func (m *PodTemplateMetadata) Reset() { *m = PodTemplateMetadata{} } func (*PodTemplateMetadata) ProtoMessage() {} func (*PodTemplateMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{60} + return fileDescriptor_e0e705f843545fab, []int{61} } func (m *PodTemplateMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1761,7 +1789,7 @@ func (m *PreferredDuringSchedulingIgnoredDuringExecution) Reset() { } func (*PreferredDuringSchedulingIgnoredDuringExecution) ProtoMessage() {} func (*PreferredDuringSchedulingIgnoredDuringExecution) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{61} + return fileDescriptor_e0e705f843545fab, []int{62} } func (m *PreferredDuringSchedulingIgnoredDuringExecution) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1789,7 +1817,7 @@ var xxx_messageInfo_PreferredDuringSchedulingIgnoredDuringExecution proto.Intern func (m *PrometheusMetric) Reset() { *m = PrometheusMetric{} } func (*PrometheusMetric) ProtoMessage() {} func (*PrometheusMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{62} + return fileDescriptor_e0e705f843545fab, []int{63} } func (m *PrometheusMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1819,7 +1847,7 @@ func (m *RequiredDuringSchedulingIgnoredDuringExecution) Reset() { } func (*RequiredDuringSchedulingIgnoredDuringExecution) ProtoMessage() {} func (*RequiredDuringSchedulingIgnoredDuringExecution) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{63} + return fileDescriptor_e0e705f843545fab, []int{64} } func (m *RequiredDuringSchedulingIgnoredDuringExecution) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1847,7 +1875,7 @@ var xxx_messageInfo_RequiredDuringSchedulingIgnoredDuringExecution proto.Interna func (m *Rollout) Reset() { *m = Rollout{} } func (*Rollout) ProtoMessage() {} func (*Rollout) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{64} + return fileDescriptor_e0e705f843545fab, []int{65} } func (m *Rollout) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1875,7 +1903,7 @@ var xxx_messageInfo_Rollout proto.InternalMessageInfo func (m *RolloutAnalysis) Reset() { *m = RolloutAnalysis{} } func (*RolloutAnalysis) ProtoMessage() {} func (*RolloutAnalysis) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{65} + return fileDescriptor_e0e705f843545fab, []int{66} } func (m *RolloutAnalysis) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1903,7 +1931,7 @@ var xxx_messageInfo_RolloutAnalysis proto.InternalMessageInfo func (m *RolloutAnalysisBackground) Reset() { *m = RolloutAnalysisBackground{} } func (*RolloutAnalysisBackground) ProtoMessage() {} func (*RolloutAnalysisBackground) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{66} + return fileDescriptor_e0e705f843545fab, []int{67} } func (m *RolloutAnalysisBackground) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1931,7 +1959,7 @@ var xxx_messageInfo_RolloutAnalysisBackground proto.InternalMessageInfo func (m *RolloutAnalysisRunStatus) Reset() { *m = RolloutAnalysisRunStatus{} } func (*RolloutAnalysisRunStatus) ProtoMessage() {} func (*RolloutAnalysisRunStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{67} + return fileDescriptor_e0e705f843545fab, []int{68} } func (m *RolloutAnalysisRunStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1959,7 +1987,7 @@ var xxx_messageInfo_RolloutAnalysisRunStatus proto.InternalMessageInfo func (m *RolloutAnalysisTemplate) Reset() { *m = RolloutAnalysisTemplate{} } func (*RolloutAnalysisTemplate) ProtoMessage() {} func (*RolloutAnalysisTemplate) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{68} + return fileDescriptor_e0e705f843545fab, []int{69} } func (m *RolloutAnalysisTemplate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1987,7 +2015,7 @@ var xxx_messageInfo_RolloutAnalysisTemplate proto.InternalMessageInfo func (m *RolloutCondition) Reset() { *m = RolloutCondition{} } func (*RolloutCondition) ProtoMessage() {} func (*RolloutCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{69} + return fileDescriptor_e0e705f843545fab, []int{70} } func (m *RolloutCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2015,7 +2043,7 @@ var xxx_messageInfo_RolloutCondition proto.InternalMessageInfo func (m *RolloutExperimentStep) Reset() { *m = RolloutExperimentStep{} } func (*RolloutExperimentStep) ProtoMessage() {} func (*RolloutExperimentStep) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{70} + return fileDescriptor_e0e705f843545fab, []int{71} } func (m *RolloutExperimentStep) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2045,7 +2073,7 @@ func (m *RolloutExperimentStepAnalysisTemplateRef) Reset() { } func (*RolloutExperimentStepAnalysisTemplateRef) ProtoMessage() {} func (*RolloutExperimentStepAnalysisTemplateRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{71} + return fileDescriptor_e0e705f843545fab, []int{72} } func (m *RolloutExperimentStepAnalysisTemplateRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2073,7 +2101,7 @@ var xxx_messageInfo_RolloutExperimentStepAnalysisTemplateRef proto.InternalMessa func (m *RolloutExperimentTemplate) Reset() { *m = RolloutExperimentTemplate{} } func (*RolloutExperimentTemplate) ProtoMessage() {} func (*RolloutExperimentTemplate) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{72} + return fileDescriptor_e0e705f843545fab, []int{73} } func (m *RolloutExperimentTemplate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2101,7 +2129,7 @@ var xxx_messageInfo_RolloutExperimentTemplate proto.InternalMessageInfo func (m *RolloutList) Reset() { *m = RolloutList{} } func (*RolloutList) ProtoMessage() {} func (*RolloutList) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{73} + return fileDescriptor_e0e705f843545fab, []int{74} } func (m *RolloutList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2129,7 +2157,7 @@ var xxx_messageInfo_RolloutList proto.InternalMessageInfo func (m *RolloutPause) Reset() { *m = RolloutPause{} } func (*RolloutPause) ProtoMessage() {} func (*RolloutPause) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{74} + return fileDescriptor_e0e705f843545fab, []int{75} } func (m *RolloutPause) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2157,7 +2185,7 @@ var xxx_messageInfo_RolloutPause proto.InternalMessageInfo func (m *RolloutSpec) Reset() { *m = RolloutSpec{} } func (*RolloutSpec) ProtoMessage() {} func (*RolloutSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{75} + return fileDescriptor_e0e705f843545fab, []int{76} } func (m *RolloutSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2185,7 +2213,7 @@ var xxx_messageInfo_RolloutSpec proto.InternalMessageInfo func (m *RolloutStatus) Reset() { *m = RolloutStatus{} } func (*RolloutStatus) ProtoMessage() {} func (*RolloutStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{76} + return fileDescriptor_e0e705f843545fab, []int{77} } func (m *RolloutStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2213,7 +2241,7 @@ var xxx_messageInfo_RolloutStatus proto.InternalMessageInfo func (m *RolloutStrategy) Reset() { *m = RolloutStrategy{} } func (*RolloutStrategy) ProtoMessage() {} func (*RolloutStrategy) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{77} + return fileDescriptor_e0e705f843545fab, []int{78} } func (m *RolloutStrategy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2241,7 +2269,7 @@ var xxx_messageInfo_RolloutStrategy proto.InternalMessageInfo func (m *RolloutTrafficRouting) Reset() { *m = RolloutTrafficRouting{} } func (*RolloutTrafficRouting) ProtoMessage() {} func (*RolloutTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{78} + return fileDescriptor_e0e705f843545fab, []int{79} } func (m *RolloutTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2269,7 +2297,7 @@ var xxx_messageInfo_RolloutTrafficRouting proto.InternalMessageInfo func (m *RunSummary) Reset() { *m = RunSummary{} } func (*RunSummary) ProtoMessage() {} func (*RunSummary) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{79} + return fileDescriptor_e0e705f843545fab, []int{80} } func (m *RunSummary) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2297,7 +2325,7 @@ var xxx_messageInfo_RunSummary proto.InternalMessageInfo func (m *SMITrafficRouting) Reset() { *m = SMITrafficRouting{} } func (*SMITrafficRouting) ProtoMessage() {} func (*SMITrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{80} + return fileDescriptor_e0e705f843545fab, []int{81} } func (m *SMITrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2325,7 +2353,7 @@ var xxx_messageInfo_SMITrafficRouting proto.InternalMessageInfo func (m *ScopeDetail) Reset() { *m = ScopeDetail{} } func (*ScopeDetail) ProtoMessage() {} func (*ScopeDetail) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{81} + return fileDescriptor_e0e705f843545fab, []int{82} } func (m *ScopeDetail) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2353,7 +2381,7 @@ var xxx_messageInfo_ScopeDetail proto.InternalMessageInfo func (m *SecretKeyRef) Reset() { *m = SecretKeyRef{} } func (*SecretKeyRef) ProtoMessage() {} func (*SecretKeyRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{82} + return fileDescriptor_e0e705f843545fab, []int{83} } func (m *SecretKeyRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2381,7 +2409,7 @@ var xxx_messageInfo_SecretKeyRef proto.InternalMessageInfo func (m *SetCanaryScale) Reset() { *m = SetCanaryScale{} } func (*SetCanaryScale) ProtoMessage() {} func (*SetCanaryScale) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{83} + return fileDescriptor_e0e705f843545fab, []int{84} } func (m *SetCanaryScale) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2406,10 +2434,38 @@ func (m *SetCanaryScale) XXX_DiscardUnknown() { var xxx_messageInfo_SetCanaryScale proto.InternalMessageInfo +func (m *SetHeaderRouting) Reset() { *m = SetHeaderRouting{} } +func (*SetHeaderRouting) ProtoMessage() {} +func (*SetHeaderRouting) Descriptor() ([]byte, []int) { + return fileDescriptor_e0e705f843545fab, []int{85} +} +func (m *SetHeaderRouting) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SetHeaderRouting) 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 *SetHeaderRouting) XXX_Merge(src proto.Message) { + xxx_messageInfo_SetHeaderRouting.Merge(m, src) +} +func (m *SetHeaderRouting) XXX_Size() int { + return m.Size() +} +func (m *SetHeaderRouting) XXX_DiscardUnknown() { + xxx_messageInfo_SetHeaderRouting.DiscardUnknown(m) +} + +var xxx_messageInfo_SetHeaderRouting proto.InternalMessageInfo + func (m *StickinessConfig) Reset() { *m = StickinessConfig{} } func (*StickinessConfig) ProtoMessage() {} func (*StickinessConfig) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{84} + return fileDescriptor_e0e705f843545fab, []int{86} } func (m *StickinessConfig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2434,10 +2490,38 @@ func (m *StickinessConfig) XXX_DiscardUnknown() { var xxx_messageInfo_StickinessConfig proto.InternalMessageInfo +func (m *StringMatch) Reset() { *m = StringMatch{} } +func (*StringMatch) ProtoMessage() {} +func (*StringMatch) Descriptor() ([]byte, []int) { + return fileDescriptor_e0e705f843545fab, []int{87} +} +func (m *StringMatch) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StringMatch) 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 *StringMatch) XXX_Merge(src proto.Message) { + xxx_messageInfo_StringMatch.Merge(m, src) +} +func (m *StringMatch) XXX_Size() int { + return m.Size() +} +func (m *StringMatch) XXX_DiscardUnknown() { + xxx_messageInfo_StringMatch.DiscardUnknown(m) +} + +var xxx_messageInfo_StringMatch proto.InternalMessageInfo + func (m *TLSRoute) Reset() { *m = TLSRoute{} } func (*TLSRoute) ProtoMessage() {} func (*TLSRoute) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{85} + return fileDescriptor_e0e705f843545fab, []int{88} } func (m *TLSRoute) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2465,7 +2549,7 @@ var xxx_messageInfo_TLSRoute proto.InternalMessageInfo func (m *TemplateService) Reset() { *m = TemplateService{} } func (*TemplateService) ProtoMessage() {} func (*TemplateService) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{86} + return fileDescriptor_e0e705f843545fab, []int{89} } func (m *TemplateService) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2493,7 +2577,7 @@ var xxx_messageInfo_TemplateService proto.InternalMessageInfo func (m *TemplateSpec) Reset() { *m = TemplateSpec{} } func (*TemplateSpec) ProtoMessage() {} func (*TemplateSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{87} + return fileDescriptor_e0e705f843545fab, []int{90} } func (m *TemplateSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2521,7 +2605,7 @@ var xxx_messageInfo_TemplateSpec proto.InternalMessageInfo func (m *TemplateStatus) Reset() { *m = TemplateStatus{} } func (*TemplateStatus) ProtoMessage() {} func (*TemplateStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{88} + return fileDescriptor_e0e705f843545fab, []int{91} } func (m *TemplateStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2549,7 +2633,7 @@ var xxx_messageInfo_TemplateStatus proto.InternalMessageInfo func (m *TraefikTrafficRouting) Reset() { *m = TraefikTrafficRouting{} } func (*TraefikTrafficRouting) ProtoMessage() {} func (*TraefikTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{89} + return fileDescriptor_e0e705f843545fab, []int{92} } func (m *TraefikTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2577,7 +2661,7 @@ var xxx_messageInfo_TraefikTrafficRouting proto.InternalMessageInfo func (m *TrafficWeights) Reset() { *m = TrafficWeights{} } func (*TrafficWeights) ProtoMessage() {} func (*TrafficWeights) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{90} + return fileDescriptor_e0e705f843545fab, []int{93} } func (m *TrafficWeights) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2605,7 +2689,7 @@ var xxx_messageInfo_TrafficWeights proto.InternalMessageInfo func (m *ValueFrom) Reset() { *m = ValueFrom{} } func (*ValueFrom) ProtoMessage() {} func (*ValueFrom) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{91} + return fileDescriptor_e0e705f843545fab, []int{94} } func (m *ValueFrom) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2633,7 +2717,7 @@ var xxx_messageInfo_ValueFrom proto.InternalMessageInfo func (m *WavefrontMetric) Reset() { *m = WavefrontMetric{} } func (*WavefrontMetric) ProtoMessage() {} func (*WavefrontMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{92} + return fileDescriptor_e0e705f843545fab, []int{95} } func (m *WavefrontMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2661,7 +2745,7 @@ var xxx_messageInfo_WavefrontMetric proto.InternalMessageInfo func (m *WebMetric) Reset() { *m = WebMetric{} } func (*WebMetric) ProtoMessage() {} func (*WebMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{93} + return fileDescriptor_e0e705f843545fab, []int{96} } func (m *WebMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2689,7 +2773,7 @@ var xxx_messageInfo_WebMetric proto.InternalMessageInfo func (m *WebMetricHeader) Reset() { *m = WebMetricHeader{} } func (*WebMetricHeader) ProtoMessage() {} func (*WebMetricHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{94} + return fileDescriptor_e0e705f843545fab, []int{97} } func (m *WebMetricHeader) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2717,7 +2801,7 @@ var xxx_messageInfo_WebMetricHeader proto.InternalMessageInfo func (m *WeightDestination) Reset() { *m = WeightDestination{} } func (*WeightDestination) ProtoMessage() {} func (*WeightDestination) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{95} + return fileDescriptor_e0e705f843545fab, []int{98} } func (m *WeightDestination) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2786,6 +2870,7 @@ func init() { proto.RegisterType((*ExperimentStatus)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ExperimentStatus") proto.RegisterType((*FieldRef)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.FieldRef") proto.RegisterType((*GraphiteMetric)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.GraphiteMetric") + proto.RegisterType((*HeaderRoutingMatch)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.HeaderRoutingMatch") proto.RegisterType((*IstioDestinationRule)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.IstioDestinationRule") proto.RegisterType((*IstioTrafficRouting)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.IstioTrafficRouting") proto.RegisterType((*IstioVirtualService)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.IstioVirtualService") @@ -2832,7 +2917,9 @@ func init() { proto.RegisterType((*ScopeDetail)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ScopeDetail") proto.RegisterType((*SecretKeyRef)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SecretKeyRef") proto.RegisterType((*SetCanaryScale)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SetCanaryScale") + proto.RegisterType((*SetHeaderRouting)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SetHeaderRouting") proto.RegisterType((*StickinessConfig)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.StickinessConfig") + proto.RegisterType((*StringMatch)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.StringMatch") proto.RegisterType((*TLSRoute)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.TLSRoute") proto.RegisterType((*TemplateService)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.TemplateService") proto.RegisterType((*TemplateSpec)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.TemplateSpec") @@ -2851,455 +2938,465 @@ func init() { } var fileDescriptor_e0e705f843545fab = []byte{ - // 7167 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x5d, 0x8c, 0x24, 0xd7, - 0x55, 0xb0, 0xab, 0x7b, 0x7a, 0xa6, 0xfb, 0xcc, 0xff, 0xdd, 0xd9, 0xec, 0x78, 0xec, 0xdd, 0x76, - 0xca, 0x91, 0x3f, 0xe7, 0x23, 0x99, 0x4d, 0xfc, 0x03, 0x4e, 0x1c, 0x19, 0xba, 0x67, 0x76, 0xbd, - 0xb3, 0x9e, 0x99, 0x9d, 0xbd, 0x3d, 0xbb, 0x9b, 0x38, 0x71, 0x48, 0x4d, 0xf7, 0x9d, 0x9e, 0xda, - 0xe9, 0xae, 0xea, 0x54, 0x55, 0xcf, 0xee, 0x38, 0x56, 0x62, 0x13, 0xd9, 0x04, 0x94, 0x28, 0x86, - 0x24, 0x42, 0x08, 0x05, 0x45, 0x28, 0x12, 0x88, 0xe4, 0x01, 0x45, 0x20, 0x5e, 0x22, 0x81, 0x48, - 0x22, 0xc2, 0x03, 0x28, 0x20, 0x20, 0x09, 0x52, 0x1a, 0xdc, 0xe1, 0x05, 0x04, 0x42, 0x48, 0x41, - 0x28, 0xfb, 0x84, 0xee, 0x6f, 0xdd, 0xaa, 0xae, 0x9e, 0xed, 0x9e, 0xae, 0xd9, 0x58, 0x90, 0xb7, - 0xee, 0x7b, 0xce, 0x3d, 0xe7, 0xfe, 0x9e, 0x73, 0xee, 0xb9, 0xe7, 0x9e, 0x82, 0xf5, 0xba, 0x1d, - 0xec, 0xb5, 0x77, 0x96, 0xab, 0x6e, 0xf3, 0xbc, 0xe5, 0xd5, 0xdd, 0x96, 0xe7, 0xde, 0x64, 0x3f, - 0xde, 0xe9, 0xb9, 0x8d, 0x86, 0xdb, 0x0e, 0xfc, 0xf3, 0xad, 0xfd, 0xfa, 0x79, 0xab, 0x65, 0xfb, - 0xe7, 0x55, 0xc9, 0xc1, 0xbb, 0xad, 0x46, 0x6b, 0xcf, 0x7a, 0xf7, 0xf9, 0x3a, 0x71, 0x88, 0x67, - 0x05, 0xa4, 0xb6, 0xdc, 0xf2, 0xdc, 0xc0, 0x45, 0xef, 0x0b, 0xa9, 0x2d, 0x4b, 0x6a, 0xec, 0xc7, - 0x2f, 0xca, 0xba, 0xcb, 0xad, 0xfd, 0xfa, 0x32, 0xa5, 0xb6, 0xac, 0x4a, 0x24, 0xb5, 0xa5, 0x77, - 0x6a, 0x6d, 0xa9, 0xbb, 0x75, 0xf7, 0x3c, 0x23, 0xba, 0xd3, 0xde, 0x65, 0xff, 0xd8, 0x1f, 0xf6, - 0x8b, 0x33, 0x5b, 0x7a, 0x78, 0xff, 0x29, 0x7f, 0xd9, 0x76, 0x69, 0xdb, 0xce, 0xef, 0x58, 0x41, - 0x75, 0xef, 0xfc, 0x41, 0x4f, 0x8b, 0x96, 0x4c, 0x0d, 0xa9, 0xea, 0x7a, 0x24, 0x09, 0xe7, 0x89, - 0x10, 0xa7, 0x69, 0x55, 0xf7, 0x6c, 0x87, 0x78, 0x87, 0x61, 0xaf, 0x9b, 0x24, 0xb0, 0x92, 0x6a, - 0x9d, 0xef, 0x57, 0xcb, 0x6b, 0x3b, 0x81, 0xdd, 0x24, 0x3d, 0x15, 0x7e, 0xf6, 0x6e, 0x15, 0xfc, - 0xea, 0x1e, 0x69, 0x5a, 0x3d, 0xf5, 0x1e, 0xef, 0x57, 0xaf, 0x1d, 0xd8, 0x8d, 0xf3, 0xb6, 0x13, - 0xf8, 0x81, 0x17, 0xaf, 0x64, 0x7e, 0x33, 0x0b, 0x85, 0xd2, 0x7a, 0xb9, 0x12, 0x58, 0x41, 0xdb, - 0x47, 0xaf, 0x19, 0x30, 0xd5, 0x70, 0xad, 0x5a, 0xd9, 0x6a, 0x58, 0x4e, 0x95, 0x78, 0x8b, 0xc6, - 0x43, 0xc6, 0xa3, 0x93, 0x8f, 0xad, 0x2f, 0x8f, 0x32, 0x5f, 0xcb, 0xa5, 0x5b, 0x3e, 0x26, 0xbe, - 0xdb, 0xf6, 0xaa, 0x04, 0x93, 0xdd, 0xf2, 0xc2, 0xb7, 0x3b, 0xc5, 0xfb, 0xba, 0x9d, 0xe2, 0xd4, - 0xba, 0xc6, 0x09, 0x47, 0xf8, 0xa2, 0x2f, 0x18, 0x30, 0x5f, 0xb5, 0x1c, 0xcb, 0x3b, 0xdc, 0xb6, - 0xbc, 0x3a, 0x09, 0x9e, 0xf5, 0xdc, 0x76, 0x6b, 0x31, 0x73, 0x02, 0xad, 0xb9, 0x5f, 0xb4, 0x66, - 0x7e, 0x25, 0xce, 0x0e, 0xf7, 0xb6, 0x80, 0xb5, 0xcb, 0x0f, 0xac, 0x9d, 0x06, 0xd1, 0xdb, 0x95, - 0x3d, 0xc9, 0x76, 0x55, 0xe2, 0xec, 0x70, 0x6f, 0x0b, 0xcc, 0x57, 0xb3, 0x30, 0x5f, 0x5a, 0x2f, - 0x6f, 0x7b, 0xd6, 0xee, 0xae, 0x5d, 0xc5, 0x6e, 0x3b, 0xb0, 0x9d, 0x3a, 0x7a, 0x3b, 0x4c, 0xd8, - 0x4e, 0xdd, 0x23, 0xbe, 0xcf, 0x26, 0xb2, 0x50, 0x9e, 0x15, 0x44, 0x27, 0xd6, 0x78, 0x31, 0x96, - 0x70, 0xf4, 0x24, 0x4c, 0xfa, 0xc4, 0x3b, 0xb0, 0xab, 0x64, 0xcb, 0xf5, 0x02, 0x36, 0xd2, 0xb9, - 0xf2, 0x29, 0x81, 0x3e, 0x59, 0x09, 0x41, 0x58, 0xc7, 0xa3, 0xd5, 0x3c, 0xd7, 0x0d, 0x04, 0x9c, - 0x0d, 0x44, 0x21, 0xac, 0x86, 0x43, 0x10, 0xd6, 0xf1, 0xd0, 0xeb, 0x06, 0xcc, 0xf9, 0x81, 0x5d, - 0xdd, 0xb7, 0x1d, 0xe2, 0xfb, 0x2b, 0xae, 0xb3, 0x6b, 0xd7, 0x17, 0x73, 0x6c, 0x14, 0x37, 0x47, - 0x1b, 0xc5, 0x4a, 0x8c, 0x6a, 0x79, 0xa1, 0xdb, 0x29, 0xce, 0xc5, 0x4b, 0x71, 0x0f, 0x77, 0xb4, - 0x0a, 0x73, 0x96, 0xe3, 0xb8, 0x81, 0x15, 0xd8, 0xae, 0xb3, 0xe5, 0x91, 0x5d, 0xfb, 0xf6, 0xe2, - 0x18, 0xeb, 0xce, 0xa2, 0xe8, 0xce, 0x5c, 0x29, 0x06, 0xc7, 0x3d, 0x35, 0xcc, 0x55, 0x58, 0x2c, - 0x35, 0x77, 0x2c, 0xdf, 0xb7, 0x6a, 0xae, 0x17, 0x9b, 0x8d, 0x47, 0x21, 0xdf, 0xb4, 0x5a, 0x2d, - 0xdb, 0xa9, 0xd3, 0xe9, 0xc8, 0x3e, 0x5a, 0x28, 0x4f, 0x75, 0x3b, 0xc5, 0xfc, 0x86, 0x28, 0xc3, - 0x0a, 0x6a, 0x7e, 0x3f, 0x03, 0x93, 0x25, 0xc7, 0x6a, 0x1c, 0xfa, 0xb6, 0x8f, 0xdb, 0x0e, 0xfa, - 0x08, 0xe4, 0xa9, 0x74, 0xa9, 0x59, 0x81, 0x25, 0x76, 0xe4, 0xbb, 0x96, 0xf9, 0x66, 0x5f, 0xd6, - 0x37, 0x7b, 0x38, 0x2e, 0x14, 0x7b, 0xf9, 0xe0, 0xdd, 0xcb, 0x57, 0x76, 0x6e, 0x92, 0x6a, 0xb0, - 0x41, 0x02, 0xab, 0x8c, 0x44, 0x2f, 0x20, 0x2c, 0xc3, 0x8a, 0x2a, 0x72, 0x61, 0xcc, 0x6f, 0x91, - 0xaa, 0xd8, 0x61, 0x1b, 0x23, 0xae, 0xe4, 0xb0, 0xe9, 0x95, 0x16, 0xa9, 0x96, 0xa7, 0x04, 0xeb, - 0x31, 0xfa, 0x0f, 0x33, 0x46, 0xe8, 0x16, 0x8c, 0xfb, 0x4c, 0xe6, 0x88, 0xcd, 0x73, 0x25, 0x3d, - 0x96, 0x8c, 0x6c, 0x79, 0x46, 0x30, 0x1d, 0xe7, 0xff, 0xb1, 0x60, 0x67, 0xfe, 0x83, 0x01, 0xa7, - 0x34, 0xec, 0x92, 0x57, 0x6f, 0x37, 0x89, 0x13, 0xa0, 0x87, 0x60, 0xcc, 0xb1, 0x9a, 0x44, 0x6c, - 0x14, 0xd5, 0xe4, 0x4d, 0xab, 0x49, 0x30, 0x83, 0xa0, 0x87, 0x21, 0x77, 0x60, 0x35, 0xda, 0x84, - 0x0d, 0x52, 0xa1, 0x3c, 0x2d, 0x50, 0x72, 0xd7, 0x69, 0x21, 0xe6, 0x30, 0xf4, 0x12, 0x14, 0xd8, - 0x8f, 0x8b, 0x9e, 0xdb, 0x4c, 0xa9, 0x6b, 0xa2, 0x85, 0xd7, 0x25, 0xd9, 0xf2, 0x74, 0xb7, 0x53, - 0x2c, 0xa8, 0xbf, 0x38, 0x64, 0x68, 0xfe, 0xa3, 0x01, 0xb3, 0x5a, 0xe7, 0xd6, 0x6d, 0x3f, 0x40, - 0x1f, 0xea, 0x59, 0x3c, 0xcb, 0x83, 0x2d, 0x1e, 0x5a, 0x9b, 0x2d, 0x9d, 0x39, 0xd1, 0xd3, 0xbc, - 0x2c, 0xd1, 0x16, 0x8e, 0x03, 0x39, 0x3b, 0x20, 0x4d, 0x7f, 0x31, 0xf3, 0x50, 0xf6, 0xd1, 0xc9, - 0xc7, 0xd6, 0x52, 0x9b, 0xc6, 0x70, 0x7c, 0xd7, 0x28, 0x7d, 0xcc, 0xd9, 0x98, 0x5f, 0x1b, 0x8b, - 0xf4, 0x90, 0xae, 0x28, 0xe4, 0xc2, 0x44, 0x93, 0x04, 0x9e, 0x5d, 0xe5, 0xfb, 0x6a, 0xf2, 0xb1, - 0xd5, 0xd1, 0x5a, 0xb1, 0xc1, 0x88, 0x85, 0xc2, 0x92, 0xff, 0xf7, 0xb1, 0xe4, 0x82, 0xf6, 0x60, - 0xcc, 0xf2, 0xea, 0xb2, 0xcf, 0x17, 0xd3, 0x99, 0xdf, 0x70, 0xcd, 0x95, 0xbc, 0xba, 0x8f, 0x19, - 0x07, 0x74, 0x1e, 0x0a, 0x01, 0xf1, 0x9a, 0xb6, 0x63, 0x05, 0x5c, 0xba, 0xe6, 0xcb, 0xf3, 0x02, - 0xad, 0xb0, 0x2d, 0x01, 0x38, 0xc4, 0x41, 0x0d, 0x18, 0xaf, 0x79, 0x87, 0xb8, 0xed, 0x2c, 0x8e, - 0xa5, 0x31, 0x14, 0xab, 0x8c, 0x56, 0xb8, 0x99, 0xf8, 0x7f, 0x2c, 0x78, 0xa0, 0x2f, 0x1b, 0xb0, - 0xd0, 0x24, 0x96, 0xdf, 0xf6, 0x08, 0xed, 0x02, 0x26, 0x01, 0x71, 0xa8, 0x34, 0x5c, 0xcc, 0x31, - 0xe6, 0x78, 0xd4, 0x79, 0xe8, 0xa5, 0x5c, 0x7e, 0x50, 0x34, 0x65, 0x21, 0x09, 0x8a, 0x13, 0x5b, - 0x63, 0x7e, 0x7f, 0x0c, 0xe6, 0x7b, 0x24, 0x04, 0x7a, 0x02, 0x72, 0xad, 0x3d, 0xcb, 0x97, 0x5b, - 0xfe, 0x9c, 0x5c, 0x6f, 0x5b, 0xb4, 0xf0, 0x4e, 0xa7, 0x38, 0x2d, 0xab, 0xb0, 0x02, 0xcc, 0x91, - 0xa9, 0x4e, 0x6d, 0x12, 0xdf, 0xb7, 0xea, 0x52, 0x0e, 0x68, 0xcb, 0x84, 0x15, 0x63, 0x09, 0x47, - 0xbf, 0x6c, 0xc0, 0x34, 0x5f, 0x32, 0x98, 0xf8, 0xed, 0x46, 0x40, 0x65, 0x1d, 0x1d, 0x96, 0xcb, - 0x69, 0x2c, 0x4f, 0x4e, 0xb2, 0x7c, 0x5a, 0x70, 0x9f, 0xd6, 0x4b, 0x7d, 0x1c, 0xe5, 0x8b, 0x6e, - 0x40, 0xc1, 0x0f, 0x2c, 0x2f, 0x20, 0xb5, 0x52, 0xc0, 0xb4, 0xda, 0xe4, 0x63, 0xff, 0x7f, 0x30, - 0x21, 0xb0, 0x6d, 0x37, 0x09, 0x17, 0x38, 0x15, 0x49, 0x00, 0x87, 0xb4, 0xd0, 0x4b, 0x00, 0x5e, - 0xdb, 0xa9, 0xb4, 0x9b, 0x4d, 0xcb, 0x3b, 0x14, 0x1a, 0xfc, 0xd2, 0x68, 0xdd, 0xc3, 0x8a, 0x5e, - 0xa8, 0xb3, 0xc2, 0x32, 0xac, 0xf1, 0x43, 0xaf, 0x18, 0x30, 0xcd, 0x57, 0xa2, 0x6c, 0xc1, 0x78, - 0xca, 0x2d, 0x98, 0xa7, 0x43, 0xbb, 0xaa, 0xb3, 0xc0, 0x51, 0x8e, 0xe6, 0xdf, 0x45, 0xf5, 0x49, - 0x25, 0xa0, 0xd6, 0x75, 0xfd, 0x10, 0x7d, 0x10, 0xee, 0xf7, 0xdb, 0xd5, 0x2a, 0xf1, 0xfd, 0xdd, - 0x76, 0x03, 0xb7, 0x9d, 0x4b, 0xb6, 0x1f, 0xb8, 0xde, 0xe1, 0xba, 0xdd, 0xb4, 0x03, 0xb6, 0xe2, - 0x72, 0xe5, 0xb3, 0xdd, 0x4e, 0xf1, 0xfe, 0x4a, 0x3f, 0x24, 0xdc, 0xbf, 0x3e, 0xb2, 0xe0, 0x81, - 0xb6, 0xd3, 0x9f, 0x3c, 0xb7, 0xde, 0x8a, 0xdd, 0x4e, 0xf1, 0x81, 0x6b, 0xfd, 0xd1, 0xf0, 0x51, - 0x34, 0xcc, 0x7f, 0x35, 0x60, 0x4e, 0xf6, 0x6b, 0x9b, 0x34, 0x5b, 0x0d, 0x2a, 0x5d, 0x4e, 0xde, - 0x10, 0x09, 0x22, 0x86, 0x08, 0x4e, 0x47, 0x9d, 0xc8, 0xf6, 0xf7, 0xb3, 0x46, 0xcc, 0x7f, 0x31, - 0x60, 0x21, 0x8e, 0x7c, 0x0f, 0x94, 0xa7, 0x1f, 0x55, 0x9e, 0x9b, 0xe9, 0xf6, 0xb6, 0x8f, 0x06, - 0x7d, 0x6d, 0xac, 0xb7, 0xaf, 0xff, 0xdb, 0xd5, 0x68, 0xa8, 0x15, 0xb3, 0x3f, 0x49, 0xad, 0x38, - 0xf6, 0xa6, 0xd2, 0x8a, 0xbf, 0x37, 0x06, 0x53, 0x25, 0x27, 0xb0, 0x4b, 0xbb, 0xbb, 0xb6, 0x63, - 0x07, 0x87, 0xe8, 0xd3, 0x19, 0x38, 0xdf, 0xf2, 0xc8, 0x2e, 0xf1, 0x3c, 0x52, 0x5b, 0x6d, 0x7b, - 0xb6, 0x53, 0xaf, 0x54, 0xf7, 0x48, 0xad, 0xdd, 0xb0, 0x9d, 0xfa, 0x5a, 0xdd, 0x71, 0x55, 0xf1, - 0x85, 0xdb, 0xa4, 0xda, 0x66, 0x5d, 0xe2, 0x9b, 0xa2, 0x39, 0x5a, 0x97, 0xb6, 0x86, 0x63, 0x5a, - 0x7e, 0xbc, 0xdb, 0x29, 0x9e, 0x1f, 0xb2, 0x12, 0x1e, 0xb6, 0x6b, 0xe8, 0x53, 0x19, 0x58, 0xf6, - 0xc8, 0x47, 0xdb, 0xf6, 0xe0, 0xa3, 0xc1, 0xa5, 0x56, 0x63, 0x44, 0xf5, 0x33, 0x14, 0xcf, 0xf2, - 0x63, 0xdd, 0x4e, 0x71, 0xc8, 0x3a, 0x78, 0xc8, 0x7e, 0x99, 0xdf, 0xc8, 0xc0, 0xe9, 0x52, 0xab, - 0xb5, 0x41, 0xfc, 0xbd, 0xd8, 0xa1, 0xf6, 0xb3, 0x06, 0xcc, 0x1c, 0xd8, 0x5e, 0xd0, 0xb6, 0x1a, - 0xd2, 0x09, 0xc0, 0x97, 0x44, 0x65, 0xc4, 0xed, 0xcc, 0xb9, 0x5d, 0x8f, 0x90, 0x2e, 0xa3, 0x6e, - 0xa7, 0x38, 0x13, 0x2d, 0xc3, 0x31, 0xf6, 0xe8, 0x37, 0x0c, 0x98, 0x13, 0x45, 0x9b, 0x6e, 0x8d, - 0xe8, 0x9e, 0xa3, 0x6b, 0x69, 0xb6, 0x49, 0x11, 0xe7, 0x2e, 0x86, 0x78, 0x29, 0xee, 0x69, 0x84, - 0xf9, 0xef, 0x19, 0x38, 0xd3, 0x87, 0x06, 0xfa, 0x5d, 0x03, 0x16, 0xb8, 0xbb, 0x49, 0x03, 0x61, - 0xb2, 0x2b, 0x46, 0xf3, 0x03, 0x69, 0xb7, 0x1c, 0xd3, 0xbd, 0x40, 0x9c, 0x2a, 0x29, 0x2f, 0x52, - 0xb1, 0xb1, 0x92, 0xc0, 0x1a, 0x27, 0x36, 0x88, 0xb5, 0x94, 0x3b, 0xa0, 0x62, 0x2d, 0xcd, 0xdc, - 0x93, 0x96, 0x56, 0x12, 0x58, 0xe3, 0xc4, 0x06, 0x99, 0x3f, 0x0f, 0x0f, 0x1c, 0x41, 0xee, 0xee, - 0x27, 0x7e, 0xf3, 0x05, 0xb5, 0xea, 0xa3, 0x6b, 0x6e, 0x00, 0x67, 0x81, 0x09, 0xe3, 0x9e, 0xdb, - 0x0e, 0x08, 0xd7, 0x6e, 0x85, 0x32, 0x50, 0x3d, 0x81, 0x59, 0x09, 0x16, 0x10, 0xf3, 0x1b, 0x06, - 0xe4, 0x87, 0xf0, 0x3f, 0x14, 0xa3, 0xfe, 0x87, 0x42, 0x8f, 0xef, 0x21, 0xe8, 0xf5, 0x3d, 0x3c, - 0x3b, 0xda, 0x6c, 0x0c, 0xe2, 0x73, 0xf8, 0x0f, 0x03, 0xe6, 0x7b, 0x7c, 0x14, 0x68, 0x0f, 0x16, - 0x5a, 0x6e, 0x4d, 0xda, 0x17, 0x97, 0x2c, 0x7f, 0x8f, 0xc1, 0x44, 0xf7, 0x9e, 0xa0, 0x33, 0xb9, - 0x95, 0x00, 0xbf, 0xd3, 0x29, 0x2e, 0x2a, 0x22, 0x31, 0x04, 0x9c, 0x48, 0x11, 0xb5, 0x20, 0xbf, - 0x6b, 0x93, 0x46, 0x2d, 0x5c, 0x82, 0x23, 0x5a, 0x12, 0x17, 0x05, 0x35, 0xee, 0x9e, 0x93, 0xff, - 0xb0, 0xe2, 0x62, 0x5e, 0x85, 0x99, 0xa8, 0xb3, 0x76, 0x80, 0xc9, 0x3b, 0x0b, 0x59, 0xcb, 0x73, - 0xc4, 0xd4, 0x4d, 0x0a, 0x84, 0x6c, 0x09, 0x6f, 0x62, 0x5a, 0x6e, 0xfe, 0x78, 0x0c, 0x66, 0xcb, - 0x8d, 0x36, 0x79, 0xd6, 0x23, 0x44, 0x9e, 0x4f, 0x4b, 0x30, 0xdb, 0xf2, 0xc8, 0x81, 0x4d, 0x6e, - 0x55, 0x48, 0x83, 0x54, 0x03, 0xd7, 0x13, 0xf4, 0xcf, 0x88, 0xea, 0xb3, 0x5b, 0x51, 0x30, 0x8e, - 0xe3, 0xa3, 0x67, 0x60, 0xc6, 0xaa, 0x06, 0xf6, 0x01, 0x51, 0x14, 0x78, 0x03, 0xde, 0x22, 0x28, - 0xcc, 0x94, 0x22, 0x50, 0x1c, 0xc3, 0x46, 0x1f, 0x82, 0x45, 0xbf, 0x6a, 0x35, 0xc8, 0xb5, 0x96, - 0x60, 0xb5, 0xb2, 0x47, 0xaa, 0xfb, 0x5b, 0xae, 0xed, 0x04, 0xc2, 0x1b, 0xf1, 0x90, 0xa0, 0xb4, - 0x58, 0xe9, 0x83, 0x87, 0xfb, 0x52, 0x40, 0x7f, 0x62, 0xc0, 0xd9, 0x96, 0x47, 0xb6, 0x3c, 0xb7, - 0xe9, 0x52, 0x35, 0xd3, 0x73, 0x44, 0x17, 0x47, 0xd5, 0xeb, 0x23, 0xea, 0x53, 0x5e, 0xd2, 0xeb, - 0x22, 0x7c, 0x6b, 0xb7, 0x53, 0x3c, 0xbb, 0x75, 0x54, 0x03, 0xf0, 0xd1, 0xed, 0x43, 0x7f, 0x66, - 0xc0, 0xb9, 0x96, 0xeb, 0x07, 0x47, 0x74, 0x21, 0x77, 0xa2, 0x5d, 0x30, 0xbb, 0x9d, 0xe2, 0xb9, - 0xad, 0x23, 0x5b, 0x80, 0xef, 0xd2, 0x42, 0xb3, 0x3b, 0x09, 0xf3, 0xda, 0xda, 0x13, 0xe7, 0xd7, - 0xa7, 0x61, 0x5a, 0x2e, 0x86, 0x50, 0xad, 0x17, 0x42, 0x7f, 0x43, 0x49, 0x07, 0xe2, 0x28, 0x2e, - 0x5d, 0x77, 0x6a, 0x29, 0xf2, 0xda, 0xb1, 0x75, 0xb7, 0x15, 0x81, 0xe2, 0x18, 0x36, 0x5a, 0x83, - 0x53, 0xa2, 0x04, 0x93, 0x56, 0xc3, 0xae, 0x5a, 0x2b, 0x6e, 0x5b, 0x2c, 0xb9, 0x5c, 0xf9, 0x4c, - 0xb7, 0x53, 0x3c, 0xb5, 0xd5, 0x0b, 0xc6, 0x49, 0x75, 0xd0, 0x3a, 0x2c, 0x58, 0xed, 0xc0, 0x55, - 0xfd, 0xbf, 0xe0, 0x50, 0x4d, 0x51, 0x63, 0x4b, 0x2b, 0xcf, 0x55, 0x4a, 0x29, 0x01, 0x8e, 0x13, - 0x6b, 0xa1, 0xad, 0x18, 0xb5, 0x0a, 0xa9, 0xba, 0x4e, 0x8d, 0xcf, 0x72, 0x2e, 0xb4, 0xc2, 0x4b, - 0x09, 0x38, 0x38, 0xb1, 0x26, 0x6a, 0xc0, 0x4c, 0xd3, 0xba, 0x7d, 0xcd, 0xb1, 0x0e, 0x2c, 0xbb, - 0x41, 0x99, 0x08, 0x1f, 0x46, 0xff, 0x83, 0x75, 0x3b, 0xb0, 0x1b, 0xcb, 0xfc, 0x3a, 0x6f, 0x79, - 0xcd, 0x09, 0xae, 0x78, 0x95, 0x80, 0x5a, 0x6b, 0xdc, 0x38, 0xda, 0x88, 0xd0, 0xc2, 0x31, 0xda, - 0xe8, 0x0a, 0x9c, 0x66, 0xdb, 0x71, 0xd5, 0xbd, 0xe5, 0xac, 0x92, 0x86, 0x75, 0x28, 0x3b, 0x30, - 0xc1, 0x3a, 0x70, 0x7f, 0xb7, 0x53, 0x3c, 0x5d, 0x49, 0x42, 0xc0, 0xc9, 0xf5, 0x90, 0x05, 0x0f, - 0x44, 0x01, 0x98, 0x1c, 0xd8, 0xbe, 0xed, 0x3a, 0xdc, 0x13, 0x91, 0x0f, 0x3d, 0x11, 0x95, 0xfe, - 0x68, 0xf8, 0x28, 0x1a, 0xe8, 0xb7, 0x0c, 0x58, 0x48, 0xda, 0x86, 0x8b, 0x85, 0x34, 0x2e, 0x2b, - 0x62, 0x5b, 0x8b, 0xaf, 0x88, 0x44, 0xa1, 0x90, 0xd8, 0x08, 0xf4, 0xb2, 0x01, 0x53, 0x96, 0x76, - 0x8a, 0x5a, 0x04, 0xd6, 0xaa, 0xcb, 0xa3, 0x9e, 0xe5, 0x43, 0x8a, 0xe5, 0xb9, 0x6e, 0xa7, 0x18, - 0x39, 0xa9, 0xe1, 0x08, 0x47, 0xf4, 0xdb, 0x06, 0x9c, 0x4e, 0xdc, 0xe3, 0x8b, 0x93, 0x27, 0x31, - 0x42, 0x6c, 0x91, 0x24, 0xcb, 0x9c, 0xe4, 0x66, 0xa0, 0xd7, 0x0d, 0xa5, 0xca, 0x36, 0xa4, 0x37, - 0x65, 0x8a, 0x35, 0xed, 0xea, 0x88, 0x07, 0xc7, 0xd0, 0x20, 0x90, 0x84, 0xcb, 0xa7, 0x34, 0xcd, - 0x28, 0x0b, 0x71, 0x9c, 0x3d, 0xfa, 0x8c, 0x21, 0x55, 0xa3, 0x6a, 0xd1, 0xf4, 0x49, 0xb5, 0x08, - 0x85, 0x9a, 0x56, 0x35, 0x28, 0xc6, 0x1c, 0x7d, 0x18, 0x96, 0xac, 0x1d, 0xd7, 0x0b, 0x12, 0x37, - 0xdf, 0xe2, 0x0c, 0xdb, 0x46, 0xe7, 0xba, 0x9d, 0xe2, 0x52, 0xa9, 0x2f, 0x16, 0x3e, 0x82, 0x82, - 0xf9, 0xd5, 0x1c, 0x4c, 0x71, 0x23, 0x5f, 0xa8, 0xae, 0xaf, 0x1b, 0xf0, 0x60, 0xb5, 0xed, 0x79, - 0xc4, 0x09, 0x2a, 0x01, 0x69, 0xf5, 0x2a, 0x2e, 0xe3, 0x44, 0x15, 0xd7, 0x43, 0xdd, 0x4e, 0xf1, - 0xc1, 0x95, 0x23, 0xf8, 0xe3, 0x23, 0x5b, 0x87, 0xfe, 0xca, 0x00, 0x53, 0x20, 0x94, 0xad, 0xea, - 0x7e, 0xdd, 0x73, 0xdb, 0x4e, 0xad, 0xb7, 0x13, 0x99, 0x13, 0xed, 0xc4, 0x23, 0xdd, 0x4e, 0xd1, - 0x5c, 0xb9, 0x6b, 0x2b, 0xf0, 0x00, 0x2d, 0x45, 0xcf, 0xc2, 0xbc, 0xc0, 0xba, 0x70, 0xbb, 0x45, - 0x3c, 0x9b, 0x9a, 0xd3, 0xe2, 0x3e, 0x3d, 0x0c, 0x51, 0x88, 0x23, 0xe0, 0xde, 0x3a, 0xc8, 0x87, - 0x89, 0x5b, 0xc4, 0xae, 0xef, 0x05, 0xd2, 0x7c, 0x1a, 0x31, 0x2e, 0x41, 0x1c, 0xf8, 0x6f, 0x70, - 0x9a, 0xe5, 0xc9, 0x6e, 0xa7, 0x38, 0x21, 0xfe, 0x60, 0xc9, 0x09, 0x6d, 0xc2, 0x0c, 0x3f, 0x82, - 0x6d, 0xd9, 0x4e, 0x7d, 0xcb, 0x75, 0xf8, 0x6d, 0x7e, 0xa1, 0xfc, 0x88, 0x54, 0xf8, 0x95, 0x08, - 0xf4, 0x4e, 0xa7, 0x38, 0x25, 0x7f, 0x6f, 0x1f, 0xb6, 0x08, 0x8e, 0xd5, 0x36, 0xff, 0x60, 0x0c, - 0x40, 0x2e, 0x57, 0xd2, 0x42, 0x3f, 0x03, 0x05, 0x9f, 0x04, 0x9c, 0xab, 0x70, 0x9e, 0xf3, 0x3b, - 0x09, 0x59, 0x88, 0x43, 0x38, 0xda, 0x87, 0x5c, 0xcb, 0x6a, 0xfb, 0x44, 0x4c, 0xfe, 0xe5, 0x54, - 0x26, 0x7f, 0x8b, 0x52, 0xe4, 0x67, 0x2e, 0xf6, 0x13, 0x73, 0x1e, 0xe8, 0x93, 0x06, 0x00, 0x89, - 0x4e, 0xd8, 0xc8, 0xbe, 0x0f, 0xc1, 0x32, 0x9c, 0x53, 0x3a, 0x06, 0xe5, 0x99, 0x6e, 0xa7, 0x08, - 0xda, 0xd4, 0x6b, 0x6c, 0xd1, 0x2d, 0xc8, 0x5b, 0x52, 0xe6, 0x8f, 0x9d, 0x84, 0xcc, 0x67, 0x47, - 0x21, 0xb5, 0x68, 0x15, 0x33, 0xf4, 0x29, 0x03, 0x66, 0x7c, 0x12, 0x88, 0xa9, 0xa2, 0x92, 0x47, - 0x18, 0xbc, 0x23, 0x2e, 0xba, 0x4a, 0x84, 0x26, 0x97, 0xa0, 0xd1, 0x32, 0x1c, 0xe3, 0x6b, 0xfe, - 0xcd, 0x14, 0xcc, 0xc8, 0x25, 0x13, 0xda, 0xb0, 0xdc, 0x85, 0xd1, 0xc7, 0x86, 0x5d, 0xd1, 0x81, - 0x38, 0x8a, 0x4b, 0x2b, 0xf3, 0x45, 0x19, 0x35, 0x61, 0x55, 0xe5, 0x8a, 0x0e, 0xc4, 0x51, 0x5c, - 0xd4, 0x84, 0x9c, 0x1f, 0x90, 0x96, 0xbc, 0xf1, 0x1b, 0xf1, 0x42, 0x2a, 0xdc, 0x09, 0xa1, 0x4f, - 0x9f, 0xfe, 0xf3, 0x31, 0xe7, 0xc2, 0xbc, 0x70, 0x41, 0xc4, 0x31, 0x27, 0x96, 0x41, 0x3a, 0x2b, - 0x31, 0xea, 0xf3, 0xe3, 0xb3, 0x11, 0x2d, 0xc3, 0x31, 0xf6, 0x09, 0x66, 0x6d, 0xee, 0x04, 0xcd, - 0xda, 0xe7, 0x21, 0xdf, 0xb4, 0x6e, 0x57, 0xda, 0x5e, 0xfd, 0xf8, 0xe6, 0xb3, 0x08, 0xc6, 0xe1, - 0x54, 0xb0, 0xa2, 0x87, 0x5e, 0x31, 0xb4, 0xcd, 0x35, 0xc1, 0x88, 0xdf, 0x48, 0x77, 0x73, 0x29, - 0xad, 0xd0, 0x77, 0x9b, 0xf5, 0x18, 0x99, 0xf9, 0x7b, 0x6e, 0x64, 0x52, 0x83, 0x89, 0x6f, 0x10, - 0x65, 0x30, 0x15, 0x4e, 0xd4, 0x60, 0x5a, 0x89, 0x30, 0xc3, 0x31, 0xe6, 0xac, 0x3d, 0x7c, 0xcf, - 0xa9, 0xf6, 0xc0, 0x89, 0xb6, 0xa7, 0x12, 0x61, 0x86, 0x63, 0xcc, 0xfb, 0x9f, 0xac, 0x26, 0x4f, - 0xe6, 0x64, 0x35, 0x95, 0xc2, 0xc9, 0xea, 0x68, 0xa3, 0x73, 0x7a, 0x54, 0xa3, 0x13, 0x5d, 0x06, - 0x54, 0x3b, 0x74, 0xac, 0xa6, 0x5d, 0x15, 0xc2, 0x92, 0x29, 0x88, 0x19, 0x76, 0xf2, 0x5e, 0x12, - 0x82, 0x0c, 0xad, 0xf6, 0x60, 0xe0, 0x84, 0x5a, 0x28, 0x80, 0x7c, 0x4b, 0xda, 0x16, 0xb3, 0x69, - 0xac, 0x7e, 0x69, 0x6b, 0xf0, 0x4b, 0x61, 0xba, 0xf1, 0x64, 0x09, 0x56, 0x9c, 0xcc, 0xff, 0x32, - 0x60, 0x6e, 0xa5, 0xe1, 0xb6, 0x6b, 0x37, 0xac, 0xa0, 0xba, 0xc7, 0x6f, 0x30, 0xd1, 0x33, 0x90, - 0xb7, 0x9d, 0x80, 0x78, 0x07, 0x56, 0x43, 0x68, 0x14, 0x53, 0x5e, 0xf2, 0xae, 0x89, 0xf2, 0x3b, - 0x9d, 0xe2, 0xcc, 0x6a, 0xdb, 0x63, 0xa1, 0x81, 0x5c, 0xbe, 0x60, 0x55, 0x07, 0x7d, 0xc9, 0x80, - 0x79, 0x7e, 0x07, 0xba, 0x6a, 0x05, 0xd6, 0xd5, 0x36, 0xf1, 0x6c, 0x22, 0x6f, 0x41, 0x47, 0x14, - 0x2d, 0xf1, 0xb6, 0x4a, 0x06, 0x87, 0xa1, 0x11, 0xb9, 0x11, 0xe7, 0x8c, 0x7b, 0x1b, 0x63, 0x7e, - 0x2e, 0x0b, 0xf7, 0xf7, 0xa5, 0x85, 0x96, 0x20, 0x63, 0xd7, 0x44, 0xd7, 0x41, 0xd0, 0xcd, 0xac, - 0xd5, 0x70, 0xc6, 0xae, 0xa1, 0x65, 0x66, 0x0f, 0x79, 0xc4, 0xf7, 0xe5, 0x85, 0x58, 0x41, 0x99, - 0x2e, 0xa2, 0x14, 0x6b, 0x18, 0xa8, 0x08, 0xb9, 0x86, 0xb5, 0x43, 0x1a, 0xc2, 0xd6, 0x65, 0x16, - 0xd6, 0x3a, 0x2d, 0xc0, 0xbc, 0x1c, 0xfd, 0x92, 0x01, 0xc0, 0x1b, 0x48, 0x2d, 0x65, 0xa1, 0xd7, - 0x70, 0xba, 0xc3, 0x44, 0x29, 0xf3, 0x56, 0x86, 0xff, 0xb1, 0xc6, 0x15, 0x6d, 0xc3, 0x38, 0x35, - 0xb6, 0xdc, 0xda, 0xb1, 0xd5, 0x18, 0xbb, 0x00, 0xd8, 0x62, 0x34, 0xb0, 0xa0, 0x45, 0xc7, 0xca, - 0x23, 0x41, 0xdb, 0x73, 0xe8, 0xd0, 0x32, 0xc5, 0x95, 0xe7, 0xad, 0xc0, 0xaa, 0x14, 0x6b, 0x18, - 0xe6, 0x1f, 0x67, 0x60, 0x21, 0xa9, 0xe9, 0x54, 0x3f, 0x8c, 0xf3, 0xd6, 0x8a, 0x63, 0xdb, 0xfb, - 0xd3, 0x1f, 0x1f, 0x71, 0x9d, 0xaf, 0x2e, 0xbd, 0x45, 0xc0, 0x91, 0xe0, 0x8b, 0xde, 0xaf, 0x46, - 0x28, 0x73, 0xcc, 0x11, 0x52, 0x94, 0x63, 0xa3, 0xf4, 0x10, 0x8c, 0xf9, 0x74, 0xe6, 0xb3, 0x51, - 0xe7, 0x3a, 0x9b, 0x23, 0x06, 0xa1, 0x18, 0x6d, 0xc7, 0x0e, 0x44, 0xbc, 0xae, 0xc2, 0xb8, 0xe6, - 0xd8, 0x01, 0x66, 0x10, 0xf3, 0x0b, 0x19, 0x58, 0xea, 0xdf, 0x29, 0xf4, 0x05, 0x03, 0xa0, 0x46, - 0x4d, 0x69, 0xba, 0x24, 0x65, 0xf8, 0x83, 0x75, 0x52, 0x63, 0xb8, 0x2a, 0x39, 0x85, 0xb1, 0x30, - 0xaa, 0xc8, 0xc7, 0x5a, 0x43, 0xd0, 0x63, 0x72, 0xe9, 0x6f, 0x5a, 0x4d, 0x69, 0x80, 0xaa, 0x3a, - 0x1b, 0x0a, 0x82, 0x35, 0x2c, 0x7a, 0x56, 0x72, 0xac, 0x26, 0xf1, 0x5b, 0x96, 0x0a, 0xc8, 0x66, - 0x67, 0xa5, 0x4d, 0x59, 0x88, 0x43, 0xb8, 0xd9, 0x80, 0x87, 0x07, 0x68, 0x67, 0x4a, 0xc1, 0xb1, - 0xe6, 0x7f, 0x1a, 0x70, 0x66, 0xa5, 0xd1, 0xf6, 0x03, 0xe2, 0xfd, 0x9f, 0x09, 0x2d, 0xfa, 0x6f, - 0x03, 0x1e, 0xe8, 0xd3, 0xe7, 0x7b, 0x10, 0x61, 0xf4, 0x62, 0x34, 0xc2, 0xe8, 0xda, 0xa8, 0x4b, - 0x3a, 0xb1, 0x1f, 0x7d, 0x02, 0x8d, 0x02, 0x98, 0xa6, 0x52, 0xab, 0xe6, 0xd6, 0x53, 0xd2, 0x9b, - 0x0f, 0x43, 0xee, 0xa3, 0x54, 0xff, 0xc4, 0xd7, 0x18, 0x53, 0x4a, 0x98, 0xc3, 0xcc, 0xf7, 0x81, - 0x08, 0xc7, 0x89, 0x6d, 0x1e, 0x63, 0x90, 0xcd, 0x63, 0xfe, 0x7d, 0x06, 0xb4, 0x33, 0xf6, 0x3d, - 0x58, 0x94, 0x4e, 0x64, 0x51, 0x8e, 0x78, 0x6a, 0xd6, 0x3c, 0x06, 0xfd, 0xe2, 0xee, 0x0f, 0x62, - 0x71, 0xf7, 0x9b, 0xa9, 0x71, 0x3c, 0x3a, 0xec, 0xfe, 0xbb, 0x06, 0x3c, 0x10, 0x22, 0xf7, 0xba, - 0xbf, 0xee, 0x2e, 0x61, 0x9e, 0x84, 0x49, 0x2b, 0xac, 0x26, 0xd6, 0x80, 0x7a, 0x6a, 0xa2, 0x51, - 0xc4, 0x3a, 0x5e, 0x18, 0xe5, 0x9b, 0x3d, 0x66, 0x94, 0xef, 0xd8, 0xd1, 0x51, 0xbe, 0xe6, 0x8f, - 0x32, 0x70, 0xb6, 0xb7, 0x67, 0x72, 0x6f, 0x0c, 0x76, 0x3b, 0xfc, 0x14, 0x4c, 0x05, 0xa2, 0x82, - 0x26, 0xe9, 0xd5, 0x43, 0xa9, 0x6d, 0x0d, 0x86, 0x23, 0x98, 0xb4, 0x66, 0x95, 0xef, 0xca, 0x4a, - 0xd5, 0x6d, 0xc9, 0x18, 0x71, 0x55, 0x73, 0x45, 0x83, 0xe1, 0x08, 0xa6, 0x8a, 0xbe, 0x1b, 0x3b, - 0xf1, 0xe8, 0xbb, 0x0a, 0x9c, 0x96, 0xf1, 0x46, 0x17, 0x5d, 0x6f, 0xc5, 0x6d, 0xb6, 0x1a, 0x44, - 0x44, 0x89, 0xd3, 0xc6, 0x9e, 0x15, 0x55, 0x4e, 0xe3, 0x24, 0x24, 0x9c, 0x5c, 0xd7, 0xfc, 0x6e, - 0x16, 0x4e, 0x85, 0xc3, 0xbe, 0xe2, 0x3a, 0x35, 0x9b, 0x45, 0x6d, 0x3d, 0x0d, 0x63, 0xc1, 0x61, - 0x4b, 0x0e, 0xf6, 0xff, 0x93, 0xcd, 0xd9, 0x3e, 0x6c, 0xd1, 0xd9, 0x3e, 0x93, 0x50, 0x85, 0x39, - 0x20, 0x59, 0x25, 0xb4, 0xae, 0x76, 0x07, 0x9f, 0x81, 0x27, 0xa2, 0xab, 0xf9, 0x4e, 0xa7, 0x98, - 0xf0, 0x4e, 0x70, 0x59, 0x51, 0x8a, 0xae, 0x79, 0x74, 0x13, 0x66, 0x1a, 0x96, 0x1f, 0x5c, 0x6b, - 0xd5, 0xac, 0x80, 0x6c, 0xdb, 0x4d, 0x22, 0xf6, 0xdc, 0x30, 0xa1, 0xd7, 0xea, 0xc6, 0x74, 0x3d, - 0x42, 0x09, 0xc7, 0x28, 0xa3, 0x03, 0x40, 0xb4, 0x64, 0xdb, 0xb3, 0x1c, 0x9f, 0xf7, 0x8a, 0xf2, - 0x1b, 0x3e, 0xd4, 0x5b, 0x1d, 0xcb, 0xd6, 0x7b, 0xa8, 0xe1, 0x04, 0x0e, 0xe8, 0x11, 0x18, 0xf7, - 0x88, 0xe5, 0x8b, 0xc9, 0x2c, 0x84, 0xfb, 0x1f, 0xb3, 0x52, 0x2c, 0xa0, 0xfa, 0x86, 0x1a, 0xbf, - 0xcb, 0x86, 0xfa, 0x81, 0x01, 0x33, 0xe1, 0x34, 0xdd, 0x03, 0x25, 0xd9, 0x8c, 0x2a, 0xc9, 0x4b, - 0x69, 0x89, 0xc4, 0x3e, 0x7a, 0xf1, 0xcf, 0xc7, 0xf5, 0xfe, 0xb1, 0xd0, 0xdb, 0x8f, 0x41, 0x41, - 0xee, 0x6a, 0x69, 0x7d, 0x8e, 0x78, 0xba, 0x8d, 0xd8, 0x25, 0xda, 0x93, 0x11, 0xc1, 0x04, 0x87, - 0xfc, 0xa8, 0x5a, 0xae, 0x09, 0x95, 0x2b, 0x96, 0xbd, 0x52, 0xcb, 0x52, 0x15, 0x27, 0xa9, 0x65, - 0x59, 0x07, 0x5d, 0x83, 0x33, 0x2d, 0xcf, 0x65, 0xcf, 0x08, 0x57, 0x89, 0x55, 0x6b, 0xd8, 0x0e, - 0x91, 0x2e, 0x04, 0x7e, 0x61, 0xff, 0x40, 0xb7, 0x53, 0x3c, 0xb3, 0x95, 0x8c, 0x82, 0xfb, 0xd5, - 0x8d, 0x3e, 0x7d, 0x19, 0x1b, 0xe0, 0xe9, 0xcb, 0xaf, 0x28, 0x47, 0x1d, 0xf1, 0xc5, 0x03, 0x94, - 0x0f, 0xa6, 0x35, 0x95, 0x09, 0x62, 0x3d, 0x5c, 0x52, 0x25, 0xc1, 0x14, 0x2b, 0xf6, 0xfd, 0xbd, - 0x41, 0xe3, 0xc7, 0xf4, 0x06, 0x85, 0x11, 0xcc, 0x13, 0x3f, 0xc9, 0x08, 0xe6, 0xfc, 0x9b, 0x2a, - 0x82, 0xf9, 0xd5, 0x1c, 0xcc, 0xc5, 0x2d, 0x90, 0x93, 0x7f, 0xd6, 0xf3, 0xeb, 0x06, 0xcc, 0xc9, - 0xdd, 0xc3, 0x79, 0x12, 0xe9, 0xe7, 0x5f, 0x4f, 0x69, 0xd3, 0x72, 0x5b, 0x4a, 0x3d, 0x3c, 0xdd, - 0x8e, 0x71, 0xc3, 0x3d, 0xfc, 0xd1, 0x0b, 0x30, 0xa9, 0xdc, 0xe1, 0xc7, 0x7a, 0xe3, 0x33, 0xcb, - 0xac, 0xa8, 0x90, 0x04, 0xd6, 0xe9, 0xa1, 0x57, 0x0d, 0x80, 0xaa, 0x54, 0x73, 0x72, 0x77, 0x5d, - 0x4d, 0x6b, 0x77, 0x29, 0x05, 0x1a, 0x1a, 0xcb, 0xaa, 0xc8, 0xc7, 0x1a, 0x63, 0xf4, 0x39, 0xe6, - 0x08, 0x57, 0xd6, 0x1d, 0xdd, 0x4f, 0xd9, 0xd1, 0x83, 0x4e, 0x8f, 0x30, 0x4c, 0x43, 0x53, 0x4a, - 0x03, 0xf9, 0x38, 0xd2, 0x08, 0xf3, 0x69, 0x50, 0x61, 0x82, 0x54, 0x6c, 0xb1, 0x40, 0xc1, 0x2d, - 0x2b, 0xd8, 0x13, 0x4b, 0x50, 0x89, 0xad, 0x8b, 0x12, 0x80, 0x43, 0x1c, 0xf3, 0x23, 0x30, 0xf3, - 0xac, 0x67, 0xb5, 0xf6, 0x6c, 0xe6, 0x70, 0xa6, 0xe7, 0xa4, 0xb7, 0xc3, 0x84, 0x55, 0xab, 0x25, - 0x3d, 0xdb, 0x2e, 0xf1, 0x62, 0x2c, 0xe1, 0x83, 0x1d, 0x89, 0xbe, 0x69, 0xc0, 0xc2, 0x9a, 0x1f, - 0xd8, 0xee, 0x2a, 0xf1, 0x03, 0x2a, 0x2b, 0xe9, 0x8e, 0x6a, 0x37, 0x06, 0x09, 0x63, 0x5d, 0x85, - 0x39, 0x71, 0x2b, 0xd6, 0xde, 0xf1, 0x49, 0xa0, 0x19, 0xa7, 0x6a, 0x71, 0xae, 0xc4, 0xe0, 0xb8, - 0xa7, 0x06, 0xa5, 0x22, 0xae, 0xc7, 0x42, 0x2a, 0xd9, 0x28, 0x95, 0x4a, 0x0c, 0x8e, 0x7b, 0x6a, - 0x98, 0xdf, 0xc9, 0xc2, 0x29, 0xd6, 0x8d, 0x58, 0x08, 0xfa, 0x67, 0xfa, 0x85, 0xa0, 0x8f, 0xb8, - 0x3e, 0x19, 0xaf, 0x63, 0x04, 0xa0, 0xff, 0x9a, 0x01, 0xb3, 0xb5, 0xe8, 0x48, 0xa7, 0xe3, 0x73, - 0x48, 0x9a, 0x43, 0x1e, 0xee, 0x12, 0x2b, 0xc4, 0x71, 0xfe, 0xe8, 0xf3, 0x06, 0xcc, 0x46, 0x9b, - 0x29, 0x45, 0xd6, 0x09, 0x0c, 0x92, 0x8a, 0x4f, 0x8d, 0x96, 0xfb, 0x38, 0xde, 0x04, 0xf3, 0x6f, - 0x0d, 0x31, 0xa5, 0x27, 0x11, 0x5f, 0x8d, 0x6e, 0x41, 0x21, 0x68, 0xf8, 0xbc, 0x50, 0xf4, 0x76, - 0xc4, 0x63, 0xce, 0xf6, 0x7a, 0x85, 0x91, 0xd3, 0x2c, 0x11, 0x51, 0x42, 0x2d, 0x2a, 0xc9, 0xcb, - 0xfc, 0x8a, 0x01, 0x85, 0xcb, 0xee, 0x8e, 0xd8, 0xce, 0x1f, 0x4e, 0xc1, 0x89, 0xa0, 0x6c, 0x0d, - 0x75, 0xff, 0x14, 0x9a, 0xaf, 0xcf, 0x44, 0x5c, 0x08, 0x0f, 0x6a, 0xb4, 0x97, 0x59, 0xba, 0x13, - 0x4a, 0xea, 0xb2, 0xbb, 0xd3, 0xd7, 0x43, 0xf5, 0x3b, 0x39, 0x98, 0x7e, 0xce, 0x3a, 0x24, 0x4e, - 0x60, 0x0d, 0x2f, 0x80, 0xe8, 0xa9, 0xbc, 0xc5, 0xc2, 0x2d, 0x35, 0xfb, 0x31, 0x3c, 0x95, 0x87, - 0x20, 0xac, 0xe3, 0x85, 0x72, 0x85, 0x67, 0x5f, 0x48, 0x92, 0x08, 0x2b, 0x31, 0x38, 0xee, 0xa9, - 0x81, 0x2e, 0x03, 0x12, 0x6f, 0xc9, 0x4a, 0xd5, 0xaa, 0xdb, 0x76, 0xb8, 0x64, 0xe1, 0x07, 0x76, - 0x75, 0x90, 0xd9, 0xe8, 0xc1, 0xc0, 0x09, 0xb5, 0xd0, 0x87, 0x60, 0xb1, 0xca, 0x28, 0x0b, 0xb3, - 0x56, 0xa7, 0xc8, 0x8f, 0x36, 0x2a, 0xd4, 0x79, 0xa5, 0x0f, 0x1e, 0xee, 0x4b, 0x81, 0xb6, 0xd4, - 0x0f, 0x5c, 0xcf, 0xaa, 0x13, 0x9d, 0xee, 0x78, 0xb4, 0xa5, 0x95, 0x1e, 0x0c, 0x9c, 0x50, 0x0b, - 0x7d, 0x02, 0x0a, 0xc1, 0x9e, 0x47, 0xfc, 0x3d, 0xb7, 0x51, 0x13, 0x17, 0xd2, 0x23, 0x7a, 0x71, - 0xc4, 0xec, 0x6f, 0x4b, 0xaa, 0xda, 0xf2, 0x96, 0x45, 0x38, 0xe4, 0x89, 0x3c, 0x18, 0xf7, 0xab, - 0x6e, 0x8b, 0xf8, 0xc2, 0x1c, 0xbc, 0x9c, 0x0a, 0x77, 0xe6, 0x95, 0xd0, 0xfc, 0x47, 0x8c, 0x03, - 0x16, 0x9c, 0xcc, 0x6f, 0x65, 0x60, 0x4a, 0x47, 0x1c, 0x40, 0x44, 0x7c, 0xd2, 0x80, 0xa9, 0xaa, - 0xeb, 0x04, 0x9e, 0xdb, 0xe0, 0xbe, 0x11, 0xbe, 0x41, 0x46, 0x4c, 0x51, 0xc0, 0x48, 0xad, 0x92, - 0xc0, 0xb2, 0x1b, 0x9a, 0x9b, 0x45, 0x63, 0x83, 0x23, 0x4c, 0xd1, 0xa7, 0x0d, 0x98, 0x0d, 0x23, - 0x75, 0x42, 0x27, 0x4d, 0xaa, 0x0d, 0x51, 0x12, 0xf7, 0x42, 0x94, 0x13, 0x8e, 0xb3, 0x36, 0x77, - 0x60, 0x2e, 0x3e, 0xdb, 0x74, 0x28, 0x5b, 0x96, 0xd8, 0xeb, 0xd9, 0x70, 0x28, 0xb7, 0x2c, 0xdf, - 0xc7, 0x0c, 0x82, 0xde, 0x01, 0xf9, 0xa6, 0xe5, 0xd5, 0x6d, 0xc7, 0x6a, 0xb0, 0x51, 0xcc, 0x6a, - 0x02, 0x49, 0x94, 0x63, 0x85, 0x61, 0xfe, 0x70, 0x0c, 0x26, 0x35, 0x2b, 0xfe, 0xe4, 0x2d, 0xf2, - 0xc8, 0xf3, 0xf6, 0x6c, 0x8a, 0xcf, 0xdb, 0x9f, 0x07, 0xd8, 0xb5, 0x1d, 0xdb, 0xdf, 0x3b, 0xe6, - 0xc3, 0x79, 0x76, 0x99, 0x77, 0x51, 0x51, 0xc0, 0x1a, 0xb5, 0xf0, 0xc6, 0x24, 0x77, 0x44, 0x3a, - 0x91, 0x57, 0x0d, 0x4d, 0x79, 0x8c, 0xa7, 0x71, 0x43, 0xac, 0x4d, 0xcc, 0xb2, 0x54, 0x26, 0x17, - 0x9c, 0xc0, 0x3b, 0x3c, 0x52, 0xc7, 0x6c, 0x43, 0xde, 0x23, 0x7e, 0xbb, 0x49, 0xcf, 0x16, 0x13, - 0x43, 0x0f, 0x03, 0xbb, 0x5d, 0xc7, 0xa2, 0x3e, 0x56, 0x94, 0x96, 0x9e, 0x86, 0xe9, 0x48, 0x13, - 0xd0, 0x1c, 0x64, 0xf7, 0xc9, 0x21, 0x5f, 0x27, 0x98, 0xfe, 0x44, 0x0b, 0x91, 0x7b, 0x25, 0x31, - 0x2c, 0xef, 0xcd, 0x3c, 0x65, 0x98, 0x2e, 0x24, 0x1e, 0x15, 0x8f, 0xe3, 0xf6, 0xa7, 0x73, 0xd1, - 0xd0, 0x5e, 0xce, 0xab, 0xb9, 0xe0, 0x31, 0x14, 0x1c, 0x66, 0xfe, 0x68, 0x1c, 0xc4, 0xa5, 0xe7, - 0x00, 0xc2, 0x47, 0xbf, 0xeb, 0xc8, 0x1c, 0xe3, 0xae, 0xe3, 0x32, 0x4c, 0xd9, 0x8e, 0x1d, 0xd8, - 0x56, 0x83, 0xb9, 0x01, 0x84, 0x72, 0x94, 0xe1, 0x94, 0x53, 0x6b, 0x1a, 0x2c, 0x81, 0x4e, 0xa4, - 0x2e, 0xba, 0x0a, 0x39, 0xa6, 0x3d, 0xc4, 0x02, 0x1e, 0xfe, 0x66, 0x96, 0x5d, 0xca, 0xf3, 0x37, - 0x16, 0x9c, 0x12, 0xb3, 0xe8, 0x79, 0xea, 0x00, 0x75, 0x50, 0x13, 0xeb, 0x38, 0xb4, 0xe8, 0x63, - 0x70, 0xdc, 0x53, 0x83, 0x52, 0xd9, 0xb5, 0xec, 0x46, 0xdb, 0x23, 0x21, 0x95, 0xf1, 0x28, 0x95, - 0x8b, 0x31, 0x38, 0xee, 0xa9, 0x81, 0x76, 0x61, 0x4a, 0x94, 0xf1, 0xc8, 0x98, 0x89, 0x63, 0xf6, - 0x92, 0x45, 0x40, 0x5d, 0xd4, 0x28, 0xe1, 0x08, 0x5d, 0xd4, 0x86, 0x79, 0xdb, 0xa9, 0xba, 0x4e, - 0xb5, 0xd1, 0xf6, 0xed, 0x03, 0x12, 0x3e, 0x70, 0x38, 0x0e, 0xb3, 0xd3, 0xdd, 0x4e, 0x71, 0x7e, - 0x2d, 0x4e, 0x0e, 0xf7, 0x72, 0x40, 0xaf, 0x18, 0x70, 0xba, 0xea, 0x3a, 0x3e, 0x7b, 0x8b, 0x7b, - 0x40, 0x2e, 0x78, 0x9e, 0xeb, 0x71, 0xde, 0x85, 0x63, 0xf2, 0x66, 0xde, 0xa7, 0x95, 0x24, 0x92, - 0x38, 0x99, 0x13, 0x7a, 0x11, 0xf2, 0x2d, 0xcf, 0x3d, 0xb0, 0x6b, 0xc4, 0x13, 0x51, 0x56, 0xeb, - 0x69, 0xe4, 0x06, 0xd8, 0x12, 0x34, 0x43, 0xd1, 0x23, 0x4b, 0xb0, 0xe2, 0x67, 0x7e, 0x35, 0x0f, - 0x33, 0x51, 0x74, 0xf4, 0x71, 0x80, 0x96, 0xe7, 0x36, 0x49, 0xb0, 0x47, 0x54, 0xa0, 0xfa, 0xe6, - 0xa8, 0x4f, 0xd0, 0x25, 0x3d, 0x19, 0xe7, 0x40, 0xc5, 0x45, 0x58, 0x8a, 0x35, 0x8e, 0xc8, 0x83, - 0x89, 0x7d, 0xae, 0x44, 0x85, 0x4d, 0xf1, 0x5c, 0x2a, 0x16, 0x90, 0xe0, 0xcc, 0x22, 0xac, 0x45, - 0x11, 0x96, 0x8c, 0xd0, 0x0e, 0x64, 0x6f, 0x91, 0x9d, 0x74, 0x9e, 0x75, 0xde, 0x20, 0xe2, 0x6c, - 0x52, 0x9e, 0xe8, 0x76, 0x8a, 0xd9, 0x1b, 0x64, 0x07, 0x53, 0xe2, 0xb4, 0x5f, 0x35, 0x7e, 0x63, - 0x2b, 0x44, 0xc5, 0x88, 0xfd, 0x8a, 0x5c, 0xff, 0xf2, 0x7e, 0x89, 0x22, 0x2c, 0x19, 0xa1, 0x17, - 0xa1, 0x70, 0xcb, 0x3a, 0x20, 0xbb, 0x9e, 0xeb, 0x04, 0x22, 0xb8, 0x66, 0xc4, 0xd8, 0xe5, 0x1b, - 0x92, 0x9c, 0xe0, 0xcb, 0xd4, 0xbb, 0x2a, 0xc4, 0x21, 0x3b, 0x74, 0x00, 0x79, 0x87, 0xdc, 0xc2, - 0xa4, 0x61, 0x57, 0x45, 0xd8, 0xe8, 0x88, 0xcb, 0x7a, 0x53, 0x50, 0x13, 0x9c, 0x99, 0xde, 0x93, - 0x65, 0x58, 0xf1, 0xa2, 0x73, 0x79, 0xd3, 0xdd, 0x11, 0x82, 0x6a, 0xc4, 0xb9, 0x54, 0xe7, 0x4c, - 0x3e, 0x97, 0x97, 0xdd, 0x1d, 0x4c, 0x89, 0xd3, 0x3d, 0x52, 0x55, 0x91, 0x1d, 0x42, 0x4c, 0x6d, - 0xa6, 0x1b, 0xd1, 0xc2, 0xf7, 0x48, 0x58, 0x8a, 0x35, 0x8e, 0x74, 0x6c, 0xeb, 0xc2, 0xad, 0x25, - 0x04, 0xd5, 0x88, 0x63, 0x1b, 0x75, 0x92, 0xf1, 0xb1, 0x95, 0x65, 0x58, 0xf1, 0x32, 0xbf, 0x32, - 0x0e, 0x53, 0x7a, 0x2e, 0xa4, 0x01, 0x74, 0xb5, 0xb2, 0x4f, 0x33, 0xc3, 0xd8, 0xa7, 0xf4, 0x78, - 0xa1, 0x79, 0xa5, 0xa5, 0x87, 0x61, 0x2d, 0x35, 0xf3, 0x2c, 0x3c, 0x5e, 0x68, 0x85, 0x3e, 0x8e, - 0x30, 0x1d, 0xe2, 0xa2, 0x9a, 0x1a, 0x39, 0xdc, 0x0c, 0xc8, 0x45, 0x8d, 0x9c, 0x88, 0x62, 0x7f, - 0x0c, 0x20, 0xcc, 0x09, 0x24, 0x6e, 0x2b, 0x94, 0xf5, 0xa4, 0xe5, 0x2a, 0xd2, 0xb0, 0xd0, 0x23, - 0x30, 0x4e, 0x15, 0x25, 0xa9, 0x89, 0x57, 0x84, 0xea, 0x0c, 0x77, 0x91, 0x95, 0x62, 0x01, 0x45, - 0x4f, 0x51, 0x9b, 0x26, 0x54, 0x6f, 0xe2, 0x71, 0xe0, 0x42, 0x68, 0xd3, 0x84, 0x30, 0x1c, 0xc1, - 0xa4, 0x4d, 0x27, 0x54, 0x1b, 0xb1, 0x95, 0xa4, 0x35, 0x9d, 0xa9, 0x28, 0xcc, 0x61, 0xcc, 0xa7, - 0x10, 0xd3, 0x5e, 0x4c, 0x59, 0xe5, 0x34, 0x9f, 0x42, 0x0c, 0x8e, 0x7b, 0x6a, 0xd0, 0xce, 0x88, - 0x8b, 0x96, 0x49, 0x1e, 0x8f, 0xd7, 0xe7, 0x8a, 0xe4, 0x35, 0xdd, 0x32, 0x9f, 0x62, 0x53, 0xff, - 0xfe, 0xf4, 0xf2, 0x7a, 0x0d, 0x6e, 0x9a, 0x8f, 0x66, 0x44, 0x7f, 0x04, 0x66, 0xa2, 0x32, 0x8b, - 0x2e, 0xa8, 0x96, 0xe7, 0xee, 0xda, 0x0d, 0x12, 0xf7, 0xfd, 0x6c, 0xf1, 0x62, 0x2c, 0xe1, 0x83, - 0x39, 0x9f, 0xff, 0x22, 0x0b, 0xa7, 0x36, 0xeb, 0xb6, 0x73, 0x3b, 0xe6, 0xb5, 0x4d, 0xca, 0xb7, - 0x69, 0x0c, 0x9b, 0x6f, 0x33, 0x7c, 0xa4, 0x21, 0x12, 0x9a, 0x26, 0x3f, 0xd2, 0x90, 0xd9, 0x4e, - 0xa3, 0xb8, 0xe8, 0x07, 0x06, 0x3c, 0x68, 0xd5, 0xb8, 0x15, 0x69, 0x35, 0x44, 0x69, 0xc8, 0x54, - 0xee, 0x68, 0x7f, 0x44, 0x9d, 0xd0, 0xdb, 0xf9, 0xe5, 0xd2, 0x11, 0x5c, 0xf9, 0x8c, 0xbf, 0x4d, - 0xf4, 0xe0, 0xc1, 0xa3, 0x50, 0xf1, 0x91, 0xcd, 0x5f, 0xba, 0x02, 0x6f, 0xbd, 0x2b, 0xa3, 0xa1, - 0x56, 0xcb, 0x27, 0x0d, 0x28, 0x70, 0xa7, 0x24, 0x26, 0xbb, 0x54, 0x54, 0x58, 0x2d, 0xfb, 0x3a, - 0xf1, 0x7c, 0x99, 0x08, 0x48, 0x3b, 0x68, 0x95, 0xb6, 0xd6, 0x04, 0x04, 0x6b, 0x58, 0x54, 0x18, - 0xef, 0xdb, 0x4e, 0x4d, 0x4c, 0x93, 0x12, 0xc6, 0xcf, 0xd9, 0x4e, 0x0d, 0x33, 0x88, 0x12, 0xd7, - 0xd9, 0xbe, 0x59, 0x39, 0xbe, 0x6c, 0xc0, 0x0c, 0x7b, 0x83, 0x15, 0x1e, 0x01, 0x9e, 0x54, 0x51, - 0x08, 0xbc, 0x19, 0x67, 0xa3, 0x51, 0x08, 0x77, 0x3a, 0xc5, 0x49, 0xfe, 0x6a, 0x2b, 0x1a, 0x94, - 0xf0, 0x41, 0xe1, 0x37, 0x60, 0xb1, 0x12, 0x99, 0xa1, 0x8f, 0xb5, 0xca, 0x4b, 0x56, 0x91, 0x44, - 0x70, 0x48, 0xcf, 0x7c, 0x09, 0xa6, 0xf4, 0x10, 0x73, 0xf4, 0x24, 0x4c, 0xb6, 0x6c, 0xa7, 0x1e, - 0x7d, 0x8a, 0xa4, 0x3c, 0xa5, 0x5b, 0x21, 0x08, 0xeb, 0x78, 0xac, 0x9a, 0x1b, 0x56, 0x8b, 0x39, - 0x58, 0xb7, 0x5c, 0xbd, 0x5a, 0xf8, 0xc7, 0xfc, 0xc3, 0x2c, 0x9c, 0x4a, 0x78, 0xca, 0x80, 0x5e, - 0x35, 0x60, 0x9c, 0xc5, 0x55, 0xcb, 0x38, 0x83, 0x17, 0x52, 0x7f, 0x2e, 0xb1, 0xcc, 0xc2, 0xb7, - 0xc5, 0x3a, 0x56, 0xe2, 0x93, 0x17, 0x62, 0xc1, 0x1c, 0xfd, 0xa6, 0x01, 0x93, 0x96, 0xb6, 0xd5, - 0x78, 0xe8, 0xc5, 0x4e, 0xfa, 0x8d, 0xe9, 0xd9, 0x59, 0x5a, 0xc8, 0x58, 0xb8, 0x91, 0xf4, 0xb6, - 0x2c, 0xbd, 0x07, 0x26, 0xb5, 0x2e, 0x0c, 0xb3, 0x43, 0x96, 0x9e, 0x81, 0xb9, 0x91, 0x76, 0xd8, - 0x07, 0x60, 0xd8, 0xbc, 0x56, 0x54, 0x61, 0xdd, 0xd2, 0x1f, 0x46, 0xaa, 0x11, 0x17, 0x2f, 0x23, - 0x05, 0xd4, 0xdc, 0x81, 0xb9, 0xf8, 0x21, 0x27, 0xf5, 0x9b, 0xc6, 0x77, 0xc1, 0x90, 0x99, 0xa8, - 0xcc, 0xbf, 0xcc, 0xc0, 0x84, 0x78, 0x0f, 0x75, 0x0f, 0xa2, 0x2d, 0xf7, 0x23, 0x57, 0x25, 0x6b, - 0xa9, 0x3c, 0xe3, 0xea, 0x1b, 0x6a, 0xe9, 0xc7, 0x42, 0x2d, 0x9f, 0x4b, 0x87, 0xdd, 0xd1, 0x71, - 0x96, 0x5f, 0x1e, 0x83, 0xd9, 0xd8, 0xfb, 0x32, 0x6a, 0xaa, 0xf4, 0x84, 0x17, 0x5d, 0x4b, 0xf5, - 0x09, 0x9b, 0x8a, 0x04, 0x3e, 0x3a, 0xd2, 0xc8, 0x8f, 0x24, 0xfc, 0xbb, 0x9a, 0x5a, 0xae, 0xe0, - 0x9f, 0xe6, 0xfe, 0x1b, 0x36, 0x72, 0xe6, 0x9f, 0x0d, 0xb8, 0xbf, 0xef, 0x33, 0x44, 0x96, 0xaf, - 0xc1, 0x8b, 0x42, 0xc5, 0x86, 0x4c, 0xf9, 0x59, 0xb1, 0xba, 0xb7, 0x88, 0x3f, 0xb1, 0x8f, 0xb3, - 0x47, 0x4f, 0xc0, 0x14, 0x53, 0xad, 0x54, 0xa6, 0x04, 0xa4, 0x25, 0x1c, 0xb5, 0xcc, 0x65, 0x57, - 0xd1, 0xca, 0x71, 0x04, 0xcb, 0xfc, 0x92, 0x01, 0x8b, 0xfd, 0x5e, 0xef, 0x0f, 0x70, 0x30, 0xfc, - 0xb9, 0x58, 0x38, 0x68, 0xb1, 0x27, 0x1c, 0x34, 0x76, 0x34, 0x94, 0x91, 0x9f, 0xda, 0xa9, 0x2c, - 0x7b, 0x97, 0x68, 0xc7, 0xcf, 0x18, 0x70, 0xa6, 0xcf, 0x6e, 0xea, 0x09, 0x0b, 0x36, 0x8e, 0x1d, - 0x16, 0x9c, 0x19, 0x34, 0x2c, 0xd8, 0xfc, 0xeb, 0x2c, 0xcc, 0x89, 0xf6, 0x84, 0xf6, 0xd5, 0x53, - 0x91, 0xa0, 0xda, 0xb7, 0xc5, 0x82, 0x6a, 0x17, 0xe2, 0xf8, 0x3f, 0x8d, 0xa8, 0x7d, 0x73, 0x45, - 0xd4, 0xfe, 0x38, 0x03, 0xa7, 0x13, 0x93, 0x0a, 0xa0, 0x4f, 0x25, 0xa8, 0x86, 0x1b, 0x29, 0x67, - 0x2f, 0x18, 0x50, 0x39, 0x8c, 0x1a, 0x86, 0xfa, 0x79, 0x3d, 0xfc, 0x93, 0x8b, 0xfa, 0xdd, 0x13, - 0xc8, 0xc3, 0x30, 0x64, 0x24, 0xa8, 0xf9, 0xab, 0x59, 0x78, 0x74, 0x50, 0x42, 0x6f, 0xd2, 0x97, - 0x02, 0x7e, 0xe4, 0xa5, 0xc0, 0x3d, 0x52, 0xdb, 0x27, 0xf2, 0x68, 0xe0, 0x2b, 0x59, 0xa5, 0xf6, - 0x7a, 0xd7, 0xe7, 0x40, 0xb7, 0x7a, 0x13, 0xd4, 0xb4, 0x93, 0xa9, 0x06, 0x43, 0x51, 0x38, 0x51, - 0xe1, 0xc5, 0x77, 0x3a, 0xc5, 0x79, 0x91, 0x7e, 0xac, 0x42, 0x02, 0x51, 0x88, 0x65, 0x25, 0xf4, - 0x28, 0xe4, 0x3d, 0x0e, 0x95, 0xb1, 0xd1, 0xe2, 0x6a, 0x94, 0x97, 0x61, 0x05, 0x45, 0x9f, 0xd0, - 0x6c, 0xe1, 0xb1, 0x93, 0x7a, 0xd7, 0x7e, 0xd4, 0x8d, 0xef, 0x0b, 0x90, 0xf7, 0x65, 0xd2, 0x40, - 0xee, 0x96, 0x7f, 0x7c, 0xc0, 0x90, 0x7b, 0x7a, 0x74, 0x92, 0x19, 0x04, 0x79, 0xff, 0x54, 0x7e, - 0x41, 0x45, 0x12, 0x99, 0xea, 0xd4, 0xc2, 0x7d, 0x8c, 0x90, 0x70, 0x62, 0xf9, 0xae, 0x01, 0x93, - 0x62, 0xb6, 0xee, 0xc1, 0x2b, 0x80, 0x9b, 0xd1, 0x57, 0x00, 0x17, 0x52, 0x91, 0x1d, 0x7d, 0x9e, - 0x00, 0xdc, 0x84, 0x29, 0x3d, 0xaf, 0x0c, 0x7a, 0x5e, 0x93, 0x7d, 0xc6, 0x28, 0xf9, 0x2b, 0xa4, - 0x74, 0x0c, 0xe5, 0xa2, 0xf9, 0xc5, 0xbc, 0x1a, 0x45, 0xe6, 0x87, 0xd0, 0xd7, 0xa0, 0x71, 0xe4, - 0x1a, 0xd4, 0x97, 0x40, 0x26, 0xfd, 0x25, 0x70, 0x15, 0xf2, 0x52, 0x40, 0x09, 0x35, 0xfe, 0xb0, - 0x1e, 0xbb, 0x46, 0x6d, 0x01, 0x4a, 0x4c, 0x5b, 0xb8, 0xec, 0xa8, 0xa5, 0xe6, 0x50, 0x09, 0x4e, - 0x45, 0x06, 0xbd, 0x08, 0x93, 0xb7, 0x5c, 0x6f, 0xbf, 0xe1, 0x5a, 0x2c, 0x1d, 0x28, 0xa4, 0x71, - 0xc1, 0xa2, 0x1c, 0x5e, 0x3c, 0x44, 0xfa, 0x46, 0x48, 0x1f, 0xeb, 0xcc, 0x50, 0x09, 0x66, 0x9b, - 0xb6, 0x83, 0x89, 0x55, 0x53, 0xc1, 0xfe, 0x63, 0x3c, 0x5f, 0xa1, 0x34, 0x72, 0x37, 0xa2, 0x60, - 0x1c, 0xc7, 0x47, 0x1f, 0x83, 0xbc, 0x2f, 0x72, 0xd7, 0xa4, 0x73, 0x15, 0xa6, 0xce, 0x8c, 0x9c, - 0x68, 0x38, 0x76, 0xb2, 0x04, 0x2b, 0x86, 0x68, 0x1d, 0x16, 0x3c, 0x91, 0x1d, 0x22, 0xf2, 0x31, - 0x01, 0xbe, 0x3f, 0x59, 0x5a, 0x3c, 0x9c, 0x00, 0xc7, 0x89, 0xb5, 0xa8, 0x15, 0xc3, 0x12, 0x24, - 0xf1, 0x3b, 0x01, 0xcd, 0x8d, 0xce, 0x16, 0x7c, 0x0d, 0x0b, 0xe8, 0x51, 0x8f, 0x47, 0xf2, 0x23, - 0x3c, 0x1e, 0xa9, 0xc0, 0xe9, 0x38, 0x88, 0xe5, 0xb0, 0x60, 0x69, 0x33, 0x34, 0xed, 0xb1, 0x95, - 0x84, 0x84, 0x93, 0xeb, 0xa2, 0x1b, 0x50, 0xf0, 0x08, 0x3b, 0x5f, 0x94, 0xe4, 0xe5, 0xfb, 0xd0, - 0x61, 0x46, 0x58, 0x12, 0xc0, 0x21, 0x2d, 0x3a, 0xef, 0x56, 0x34, 0x65, 0xdf, 0xd5, 0x14, 0x3f, - 0x87, 0x24, 0xe6, 0xbe, 0x4f, 0x6e, 0x19, 0xf3, 0x8d, 0x19, 0x98, 0x8e, 0xf8, 0x16, 0xd0, 0xc3, - 0x90, 0x63, 0x49, 0x3d, 0x98, 0x78, 0xc8, 0x87, 0x22, 0x8c, 0x0f, 0x0e, 0x87, 0xa1, 0xcf, 0x1a, - 0x30, 0xdb, 0x8a, 0x78, 0x61, 0xa5, 0xe4, 0x1c, 0xf1, 0x9e, 0x2f, 0xea, 0xda, 0xd5, 0x92, 0xdd, - 0x46, 0x99, 0xe1, 0x38, 0x77, 0xba, 0x01, 0x45, 0xe4, 0x5d, 0x83, 0x78, 0x0c, 0x5b, 0xd8, 0x38, - 0x8a, 0xc4, 0x4a, 0x14, 0x8c, 0xe3, 0xf8, 0x74, 0x86, 0x59, 0xef, 0x46, 0xf9, 0x4e, 0x4a, 0x49, - 0x12, 0xc0, 0x21, 0x2d, 0xf4, 0x0c, 0xcc, 0x88, 0x4c, 0x6d, 0x5b, 0x6e, 0xed, 0x92, 0xe5, 0xef, - 0x09, 0xe3, 0x5e, 0x1d, 0x46, 0x56, 0x22, 0x50, 0x1c, 0xc3, 0x66, 0x7d, 0x0b, 0xd3, 0xe1, 0x31, - 0x02, 0xe3, 0xd1, 0x5c, 0xc0, 0x2b, 0x51, 0x30, 0x8e, 0xe3, 0xa3, 0x77, 0x68, 0x72, 0x9f, 0xdf, - 0xd3, 0x29, 0x69, 0x90, 0x20, 0xfb, 0x4b, 0x30, 0xdb, 0x66, 0x67, 0xa1, 0x9a, 0x04, 0x8a, 0xfd, - 0xa8, 0x18, 0x5e, 0x8b, 0x82, 0x71, 0x1c, 0x1f, 0x3d, 0x0d, 0xd3, 0x1e, 0x95, 0x6e, 0x8a, 0x00, - 0xbf, 0xbc, 0x53, 0x77, 0x33, 0x58, 0x07, 0xe2, 0x28, 0x2e, 0x7a, 0x16, 0xe6, 0xc3, 0x74, 0x4f, - 0x92, 0x00, 0xbf, 0xcd, 0x53, 0x99, 0x4c, 0x4a, 0x71, 0x04, 0xdc, 0x5b, 0x07, 0xfd, 0x02, 0xcc, - 0x69, 0x23, 0xb1, 0xe6, 0xd4, 0xc8, 0x6d, 0x91, 0x92, 0x87, 0xa5, 0x6d, 0x5f, 0x89, 0xc1, 0x70, - 0x0f, 0x36, 0x7a, 0x2f, 0xcc, 0x54, 0xdd, 0x46, 0x83, 0xc9, 0x38, 0x9e, 0x87, 0x96, 0xe7, 0xde, - 0xe1, 0x59, 0x8a, 0x22, 0x10, 0x1c, 0xc3, 0x44, 0x97, 0x01, 0xb9, 0x3b, 0x3e, 0xf1, 0x0e, 0x48, - 0xed, 0x59, 0xfe, 0xe5, 0x45, 0xaa, 0xe2, 0xa7, 0xa3, 0x71, 0xbf, 0x57, 0x7a, 0x30, 0x70, 0x42, - 0x2d, 0x96, 0x08, 0x45, 0x7b, 0x83, 0x33, 0x93, 0xc6, 0x37, 0x43, 0xe2, 0x27, 0xf7, 0xbb, 0x3e, - 0xc0, 0xf1, 0x60, 0x9c, 0x87, 0x61, 0xa7, 0x93, 0x84, 0x47, 0x4f, 0x49, 0x19, 0xea, 0x08, 0x5e, - 0x8a, 0x05, 0x27, 0xf4, 0x71, 0x28, 0xec, 0xc8, 0xfc, 0xc4, 0x8b, 0x73, 0x69, 0xe8, 0xc5, 0x58, - 0xaa, 0xed, 0xf0, 0x64, 0xaa, 0x00, 0x38, 0x64, 0x89, 0x1e, 0x81, 0xc9, 0x4b, 0x5b, 0x25, 0xb5, - 0x0a, 0xe7, 0xd9, 0xec, 0x8f, 0xd1, 0x2a, 0x58, 0x07, 0xd0, 0x1d, 0xa6, 0xec, 0x25, 0xc4, 0xa6, - 0x38, 0xd4, 0xb7, 0xbd, 0xe6, 0x0f, 0xc5, 0x66, 0xd7, 0x91, 0xb8, 0xb2, 0x78, 0x2a, 0x86, 0x2d, - 0xca, 0xb1, 0xc2, 0x40, 0x2f, 0xc0, 0xa4, 0xd0, 0x17, 0x4c, 0x36, 0x2d, 0x1c, 0xef, 0x7d, 0x17, - 0x0e, 0x49, 0x60, 0x9d, 0x1e, 0xbb, 0x65, 0x62, 0x69, 0x5b, 0xc9, 0xc5, 0x76, 0xa3, 0xb1, 0x78, - 0x9a, 0xc9, 0xcd, 0xf0, 0x96, 0x29, 0x04, 0x61, 0x1d, 0x0f, 0x3d, 0x2e, 0x23, 0x27, 0xde, 0x12, - 0xb9, 0x76, 0x53, 0x91, 0x13, 0xca, 0xca, 0xed, 0x13, 0xd8, 0x7b, 0xe6, 0x2e, 0x21, 0x0b, 0x3b, - 0xb0, 0x24, 0x4d, 0xac, 0xde, 0x4d, 0xb2, 0xb8, 0x18, 0xf1, 0x12, 0x2c, 0xdd, 0xe8, 0x8b, 0x89, - 0x8f, 0xa0, 0x82, 0x76, 0x20, 0x6b, 0x35, 0x76, 0x16, 0xef, 0x4f, 0xc3, 0x56, 0x54, 0x5f, 0x52, - 0xe5, 0xc1, 0x38, 0xa5, 0xf5, 0x32, 0xa6, 0xc4, 0xcd, 0x57, 0x32, 0xca, 0x2b, 0xaf, 0x92, 0x13, - 0xbe, 0xa4, 0xaf, 0x6a, 0x23, 0x8d, 0x2f, 0x05, 0xf6, 0x24, 0xf1, 0xe6, 0x0a, 0x29, 0x71, 0x4d, - 0xb7, 0xd4, 0x3e, 0x4e, 0x25, 0xf3, 0x44, 0x34, 0xf1, 0x22, 0x3f, 0xcd, 0x45, 0x77, 0xb1, 0xf9, - 0xbd, 0x71, 0xe5, 0x84, 0x8a, 0x85, 0x02, 0x78, 0x90, 0xb3, 0xfd, 0xc0, 0x76, 0x53, 0x7c, 0xb6, - 0x15, 0xcb, 0x58, 0xc8, 0x02, 0x58, 0x19, 0x00, 0x73, 0x56, 0x94, 0xa7, 0x53, 0xb7, 0x9d, 0xdb, - 0xa2, 0xfb, 0x57, 0x53, 0xbf, 0xe3, 0xe7, 0x3c, 0x19, 0x00, 0x73, 0x56, 0xe8, 0x26, 0x5f, 0x69, - 0xe9, 0x7c, 0x15, 0x32, 0xfe, 0xb1, 0xd7, 0xe8, 0x8a, 0xa3, 0xbc, 0xfc, 0xa6, 0x2d, 0x6c, 0x98, - 0x11, 0x79, 0x55, 0x36, 0xd6, 0x92, 0x78, 0x55, 0x36, 0xd6, 0x30, 0x65, 0x82, 0x5e, 0x33, 0x00, - 0x2c, 0xf5, 0xd5, 0xd3, 0x74, 0x32, 0xde, 0xf7, 0xfb, 0x8a, 0x2a, 0x8f, 0x39, 0x0b, 0xa1, 0x58, - 0xe3, 0x8c, 0x5e, 0x84, 0x09, 0x8b, 0x7f, 0xaf, 0x43, 0x84, 0xf3, 0xa5, 0xf3, 0x11, 0x9a, 0x58, - 0x0b, 0x58, 0x1c, 0xa3, 0x00, 0x61, 0xc9, 0x90, 0xf2, 0x0e, 0x3c, 0x8b, 0xec, 0xda, 0xfb, 0x22, - 0xae, 0xaf, 0x32, 0x72, 0xda, 0x5d, 0x4a, 0x2c, 0x89, 0xb7, 0x00, 0x61, 0xc9, 0xd0, 0xfc, 0x37, - 0x03, 0xb4, 0x4f, 0xe4, 0x85, 0x81, 0x5e, 0xc6, 0xc0, 0x81, 0x5e, 0x99, 0x21, 0x03, 0xbd, 0xb2, - 0x43, 0x05, 0x7a, 0x8d, 0x0d, 0x1f, 0xe8, 0x95, 0xeb, 0x1f, 0xe8, 0x65, 0xbe, 0x6e, 0xc0, 0x7c, - 0xcf, 0x9a, 0x8c, 0x7f, 0x8a, 0xd8, 0x18, 0xf0, 0x53, 0xc4, 0xab, 0x30, 0x27, 0x52, 0x97, 0x56, - 0x5a, 0x0d, 0x3b, 0xf1, 0x85, 0xeb, 0x76, 0x0c, 0x8e, 0x7b, 0x6a, 0x98, 0x7f, 0x6a, 0xc0, 0xa4, - 0xf6, 0x20, 0x87, 0xf6, 0x83, 0x3d, 0x5c, 0x12, 0xcd, 0x08, 0xb3, 0xb6, 0x32, 0xf7, 0x2a, 0x87, - 0x71, 0x4f, 0x7f, 0x5d, 0x4b, 0x93, 0x17, 0x7a, 0xfa, 0x69, 0x29, 0x16, 0x50, 0x9e, 0x00, 0x8d, - 0xf0, 0xcf, 0x4c, 0x67, 0xf5, 0x04, 0x68, 0xa4, 0x85, 0x19, 0x84, 0xb1, 0xa3, 0xba, 0x5c, 0xc4, - 0x00, 0x6a, 0x49, 0x62, 0x2d, 0x7a, 0x62, 0x63, 0x30, 0x74, 0x16, 0xb2, 0xc4, 0xa9, 0x89, 0x83, - 0x87, 0xfa, 0x04, 0xc9, 0x05, 0xa7, 0x86, 0x69, 0xb9, 0x79, 0x05, 0xa6, 0x2a, 0xa4, 0xea, 0x91, - 0xe0, 0x39, 0x72, 0x38, 0xf0, 0x37, 0x4d, 0xf6, 0xc9, 0x61, 0xfc, 0x9b, 0x26, 0xb4, 0x3a, 0x2d, - 0x37, 0x7f, 0xdf, 0x80, 0x58, 0xce, 0x5e, 0xcd, 0xeb, 0x67, 0xf4, 0xf3, 0xfa, 0x45, 0xfc, 0x53, - 0x99, 0x23, 0xfd, 0x53, 0x97, 0x01, 0x35, 0xad, 0xa0, 0xba, 0x17, 0xc9, 0x50, 0x2d, 0xce, 0x7c, - 0xe1, 0xf3, 0xbf, 0x1e, 0x0c, 0x9c, 0x50, 0xcb, 0x7c, 0xd9, 0x80, 0x9e, 0xaf, 0x44, 0x53, 0x4b, - 0x85, 0x88, 0xcf, 0x45, 0xf0, 0xa3, 0xb0, 0xb2, 0x54, 0xe4, 0x57, 0x22, 0x24, 0x9c, 0x9e, 0x97, - 0xa4, 0xc7, 0x4d, 0xfa, 0x2f, 0xf8, 0x43, 0x29, 0x75, 0x5e, 0x5a, 0x8d, 0x82, 0x71, 0x1c, 0xdf, - 0xbc, 0x0e, 0x79, 0xf9, 0x9a, 0x94, 0x3d, 0xc9, 0x92, 0x27, 0x70, 0xfd, 0x49, 0x16, 0x3d, 0x80, - 0x33, 0x08, 0x1d, 0x26, 0xdf, 0xb1, 0x2f, 0xb9, 0x7e, 0x20, 0x9f, 0xc0, 0x72, 0x3f, 0xdb, 0xe6, - 0x1a, 0x2b, 0xc3, 0x0a, 0x6a, 0xce, 0xc3, 0xac, 0x72, 0xa0, 0x89, 0xe8, 0xa0, 0x6f, 0x65, 0x61, - 0x2a, 0xf2, 0xed, 0xbf, 0xbb, 0x4f, 0xf6, 0xe0, 0xd3, 0x92, 0xe0, 0x08, 0xcb, 0x0e, 0xe9, 0x08, - 0xd3, 0x3d, 0x8f, 0x63, 0x27, 0xeb, 0x79, 0xcc, 0xa5, 0xe3, 0x79, 0x0c, 0x60, 0x42, 0x7c, 0x17, - 0x5d, 0xa8, 0x9e, 0x8d, 0x94, 0x52, 0x41, 0x88, 0x37, 0xd5, 0x4c, 0xf0, 0x4b, 0x01, 0x26, 0x59, - 0x99, 0x5f, 0xcf, 0xc1, 0x4c, 0x34, 0x39, 0xc4, 0x00, 0x33, 0xf9, 0x8e, 0x9e, 0x99, 0x1c, 0xd2, - 0x11, 0x90, 0x1d, 0xd5, 0x11, 0x30, 0x36, 0xaa, 0x23, 0x20, 0x77, 0x0c, 0x47, 0x40, 0xef, 0x31, - 0x7e, 0x7c, 0xe0, 0x63, 0xfc, 0xfb, 0xd4, 0x2d, 0xf6, 0x44, 0xe4, 0xda, 0x27, 0xbc, 0xc5, 0x46, - 0xd1, 0x69, 0x58, 0x71, 0x6b, 0x89, 0xd1, 0x00, 0xf9, 0xbb, 0x1c, 0x78, 0xbc, 0xc4, 0x4b, 0xe7, - 0xe1, 0x7d, 0x8d, 0x6f, 0x19, 0xe2, 0xc2, 0x39, 0xfc, 0xf4, 0x3f, 0x53, 0x7e, 0x10, 0x55, 0x9c, - 0x95, 0x10, 0x84, 0x75, 0x3c, 0xf6, 0x79, 0xaa, 0xe8, 0xf7, 0xb8, 0x98, 0x5f, 0x45, 0xff, 0x3c, - 0x55, 0xec, 0xfb, 0x5d, 0x71, 0x7c, 0xf3, 0x63, 0x70, 0x3a, 0xd1, 0xcc, 0x61, 0xe7, 0x3e, 0x26, - 0x97, 0x49, 0x4d, 0x20, 0x68, 0xcd, 0x88, 0xe5, 0x0e, 0x5c, 0xba, 0xd1, 0x17, 0x13, 0x1f, 0x41, - 0xc5, 0xfc, 0x5a, 0x16, 0x66, 0xa2, 0xdf, 0x36, 0x40, 0xb7, 0xd4, 0xa1, 0x28, 0x95, 0xf3, 0x18, - 0x27, 0xab, 0xe5, 0x66, 0xe8, 0xeb, 0xe1, 0xe0, 0x5f, 0xc3, 0xdf, 0x51, 0x89, 0x22, 0x4e, 0x8e, - 0xb1, 0x70, 0x2d, 0x08, 0x76, 0xec, 0xf3, 0x05, 0x61, 0x0c, 0xb1, 0xb8, 0x36, 0x4f, 0x9d, 0x7b, - 0x18, 0x15, 0xac, 0x58, 0x61, 0x8d, 0x2d, 0xd5, 0x2d, 0x07, 0xc4, 0xb3, 0x77, 0x6d, 0xf5, 0x5d, - 0x26, 0x26, 0xb9, 0xaf, 0x8b, 0x32, 0xac, 0xa0, 0xe6, 0xcb, 0x19, 0x08, 0xbf, 0x42, 0xc7, 0xd2, - 0xa2, 0xfb, 0x9a, 0xcd, 0x22, 0xa6, 0xed, 0xf2, 0xa8, 0xdf, 0x1e, 0x08, 0x29, 0x8a, 0x08, 0x23, - 0xad, 0x04, 0x47, 0x38, 0xfe, 0x04, 0xbe, 0x3e, 0x67, 0xc1, 0x6c, 0xec, 0x85, 0x53, 0xea, 0x61, - 0x9c, 0x5f, 0xcc, 0x42, 0x41, 0xbd, 0x11, 0x43, 0xef, 0x61, 0xb9, 0x85, 0xf7, 0x5c, 0x99, 0xf1, - 0xf9, 0xad, 0x5a, 0x06, 0xe0, 0x3d, 0xb7, 0x76, 0xa7, 0x53, 0x9c, 0x55, 0xc8, 0xbc, 0x08, 0x8b, - 0x0a, 0xd4, 0x42, 0x6c, 0x7b, 0x8d, 0xb8, 0x85, 0x78, 0x0d, 0xaf, 0x63, 0x5a, 0x8e, 0x6e, 0xc3, - 0xc4, 0x1e, 0xb1, 0x6a, 0xc4, 0x93, 0x01, 0x1b, 0x1b, 0x29, 0xbd, 0x6b, 0xbb, 0xc4, 0xa8, 0x86, - 0xc3, 0xc0, 0xff, 0xfb, 0x58, 0xb2, 0xa3, 0x5a, 0x72, 0xc7, 0xad, 0x1d, 0xc6, 0x33, 0x06, 0x97, - 0xdd, 0xda, 0x21, 0x66, 0x10, 0xf4, 0x0c, 0xcc, 0x04, 0x76, 0x93, 0xb8, 0xed, 0x40, 0xff, 0xc6, - 0x57, 0x36, 0xf4, 0xd8, 0x6f, 0x47, 0xa0, 0x38, 0x86, 0x4d, 0xb5, 0xec, 0x4d, 0xdf, 0x75, 0x58, - 0x1a, 0xa0, 0xf1, 0xa8, 0x7b, 0xef, 0x72, 0xe5, 0xca, 0x26, 0xcb, 0x02, 0xa4, 0x30, 0x28, 0xb6, - 0xcd, 0x1e, 0xa2, 0x78, 0x44, 0x5c, 0x98, 0xcd, 0x85, 0xcf, 0x85, 0x79, 0x39, 0x56, 0x18, 0xe6, - 0x35, 0x98, 0x8d, 0x75, 0x55, 0xda, 0xe2, 0x46, 0xb2, 0x2d, 0x3e, 0x58, 0x7a, 0xde, 0x3f, 0x32, - 0x60, 0xbe, 0x67, 0xf3, 0x0e, 0x1a, 0x5f, 0x1c, 0x57, 0x23, 0x99, 0xe3, 0xab, 0x91, 0xec, 0x70, - 0x6a, 0xa4, 0xbc, 0xfc, 0xed, 0x37, 0xce, 0xdd, 0xf7, 0x9d, 0x37, 0xce, 0xdd, 0xf7, 0xbd, 0x37, - 0xce, 0xdd, 0xf7, 0x72, 0xf7, 0x9c, 0xf1, 0xed, 0xee, 0x39, 0xe3, 0x3b, 0xdd, 0x73, 0xc6, 0xf7, - 0xba, 0xe7, 0x8c, 0x7f, 0xea, 0x9e, 0x33, 0x5e, 0xff, 0xe1, 0xb9, 0xfb, 0x9e, 0xcf, 0xcb, 0x65, - 0xf2, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xcc, 0x41, 0xfc, 0x5a, 0xcc, 0x8a, 0x00, 0x00, + // 7317 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x5d, 0x6c, 0x24, 0x59, + 0x75, 0xf0, 0x56, 0xb7, 0xdb, 0x6e, 0x1f, 0x7b, 0xfc, 0x73, 0xc7, 0xc3, 0x78, 0xbd, 0x3b, 0xd3, + 0x4b, 0x2d, 0xda, 0x6f, 0xf9, 0x3e, 0xf0, 0xc0, 0xfe, 0x7c, 0x59, 0x58, 0xb4, 0x49, 0xb7, 0x3d, + 0xb3, 0xe3, 0x59, 0xdb, 0xd3, 0x73, 0xdb, 0x33, 0x03, 0x0b, 0x4b, 0x28, 0x77, 0x5f, 0xb7, 0x6b, + 0xa6, 0xbb, 0xaa, 0xa9, 0xaa, 0xf6, 0x8c, 0x97, 0x15, 0xec, 0x06, 0xed, 0x06, 0x22, 0x10, 0x9b, + 0x00, 0x8a, 0xa2, 0x88, 0x08, 0x45, 0x48, 0x89, 0x02, 0x4f, 0x28, 0x51, 0x5e, 0x90, 0x12, 0x05, + 0x50, 0x88, 0xa2, 0x44, 0x24, 0x4a, 0x02, 0x44, 0xa2, 0x93, 0x35, 0x79, 0x49, 0x94, 0x28, 0x8a, + 0x44, 0x14, 0x31, 0x4f, 0xd1, 0xfd, 0xad, 0x5b, 0x3f, 0xed, 0xe9, 0x76, 0x97, 0x87, 0x55, 0xc2, + 0x5b, 0xf7, 0x39, 0xe7, 0x9e, 0x73, 0xff, 0xcf, 0xb9, 0xe7, 0x9e, 0x7b, 0x0a, 0xd6, 0x9b, 0x76, + 0xb0, 0xdb, 0xdd, 0x5e, 0xae, 0xbb, 0xed, 0x73, 0x96, 0xd7, 0x74, 0x3b, 0x9e, 0x7b, 0x83, 0xfd, + 0x78, 0xa7, 0xe7, 0xb6, 0x5a, 0x6e, 0x37, 0xf0, 0xcf, 0x75, 0x6e, 0x36, 0xcf, 0x59, 0x1d, 0xdb, + 0x3f, 0xa7, 0x20, 0x7b, 0xef, 0xb6, 0x5a, 0x9d, 0x5d, 0xeb, 0xdd, 0xe7, 0x9a, 0xc4, 0x21, 0x9e, + 0x15, 0x90, 0xc6, 0x72, 0xc7, 0x73, 0x03, 0x17, 0xbd, 0x2f, 0xe4, 0xb6, 0x2c, 0xb9, 0xb1, 0x1f, + 0xbf, 0x28, 0xcb, 0x2e, 0x77, 0x6e, 0x36, 0x97, 0x29, 0xb7, 0x65, 0x05, 0x91, 0xdc, 0x96, 0xde, + 0xa9, 0xd5, 0xa5, 0xe9, 0x36, 0xdd, 0x73, 0x8c, 0xe9, 0x76, 0x77, 0x87, 0xfd, 0x63, 0x7f, 0xd8, + 0x2f, 0x2e, 0x6c, 0xe9, 0xe1, 0x9b, 0x4f, 0xf9, 0xcb, 0xb6, 0x4b, 0xeb, 0x76, 0x6e, 0xdb, 0x0a, + 0xea, 0xbb, 0xe7, 0xf6, 0x12, 0x35, 0x5a, 0x32, 0x35, 0xa2, 0xba, 0xeb, 0x91, 0x34, 0x9a, 0x27, + 0x42, 0x9a, 0xb6, 0x55, 0xdf, 0xb5, 0x1d, 0xe2, 0xed, 0x87, 0xad, 0x6e, 0x93, 0xc0, 0x4a, 0x2b, + 0x75, 0xae, 0x5f, 0x29, 0xaf, 0xeb, 0x04, 0x76, 0x9b, 0x24, 0x0a, 0xfc, 0xff, 0xbb, 0x15, 0xf0, + 0xeb, 0xbb, 0xa4, 0x6d, 0x25, 0xca, 0x3d, 0xde, 0xaf, 0x5c, 0x37, 0xb0, 0x5b, 0xe7, 0x6c, 0x27, + 0xf0, 0x03, 0x2f, 0x5e, 0xc8, 0xfc, 0x56, 0x1e, 0x26, 0xcb, 0xeb, 0x95, 0x5a, 0x60, 0x05, 0x5d, + 0x1f, 0xbd, 0x66, 0xc0, 0x74, 0xcb, 0xb5, 0x1a, 0x15, 0xab, 0x65, 0x39, 0x75, 0xe2, 0x2d, 0x1a, + 0x0f, 0x19, 0x8f, 0x4e, 0x3d, 0xb6, 0xbe, 0x3c, 0xca, 0x78, 0x2d, 0x97, 0x6f, 0xf9, 0x98, 0xf8, + 0x6e, 0xd7, 0xab, 0x13, 0x4c, 0x76, 0x2a, 0x0b, 0xdf, 0xe9, 0x95, 0xee, 0x3b, 0xe8, 0x95, 0xa6, + 0xd7, 0x35, 0x49, 0x38, 0x22, 0x17, 0x7d, 0xd1, 0x80, 0xf9, 0xba, 0xe5, 0x58, 0xde, 0xfe, 0x96, + 0xe5, 0x35, 0x49, 0xf0, 0xac, 0xe7, 0x76, 0x3b, 0x8b, 0xb9, 0x63, 0xa8, 0xcd, 0xfd, 0xa2, 0x36, + 0xf3, 0x2b, 0x71, 0x71, 0x38, 0x59, 0x03, 0x56, 0x2f, 0x3f, 0xb0, 0xb6, 0x5b, 0x44, 0xaf, 0x57, + 0xfe, 0x38, 0xeb, 0x55, 0x8b, 0x8b, 0xc3, 0xc9, 0x1a, 0x98, 0xaf, 0xe6, 0x61, 0xbe, 0xbc, 0x5e, + 0xd9, 0xf2, 0xac, 0x9d, 0x1d, 0xbb, 0x8e, 0xdd, 0x6e, 0x60, 0x3b, 0x4d, 0xf4, 0x76, 0x98, 0xb0, + 0x9d, 0xa6, 0x47, 0x7c, 0x9f, 0x0d, 0xe4, 0x64, 0x65, 0x56, 0x30, 0x9d, 0x58, 0xe3, 0x60, 0x2c, + 0xf1, 0xe8, 0x49, 0x98, 0xf2, 0x89, 0xb7, 0x67, 0xd7, 0x49, 0xd5, 0xf5, 0x02, 0xd6, 0xd3, 0x85, + 0xca, 0x49, 0x41, 0x3e, 0x55, 0x0b, 0x51, 0x58, 0xa7, 0xa3, 0xc5, 0x3c, 0xd7, 0x0d, 0x04, 0x9e, + 0x75, 0xc4, 0x64, 0x58, 0x0c, 0x87, 0x28, 0xac, 0xd3, 0xa1, 0xd7, 0x0d, 0x98, 0xf3, 0x03, 0xbb, + 0x7e, 0xd3, 0x76, 0x88, 0xef, 0xaf, 0xb8, 0xce, 0x8e, 0xdd, 0x5c, 0x2c, 0xb0, 0x5e, 0xdc, 0x1c, + 0xad, 0x17, 0x6b, 0x31, 0xae, 0x95, 0x85, 0x83, 0x5e, 0x69, 0x2e, 0x0e, 0xc5, 0x09, 0xe9, 0x68, + 0x15, 0xe6, 0x2c, 0xc7, 0x71, 0x03, 0x2b, 0xb0, 0x5d, 0xa7, 0xea, 0x91, 0x1d, 0xfb, 0xf6, 0xe2, + 0x18, 0x6b, 0xce, 0xa2, 0x68, 0xce, 0x5c, 0x39, 0x86, 0xc7, 0x89, 0x12, 0xe6, 0x2a, 0x2c, 0x96, + 0xdb, 0xdb, 0x96, 0xef, 0x5b, 0x0d, 0xd7, 0x8b, 0x8d, 0xc6, 0xa3, 0x50, 0x6c, 0x5b, 0x9d, 0x8e, + 0xed, 0x34, 0xe9, 0x70, 0xe4, 0x1f, 0x9d, 0xac, 0x4c, 0x1f, 0xf4, 0x4a, 0xc5, 0x0d, 0x01, 0xc3, + 0x0a, 0x6b, 0xfe, 0x20, 0x07, 0x53, 0x65, 0xc7, 0x6a, 0xed, 0xfb, 0xb6, 0x8f, 0xbb, 0x0e, 0xfa, + 0x08, 0x14, 0xe9, 0xee, 0xd2, 0xb0, 0x02, 0x4b, 0xac, 0xc8, 0x77, 0x2d, 0xf3, 0xc5, 0xbe, 0xac, + 0x2f, 0xf6, 0xb0, 0x5f, 0x28, 0xf5, 0xf2, 0xde, 0xbb, 0x97, 0x2f, 0x6f, 0xdf, 0x20, 0xf5, 0x60, + 0x83, 0x04, 0x56, 0x05, 0x89, 0x56, 0x40, 0x08, 0xc3, 0x8a, 0x2b, 0x72, 0x61, 0xcc, 0xef, 0x90, + 0xba, 0x58, 0x61, 0x1b, 0x23, 0xce, 0xe4, 0xb0, 0xea, 0xb5, 0x0e, 0xa9, 0x57, 0xa6, 0x85, 0xe8, + 0x31, 0xfa, 0x0f, 0x33, 0x41, 0xe8, 0x16, 0x8c, 0xfb, 0x6c, 0xcf, 0x11, 0x8b, 0xe7, 0x72, 0x76, + 0x22, 0x19, 0xdb, 0xca, 0x8c, 0x10, 0x3a, 0xce, 0xff, 0x63, 0x21, 0xce, 0xfc, 0x7b, 0x03, 0x4e, + 0x6a, 0xd4, 0x65, 0xaf, 0xd9, 0x6d, 0x13, 0x27, 0x40, 0x0f, 0xc1, 0x98, 0x63, 0xb5, 0x89, 0x58, + 0x28, 0xaa, 0xca, 0x9b, 0x56, 0x9b, 0x60, 0x86, 0x41, 0x0f, 0x43, 0x61, 0xcf, 0x6a, 0x75, 0x09, + 0xeb, 0xa4, 0xc9, 0xca, 0x09, 0x41, 0x52, 0xb8, 0x46, 0x81, 0x98, 0xe3, 0xd0, 0x4b, 0x30, 0xc9, + 0x7e, 0x5c, 0xf0, 0xdc, 0x76, 0x46, 0x4d, 0x13, 0x35, 0xbc, 0x26, 0xd9, 0x56, 0x4e, 0x1c, 0xf4, + 0x4a, 0x93, 0xea, 0x2f, 0x0e, 0x05, 0x9a, 0xff, 0x60, 0xc0, 0xac, 0xd6, 0xb8, 0x75, 0xdb, 0x0f, + 0xd0, 0x87, 0x12, 0x93, 0x67, 0x79, 0xb0, 0xc9, 0x43, 0x4b, 0xb3, 0xa9, 0x33, 0x27, 0x5a, 0x5a, + 0x94, 0x10, 0x6d, 0xe2, 0x38, 0x50, 0xb0, 0x03, 0xd2, 0xf6, 0x17, 0x73, 0x0f, 0xe5, 0x1f, 0x9d, + 0x7a, 0x6c, 0x2d, 0xb3, 0x61, 0x0c, 0xfb, 0x77, 0x8d, 0xf2, 0xc7, 0x5c, 0x8c, 0xf9, 0xf5, 0xb1, + 0x48, 0x0b, 0xe9, 0x8c, 0x42, 0x2e, 0x4c, 0xb4, 0x49, 0xe0, 0xd9, 0x75, 0xbe, 0xae, 0xa6, 0x1e, + 0x5b, 0x1d, 0xad, 0x16, 0x1b, 0x8c, 0x59, 0xb8, 0x59, 0xf2, 0xff, 0x3e, 0x96, 0x52, 0xd0, 0x2e, + 0x8c, 0x59, 0x5e, 0x53, 0xb6, 0xf9, 0x42, 0x36, 0xe3, 0x1b, 0xce, 0xb9, 0xb2, 0xd7, 0xf4, 0x31, + 0x93, 0x80, 0xce, 0xc1, 0x64, 0x40, 0xbc, 0xb6, 0xed, 0x58, 0x01, 0xdf, 0x5d, 0x8b, 0x95, 0x79, + 0x41, 0x36, 0xb9, 0x25, 0x11, 0x38, 0xa4, 0x41, 0x2d, 0x18, 0x6f, 0x78, 0xfb, 0xb8, 0xeb, 0x2c, + 0x8e, 0x65, 0xd1, 0x15, 0xab, 0x8c, 0x57, 0xb8, 0x98, 0xf8, 0x7f, 0x2c, 0x64, 0xa0, 0xaf, 0x18, + 0xb0, 0xd0, 0x26, 0x96, 0xdf, 0xf5, 0x08, 0x6d, 0x02, 0x26, 0x01, 0x71, 0xe8, 0x6e, 0xb8, 0x58, + 0x60, 0xc2, 0xf1, 0xa8, 0xe3, 0x90, 0xe4, 0x5c, 0x79, 0x50, 0x54, 0x65, 0x21, 0x0d, 0x8b, 0x53, + 0x6b, 0x63, 0xfe, 0x60, 0x0c, 0xe6, 0x13, 0x3b, 0x04, 0x7a, 0x02, 0x0a, 0x9d, 0x5d, 0xcb, 0x97, + 0x4b, 0xfe, 0xac, 0x9c, 0x6f, 0x55, 0x0a, 0xbc, 0xd3, 0x2b, 0x9d, 0x90, 0x45, 0x18, 0x00, 0x73, + 0x62, 0xaa, 0x53, 0xdb, 0xc4, 0xf7, 0xad, 0xa6, 0xdc, 0x07, 0xb4, 0x69, 0xc2, 0xc0, 0x58, 0xe2, + 0xd1, 0x2f, 0x1b, 0x70, 0x82, 0x4f, 0x19, 0x4c, 0xfc, 0x6e, 0x2b, 0xa0, 0x7b, 0x1d, 0xed, 0x96, + 0x4b, 0x59, 0x4c, 0x4f, 0xce, 0xb2, 0x72, 0x4a, 0x48, 0x3f, 0xa1, 0x43, 0x7d, 0x1c, 0x95, 0x8b, + 0xae, 0xc3, 0xa4, 0x1f, 0x58, 0x5e, 0x40, 0x1a, 0xe5, 0x80, 0x69, 0xb5, 0xa9, 0xc7, 0xfe, 0xef, + 0x60, 0x9b, 0xc0, 0x96, 0xdd, 0x26, 0x7c, 0xc3, 0xa9, 0x49, 0x06, 0x38, 0xe4, 0x85, 0x5e, 0x02, + 0xf0, 0xba, 0x4e, 0xad, 0xdb, 0x6e, 0x5b, 0xde, 0xbe, 0xd0, 0xe0, 0x17, 0x47, 0x6b, 0x1e, 0x56, + 0xfc, 0x42, 0x9d, 0x15, 0xc2, 0xb0, 0x26, 0x0f, 0xbd, 0x62, 0xc0, 0x09, 0x3e, 0x13, 0x65, 0x0d, + 0xc6, 0x33, 0xae, 0xc1, 0x3c, 0xed, 0xda, 0x55, 0x5d, 0x04, 0x8e, 0x4a, 0x34, 0xff, 0x36, 0xaa, + 0x4f, 0x6a, 0x01, 0xb5, 0xae, 0x9b, 0xfb, 0xe8, 0x83, 0x70, 0xbf, 0xdf, 0xad, 0xd7, 0x89, 0xef, + 0xef, 0x74, 0x5b, 0xb8, 0xeb, 0x5c, 0xb4, 0xfd, 0xc0, 0xf5, 0xf6, 0xd7, 0xed, 0xb6, 0x1d, 0xb0, + 0x19, 0x57, 0xa8, 0x9c, 0x39, 0xe8, 0x95, 0xee, 0xaf, 0xf5, 0x23, 0xc2, 0xfd, 0xcb, 0x23, 0x0b, + 0x1e, 0xe8, 0x3a, 0xfd, 0xd9, 0x73, 0xeb, 0xad, 0x74, 0xd0, 0x2b, 0x3d, 0x70, 0xb5, 0x3f, 0x19, + 0x3e, 0x8c, 0x87, 0xf9, 0x2f, 0x06, 0xcc, 0xc9, 0x76, 0x6d, 0x91, 0x76, 0xa7, 0x45, 0x77, 0x97, + 0xe3, 0x37, 0x44, 0x82, 0x88, 0x21, 0x82, 0xb3, 0x51, 0x27, 0xb2, 0xfe, 0xfd, 0xac, 0x11, 0xf3, + 0x9f, 0x0d, 0x58, 0x88, 0x13, 0xdf, 0x03, 0xe5, 0xe9, 0x47, 0x95, 0xe7, 0x66, 0xb6, 0xad, 0xed, + 0xa3, 0x41, 0x5f, 0x1b, 0x4b, 0xb6, 0xf5, 0x7f, 0xba, 0x1a, 0x0d, 0xb5, 0x62, 0xfe, 0xa7, 0xa9, + 0x15, 0xc7, 0xde, 0x54, 0x5a, 0xf1, 0x77, 0xc7, 0x60, 0xba, 0xec, 0x04, 0x76, 0x79, 0x67, 0xc7, + 0x76, 0xec, 0x60, 0x1f, 0x7d, 0x26, 0x07, 0xe7, 0x3a, 0x1e, 0xd9, 0x21, 0x9e, 0x47, 0x1a, 0xab, + 0x5d, 0xcf, 0x76, 0x9a, 0xb5, 0xfa, 0x2e, 0x69, 0x74, 0x5b, 0xb6, 0xd3, 0x5c, 0x6b, 0x3a, 0xae, + 0x02, 0x9f, 0xbf, 0x4d, 0xea, 0x5d, 0xd6, 0x24, 0xbe, 0x28, 0xda, 0xa3, 0x35, 0xa9, 0x3a, 0x9c, + 0xd0, 0xca, 0xe3, 0x07, 0xbd, 0xd2, 0xb9, 0x21, 0x0b, 0xe1, 0x61, 0x9b, 0x86, 0x3e, 0x95, 0x83, + 0x65, 0x8f, 0x7c, 0xb4, 0x6b, 0x0f, 0xde, 0x1b, 0x7c, 0xd7, 0x6a, 0x8d, 0xa8, 0x7e, 0x86, 0x92, + 0x59, 0x79, 0xec, 0xa0, 0x57, 0x1a, 0xb2, 0x0c, 0x1e, 0xb2, 0x5d, 0xe6, 0x37, 0x73, 0x70, 0xaa, + 0xdc, 0xe9, 0x6c, 0x10, 0x7f, 0x37, 0x76, 0xa8, 0xfd, 0x9c, 0x01, 0x33, 0x7b, 0xb6, 0x17, 0x74, + 0xad, 0x96, 0x74, 0x02, 0xf0, 0x29, 0x51, 0x1b, 0x71, 0x39, 0x73, 0x69, 0xd7, 0x22, 0xac, 0x2b, + 0xe8, 0xa0, 0x57, 0x9a, 0x89, 0xc2, 0x70, 0x4c, 0x3c, 0xfa, 0x75, 0x03, 0xe6, 0x04, 0x68, 0xd3, + 0x6d, 0x10, 0xdd, 0x73, 0x74, 0x35, 0xcb, 0x3a, 0x29, 0xe6, 0xdc, 0xc5, 0x10, 0x87, 0xe2, 0x44, + 0x25, 0xcc, 0x7f, 0xcb, 0xc1, 0xe9, 0x3e, 0x3c, 0xd0, 0xef, 0x18, 0xb0, 0xc0, 0xdd, 0x4d, 0x1a, + 0x0a, 0x93, 0x1d, 0xd1, 0x9b, 0x1f, 0xc8, 0xba, 0xe6, 0x98, 0xae, 0x05, 0xe2, 0xd4, 0x49, 0x65, + 0x91, 0x6e, 0x1b, 0x2b, 0x29, 0xa2, 0x71, 0x6a, 0x85, 0x58, 0x4d, 0xb9, 0x03, 0x2a, 0x56, 0xd3, + 0xdc, 0x3d, 0xa9, 0x69, 0x2d, 0x45, 0x34, 0x4e, 0xad, 0x90, 0xf9, 0xf3, 0xf0, 0xc0, 0x21, 0xec, + 0xee, 0x7e, 0xe2, 0x37, 0x5f, 0x50, 0xb3, 0x3e, 0x3a, 0xe7, 0x06, 0x70, 0x16, 0x98, 0x30, 0xee, + 0xb9, 0xdd, 0x80, 0x70, 0xed, 0x36, 0x59, 0x01, 0xaa, 0x27, 0x30, 0x83, 0x60, 0x81, 0x31, 0xbf, + 0x69, 0x40, 0x71, 0x08, 0xff, 0x43, 0x29, 0xea, 0x7f, 0x98, 0x4c, 0xf8, 0x1e, 0x82, 0xa4, 0xef, + 0xe1, 0xd9, 0xd1, 0x46, 0x63, 0x10, 0x9f, 0xc3, 0xbf, 0x1b, 0x30, 0x9f, 0xf0, 0x51, 0xa0, 0x5d, + 0x58, 0xe8, 0xb8, 0x0d, 0x69, 0x5f, 0x5c, 0xb4, 0xfc, 0x5d, 0x86, 0x13, 0xcd, 0x7b, 0x82, 0x8e, + 0x64, 0x35, 0x05, 0x7f, 0xa7, 0x57, 0x5a, 0x54, 0x4c, 0x62, 0x04, 0x38, 0x95, 0x23, 0xea, 0x40, + 0x71, 0xc7, 0x26, 0xad, 0x46, 0x38, 0x05, 0x47, 0xb4, 0x24, 0x2e, 0x08, 0x6e, 0xdc, 0x3d, 0x27, + 0xff, 0x61, 0x25, 0xc5, 0xbc, 0x02, 0x33, 0x51, 0x67, 0xed, 0x00, 0x83, 0x77, 0x06, 0xf2, 0x96, + 0xe7, 0x88, 0xa1, 0x9b, 0x12, 0x04, 0xf9, 0x32, 0xde, 0xc4, 0x14, 0x6e, 0xfe, 0x64, 0x0c, 0x66, + 0x2b, 0xad, 0x2e, 0x79, 0xd6, 0x23, 0x44, 0x9e, 0x4f, 0xcb, 0x30, 0xdb, 0xf1, 0xc8, 0x9e, 0x4d, + 0x6e, 0xd5, 0x48, 0x8b, 0xd4, 0x03, 0xd7, 0x13, 0xfc, 0x4f, 0x8b, 0xe2, 0xb3, 0xd5, 0x28, 0x1a, + 0xc7, 0xe9, 0xd1, 0x33, 0x30, 0x63, 0xd5, 0x03, 0x7b, 0x8f, 0x28, 0x0e, 0xbc, 0x02, 0x6f, 0x11, + 0x1c, 0x66, 0xca, 0x11, 0x2c, 0x8e, 0x51, 0xa3, 0x0f, 0xc1, 0xa2, 0x5f, 0xb7, 0x5a, 0xe4, 0x6a, + 0x47, 0x88, 0x5a, 0xd9, 0x25, 0xf5, 0x9b, 0x55, 0xd7, 0x76, 0x02, 0xe1, 0x8d, 0x78, 0x48, 0x70, + 0x5a, 0xac, 0xf5, 0xa1, 0xc3, 0x7d, 0x39, 0xa0, 0x3f, 0x32, 0xe0, 0x4c, 0xc7, 0x23, 0x55, 0xcf, + 0x6d, 0xbb, 0x54, 0xcd, 0x24, 0x8e, 0xe8, 0xe2, 0xa8, 0x7a, 0x6d, 0x44, 0x7d, 0xca, 0x21, 0x49, + 0x17, 0xe1, 0x5b, 0x0f, 0x7a, 0xa5, 0x33, 0xd5, 0xc3, 0x2a, 0x80, 0x0f, 0xaf, 0x1f, 0xfa, 0x13, + 0x03, 0xce, 0x76, 0x5c, 0x3f, 0x38, 0xa4, 0x09, 0x85, 0x63, 0x6d, 0x82, 0x79, 0xd0, 0x2b, 0x9d, + 0xad, 0x1e, 0x5a, 0x03, 0x7c, 0x97, 0x1a, 0x9a, 0x07, 0x53, 0x30, 0xaf, 0xcd, 0x3d, 0x71, 0x7e, + 0x7d, 0x1a, 0x4e, 0xc8, 0xc9, 0x10, 0xaa, 0xf5, 0xc9, 0xd0, 0xdf, 0x50, 0xd6, 0x91, 0x38, 0x4a, + 0x4b, 0xe7, 0x9d, 0x9a, 0x8a, 0xbc, 0x74, 0x6c, 0xde, 0x55, 0x23, 0x58, 0x1c, 0xa3, 0x46, 0x6b, + 0x70, 0x52, 0x40, 0x30, 0xe9, 0xb4, 0xec, 0xba, 0xb5, 0xe2, 0x76, 0xc5, 0x94, 0x2b, 0x54, 0x4e, + 0x1f, 0xf4, 0x4a, 0x27, 0xab, 0x49, 0x34, 0x4e, 0x2b, 0x83, 0xd6, 0x61, 0xc1, 0xea, 0x06, 0xae, + 0x6a, 0xff, 0x79, 0x87, 0x6a, 0x8a, 0x06, 0x9b, 0x5a, 0x45, 0xae, 0x52, 0xca, 0x29, 0x78, 0x9c, + 0x5a, 0x0a, 0x55, 0x63, 0xdc, 0x6a, 0xa4, 0xee, 0x3a, 0x0d, 0x3e, 0xca, 0x85, 0xd0, 0x0a, 0x2f, + 0xa7, 0xd0, 0xe0, 0xd4, 0x92, 0xa8, 0x05, 0x33, 0x6d, 0xeb, 0xf6, 0x55, 0xc7, 0xda, 0xb3, 0xec, + 0x16, 0x15, 0x22, 0x7c, 0x18, 0xfd, 0x0f, 0xd6, 0xdd, 0xc0, 0x6e, 0x2d, 0xf3, 0xeb, 0xbc, 0xe5, + 0x35, 0x27, 0xb8, 0xec, 0xd5, 0x02, 0x6a, 0xad, 0x71, 0xe3, 0x68, 0x23, 0xc2, 0x0b, 0xc7, 0x78, + 0xa3, 0xcb, 0x70, 0x8a, 0x2d, 0xc7, 0x55, 0xf7, 0x96, 0xb3, 0x4a, 0x5a, 0xd6, 0xbe, 0x6c, 0xc0, + 0x04, 0x6b, 0xc0, 0xfd, 0x07, 0xbd, 0xd2, 0xa9, 0x5a, 0x1a, 0x01, 0x4e, 0x2f, 0x87, 0x2c, 0x78, + 0x20, 0x8a, 0xc0, 0x64, 0xcf, 0xf6, 0x6d, 0xd7, 0xe1, 0x9e, 0x88, 0x62, 0xe8, 0x89, 0xa8, 0xf5, + 0x27, 0xc3, 0x87, 0xf1, 0x40, 0xbf, 0x69, 0xc0, 0x42, 0xda, 0x32, 0x5c, 0x9c, 0xcc, 0xe2, 0xb2, + 0x22, 0xb6, 0xb4, 0xf8, 0x8c, 0x48, 0xdd, 0x14, 0x52, 0x2b, 0x81, 0x5e, 0x36, 0x60, 0xda, 0xd2, + 0x4e, 0x51, 0x8b, 0xc0, 0x6a, 0x75, 0x69, 0xd4, 0xb3, 0x7c, 0xc8, 0xb1, 0x32, 0x77, 0xd0, 0x2b, + 0x45, 0x4e, 0x6a, 0x38, 0x22, 0x11, 0xfd, 0x96, 0x01, 0xa7, 0x52, 0xd7, 0xf8, 0xe2, 0xd4, 0x71, + 0xf4, 0x10, 0x9b, 0x24, 0xe9, 0x7b, 0x4e, 0x7a, 0x35, 0xd0, 0xeb, 0x86, 0x52, 0x65, 0x1b, 0xd2, + 0x9b, 0x32, 0xcd, 0xaa, 0x76, 0x65, 0xc4, 0x83, 0x63, 0x68, 0x10, 0x48, 0xc6, 0x95, 0x93, 0x9a, + 0x66, 0x94, 0x40, 0x1c, 0x17, 0x8f, 0x3e, 0x6b, 0x48, 0xd5, 0xa8, 0x6a, 0x74, 0xe2, 0xb8, 0x6a, + 0x84, 0x42, 0x4d, 0xab, 0x2a, 0x14, 0x13, 0x8e, 0x3e, 0x0c, 0x4b, 0xd6, 0xb6, 0xeb, 0x05, 0xa9, + 0x8b, 0x6f, 0x71, 0x86, 0x2d, 0xa3, 0xb3, 0x07, 0xbd, 0xd2, 0x52, 0xb9, 0x2f, 0x15, 0x3e, 0x84, + 0x83, 0xf9, 0xb5, 0x02, 0x4c, 0x73, 0x23, 0x5f, 0xa8, 0xae, 0x6f, 0x18, 0xf0, 0x60, 0xbd, 0xeb, + 0x79, 0xc4, 0x09, 0x6a, 0x01, 0xe9, 0x24, 0x15, 0x97, 0x71, 0xac, 0x8a, 0xeb, 0xa1, 0x83, 0x5e, + 0xe9, 0xc1, 0x95, 0x43, 0xe4, 0xe3, 0x43, 0x6b, 0x87, 0xfe, 0xd2, 0x00, 0x53, 0x10, 0x54, 0xac, + 0xfa, 0xcd, 0xa6, 0xe7, 0x76, 0x9d, 0x46, 0xb2, 0x11, 0xb9, 0x63, 0x6d, 0xc4, 0x23, 0x07, 0xbd, + 0x92, 0xb9, 0x72, 0xd7, 0x5a, 0xe0, 0x01, 0x6a, 0x8a, 0x9e, 0x85, 0x79, 0x41, 0x75, 0xfe, 0x76, + 0x87, 0x78, 0x36, 0x35, 0xa7, 0xc5, 0x7d, 0x7a, 0x18, 0xa2, 0x10, 0x27, 0xc0, 0xc9, 0x32, 0xc8, + 0x87, 0x89, 0x5b, 0xc4, 0x6e, 0xee, 0x06, 0xd2, 0x7c, 0x1a, 0x31, 0x2e, 0x41, 0x1c, 0xf8, 0xaf, + 0x73, 0x9e, 0x95, 0xa9, 0x83, 0x5e, 0x69, 0x42, 0xfc, 0xc1, 0x52, 0x12, 0xda, 0x84, 0x19, 0x7e, + 0x04, 0xab, 0xda, 0x4e, 0xb3, 0xea, 0x3a, 0xfc, 0x36, 0x7f, 0xb2, 0xf2, 0x88, 0x54, 0xf8, 0xb5, + 0x08, 0xf6, 0x4e, 0xaf, 0x34, 0x2d, 0x7f, 0x6f, 0xed, 0x77, 0x08, 0x8e, 0x95, 0x36, 0xbf, 0x59, + 0x00, 0x90, 0xd3, 0x95, 0x74, 0xd0, 0xff, 0x83, 0x49, 0x9f, 0x04, 0x5c, 0xaa, 0x70, 0x9e, 0xf3, + 0x3b, 0x09, 0x09, 0xc4, 0x21, 0x1e, 0xdd, 0x84, 0x42, 0xc7, 0xea, 0xfa, 0x44, 0x0c, 0xfe, 0xa5, + 0x4c, 0x06, 0xbf, 0x4a, 0x39, 0xf2, 0x33, 0x17, 0xfb, 0x89, 0xb9, 0x0c, 0xf4, 0x49, 0x03, 0x80, + 0x44, 0x07, 0x6c, 0x64, 0xdf, 0x87, 0x10, 0x19, 0x8e, 0x29, 0xed, 0x83, 0xca, 0xcc, 0x41, 0xaf, + 0x04, 0xda, 0xd0, 0x6b, 0x62, 0xd1, 0x2d, 0x28, 0x5a, 0x72, 0xcf, 0x1f, 0x3b, 0x8e, 0x3d, 0x9f, + 0x1d, 0x85, 0xd4, 0xa4, 0x55, 0xc2, 0xd0, 0xa7, 0x0c, 0x98, 0xf1, 0x49, 0x20, 0x86, 0x8a, 0xee, + 0x3c, 0xc2, 0xe0, 0x1d, 0x71, 0xd2, 0xd5, 0x22, 0x3c, 0xf9, 0x0e, 0x1a, 0x85, 0xe1, 0x98, 0x5c, + 0x1e, 0x53, 0x42, 0x82, 0x8b, 0xc4, 0x6a, 0x10, 0x4f, 0xb8, 0xa7, 0x84, 0x2d, 0xb5, 0x39, 0x72, + 0x65, 0x22, 0x5c, 0x45, 0x4c, 0x49, 0x0c, 0x8a, 0x13, 0xd2, 0xcd, 0xbf, 0x9e, 0x86, 0x19, 0x39, + 0x8b, 0x43, 0xb3, 0x9a, 0x7b, 0x55, 0xfa, 0x98, 0xd5, 0x2b, 0x3a, 0x12, 0x47, 0x69, 0x69, 0x61, + 0xbe, 0x4e, 0xa2, 0x56, 0xb5, 0x2a, 0x5c, 0xd3, 0x91, 0x38, 0x4a, 0x8b, 0xda, 0x50, 0xf0, 0x03, + 0xd2, 0x91, 0x97, 0x90, 0x23, 0xde, 0x91, 0x85, 0x8b, 0x33, 0xbc, 0x66, 0xa0, 0xff, 0x7c, 0xcc, + 0xa5, 0x30, 0xc7, 0x60, 0x10, 0xf1, 0x15, 0x8a, 0x99, 0x99, 0xcd, 0xe2, 0x88, 0xba, 0x21, 0xf9, + 0x04, 0x89, 0xc2, 0x70, 0x4c, 0x7c, 0x8a, 0xa5, 0x5d, 0x38, 0x46, 0x4b, 0xfb, 0x79, 0x28, 0xb6, + 0xad, 0xdb, 0xb5, 0xae, 0xd7, 0x3c, 0xba, 0x45, 0x2f, 0xe2, 0x83, 0x38, 0x17, 0xac, 0xf8, 0xa1, + 0x57, 0x0c, 0x6d, 0xbd, 0x4f, 0x30, 0xe6, 0xd7, 0xb3, 0x5d, 0xef, 0x4a, 0x51, 0xf5, 0x5d, 0xf9, + 0x09, 0xbb, 0xb7, 0x78, 0xcf, 0xed, 0x5e, 0x6a, 0xc3, 0xf1, 0x05, 0xa2, 0x6c, 0xb8, 0xc9, 0x63, + 0xb5, 0xe1, 0x56, 0x22, 0xc2, 0x70, 0x4c, 0x38, 0xab, 0x0f, 0x5f, 0x73, 0xaa, 0x3e, 0x70, 0xac, + 0xf5, 0xa9, 0x45, 0x84, 0xe1, 0x98, 0xf0, 0xfe, 0x87, 0xbd, 0xa9, 0xe3, 0x39, 0xec, 0x4d, 0x67, + 0x70, 0xd8, 0x3b, 0xdc, 0x0e, 0x3e, 0x31, 0xaa, 0x1d, 0x8c, 0x2e, 0x01, 0x6a, 0xec, 0x3b, 0x56, + 0xdb, 0xae, 0x8b, 0xcd, 0x92, 0xe9, 0xac, 0x19, 0xe6, 0x0c, 0x58, 0x12, 0x1b, 0x19, 0x5a, 0x4d, + 0x50, 0xe0, 0x94, 0x52, 0x28, 0x80, 0x62, 0x47, 0x9a, 0x3b, 0xb3, 0x59, 0xcc, 0x7e, 0x69, 0xfe, + 0xf0, 0x7b, 0x6a, 0xba, 0xf0, 0x24, 0x04, 0x2b, 0x49, 0xe6, 0x7f, 0x1a, 0x30, 0xb7, 0xd2, 0x72, + 0xbb, 0x8d, 0xeb, 0x56, 0x50, 0xdf, 0xe5, 0x97, 0xaa, 0xe8, 0x19, 0x28, 0xda, 0x4e, 0x40, 0xbc, + 0x3d, 0xab, 0x25, 0x34, 0x8a, 0x29, 0xef, 0x9d, 0xd7, 0x04, 0xfc, 0x4e, 0xaf, 0x34, 0xb3, 0xda, + 0xf5, 0x58, 0xb4, 0x22, 0xdf, 0x5f, 0xb0, 0x2a, 0x83, 0xbe, 0x6c, 0xc0, 0x3c, 0xbf, 0x96, 0x5d, + 0xb5, 0x02, 0xeb, 0x4a, 0x97, 0x78, 0x36, 0x91, 0x17, 0xb3, 0x23, 0x6e, 0x2d, 0xf1, 0xba, 0x4a, + 0x01, 0xfb, 0xa1, 0x5d, 0xbb, 0x11, 0x97, 0x8c, 0x93, 0x95, 0x31, 0x3f, 0x9f, 0x87, 0xfb, 0xfb, + 0xf2, 0x42, 0x4b, 0x90, 0xb3, 0x1b, 0xa2, 0xe9, 0x20, 0xf8, 0xe6, 0xd6, 0x1a, 0x38, 0x67, 0x37, + 0xd0, 0x32, 0x33, 0xd1, 0x3c, 0xe2, 0xfb, 0xf2, 0x8e, 0x6e, 0x52, 0x59, 0x53, 0x02, 0x8a, 0x35, + 0x0a, 0x54, 0x82, 0x42, 0xcb, 0xda, 0x26, 0x2d, 0x61, 0x7e, 0x33, 0xa3, 0x6f, 0x9d, 0x02, 0x30, + 0x87, 0xa3, 0x5f, 0x32, 0x00, 0x78, 0x05, 0xa9, 0xf1, 0x2e, 0xf4, 0x1a, 0xce, 0xb6, 0x9b, 0x28, + 0x67, 0x5e, 0xcb, 0xf0, 0x3f, 0xd6, 0xa4, 0xa2, 0x2d, 0x18, 0xa7, 0xf6, 0x9f, 0xdb, 0x38, 0xb2, + 0x1a, 0x63, 0x77, 0x12, 0x55, 0xc6, 0x03, 0x0b, 0x5e, 0xb4, 0xaf, 0x3c, 0x12, 0x74, 0x3d, 0x87, + 0x76, 0x2d, 0x53, 0x5c, 0x45, 0x5e, 0x0b, 0xac, 0xa0, 0x58, 0xa3, 0x30, 0xff, 0x30, 0x07, 0x0b, + 0x69, 0x55, 0xa7, 0xfa, 0x61, 0x9c, 0xd7, 0x56, 0x9c, 0x24, 0xdf, 0x9f, 0x7d, 0xff, 0x88, 0x08, + 0x03, 0x75, 0x0f, 0x2f, 0x62, 0xa0, 0x84, 0x5c, 0xf4, 0x7e, 0xd5, 0x43, 0xb9, 0x23, 0xf6, 0x90, + 0xe2, 0x1c, 0xeb, 0xa5, 0x87, 0x60, 0xcc, 0xa7, 0x23, 0x9f, 0x8f, 0xfa, 0xfb, 0xd9, 0x18, 0x31, + 0x0c, 0xa5, 0xe8, 0x3a, 0x76, 0x20, 0x42, 0x88, 0x15, 0xc5, 0x55, 0xc7, 0x0e, 0x30, 0xc3, 0x98, + 0x5f, 0xcc, 0xc1, 0x52, 0xff, 0x46, 0xa1, 0x2f, 0x1a, 0x00, 0x0d, 0x6a, 0xdd, 0xd3, 0x29, 0x29, + 0x23, 0x32, 0xac, 0xe3, 0xea, 0xc3, 0x55, 0x29, 0x29, 0x0c, 0xcf, 0x51, 0x20, 0x1f, 0x6b, 0x15, + 0x41, 0x8f, 0xc9, 0xa9, 0xbf, 0x69, 0xb5, 0xa5, 0x01, 0xaa, 0xca, 0x6c, 0x28, 0x0c, 0xd6, 0xa8, + 0xe8, 0xf1, 0xcd, 0xb1, 0xda, 0xc4, 0xef, 0x58, 0x2a, 0x46, 0x9c, 0x1d, 0xdf, 0x36, 0x25, 0x10, + 0x87, 0x78, 0xb3, 0x05, 0x0f, 0x0f, 0x50, 0xcf, 0x8c, 0xe2, 0x75, 0xcd, 0xff, 0x30, 0xe0, 0xf4, + 0x4a, 0xab, 0xeb, 0x07, 0xc4, 0xfb, 0x5f, 0x13, 0xed, 0xf4, 0x5f, 0x06, 0x3c, 0xd0, 0xa7, 0xcd, + 0xf7, 0x20, 0xe8, 0xe9, 0xc5, 0x68, 0xd0, 0xd3, 0xd5, 0x51, 0xa7, 0x74, 0x6a, 0x3b, 0xfa, 0xc4, + 0x3e, 0x05, 0x70, 0x82, 0xee, 0x5a, 0x0d, 0xb7, 0x99, 0x91, 0xde, 0x7c, 0x18, 0x0a, 0x1f, 0xa5, + 0xfa, 0x27, 0x3e, 0xc7, 0x98, 0x52, 0xc2, 0x1c, 0x67, 0xbe, 0x0f, 0x44, 0x84, 0x50, 0x6c, 0xf1, + 0x18, 0x83, 0x2c, 0x1e, 0xf3, 0xef, 0x72, 0xa0, 0x1d, 0xfb, 0xef, 0xc1, 0xa4, 0x74, 0x22, 0x93, + 0x72, 0xc4, 0x83, 0xbc, 0xe6, 0xc4, 0xe8, 0xf7, 0x14, 0x60, 0x2f, 0xf6, 0x14, 0x60, 0x33, 0x33, + 0x89, 0x87, 0xbf, 0x04, 0xf8, 0x9e, 0x01, 0x0f, 0x84, 0xc4, 0x49, 0x8f, 0xdc, 0xdd, 0x77, 0x98, + 0x27, 0x61, 0xca, 0x0a, 0x8b, 0x89, 0x39, 0xa0, 0x5e, 0xbf, 0x68, 0x1c, 0xb1, 0x4e, 0x17, 0x06, + 0x1e, 0xe7, 0x8f, 0x18, 0x78, 0x3c, 0x76, 0x78, 0xe0, 0xb1, 0xf9, 0xe3, 0x1c, 0x9c, 0x49, 0xb6, + 0x4c, 0xae, 0x8d, 0xc1, 0x2e, 0xac, 0x9f, 0x82, 0xe9, 0x40, 0x14, 0xd0, 0x76, 0x7a, 0xf5, 0x76, + 0x6b, 0x4b, 0xc3, 0xe1, 0x08, 0x25, 0x2d, 0x59, 0xe7, 0xab, 0xb2, 0x56, 0x77, 0x3b, 0x32, 0x6c, + 0x5d, 0x95, 0x5c, 0xd1, 0x70, 0x38, 0x42, 0xa9, 0x02, 0x02, 0xc7, 0x8e, 0x3d, 0x20, 0xb0, 0x06, + 0xa7, 0x64, 0x08, 0xd4, 0x05, 0xd7, 0x5b, 0x71, 0xdb, 0x9d, 0x16, 0x11, 0x81, 0xeb, 0xb4, 0xb2, + 0x67, 0x44, 0x91, 0x53, 0x38, 0x8d, 0x08, 0xa7, 0x97, 0x35, 0xbf, 0x97, 0x87, 0x93, 0x61, 0xb7, + 0xaf, 0xb8, 0x4e, 0xc3, 0x66, 0x81, 0x64, 0x4f, 0xc3, 0x58, 0xb0, 0xdf, 0x91, 0x9d, 0xfd, 0x7f, + 0x64, 0x75, 0xb6, 0xf6, 0x3b, 0x74, 0xb4, 0x4f, 0xa7, 0x14, 0x61, 0x3e, 0x51, 0x56, 0x08, 0xad, + 0xab, 0xd5, 0xc1, 0x47, 0xe0, 0x89, 0xe8, 0x6c, 0xbe, 0xd3, 0x2b, 0xa5, 0x3c, 0x5d, 0x5c, 0x56, + 0x9c, 0xa2, 0x73, 0x1e, 0xdd, 0x80, 0x99, 0x96, 0xe5, 0x07, 0x57, 0x3b, 0x0d, 0x2b, 0x20, 0x5b, + 0x76, 0x9b, 0x88, 0x35, 0x37, 0x4c, 0x34, 0xb8, 0xba, 0xc4, 0x5d, 0x8f, 0x70, 0xc2, 0x31, 0xce, + 0x68, 0x0f, 0x10, 0x85, 0x6c, 0x79, 0x96, 0xe3, 0xf3, 0x56, 0x51, 0x79, 0xc3, 0x47, 0x9f, 0xab, + 0x63, 0xd9, 0x7a, 0x82, 0x1b, 0x4e, 0x91, 0x80, 0x1e, 0x81, 0x71, 0x8f, 0x58, 0xbe, 0x18, 0xcc, + 0xc9, 0x70, 0xfd, 0x63, 0x06, 0xc5, 0x02, 0xab, 0x2f, 0xa8, 0xf1, 0xbb, 0x2c, 0xa8, 0x1f, 0x1a, + 0x30, 0x13, 0x0e, 0xd3, 0x3d, 0x50, 0x92, 0xed, 0xa8, 0x92, 0xbc, 0x98, 0xd5, 0x96, 0xd8, 0x47, + 0x2f, 0xfe, 0xe9, 0xb8, 0xde, 0x3e, 0x16, 0x0d, 0xfc, 0x31, 0x98, 0x94, 0xab, 0x5a, 0x5a, 0x9f, + 0x23, 0x9e, 0x6e, 0x23, 0x76, 0x89, 0xf6, 0x8a, 0x45, 0x08, 0xc1, 0xa1, 0x3c, 0xaa, 0x96, 0x1b, + 0x42, 0xe5, 0x8a, 0x69, 0xaf, 0xd4, 0xb2, 0x54, 0xc5, 0x69, 0x6a, 0x59, 0x96, 0x41, 0x57, 0xe1, + 0x74, 0xc7, 0x73, 0xd9, 0xcb, 0xc6, 0x55, 0x62, 0x35, 0x5a, 0xb6, 0x43, 0xa4, 0x0b, 0x81, 0xc7, + 0x10, 0x3c, 0x70, 0xd0, 0x2b, 0x9d, 0xae, 0xa6, 0x93, 0xe0, 0x7e, 0x65, 0xa3, 0xaf, 0x71, 0xc6, + 0x06, 0x78, 0x8d, 0xf3, 0x69, 0xe5, 0xa8, 0x23, 0xbe, 0x78, 0x13, 0xf3, 0xc1, 0xac, 0x86, 0x32, + 0x65, 0x5b, 0x0f, 0xa7, 0x54, 0x59, 0x08, 0xc5, 0x4a, 0x7c, 0x7f, 0x6f, 0xd0, 0xf8, 0x11, 0xbd, + 0x41, 0x61, 0x50, 0xf5, 0xc4, 0x4f, 0x33, 0xa8, 0xba, 0xf8, 0xa6, 0x0a, 0xaa, 0x7e, 0xb5, 0x00, + 0x73, 0x71, 0x0b, 0xe4, 0xf8, 0x5f, 0x1a, 0xfd, 0x9a, 0x01, 0x73, 0x72, 0xf5, 0x70, 0x99, 0x44, + 0xfa, 0xf9, 0xd7, 0x33, 0x5a, 0xb4, 0xdc, 0x96, 0x52, 0x6f, 0x61, 0xb7, 0x62, 0xd2, 0x70, 0x42, + 0x3e, 0x7a, 0x01, 0xa6, 0x94, 0x3b, 0xfc, 0x48, 0xcf, 0x8e, 0x66, 0x99, 0x15, 0x15, 0xb2, 0xc0, + 0x3a, 0x3f, 0xf4, 0xaa, 0x01, 0x50, 0x97, 0x6a, 0x4e, 0xae, 0xae, 0x2b, 0x59, 0xad, 0x2e, 0xa5, + 0x40, 0x43, 0x63, 0x59, 0x81, 0x7c, 0xac, 0x09, 0x46, 0x9f, 0x67, 0x8e, 0x70, 0x65, 0xdd, 0xd1, + 0xf5, 0x94, 0x1f, 0x3d, 0x0e, 0xf6, 0x10, 0xc3, 0x34, 0x34, 0xa5, 0x34, 0x94, 0x8f, 0x23, 0x95, + 0x30, 0x9f, 0x06, 0x15, 0xb9, 0x48, 0xb7, 0x2d, 0x16, 0xbb, 0x58, 0xb5, 0x82, 0x5d, 0x31, 0x05, + 0xd5, 0xb6, 0x75, 0x41, 0x22, 0x70, 0x48, 0x63, 0x7e, 0x04, 0x66, 0x9e, 0xf5, 0xac, 0xce, 0xae, + 0xcd, 0x1c, 0xce, 0xf4, 0x9c, 0xf4, 0x76, 0x98, 0xb0, 0x1a, 0x8d, 0xb4, 0x97, 0xe4, 0x65, 0x0e, + 0xc6, 0x12, 0x3f, 0xd8, 0x91, 0xe8, 0xcf, 0x0d, 0x40, 0x91, 0xbb, 0xb2, 0x0d, 0x7a, 0xda, 0xa7, + 0xe7, 0xa3, 0x5d, 0x06, 0x4d, 0x3b, 0x1f, 0x5d, 0x54, 0x18, 0xac, 0x51, 0xa1, 0x97, 0x0d, 0x98, + 0xe2, 0x7f, 0xaf, 0xa9, 0xd3, 0xfe, 0xc8, 0x0f, 0x51, 0xb9, 0x46, 0x61, 0x95, 0x0a, 0x0d, 0xfa, + 0x8b, 0xa1, 0x14, 0xac, 0x8b, 0x34, 0xbf, 0x65, 0xc0, 0xc2, 0x9a, 0x1f, 0xd8, 0xee, 0x2a, 0xf1, + 0x03, 0xba, 0xf3, 0xd3, 0xfd, 0xa1, 0xdb, 0x1a, 0x24, 0x4e, 0x78, 0x15, 0xe6, 0xc4, 0x1d, 0x5f, + 0x77, 0xdb, 0x27, 0x81, 0x66, 0x6a, 0xab, 0xa5, 0xb6, 0x12, 0xc3, 0xe3, 0x44, 0x09, 0xca, 0x45, + 0x5c, 0xf6, 0x85, 0x5c, 0xf2, 0x51, 0x2e, 0xb5, 0x18, 0x1e, 0x27, 0x4a, 0x98, 0xdf, 0xcd, 0xc3, + 0x49, 0xd6, 0x8c, 0x58, 0x8c, 0xff, 0x67, 0xfb, 0xc5, 0xf8, 0x8f, 0xb8, 0xda, 0x98, 0xac, 0x23, + 0x44, 0xf8, 0xff, 0xaa, 0x01, 0xb3, 0x8d, 0x68, 0x4f, 0x67, 0xe3, 0x41, 0x49, 0x1b, 0x43, 0x1e, + 0x4f, 0x14, 0x03, 0xe2, 0xb8, 0x7c, 0xf4, 0x05, 0x03, 0x66, 0xa3, 0xd5, 0x94, 0x1b, 0xf0, 0x31, + 0x74, 0x92, 0x0a, 0x00, 0x8e, 0xc2, 0x7d, 0x1c, 0xaf, 0x82, 0xf9, 0x37, 0x86, 0x18, 0xd2, 0xe3, + 0x08, 0x60, 0x47, 0xb7, 0x60, 0x32, 0x68, 0xf9, 0x1c, 0x28, 0x5a, 0x3b, 0xe2, 0xa1, 0x6d, 0x6b, + 0xbd, 0xc6, 0xd8, 0x69, 0x76, 0x95, 0x80, 0x50, 0xfb, 0x50, 0xca, 0x32, 0xbf, 0x6a, 0xc0, 0xe4, + 0x25, 0x77, 0x5b, 0x6c, 0x4e, 0x1f, 0xce, 0xc0, 0x25, 0xa2, 0x2c, 0x27, 0x75, 0x9b, 0x16, 0x1a, + 0xe3, 0xcf, 0x44, 0x1c, 0x22, 0x0f, 0x6a, 0xbc, 0x97, 0x59, 0x3e, 0x19, 0xca, 0xea, 0x92, 0xbb, + 0xdd, 0xd7, 0xdf, 0xf6, 0xdb, 0x05, 0x38, 0xf1, 0x9c, 0xb5, 0x4f, 0x9c, 0xc0, 0x1a, 0x7e, 0x3b, + 0x7d, 0x12, 0xa6, 0xac, 0x0e, 0x8b, 0x67, 0xd5, 0xac, 0xe1, 0xd0, 0xc7, 0x10, 0xa2, 0xb0, 0x4e, + 0x17, 0xee, 0x2b, 0x3c, 0xbd, 0x45, 0xda, 0x8e, 0xb0, 0x12, 0xc3, 0xe3, 0x44, 0x09, 0x74, 0x09, + 0x90, 0x78, 0xac, 0x57, 0xae, 0xd7, 0xdd, 0xae, 0xc3, 0x77, 0x16, 0xee, 0x7e, 0x50, 0xc7, 0xb2, + 0x8d, 0x04, 0x05, 0x4e, 0x29, 0x85, 0x3e, 0x04, 0x8b, 0x75, 0xc6, 0x59, 0x18, 0xe9, 0x3a, 0x47, + 0x7e, 0x50, 0x53, 0xb1, 0xe4, 0x2b, 0x7d, 0xe8, 0x70, 0x5f, 0x0e, 0xb4, 0xa6, 0x7e, 0xe0, 0x7a, + 0x56, 0x93, 0xe8, 0x7c, 0xc7, 0xa3, 0x35, 0xad, 0x25, 0x28, 0x70, 0x4a, 0x29, 0xf4, 0x09, 0x98, + 0x0c, 0x76, 0x3d, 0xe2, 0xef, 0xba, 0xad, 0x86, 0xb8, 0x5e, 0x1f, 0xd1, 0x27, 0x25, 0x46, 0x7f, + 0x4b, 0x72, 0xd5, 0xa6, 0xb7, 0x04, 0xe1, 0x50, 0x26, 0xf2, 0x60, 0xdc, 0xaf, 0xbb, 0x1d, 0xe2, + 0x0b, 0xe3, 0xf6, 0x52, 0x26, 0xd2, 0x99, 0x8f, 0x45, 0xf3, 0x86, 0x31, 0x09, 0x58, 0x48, 0x32, + 0xbf, 0x9d, 0x83, 0x69, 0x9d, 0x70, 0x80, 0x2d, 0xe2, 0x93, 0x06, 0x4c, 0xd7, 0x5d, 0x27, 0xf0, + 0xdc, 0x16, 0xf7, 0xf4, 0x64, 0xa3, 0x7a, 0x29, 0xab, 0x55, 0x12, 0x58, 0x76, 0x4b, 0x73, 0x1a, + 0x69, 0x62, 0x70, 0x44, 0x28, 0xfa, 0x8c, 0x01, 0xb3, 0x61, 0x28, 0x54, 0xe8, 0x72, 0xca, 0xb4, + 0x22, 0x6a, 0xc7, 0x3d, 0x1f, 0x95, 0x84, 0xe3, 0xa2, 0xcd, 0x6d, 0x98, 0x8b, 0x8f, 0x36, 0xed, + 0xca, 0x8e, 0x25, 0xd6, 0x7a, 0x3e, 0xec, 0xca, 0xaa, 0xe5, 0xfb, 0x98, 0x61, 0xd0, 0x3b, 0xa0, + 0xd8, 0xb6, 0xbc, 0xa6, 0xed, 0x58, 0x2d, 0xd6, 0x8b, 0x79, 0x6d, 0x43, 0x12, 0x70, 0xac, 0x28, + 0xcc, 0x1f, 0x8d, 0xc1, 0x94, 0x76, 0x26, 0x39, 0xfe, 0xf3, 0x45, 0x24, 0x7f, 0x40, 0x3e, 0xc3, + 0xfc, 0x01, 0xcf, 0x03, 0xec, 0xd8, 0x8e, 0xed, 0xef, 0x1e, 0x31, 0x33, 0x01, 0xbb, 0x9a, 0xbc, + 0xa0, 0x38, 0x60, 0x8d, 0x5b, 0x78, 0xff, 0x53, 0x38, 0x24, 0x5f, 0xcb, 0xab, 0x86, 0xa6, 0x3c, + 0xc6, 0xb3, 0xb8, 0xef, 0xd6, 0x06, 0x66, 0x59, 0x2a, 0x93, 0xf3, 0x4e, 0xe0, 0xed, 0x1f, 0xaa, + 0x63, 0xb6, 0xa0, 0xe8, 0x11, 0xbf, 0xdb, 0xa6, 0x27, 0xa5, 0x89, 0xa1, 0xbb, 0x81, 0xc5, 0x0a, + 0x60, 0x51, 0x1e, 0x2b, 0x4e, 0x4b, 0x4f, 0xc3, 0x89, 0x48, 0x15, 0xd0, 0x1c, 0xe4, 0x6f, 0x92, + 0x7d, 0x3e, 0x4f, 0x30, 0xfd, 0x89, 0x16, 0x22, 0xb7, 0x64, 0xa2, 0x5b, 0xde, 0x9b, 0x7b, 0xca, + 0x30, 0x5d, 0x48, 0x3d, 0xf8, 0x1e, 0xe5, 0x12, 0x83, 0x8e, 0x45, 0x4b, 0x4b, 0x4d, 0xa0, 0xc6, + 0x82, 0x47, 0x84, 0x70, 0x9c, 0xf9, 0xe3, 0x71, 0x10, 0x57, 0xb8, 0x03, 0x6c, 0x3e, 0xfa, 0xcd, + 0x4d, 0xee, 0x08, 0x37, 0x37, 0x97, 0x60, 0xda, 0x76, 0xec, 0xc0, 0xb6, 0x5a, 0xcc, 0xa9, 0x21, + 0x94, 0xa3, 0x8c, 0x57, 0x9d, 0x5e, 0xd3, 0x70, 0x29, 0x7c, 0x22, 0x65, 0xd1, 0x15, 0x28, 0x30, + 0xed, 0x21, 0x26, 0xf0, 0xf0, 0xf7, 0xcc, 0x2c, 0xc4, 0x80, 0x3f, 0x62, 0xe1, 0x9c, 0x98, 0x45, + 0xcf, 0x73, 0x33, 0xa8, 0x63, 0xa7, 0x98, 0xc7, 0xa1, 0x45, 0x1f, 0xc3, 0xe3, 0x44, 0x09, 0xca, + 0x65, 0xc7, 0xb2, 0x5b, 0x5d, 0x8f, 0x84, 0x5c, 0xc6, 0xa3, 0x5c, 0x2e, 0xc4, 0xf0, 0x38, 0x51, + 0x02, 0xed, 0xc0, 0xb4, 0x80, 0xf1, 0x38, 0x9f, 0x89, 0x23, 0xb6, 0x92, 0xc5, 0x73, 0x5d, 0xd0, + 0x38, 0xe1, 0x08, 0x5f, 0xd4, 0x85, 0x79, 0xdb, 0xa9, 0xbb, 0x4e, 0xbd, 0xd5, 0xf5, 0xed, 0x3d, + 0x12, 0xbe, 0x20, 0x39, 0x8a, 0xb0, 0x53, 0x07, 0xbd, 0xd2, 0xfc, 0x5a, 0x9c, 0x1d, 0x4e, 0x4a, + 0x40, 0xaf, 0x18, 0x70, 0xaa, 0xee, 0x3a, 0x3e, 0x7b, 0xec, 0xbc, 0x47, 0xce, 0x7b, 0x9e, 0xeb, + 0x71, 0xd9, 0x93, 0x47, 0x94, 0xcd, 0x7c, 0x69, 0x2b, 0x69, 0x2c, 0x71, 0xba, 0x24, 0xf4, 0x22, + 0x14, 0x3b, 0x9e, 0xbb, 0x67, 0x37, 0x88, 0x27, 0x62, 0xc6, 0xd6, 0xb3, 0x48, 0xbe, 0x50, 0x15, + 0x3c, 0xc3, 0xad, 0x47, 0x42, 0xb0, 0x92, 0x67, 0x7e, 0xad, 0x08, 0x33, 0x51, 0x72, 0xf4, 0x71, + 0x80, 0x8e, 0xe7, 0xb6, 0x49, 0xb0, 0x4b, 0xd4, 0x4b, 0x80, 0xcd, 0x51, 0xdf, 0xf8, 0x4b, 0x7e, + 0x32, 0x6a, 0x83, 0x6e, 0x17, 0x21, 0x14, 0x6b, 0x12, 0x91, 0x07, 0x13, 0x37, 0xb9, 0x12, 0x15, + 0x36, 0xc5, 0x73, 0x99, 0x58, 0x40, 0x42, 0x32, 0x0b, 0x61, 0x17, 0x20, 0x2c, 0x05, 0xa1, 0x6d, + 0xc8, 0xdf, 0x22, 0xdb, 0xd9, 0xbc, 0x9b, 0xbd, 0x4e, 0xc4, 0xd9, 0xa4, 0x32, 0x71, 0xd0, 0x2b, + 0xe5, 0xaf, 0x93, 0x6d, 0x4c, 0x99, 0xd3, 0x76, 0x35, 0xf8, 0xfd, 0xb3, 0xd8, 0x2a, 0x46, 0x6c, + 0x57, 0xe4, 0x32, 0x9b, 0xb7, 0x4b, 0x80, 0xb0, 0x14, 0x84, 0x5e, 0x84, 0xc9, 0x5b, 0xd6, 0x1e, + 0xd9, 0xf1, 0x5c, 0x27, 0x10, 0xa1, 0x42, 0x23, 0x06, 0x87, 0x5f, 0x97, 0xec, 0x84, 0x5c, 0xa6, + 0xde, 0x15, 0x10, 0x87, 0xe2, 0xd0, 0x1e, 0x14, 0x1d, 0x72, 0x0b, 0x93, 0x96, 0x5d, 0x17, 0x41, + 0xb0, 0x23, 0x4e, 0xeb, 0x4d, 0xc1, 0x4d, 0x48, 0x66, 0x7a, 0x4f, 0xc2, 0xb0, 0x92, 0x45, 0xc7, + 0xf2, 0x86, 0xbb, 0x2d, 0x36, 0xaa, 0x11, 0xc7, 0x52, 0x9d, 0x33, 0xf9, 0x58, 0x5e, 0x72, 0xb7, + 0x31, 0x65, 0x4e, 0xd7, 0x48, 0x5d, 0xc5, 0xa9, 0x88, 0x6d, 0x6a, 0x33, 0xdb, 0xf8, 0x1c, 0xbe, + 0x46, 0x42, 0x28, 0xd6, 0x24, 0xd2, 0xbe, 0x6d, 0x0a, 0x27, 0x9d, 0xd8, 0xa8, 0x46, 0xec, 0xdb, + 0xa8, 0xcb, 0x8f, 0xf7, 0xad, 0x84, 0x61, 0x25, 0xcb, 0xfc, 0xea, 0x38, 0x4c, 0xeb, 0xc9, 0xa6, + 0x06, 0xd0, 0xd5, 0xca, 0x3e, 0xcd, 0x0d, 0x63, 0x9f, 0xd2, 0xe3, 0x85, 0xe6, 0x63, 0x97, 0x1e, + 0x86, 0xb5, 0xcc, 0xcc, 0xb3, 0xf0, 0x78, 0xa1, 0x01, 0x7d, 0x1c, 0x11, 0x3a, 0xc4, 0xb5, 0x3b, + 0x35, 0x72, 0xb8, 0x19, 0x50, 0x88, 0x1a, 0x39, 0x11, 0xc5, 0xfe, 0x18, 0x40, 0x98, 0x74, 0x49, + 0xdc, 0xbd, 0x28, 0xeb, 0x49, 0x4b, 0x06, 0xa5, 0x51, 0xa1, 0x47, 0x60, 0x9c, 0x2a, 0x4a, 0xd2, + 0x10, 0xcf, 0x34, 0xd5, 0x19, 0xee, 0x02, 0x83, 0x62, 0x81, 0x45, 0x4f, 0x51, 0x9b, 0x26, 0x54, + 0x6f, 0xe2, 0xf5, 0xe5, 0x42, 0x68, 0xd3, 0x84, 0x38, 0x1c, 0xa1, 0xa4, 0x55, 0x27, 0x54, 0x1b, + 0xb1, 0x99, 0xa4, 0x55, 0x9d, 0xa9, 0x28, 0xcc, 0x71, 0xcc, 0xa7, 0x10, 0xd3, 0x5e, 0x4c, 0x59, + 0x15, 0x34, 0x9f, 0x42, 0x0c, 0x8f, 0x13, 0x25, 0x68, 0x63, 0xc4, 0xb5, 0xd1, 0x14, 0x8f, 0x2e, + 0xec, 0x73, 0xe1, 0xf3, 0x9a, 0x6e, 0x99, 0x4f, 0xb3, 0xa1, 0x7f, 0x7f, 0x76, 0x89, 0xd3, 0x06, + 0x37, 0xcd, 0x47, 0x33, 0xa2, 0x3f, 0x02, 0x33, 0xd1, 0x3d, 0x8b, 0x4e, 0xa8, 0x8e, 0xe7, 0xee, + 0xd8, 0x2d, 0x12, 0xf7, 0xfd, 0x54, 0x39, 0x18, 0x4b, 0xfc, 0x60, 0xae, 0xf4, 0x3f, 0xcb, 0xc3, + 0xc9, 0xcd, 0xa6, 0xed, 0xdc, 0x8e, 0x79, 0x6d, 0xd3, 0x12, 0x9a, 0x1a, 0xc3, 0x26, 0x34, 0x0d, + 0x9f, 0x9c, 0x88, 0x8c, 0xb1, 0xe9, 0x4f, 0x4e, 0x64, 0x3a, 0xd9, 0x28, 0x2d, 0xfa, 0xa1, 0x01, + 0x0f, 0x5a, 0x0d, 0x6e, 0x45, 0x5a, 0x2d, 0x01, 0x0d, 0x85, 0xca, 0x15, 0xed, 0x8f, 0xa8, 0x13, + 0x92, 0x8d, 0x5f, 0x2e, 0x1f, 0x22, 0x95, 0x8f, 0xf8, 0xdb, 0x44, 0x0b, 0x1e, 0x3c, 0x8c, 0x14, + 0x1f, 0x5a, 0xfd, 0xa5, 0xcb, 0xf0, 0xd6, 0xbb, 0x0a, 0x1a, 0x6a, 0xb6, 0x7c, 0xd2, 0x80, 0x49, + 0xee, 0x94, 0xc4, 0x64, 0x87, 0x6e, 0x15, 0x56, 0xc7, 0xbe, 0x46, 0x3c, 0x5f, 0x66, 0x5a, 0xd2, + 0x0e, 0x5a, 0xe5, 0xea, 0x9a, 0xc0, 0x60, 0x8d, 0x8a, 0x6e, 0xc6, 0x37, 0x6d, 0xa7, 0x21, 0x86, + 0x49, 0x6d, 0xc6, 0xcf, 0xd9, 0x4e, 0x03, 0x33, 0x8c, 0xda, 0xae, 0xf3, 0x7d, 0xd3, 0x9e, 0x7c, + 0xc5, 0x80, 0x19, 0xf6, 0xc8, 0x2d, 0x3c, 0x02, 0x3c, 0xa9, 0x62, 0x2a, 0x78, 0x35, 0xce, 0x44, + 0x63, 0x2a, 0xee, 0xf4, 0x4a, 0x53, 0xfc, 0x59, 0x5c, 0x34, 0xc4, 0xe2, 0x83, 0xc2, 0x6f, 0xc0, + 0x22, 0x3f, 0x72, 0x43, 0x1f, 0x6b, 0x95, 0x97, 0xac, 0x26, 0x99, 0xe0, 0x90, 0x9f, 0xf9, 0x12, + 0x4c, 0xeb, 0x01, 0xf3, 0xe8, 0x49, 0x98, 0xea, 0xd8, 0x4e, 0x33, 0xfa, 0xb0, 0x4a, 0x79, 0x4a, + 0xab, 0x21, 0x0a, 0xeb, 0x74, 0xac, 0x98, 0x1b, 0x16, 0x8b, 0x39, 0x58, 0xab, 0xae, 0x5e, 0x2c, + 0xfc, 0x63, 0xfe, 0x7e, 0x1e, 0x4e, 0xa6, 0x3c, 0xcc, 0x40, 0xaf, 0x1a, 0x30, 0xce, 0xa2, 0xc4, + 0x65, 0xd4, 0xc4, 0x0b, 0x99, 0x3f, 0xfe, 0x58, 0x66, 0xc1, 0xe8, 0x62, 0x1e, 0xab, 0xed, 0x93, + 0x03, 0xb1, 0x10, 0x8e, 0x7e, 0xc3, 0x80, 0x29, 0x4b, 0x5b, 0x6a, 0x3c, 0x90, 0x64, 0x3b, 0xfb, + 0xca, 0x24, 0x56, 0x96, 0x16, 0x00, 0x17, 0x2e, 0x24, 0xbd, 0x2e, 0x4b, 0xef, 0x81, 0x29, 0xad, + 0x09, 0xc3, 0xac, 0x90, 0xa5, 0x67, 0x60, 0x6e, 0xa4, 0x15, 0xf6, 0x01, 0x18, 0x36, 0x71, 0x18, + 0x55, 0x58, 0xb7, 0xf4, 0x97, 0xa7, 0xaa, 0xc7, 0xc5, 0xd3, 0x53, 0x81, 0x35, 0xb7, 0x61, 0x2e, + 0x7e, 0xc8, 0xc9, 0xfc, 0xde, 0xf4, 0x5d, 0x30, 0x64, 0xaa, 0x2f, 0xf3, 0x2f, 0x72, 0x30, 0x21, + 0x5e, 0x77, 0xdd, 0x83, 0xd8, 0xd1, 0x9b, 0x91, 0xab, 0x92, 0xb5, 0x4c, 0x1e, 0xa5, 0xf5, 0x0d, + 0x1c, 0xf5, 0x63, 0x81, 0xa3, 0xcf, 0x65, 0x23, 0xee, 0xf0, 0xa8, 0xd1, 0xaf, 0x8c, 0xc1, 0x6c, + 0xec, 0xb5, 0x1c, 0x35, 0x55, 0x12, 0xc1, 0x52, 0x57, 0x33, 0x7d, 0x90, 0xa7, 0xe2, 0x9a, 0x0f, + 0x8f, 0x9b, 0xf2, 0x23, 0x19, 0x15, 0xaf, 0x64, 0x96, 0x8c, 0xf9, 0x67, 0xc9, 0x15, 0x87, 0x8d, + 0x03, 0xfa, 0x27, 0x03, 0xee, 0xef, 0xfb, 0xa8, 0x92, 0x25, 0xc4, 0xf0, 0xa2, 0x58, 0xb1, 0x20, + 0x33, 0x7e, 0xb7, 0xad, 0xee, 0x2d, 0xe2, 0x39, 0x0c, 0xe2, 0xe2, 0xd1, 0x13, 0x30, 0xcd, 0x54, + 0x2b, 0xdd, 0x53, 0x02, 0xd2, 0x11, 0x8e, 0x5a, 0xe6, 0xb2, 0xab, 0x69, 0x70, 0x1c, 0xa1, 0x32, + 0xbf, 0x6c, 0xc0, 0x62, 0xbf, 0xf4, 0x08, 0x03, 0x1c, 0x0c, 0x7f, 0x2e, 0x16, 0xdc, 0x5a, 0x4a, + 0x04, 0xb7, 0xc6, 0x8e, 0x86, 0x32, 0x8e, 0x55, 0x3b, 0x95, 0xe5, 0xef, 0x12, 0xbb, 0xf9, 0x59, + 0x03, 0x4e, 0xf7, 0x59, 0x4d, 0x89, 0x20, 0x67, 0xe3, 0xc8, 0x41, 0xce, 0xb9, 0x41, 0x83, 0x9c, + 0xcd, 0xbf, 0xca, 0xc3, 0x9c, 0xa8, 0x4f, 0x68, 0x5f, 0x3d, 0x15, 0x09, 0x11, 0x7e, 0x5b, 0x2c, + 0x44, 0x78, 0x21, 0x4e, 0xff, 0xb3, 0xf8, 0xe0, 0x37, 0x57, 0x7c, 0xf0, 0x4f, 0x72, 0x70, 0x2a, + 0x35, 0x6b, 0x03, 0xfa, 0x54, 0x8a, 0x6a, 0xb8, 0x9e, 0x71, 0x7a, 0x88, 0x01, 0x95, 0xc3, 0xa8, + 0x41, 0xb5, 0x5f, 0xd0, 0x83, 0x59, 0xf9, 0x56, 0xbf, 0x73, 0x0c, 0x89, 0x2e, 0x86, 0x8c, 0x6b, + 0x35, 0x7f, 0x25, 0x0f, 0x8f, 0x0e, 0xca, 0xe8, 0x4d, 0xfa, 0xee, 0xc1, 0x8f, 0xbc, 0x7b, 0xb8, + 0x47, 0x6a, 0xfb, 0x58, 0x9e, 0x40, 0x7c, 0x35, 0xaf, 0xd4, 0x5e, 0x72, 0x7e, 0x0e, 0x74, 0xab, + 0x37, 0x41, 0x4d, 0x3b, 0x99, 0xcb, 0x31, 0xdc, 0x0a, 0x27, 0x6a, 0x1c, 0x7c, 0xa7, 0x57, 0x9a, + 0x17, 0xf9, 0xdd, 0x6a, 0x24, 0x10, 0x40, 0x2c, 0x0b, 0xa1, 0x47, 0xa1, 0xe8, 0x71, 0xac, 0x8c, + 0xf4, 0x16, 0x57, 0xa3, 0x1c, 0x86, 0x15, 0x16, 0x7d, 0x42, 0xb3, 0x85, 0xc7, 0x8e, 0xeb, 0x95, + 0xfe, 0x61, 0x37, 0xbe, 0x2f, 0x40, 0xd1, 0x97, 0x59, 0x19, 0xb9, 0x5b, 0xfe, 0xf1, 0x01, 0x1f, + 0x10, 0xd0, 0xa3, 0x93, 0x4c, 0xd1, 0xc8, 0xdb, 0xa7, 0x12, 0x38, 0x2a, 0x96, 0xc8, 0x54, 0xa7, + 0x16, 0xee, 0x63, 0x84, 0x94, 0x13, 0xcb, 0xf7, 0x0c, 0x98, 0x12, 0xa3, 0x75, 0x0f, 0xde, 0x34, + 0xdc, 0x88, 0xbe, 0x69, 0x38, 0x9f, 0xc9, 0xde, 0xd1, 0xe7, 0x41, 0xc3, 0x0d, 0x98, 0xd6, 0x13, + 0xf7, 0xa0, 0xe7, 0xb5, 0xbd, 0xcf, 0x18, 0x25, 0x1b, 0x87, 0xdc, 0x1d, 0xc3, 0x7d, 0xd1, 0xfc, + 0x52, 0x51, 0xf5, 0x22, 0xf3, 0x43, 0xe8, 0x73, 0xd0, 0x38, 0x74, 0x0e, 0xea, 0x53, 0x20, 0x97, + 0xfd, 0x14, 0xb8, 0x02, 0x45, 0xb9, 0x41, 0x09, 0x35, 0xfe, 0xb0, 0x1e, 0xbb, 0x46, 0x6d, 0x01, + 0xca, 0x4c, 0x9b, 0xb8, 0xec, 0xa8, 0xa5, 0xc6, 0x50, 0x6d, 0x9c, 0x8a, 0x0d, 0x7a, 0x11, 0xa6, + 0x6e, 0xb9, 0xde, 0xcd, 0x96, 0x6b, 0xb1, 0x7c, 0xab, 0x90, 0xc5, 0x05, 0x8b, 0x72, 0x78, 0xf1, + 0x80, 0xef, 0xeb, 0x21, 0x7f, 0xac, 0x0b, 0x43, 0x65, 0x98, 0x6d, 0xdb, 0x0e, 0x26, 0x56, 0x43, + 0x3d, 0x5d, 0x18, 0xe3, 0x09, 0x21, 0xa5, 0x91, 0xbb, 0x11, 0x45, 0xe3, 0x38, 0x3d, 0xfa, 0x18, + 0x14, 0x7d, 0x91, 0x89, 0x27, 0x9b, 0xab, 0x30, 0x75, 0x66, 0xe4, 0x4c, 0xc3, 0xbe, 0x93, 0x10, + 0xac, 0x04, 0xa2, 0x75, 0x58, 0xf0, 0x44, 0xae, 0x8b, 0xc8, 0xd7, 0x1a, 0xf8, 0xfa, 0x64, 0x79, + 0x07, 0x71, 0x0a, 0x1e, 0xa7, 0x96, 0xa2, 0x56, 0x0c, 0xcb, 0x40, 0xc5, 0xef, 0x04, 0x34, 0x37, + 0x3a, 0x9b, 0xf0, 0x0d, 0x2c, 0xb0, 0x87, 0x3d, 0x85, 0x29, 0x8e, 0xf0, 0x14, 0xa6, 0x06, 0xa7, + 0xe2, 0x28, 0x96, 0x91, 0x83, 0x25, 0x01, 0xd1, 0xb4, 0x47, 0x35, 0x8d, 0x08, 0xa7, 0x97, 0x45, + 0xd7, 0x61, 0xd2, 0x23, 0xec, 0x7c, 0x51, 0x96, 0x97, 0xef, 0x43, 0x87, 0x19, 0x61, 0xc9, 0x00, + 0x87, 0xbc, 0xe8, 0xb8, 0x5b, 0xd1, 0x9c, 0x88, 0x57, 0x32, 0xfc, 0xde, 0x94, 0x18, 0xfb, 0x3e, + 0x99, 0x72, 0xcc, 0x37, 0x66, 0xe0, 0x44, 0xc4, 0xb7, 0x80, 0x1e, 0x86, 0x02, 0x4b, 0x51, 0xc2, + 0xb6, 0x87, 0x62, 0xb8, 0x85, 0xf1, 0xce, 0xe1, 0x38, 0xf4, 0x39, 0x03, 0x66, 0x3b, 0x11, 0x2f, + 0xac, 0xdc, 0x39, 0x47, 0xbc, 0xe7, 0x8b, 0xba, 0x76, 0xb5, 0x6c, 0xc2, 0x51, 0x61, 0x38, 0x2e, + 0x9d, 0x2e, 0x40, 0x11, 0x79, 0xd7, 0x22, 0x1e, 0xa3, 0x16, 0x36, 0x8e, 0x62, 0xb1, 0x12, 0x45, + 0xe3, 0x38, 0x3d, 0x1d, 0x61, 0xd6, 0xba, 0x51, 0x3e, 0x44, 0x53, 0x96, 0x0c, 0x70, 0xc8, 0x0b, + 0x3d, 0x03, 0x33, 0x22, 0x15, 0x5e, 0xd5, 0x6d, 0x5c, 0xb4, 0xfc, 0x5d, 0x61, 0xdc, 0xab, 0xc3, + 0xc8, 0x4a, 0x04, 0x8b, 0x63, 0xd4, 0xac, 0x6d, 0x61, 0xbe, 0x41, 0xc6, 0x60, 0x3c, 0x9a, 0x6c, + 0x79, 0x25, 0x8a, 0xc6, 0x71, 0x7a, 0xf4, 0x0e, 0x6d, 0xdf, 0xe7, 0xf7, 0x74, 0x6a, 0x37, 0x48, + 0xd9, 0xfb, 0xcb, 0x30, 0xdb, 0x65, 0x67, 0xa1, 0x86, 0x44, 0x8a, 0xf5, 0xa8, 0x04, 0x5e, 0x8d, + 0xa2, 0x71, 0x9c, 0x1e, 0x3d, 0x0d, 0x27, 0x3c, 0xba, 0xbb, 0x29, 0x06, 0xfc, 0xf2, 0x4e, 0xdd, + 0xcd, 0x60, 0x1d, 0x89, 0xa3, 0xb4, 0xe8, 0x59, 0x98, 0x0f, 0x93, 0x57, 0x49, 0x06, 0xfc, 0x36, + 0x4f, 0xe5, 0x65, 0x29, 0xc7, 0x09, 0x70, 0xb2, 0x0c, 0xfa, 0x05, 0x98, 0xd3, 0x7a, 0x62, 0xcd, + 0x69, 0x90, 0xdb, 0x22, 0xc1, 0x10, 0x4b, 0x93, 0xb6, 0x12, 0xc3, 0xe1, 0x04, 0x35, 0x7a, 0x2f, + 0xcc, 0xd4, 0xdd, 0x56, 0x8b, 0xed, 0x71, 0x3c, 0xd1, 0x2f, 0xcf, 0x24, 0xc4, 0x73, 0x2e, 0x45, + 0x30, 0x38, 0x46, 0x89, 0x2e, 0x01, 0x72, 0xb7, 0x7d, 0xe2, 0xed, 0x91, 0xc6, 0xb3, 0xfc, 0xd3, + 0x96, 0x54, 0xc5, 0x9f, 0x88, 0xc6, 0xfd, 0x5e, 0x4e, 0x50, 0xe0, 0x94, 0x52, 0x2c, 0xad, 0x8b, + 0xf6, 0xa2, 0x68, 0x26, 0x8b, 0x8f, 0xb2, 0xc4, 0x4f, 0xee, 0x77, 0x7d, 0x4e, 0xe4, 0xc1, 0x38, + 0x0f, 0xc3, 0xce, 0x26, 0xa5, 0x90, 0x9e, 0xf3, 0x33, 0xd4, 0x11, 0x1c, 0x8a, 0x85, 0x24, 0xf4, + 0x71, 0x98, 0xdc, 0x96, 0x09, 0xa0, 0x17, 0xe7, 0xb2, 0xd0, 0x8b, 0xb1, 0x5c, 0xe6, 0xe1, 0xc9, + 0x54, 0x21, 0x70, 0x28, 0x12, 0x3d, 0x02, 0x53, 0x17, 0xab, 0x65, 0x35, 0x0b, 0xe7, 0xd9, 0xe8, + 0x8f, 0xd1, 0x22, 0x58, 0x47, 0xd0, 0x15, 0xa6, 0xec, 0x25, 0xc4, 0x86, 0x38, 0xd4, 0xb7, 0x49, + 0xf3, 0x87, 0x52, 0xb3, 0xeb, 0x48, 0x5c, 0x5b, 0x3c, 0x19, 0xa3, 0x16, 0x70, 0xac, 0x28, 0xd0, + 0x0b, 0x30, 0x25, 0xf4, 0x05, 0xdb, 0x9b, 0x16, 0x8e, 0xf6, 0x5a, 0x0d, 0x87, 0x2c, 0xb0, 0xce, + 0x8f, 0xdd, 0x32, 0xb1, 0xbc, 0xb8, 0xe4, 0x42, 0xb7, 0xd5, 0x5a, 0x3c, 0xc5, 0xf6, 0xcd, 0xf0, + 0x96, 0x29, 0x44, 0x61, 0x9d, 0x0e, 0x3d, 0x2e, 0x23, 0x27, 0xde, 0x12, 0xb9, 0x76, 0x53, 0x91, + 0x13, 0xca, 0xca, 0xed, 0x13, 0xd8, 0x7b, 0xfa, 0x2e, 0x21, 0x0b, 0xdb, 0xb0, 0x24, 0x4d, 0xac, + 0xe4, 0x22, 0x59, 0x5c, 0x8c, 0x78, 0x09, 0x96, 0xae, 0xf7, 0xa5, 0xc4, 0x87, 0x70, 0x41, 0xdb, + 0x90, 0xb7, 0x5a, 0xdb, 0x8b, 0xf7, 0x67, 0x61, 0x2b, 0xaa, 0x4f, 0xd5, 0xf2, 0x60, 0x9c, 0xf2, + 0x7a, 0x05, 0x53, 0xe6, 0xe6, 0x2b, 0x39, 0xe5, 0x95, 0x57, 0xa9, 0x16, 0x5f, 0xd2, 0x67, 0xb5, + 0x91, 0xc5, 0xa7, 0x18, 0x13, 0x59, 0xd2, 0xb9, 0x42, 0x4a, 0x9d, 0xd3, 0x1d, 0xb5, 0x8e, 0x33, + 0xc9, 0xa3, 0x11, 0x4d, 0x23, 0xc9, 0x4f, 0x73, 0xd1, 0x55, 0x6c, 0x7e, 0x7f, 0x5c, 0x39, 0xa1, + 0x62, 0xa1, 0x00, 0x1e, 0x14, 0x6c, 0x3f, 0xb0, 0xdd, 0x0c, 0x9f, 0x6d, 0xc5, 0xf2, 0x2f, 0xb2, + 0x00, 0x56, 0x86, 0xc0, 0x5c, 0x14, 0x95, 0xe9, 0x34, 0x6d, 0xe7, 0xb6, 0x68, 0xfe, 0x95, 0xcc, + 0xef, 0xf8, 0xb9, 0x4c, 0x86, 0xc0, 0x5c, 0x14, 0xba, 0xc1, 0x67, 0x5a, 0x36, 0x9f, 0xdd, 0x8c, + 0x7f, 0x4d, 0x37, 0x3a, 0xe3, 0xa8, 0x2c, 0xbf, 0x6d, 0x0b, 0x1b, 0x66, 0x44, 0x59, 0xb5, 0x8d, + 0xb5, 0x34, 0x59, 0xb5, 0x8d, 0x35, 0x4c, 0x85, 0xa0, 0xd7, 0x0c, 0x00, 0x4b, 0x7d, 0x56, 0x36, + 0x9b, 0x4f, 0x0a, 0xf4, 0xfb, 0x4c, 0x2d, 0x8f, 0x39, 0x0b, 0xb1, 0x58, 0x93, 0x8c, 0x5e, 0x84, + 0x09, 0x8b, 0x7f, 0x10, 0x45, 0x84, 0xf3, 0x65, 0xf3, 0x95, 0x9f, 0x58, 0x0d, 0x58, 0x1c, 0xa3, + 0x40, 0x61, 0x29, 0x90, 0xca, 0x0e, 0x3c, 0x8b, 0xec, 0xd8, 0x37, 0x45, 0x5c, 0x5f, 0x6d, 0xe4, + 0xbc, 0xc6, 0x94, 0x59, 0x9a, 0x6c, 0x81, 0xc2, 0x52, 0xa0, 0xf9, 0xaf, 0x06, 0x68, 0xdf, 0x20, + 0x0c, 0x03, 0xbd, 0x8c, 0x81, 0x03, 0xbd, 0x72, 0x43, 0x06, 0x7a, 0xe5, 0x87, 0x0a, 0xf4, 0x1a, + 0x1b, 0x3e, 0xd0, 0xab, 0xd0, 0x3f, 0xd0, 0xcb, 0x7c, 0xdd, 0x80, 0xf9, 0xc4, 0x9c, 0x8c, 0x7f, + 0xeb, 0xd9, 0x18, 0xf0, 0x5b, 0xcf, 0xab, 0x30, 0x27, 0x12, 0xb1, 0xd6, 0x3a, 0x2d, 0x3b, 0xf5, + 0x85, 0xeb, 0x56, 0x0c, 0x8f, 0x13, 0x25, 0xcc, 0x3f, 0x36, 0x60, 0x4a, 0x7b, 0x90, 0x43, 0xdb, + 0xc1, 0x1e, 0x2e, 0x89, 0x6a, 0x84, 0x39, 0x68, 0x99, 0x7b, 0x95, 0xe3, 0xb8, 0xa7, 0xbf, 0xa9, + 0x25, 0xfd, 0x0b, 0x3d, 0xfd, 0x14, 0x8a, 0x05, 0x96, 0xa7, 0x73, 0x23, 0xfc, 0x3b, 0xde, 0x79, + 0x3d, 0x9d, 0x1b, 0xe9, 0x60, 0x86, 0x61, 0xe2, 0xa8, 0x2e, 0x17, 0x31, 0x80, 0x5a, 0xca, 0x5b, + 0x8b, 0x9e, 0xd8, 0x18, 0x0e, 0x9d, 0x81, 0x3c, 0x71, 0x1a, 0xe2, 0xe0, 0xa1, 0xbe, 0xf1, 0x72, + 0xde, 0x69, 0x60, 0x0a, 0x37, 0x2f, 0xc3, 0x74, 0x8d, 0xd4, 0x3d, 0x12, 0x3c, 0x47, 0xf6, 0x07, + 0xfe, 0x68, 0xcc, 0x4d, 0xb2, 0x1f, 0xff, 0x68, 0x0c, 0x2d, 0x4e, 0xe1, 0xe6, 0xef, 0x19, 0x10, + 0x4b, 0x8a, 0xac, 0x79, 0xfd, 0x8c, 0x7e, 0x5e, 0xbf, 0x88, 0x7f, 0x2a, 0x77, 0xa8, 0x7f, 0xea, + 0x12, 0xa0, 0xb6, 0x15, 0xd4, 0x77, 0x23, 0x29, 0xc0, 0xc5, 0x99, 0x2f, 0x7c, 0xfe, 0x97, 0xa0, + 0xc0, 0x29, 0xa5, 0xcc, 0x4f, 0x1b, 0x90, 0x48, 0x99, 0x8c, 0xba, 0x50, 0x60, 0xa4, 0xe2, 0x62, + 0xa4, 0x3a, 0xda, 0x8a, 0x4e, 0x3e, 0x28, 0x0f, 0x07, 0x8a, 0xfd, 0xc5, 0x5c, 0x9a, 0xf9, 0x32, + 0xad, 0x4b, 0xfc, 0x03, 0xe0, 0x6f, 0x87, 0x09, 0x22, 0xbe, 0x0d, 0xc2, 0x8f, 0xe5, 0xca, 0x6a, + 0x92, 0x9f, 0x04, 0x91, 0x78, 0x7a, 0x76, 0x93, 0xde, 0x3f, 0xe9, 0x4b, 0xe1, 0x8f, 0xb6, 0xd4, + 0xd9, 0x6d, 0x35, 0x8a, 0xc6, 0x71, 0x7a, 0xf3, 0x13, 0x30, 0xa5, 0xbd, 0x31, 0x67, 0xcb, 0xf2, + 0xb6, 0x55, 0x0f, 0xe2, 0xd3, 0xf9, 0x3c, 0x05, 0x62, 0x8e, 0x63, 0x2e, 0x1f, 0x1e, 0xc7, 0x17, + 0x9b, 0xce, 0x22, 0x7a, 0x4f, 0x60, 0x29, 0x33, 0x8f, 0x34, 0xc9, 0x6d, 0x99, 0x6a, 0x4f, 0x32, + 0xc3, 0x14, 0x88, 0x39, 0xce, 0xbc, 0x06, 0x45, 0xf9, 0xb4, 0x96, 0xbd, 0x4f, 0x93, 0xee, 0x08, + 0xfd, 0x7d, 0x9a, 0xeb, 0x05, 0x98, 0x61, 0xe8, 0x9c, 0xf1, 0x1d, 0xfb, 0xa2, 0xeb, 0x07, 0xf2, + 0x3d, 0x30, 0x77, 0x3a, 0x6e, 0xae, 0x31, 0x18, 0x56, 0x58, 0x73, 0x1e, 0x66, 0x95, 0x37, 0x51, + 0x84, 0x4a, 0x7d, 0x3b, 0x0f, 0xd3, 0x91, 0x2f, 0x4d, 0xde, 0x7d, 0xe6, 0x0f, 0x3e, 0x47, 0x53, + 0xbc, 0x82, 0xf9, 0x21, 0xbd, 0x82, 0xba, 0x1b, 0x76, 0xec, 0x78, 0xdd, 0xb0, 0x85, 0x6c, 0xdc, + 0xb0, 0x01, 0x4c, 0x88, 0xaf, 0xf0, 0x0b, 0x3d, 0xbc, 0x91, 0x51, 0x96, 0x0f, 0xf1, 0xc0, 0x9c, + 0x69, 0x41, 0xb9, 0x9b, 0x4b, 0x51, 0xe6, 0x37, 0x0a, 0x30, 0x13, 0xcd, 0xfb, 0x31, 0xc0, 0x48, + 0xbe, 0x23, 0x31, 0x92, 0x43, 0x7a, 0x45, 0xf2, 0xa3, 0x7a, 0x45, 0xc6, 0x46, 0xf5, 0x8a, 0x14, + 0x8e, 0xe0, 0x15, 0x49, 0xfa, 0x34, 0xc6, 0x07, 0xf6, 0x69, 0xbc, 0x4f, 0x5d, 0xe9, 0x4f, 0x44, + 0xee, 0xc0, 0xc2, 0x2b, 0x7d, 0x14, 0x1d, 0x86, 0x15, 0xb7, 0x91, 0x1a, 0x1a, 0x51, 0xbc, 0xcb, + 0xe9, 0xcf, 0x4b, 0xbd, 0x81, 0x1f, 0xde, 0xf1, 0xfa, 0x96, 0x21, 0x6e, 0xdf, 0x9f, 0x84, 0x29, + 0x31, 0x9f, 0x98, 0x25, 0x00, 0x51, 0x2b, 0xa2, 0x16, 0xa2, 0xb0, 0x4e, 0xc7, 0x3e, 0x86, 0x16, + 0xfd, 0xfa, 0x1b, 0x73, 0x32, 0xe9, 0x1f, 0x43, 0x8b, 0x7d, 0x2d, 0x2e, 0x4e, 0x6f, 0x7e, 0x0c, + 0x4e, 0xa5, 0xda, 0x7c, 0xec, 0x10, 0xcc, 0x94, 0x14, 0x69, 0x08, 0x02, 0xad, 0x1a, 0xb1, 0xb4, + 0x90, 0x4b, 0xd7, 0xfb, 0x52, 0xe2, 0x43, 0xb8, 0x98, 0x5f, 0xcf, 0xc3, 0x4c, 0xf4, 0x4b, 0x1a, + 0xe8, 0x96, 0x3a, 0x21, 0x66, 0x72, 0x38, 0xe5, 0x6c, 0xb5, 0x44, 0x15, 0x7d, 0xdd, 0x3d, 0xb7, + 0xd8, 0xfc, 0xda, 0x56, 0x59, 0x33, 0x8e, 0x4f, 0xb0, 0xf0, 0xb3, 0x08, 0x71, 0xec, 0x63, 0x19, + 0x61, 0x40, 0xb5, 0x88, 0x21, 0xc8, 0x5c, 0x7a, 0x18, 0x22, 0xad, 0x44, 0x61, 0x4d, 0x2c, 0xd5, + 0x2d, 0x7b, 0xc4, 0xb3, 0x77, 0x6c, 0xf5, 0x15, 0x30, 0xb6, 0x73, 0x5f, 0x13, 0x30, 0xac, 0xb0, + 0xe6, 0xcb, 0x39, 0x08, 0xbf, 0x79, 0xc8, 0x32, 0xde, 0xfb, 0x9a, 0x01, 0x27, 0x86, 0xed, 0xd2, + 0xa8, 0x1f, 0x97, 0x08, 0x39, 0x8a, 0x70, 0x2b, 0x0d, 0x82, 0x23, 0x12, 0x7f, 0x0a, 0xdf, 0x3a, + 0xb4, 0x60, 0x36, 0xf6, 0xdc, 0x2b, 0xf3, 0x98, 0xd6, 0x2f, 0xe5, 0x61, 0x52, 0x3d, 0x98, 0x43, + 0xef, 0x61, 0x69, 0xa3, 0x77, 0x5d, 0x99, 0xcc, 0xfb, 0xad, 0x5a, 0x72, 0xe7, 0x5d, 0xb7, 0x71, + 0xa7, 0x57, 0x9a, 0x55, 0xc4, 0x1c, 0x84, 0x45, 0x01, 0x6a, 0x2e, 0x77, 0xbd, 0x56, 0xdc, 0x5c, + 0xbe, 0x8a, 0xd7, 0x31, 0x85, 0xa3, 0xdb, 0x30, 0xc1, 0x93, 0xf6, 0xc8, 0xe8, 0x95, 0x8d, 0x8c, + 0x1e, 0xf9, 0x71, 0xbb, 0x33, 0xec, 0x06, 0xfe, 0xdf, 0xc7, 0x52, 0x1c, 0xd5, 0x92, 0xdb, 0x6e, + 0x63, 0x3f, 0x9e, 0x0c, 0xba, 0xe2, 0x36, 0xf6, 0x31, 0xc3, 0xa0, 0x67, 0x60, 0x26, 0xb0, 0xdb, + 0xc4, 0xed, 0x06, 0xfa, 0x17, 0xe5, 0xf2, 0xe1, 0xf5, 0xc5, 0x56, 0x04, 0x8b, 0x63, 0xd4, 0x54, + 0xcb, 0xde, 0xf0, 0x5d, 0x87, 0x65, 0x78, 0x1a, 0x8f, 0xfa, 0x3a, 0x2f, 0xd5, 0x2e, 0x6f, 0xb2, + 0x04, 0x4f, 0x8a, 0x82, 0x52, 0xdb, 0xec, 0x55, 0x8e, 0x47, 0xc4, 0xed, 0xe1, 0x5c, 0xf8, 0x76, + 0x9a, 0xc3, 0xb1, 0xa2, 0x30, 0xaf, 0xc2, 0x6c, 0xac, 0xa9, 0xf2, 0x60, 0x62, 0xa4, 0x1f, 0x4c, + 0x06, 0xcb, 0xbc, 0xfc, 0x07, 0x06, 0xcc, 0x27, 0x16, 0xef, 0xa0, 0xc1, 0xd6, 0x71, 0x35, 0x92, + 0x3b, 0xba, 0x1a, 0xc9, 0x0f, 0xa7, 0x46, 0x2a, 0xcb, 0xdf, 0x79, 0xe3, 0xec, 0x7d, 0xdf, 0x7d, + 0xe3, 0xec, 0x7d, 0xdf, 0x7f, 0xe3, 0xec, 0x7d, 0x2f, 0x1f, 0x9c, 0x35, 0xbe, 0x73, 0x70, 0xd6, + 0xf8, 0xee, 0xc1, 0x59, 0xe3, 0xfb, 0x07, 0x67, 0x8d, 0x7f, 0x3c, 0x38, 0x6b, 0xbc, 0xfe, 0xa3, + 0xb3, 0xf7, 0x3d, 0x5f, 0x94, 0xd3, 0xe4, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0x1a, 0x88, 0xc5, + 0xd7, 0x3a, 0x8d, 0x00, 0x00, } func (m *ALBStatus) Marshal() (dAtA []byte, err error) { @@ -4575,6 +4672,18 @@ func (m *CanaryStep) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.SetHeaderRouting != nil { + { + size, err := m.SetHeaderRouting.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } if m.SetCanaryScale != nil { { size, err := m.SetCanaryScale.MarshalToSizedBuffer(dAtA[:i]) @@ -5720,6 +5829,44 @@ func (m *GraphiteMetric) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *HeaderRoutingMatch) 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 *HeaderRoutingMatch) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *HeaderRoutingMatch) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.HeaderValue.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + i -= len(m.HeaderName) + copy(dAtA[i:], m.HeaderName) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.HeaderName))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *IstioDestinationRule) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -8146,6 +8293,43 @@ func (m *SetCanaryScale) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *SetHeaderRouting) 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 *SetHeaderRouting) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SetHeaderRouting) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Match) > 0 { + for iNdEx := len(m.Match) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Match[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func (m *StickinessConfig) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -8180,6 +8364,44 @@ func (m *StickinessConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *StringMatch) 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 *StringMatch) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StringMatch) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.Regex) + copy(dAtA[i:], m.Regex) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Regex))) + i-- + dAtA[i] = 0x1a + i -= len(m.Prefix) + copy(dAtA[i:], m.Prefix) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Prefix))) + i-- + dAtA[i] = 0x12 + i -= len(m.Exact) + copy(dAtA[i:], m.Exact) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Exact))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *TLSRoute) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -9201,6 +9423,10 @@ func (m *CanaryStep) Size() (n int) { l = m.SetCanaryScale.Size() n += 1 + l + sovGenerated(uint64(l)) } + if m.SetHeaderRouting != nil { + l = m.SetHeaderRouting.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -9609,6 +9835,19 @@ func (m *GraphiteMetric) Size() (n int) { return n } +func (m *HeaderRoutingMatch) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.HeaderName) + n += 1 + l + sovGenerated(uint64(l)) + l = m.HeaderValue.Size() + n += 1 + l + sovGenerated(uint64(l)) + return n +} + func (m *IstioDestinationRule) Size() (n int) { if m == nil { return 0 @@ -10480,6 +10719,21 @@ func (m *SetCanaryScale) Size() (n int) { return n } +func (m *SetHeaderRouting) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Match) > 0 { + for _, e := range m.Match { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + func (m *StickinessConfig) Size() (n int) { if m == nil { return 0 @@ -10491,6 +10745,21 @@ func (m *StickinessConfig) Size() (n int) { return n } +func (m *StringMatch) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Exact) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Prefix) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Regex) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + func (m *TLSRoute) Size() (n int) { if m == nil { return 0 @@ -11042,6 +11311,7 @@ func (this *CanaryStep) String() string { `Experiment:` + strings.Replace(this.Experiment.String(), "RolloutExperimentStep", "RolloutExperimentStep", 1) + `,`, `Analysis:` + strings.Replace(this.Analysis.String(), "RolloutAnalysis", "RolloutAnalysis", 1) + `,`, `SetCanaryScale:` + strings.Replace(this.SetCanaryScale.String(), "SetCanaryScale", "SetCanaryScale", 1) + `,`, + `SetHeaderRouting:` + strings.Replace(this.SetHeaderRouting.String(), "SetHeaderRouting", "SetHeaderRouting", 1) + `,`, `}`, }, "") return s @@ -11358,6 +11628,17 @@ func (this *GraphiteMetric) String() string { }, "") return s } +func (this *HeaderRoutingMatch) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&HeaderRoutingMatch{`, + `HeaderName:` + fmt.Sprintf("%v", this.HeaderName) + `,`, + `HeaderValue:` + strings.Replace(strings.Replace(this.HeaderValue.String(), "StringMatch", "StringMatch", 1), `&`, ``, 1) + `,`, + `}`, + }, "") + return s +} func (this *IstioDestinationRule) String() string { if this == nil { return "nil" @@ -12028,6 +12309,21 @@ func (this *SetCanaryScale) String() string { }, "") return s } +func (this *SetHeaderRouting) String() string { + if this == nil { + return "nil" + } + repeatedStringForMatch := "[]HeaderRoutingMatch{" + for _, f := range this.Match { + repeatedStringForMatch += strings.Replace(strings.Replace(f.String(), "HeaderRoutingMatch", "HeaderRoutingMatch", 1), `&`, ``, 1) + "," + } + repeatedStringForMatch += "}" + s := strings.Join([]string{`&SetHeaderRouting{`, + `Match:` + repeatedStringForMatch + `,`, + `}`, + }, "") + return s +} func (this *StickinessConfig) String() string { if this == nil { return "nil" @@ -12039,6 +12335,18 @@ func (this *StickinessConfig) String() string { }, "") return s } +func (this *StringMatch) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&StringMatch{`, + `Exact:` + fmt.Sprintf("%v", this.Exact) + `,`, + `Prefix:` + fmt.Sprintf("%v", this.Prefix) + `,`, + `Regex:` + fmt.Sprintf("%v", this.Regex) + `,`, + `}`, + }, "") + return s +} func (this *TLSRoute) String() string { if this == nil { return "nil" @@ -16029,6 +16337,42 @@ func (m *CanaryStep) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SetHeaderRouting", 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.SetHeaderRouting == nil { + m.SetHeaderRouting = &SetHeaderRouting{} + } + if err := m.SetHeaderRouting.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -19220,19 +19564,133 @@ func (m *FieldRef) Unmarshal(dAtA []byte) error { if b < 0x80 { break } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: FieldRef: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: FieldRef: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: FieldRef: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FieldRef: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FieldPath", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FieldPath = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GraphiteMetric) 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: GraphiteMetric: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GraphiteMetric: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field FieldPath", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -19260,7 +19718,7 @@ func (m *FieldRef) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.FieldPath = string(dAtA[iNdEx:postIndex]) + m.Query = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -19283,7 +19741,7 @@ func (m *FieldRef) Unmarshal(dAtA []byte) error { } return nil } -func (m *GraphiteMetric) Unmarshal(dAtA []byte) error { +func (m *HeaderRoutingMatch) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -19306,15 +19764,15 @@ func (m *GraphiteMetric) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: GraphiteMetric: wiretype end group for non-group") + return fmt.Errorf("proto: HeaderRoutingMatch: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: GraphiteMetric: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: HeaderRoutingMatch: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field HeaderName", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -19342,13 +19800,13 @@ func (m *GraphiteMetric) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Address = string(dAtA[iNdEx:postIndex]) + m.HeaderName = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field HeaderValue", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -19358,23 +19816,24 @@ func (m *GraphiteMetric) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - m.Query = string(dAtA[iNdEx:postIndex]) + if err := m.HeaderValue.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex default: iNdEx = preIndex @@ -27379,6 +27838,90 @@ func (m *SetCanaryScale) Unmarshal(dAtA []byte) error { } return nil } +func (m *SetHeaderRouting) 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: SetHeaderRouting: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SetHeaderRouting: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Match", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Match = append(m.Match, HeaderRoutingMatch{}) + if err := m.Match[len(m.Match)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *StickinessConfig) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -27468,6 +28011,152 @@ func (m *StickinessConfig) Unmarshal(dAtA []byte) error { } return nil } +func (m *StringMatch) 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: StringMatch: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StringMatch: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Exact", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Exact = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Prefix", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Prefix = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Regex", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Regex = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *TLSRoute) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/pkg/apis/rollouts/v1alpha1/generated.proto b/pkg/apis/rollouts/v1alpha1/generated.proto index f8520bf966..d035b8aecc 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.proto +++ b/pkg/apis/rollouts/v1alpha1/generated.proto @@ -402,6 +402,9 @@ message CanaryStep { // SetCanaryScale defines how to scale the newRS without changing traffic weight // +optional optional SetCanaryScale setCanaryScale = 5; + + // SetHeaderRouting defines the route with specified header name to send 100% of traffic to the canary service + optional SetHeaderRouting setHeaderRouting = 6; } // CanaryStrategy defines parameters for a Replica Based Canary @@ -738,6 +741,14 @@ message GraphiteMetric { optional string query = 2; } +message HeaderRoutingMatch { + // HeaderName the name of the request header + optional string headerName = 1; + + // HeaderValue the value of the header + optional StringMatch headerValue = 2; +} + // IstioDestinationRule is a reference to an Istio DestinationRule to modify and shape traffic message IstioDestinationRule { // Name holds the name of the DestinationRule @@ -1467,12 +1478,29 @@ message SetCanaryScale { optional bool matchTrafficWeight = 3; } +// SetHeaderRouting defines the route with specified header name to send 100% of traffic to the canary service +message SetHeaderRouting { + repeated HeaderRoutingMatch match = 1; +} + message StickinessConfig { optional bool enabled = 1; optional int64 durationSeconds = 2; } +// StringMatch Used to define what type of matching we will use exact, prefix, or regular expression +message StringMatch { + // Exact The string must match exactly + optional string exact = 1; + + // Prefix The string will be prefixed matched + optional string prefix = 2; + + // Regex The string will be regular expression matched + optional string regex = 3; +} + // TLSRoute holds the information on the virtual service's TLS/HTTPS routes that are desired to be matched for changing weights. message TLSRoute { // Port number of the TLS Route desired to be matched in the given Istio VirtualService. diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index 747fee6e31..977aae1e8e 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -73,6 +73,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ExperimentStatus": schema_pkg_apis_rollouts_v1alpha1_ExperimentStatus(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.FieldRef": schema_pkg_apis_rollouts_v1alpha1_FieldRef(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.GraphiteMetric": schema_pkg_apis_rollouts_v1alpha1_GraphiteMetric(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.HeaderRoutingMatch": schema_pkg_apis_rollouts_v1alpha1_HeaderRoutingMatch(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.IstioDestinationRule": schema_pkg_apis_rollouts_v1alpha1_IstioDestinationRule(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.IstioTrafficRouting": schema_pkg_apis_rollouts_v1alpha1_IstioTrafficRouting(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.IstioVirtualService": schema_pkg_apis_rollouts_v1alpha1_IstioVirtualService(ref), @@ -114,7 +115,9 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ScopeDetail": schema_pkg_apis_rollouts_v1alpha1_ScopeDetail(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SecretKeyRef": schema_pkg_apis_rollouts_v1alpha1_SecretKeyRef(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetCanaryScale": schema_pkg_apis_rollouts_v1alpha1_SetCanaryScale(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetHeaderRouting": schema_pkg_apis_rollouts_v1alpha1_SetHeaderRouting(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.StickinessConfig": schema_pkg_apis_rollouts_v1alpha1_StickinessConfig(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.StringMatch": schema_pkg_apis_rollouts_v1alpha1_StringMatch(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TLSRoute": schema_pkg_apis_rollouts_v1alpha1_TLSRoute(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TemplateService": schema_pkg_apis_rollouts_v1alpha1_TemplateService(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TemplateSpec": schema_pkg_apis_rollouts_v1alpha1_TemplateSpec(ref), @@ -1230,11 +1233,17 @@ func schema_pkg_apis_rollouts_v1alpha1_CanaryStep(ref common.ReferenceCallback) Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetCanaryScale"), }, }, + "setHeaderRouting": { + SchemaProps: spec.SchemaProps{ + Description: "SetHeaderRouting defines the route with specified header name to send 100% of traffic to the canary service", + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetHeaderRouting"), + }, + }, }, }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutAnalysis", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutExperimentStep", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutPause", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetCanaryScale"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutAnalysis", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutExperimentStep", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutPause", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetCanaryScale", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetHeaderRouting"}, } } @@ -2198,6 +2207,36 @@ func schema_pkg_apis_rollouts_v1alpha1_GraphiteMetric(ref common.ReferenceCallba } } +func schema_pkg_apis_rollouts_v1alpha1_HeaderRoutingMatch(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "headerName": { + SchemaProps: spec.SchemaProps{ + Description: "HeaderName the name of the request header", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "headerValue": { + SchemaProps: spec.SchemaProps{ + Description: "HeaderValue the value of the header", + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.StringMatch"), + }, + }, + }, + Required: []string{"headerName", "headerValue"}, + }, + }, + Dependencies: []string{ + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.StringMatch"}, + } +} + func schema_pkg_apis_rollouts_v1alpha1_IstioDestinationRule(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -4314,6 +4353,34 @@ func schema_pkg_apis_rollouts_v1alpha1_SetCanaryScale(ref common.ReferenceCallba } } +func schema_pkg_apis_rollouts_v1alpha1_SetHeaderRouting(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "SetHeaderRouting defines the route with specified header name to send 100% of traffic to the canary service", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "match": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.HeaderRoutingMatch"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.HeaderRoutingMatch"}, + } +} + func schema_pkg_apis_rollouts_v1alpha1_StickinessConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -4341,6 +4408,40 @@ func schema_pkg_apis_rollouts_v1alpha1_StickinessConfig(ref common.ReferenceCall } } +func schema_pkg_apis_rollouts_v1alpha1_StringMatch(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "StringMatch Used to define what type of matching we will use exact, prefix, or regular expression", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "exact": { + SchemaProps: spec.SchemaProps{ + Description: "Exact The string must match exactly", + Type: []string{"string"}, + Format: "", + }, + }, + "prefix": { + SchemaProps: spec.SchemaProps{ + Description: "Prefix The string will be prefixed matched", + Type: []string{"string"}, + Format: "", + }, + }, + "regex": { + SchemaProps: spec.SchemaProps{ + Description: "Regex The string will be regular expression matched", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + func schema_pkg_apis_rollouts_v1alpha1_TLSRoute(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/pkg/apis/rollouts/v1alpha1/types.go b/pkg/apis/rollouts/v1alpha1/types.go index 3e3ad07532..04d45fddcd 100644 --- a/pkg/apis/rollouts/v1alpha1/types.go +++ b/pkg/apis/rollouts/v1alpha1/types.go @@ -554,6 +554,30 @@ type CanaryStep struct { // SetCanaryScale defines how to scale the newRS without changing traffic weight // +optional SetCanaryScale *SetCanaryScale `json:"setCanaryScale,omitempty" protobuf:"bytes,5,opt,name=setCanaryScale"` + // SetHeaderRouting defines the route with specified header name to send 100% of traffic to the canary service + SetHeaderRouting *SetHeaderRouting `json:"setHeaderRouting,omitempty" protobuf:"bytes,6,opt,name=setHeaderRouting"` +} + +// SetHeaderRouting defines the route with specified header name to send 100% of traffic to the canary service +type SetHeaderRouting struct { + Match []HeaderRoutingMatch `json:"match,omitempty" protobuf:"bytes,1,rep,name=match"` +} + +type HeaderRoutingMatch struct { + // HeaderName the name of the request header + HeaderName string `json:"headerName" protobuf:"bytes,1,opt,name=headerName"` + // HeaderValue the value of the header + HeaderValue StringMatch `json:"headerValue" protobuf:"bytes,2,opt,name=headerValue"` +} + +// StringMatch Used to define what type of matching we will use exact, prefix, or regular expression +type StringMatch struct { + // Exact The string must match exactly + Exact string `json:"exact,omitempty" protobuf:"bytes,1,opt,name=exact"` + // Prefix The string will be prefixed matched + Prefix string `json:"prefix,omitempty" protobuf:"bytes,2,opt,name=prefix"` + // Regex The string will be regular expression matched + Regex string `json:"regex,omitempty" protobuf:"bytes,3,opt,name=regex"` } // SetCanaryScale defines how to scale the newRS without changing traffic weight diff --git a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go index 23c49d6c09..e45cf0dba6 100644 --- a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go @@ -708,6 +708,11 @@ func (in *CanaryStep) DeepCopyInto(out *CanaryStep) { *out = new(SetCanaryScale) (*in).DeepCopyInto(*out) } + if in.SetHeaderRouting != nil { + in, out := &in.SetHeaderRouting, &out.SetHeaderRouting + *out = new(SetHeaderRouting) + (*in).DeepCopyInto(*out) + } return } @@ -1254,6 +1259,23 @@ func (in *GraphiteMetric) DeepCopy() *GraphiteMetric { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HeaderRoutingMatch) DeepCopyInto(out *HeaderRoutingMatch) { + *out = *in + out.HeaderValue = in.HeaderValue + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HeaderRoutingMatch. +func (in *HeaderRoutingMatch) DeepCopy() *HeaderRoutingMatch { + if in == nil { + return nil + } + out := new(HeaderRoutingMatch) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *IstioDestinationRule) DeepCopyInto(out *IstioDestinationRule) { *out = *in @@ -2301,6 +2323,27 @@ func (in *SetCanaryScale) DeepCopy() *SetCanaryScale { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SetHeaderRouting) DeepCopyInto(out *SetHeaderRouting) { + *out = *in + if in.Match != nil { + in, out := &in.Match, &out.Match + *out = make([]HeaderRoutingMatch, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SetHeaderRouting. +func (in *SetHeaderRouting) DeepCopy() *SetHeaderRouting { + if in == nil { + return nil + } + out := new(SetHeaderRouting) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *StickinessConfig) DeepCopyInto(out *StickinessConfig) { *out = *in @@ -2317,6 +2360,22 @@ func (in *StickinessConfig) DeepCopy() *StickinessConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StringMatch) DeepCopyInto(out *StringMatch) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StringMatch. +func (in *StringMatch) DeepCopy() *StringMatch { + if in == nil { + return nil + } + out := new(StringMatch) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TLSRoute) DeepCopyInto(out *TLSRoute) { *out = *in diff --git a/pkg/apis/rollouts/validation/validation.go b/pkg/apis/rollouts/validation/validation.go index b5e5506ed2..d71af46ed4 100644 --- a/pkg/apis/rollouts/validation/validation.go +++ b/pkg/apis/rollouts/validation/validation.go @@ -33,6 +33,12 @@ const ( InvalidCanaryExperimentTemplateWeightWithoutTrafficRouting = "Experiment template weight cannot be set unless TrafficRouting is enabled" // InvalidSetCanaryScaleTrafficPolicy indicates that TrafficRouting, required for SetCanaryScale, is missing InvalidSetCanaryScaleTrafficPolicy = "SetCanaryScale requires TrafficRouting to be set" + // InvalidSetHeaderRoutingTrafficPolicy indicates that TrafficRouting, required for SetCanaryScale, is missing + InvalidSetHeaderRoutingTrafficPolicy = "SetHeaderRouting requires TrafficRouting, supports Istio only" + // InvalidSetHeaderRoutingMultipleValuePolicy indicates that SetCanaryScale, has multiple values set + InvalidSetHeaderRoutingMultipleValuePolicy = "SetHeaderRouting match value must have one of the following: exact, regex, prefix" + // InvalidSetHeaderRoutingMissedValuePolicy indicates that SetCanaryScale, has multiple values set + InvalidSetHeaderRoutingMissedValuePolicy = "SetHeaderRouting value missed, match value must have one of the following: exact, regex, prefix" // InvalidDurationMessage indicates the Duration value needs to be greater than 0 InvalidDurationMessage = "Duration needs to be greater than 0" // InvalidMaxSurgeMaxUnavailable indicates both maxSurge and MaxUnavailable can not be set to zero @@ -274,9 +280,9 @@ func ValidateRolloutStrategyCanary(rollout *v1alpha1.Rollout, fldPath *field.Pat for i, step := range canary.Steps { stepFldPath := fldPath.Child("steps").Index(i) allErrs = append(allErrs, hasMultipleStepsType(step, stepFldPath)...) - if step.Experiment == nil && step.Pause == nil && step.SetWeight == nil && step.Analysis == nil && step.SetCanaryScale == nil { - errVal := fmt.Sprintf("step.Experiment: %t step.Pause: %t step.SetWeight: %t step.Analysis: %t step.SetCanaryScale %t", - step.Experiment == nil, step.Pause == nil, step.SetWeight == nil, step.Analysis == nil, step.SetCanaryScale == nil) + if step.Experiment == nil && step.Pause == nil && step.SetWeight == nil && step.Analysis == nil && step.SetCanaryScale == nil && step.SetHeaderRouting == nil { + errVal := fmt.Sprintf("step.Experiment: %t step.Pause: %t step.SetWeight: %t step.Analysis: %t step.SetCanaryScale: %t step.SetHeaderRouting: %t", + step.Experiment == nil, step.Pause == nil, step.SetWeight == nil, step.Analysis == nil, step.SetCanaryScale == nil, step.SetHeaderRouting == nil) allErrs = append(allErrs, field.Invalid(stepFldPath, errVal, InvalidStepMessage)) } if step.SetWeight != nil && (*step.SetWeight < 0 || *step.SetWeight > 100) { @@ -288,6 +294,19 @@ func ValidateRolloutStrategyCanary(rollout *v1alpha1.Rollout, fldPath *field.Pat if rollout.Spec.Strategy.Canary != nil && rollout.Spec.Strategy.Canary.TrafficRouting == nil && step.SetCanaryScale != nil { allErrs = append(allErrs, field.Invalid(stepFldPath.Child("setCanaryScale"), step.SetCanaryScale, InvalidSetCanaryScaleTrafficPolicy)) } + if step.SetHeaderRouting != nil { + trafficRouting := rollout.Spec.Strategy.Canary.TrafficRouting + if trafficRouting == nil || trafficRouting.Istio == nil { + allErrs = append(allErrs, field.Invalid(stepFldPath.Child("setHeaderRouting"), step.SetHeaderRouting, InvalidSetHeaderRoutingTrafficPolicy)) + } + if step.SetHeaderRouting.Match != nil && len(step.SetHeaderRouting.Match) > 0 { + for j, match := range step.SetHeaderRouting.Match { + matchFld := stepFldPath.Child("setHeaderRouting").Child("match").Index(j) + allErrs = append(allErrs, hasMultipleMatchValues(match.HeaderValue, matchFld)...) + } + } + } + analysisRunArgs := make([]v1alpha1.AnalysisRunArgument, 0) if step.Experiment != nil { for tmplIndex, template := range step.Experiment.Templates { @@ -393,3 +412,27 @@ func hasMultipleStepsType(s v1alpha1.CanaryStep, fldPath *field.Path) field.Erro } return allErrs } + +func hasMultipleMatchValues(match v1alpha1.StringMatch, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + oneOf := make([]bool, 3) + oneOf = append(oneOf, match.Exact != "") + oneOf = append(oneOf, match.Regex != "") + oneOf = append(oneOf, match.Prefix != "") + hasValue := false + for i := range oneOf { + if oneOf[i] { + if hasValue { + e := field.Invalid(fldPath, match, InvalidSetHeaderRoutingMultipleValuePolicy) + allErrs = append(allErrs, e) + break + } + hasValue = true + } + } + if !hasValue { + e := field.Invalid(fldPath, match, InvalidSetHeaderRoutingMissedValuePolicy) + allErrs = append(allErrs, e) + } + return allErrs +} diff --git a/pkg/apis/rollouts/validation/validation_references.go b/pkg/apis/rollouts/validation/validation_references.go index 39b8107f2e..5869b6ce7f 100644 --- a/pkg/apis/rollouts/validation/validation_references.go +++ b/pkg/apis/rollouts/validation/validation_references.go @@ -297,7 +297,7 @@ func ValidateVirtualService(rollout *v1alpha1.Rollout, obj unstructured.Unstruct } // Validate HTTP Routes if errHttp == nil { - httpRoutes, err := istio.GetHttpRoutes(newObj, httpRoutesI) + httpRoutes, err := istio.GetHttpRoutes(httpRoutesI) if err != nil { msg := fmt.Sprintf("Unable to get HTTP routes for Istio VirtualService") allErrs = append(allErrs, field.Invalid(fldPath, vsvcName, msg)) diff --git a/pkg/apis/rollouts/validation/validation_test.go b/pkg/apis/rollouts/validation/validation_test.go index c88c91ca9a..fead009023 100644 --- a/pkg/apis/rollouts/validation/validation_test.go +++ b/pkg/apis/rollouts/validation/validation_test.go @@ -281,6 +281,70 @@ func TestValidateRolloutStrategyAntiAffinity(t *testing.T) { assert.Equal(t, InvalidAntiAffinityWeightMessage, allErrs[0].Detail) } +func TestValidateRolloutStrategyCanary_SetHeaderRoutingIstio(t *testing.T) { + ro := &v1alpha1.Rollout{} + ro.Spec.Strategy.Canary = &v1alpha1.CanaryStrategy{ + CanaryService: "canary", + StableService: "stable", + TrafficRouting: &v1alpha1.RolloutTrafficRouting{ + Istio: &v1alpha1.IstioTrafficRouting{ + VirtualService: &v1alpha1.IstioVirtualService{Name: "virtual-service"}, + }, + }, + } + + t.Run("using SetHeaderRouting step without the traffic routing", func(t *testing.T) { + invalidRo := ro.DeepCopy() + invalidRo.Spec.Strategy.Canary.TrafficRouting = nil + invalidRo.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{ + SetHeaderRouting: &v1alpha1.SetHeaderRouting{ + Match: []v1alpha1.HeaderRoutingMatch{ + { + HeaderName: "agent", + HeaderValue: v1alpha1.StringMatch{Exact: "chrome"}, + }, + }, + }, + }} + allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) + assert.Equal(t, InvalidSetHeaderRoutingTrafficPolicy, allErrs[0].Detail) + }) + + t.Run("using SetHeaderRouting step with multiple values", func(t *testing.T) { + invalidRo := ro.DeepCopy() + invalidRo.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{ + SetHeaderRouting: &v1alpha1.SetHeaderRouting{ + Match: []v1alpha1.HeaderRoutingMatch{ + { + HeaderName: "agent", + HeaderValue: v1alpha1.StringMatch{ + Exact: "chrome", + Regex: "chrome(.*)", + }, + }, + }, + }, + }} + allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) + assert.Equal(t, InvalidSetHeaderRoutingMultipleValuePolicy, allErrs[0].Detail) + }) + + t.Run("using SetHeaderRouting step with missed values", func(t *testing.T) { + invalidRo := ro.DeepCopy() + invalidRo.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{ + SetHeaderRouting: &v1alpha1.SetHeaderRouting{ + Match: []v1alpha1.HeaderRoutingMatch{ + { + HeaderName: "agent", + }, + }, + }, + }} + allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) + assert.Equal(t, InvalidSetHeaderRoutingMissedValuePolicy, allErrs[0].Detail) + }) +} + func TestInvalidMaxSurgeMaxUnavailable(t *testing.T) { r := func(maxSurge, maxUnavailable intstr.IntOrString) *v1alpha1.Rollout { return &v1alpha1.Rollout{ diff --git a/rollout/canary.go b/rollout/canary.go index dd8b53f4c6..d428ca49b9 100644 --- a/rollout/canary.go +++ b/rollout/canary.go @@ -337,6 +337,8 @@ func (c *rolloutContext) completedCurrentCanaryStep() bool { currentStepAr := c.currentArs.CanaryStep analysisExistsAndCompleted := currentStepAr != nil && currentStepAr.Status.Phase.Completed() return analysisExistsAndCompleted && currentStepAr.Status.Phase == v1alpha1.AnalysisPhaseSuccessful + case currentStep.SetHeaderRouting != nil: + return true } return false } diff --git a/rollout/mocks/TrafficRoutingReconciler.go b/rollout/mocks/TrafficRoutingReconciler.go index bf68c301e1..0e4d6ab1cc 100644 --- a/rollout/mocks/TrafficRoutingReconciler.go +++ b/rollout/mocks/TrafficRoutingReconciler.go @@ -13,6 +13,20 @@ type TrafficRoutingReconciler struct { mock.Mock } +// SetHeaderRouting provides a mock function with given fields: headerRouting +func (_m *TrafficRoutingReconciler) SetHeaderRouting(headerRouting *v1alpha1.SetHeaderRouting) error { + ret := _m.Called(headerRouting) + + var r0 error + if rf, ok := ret.Get(0).(func(*v1alpha1.SetHeaderRouting) error); ok { + r0 = rf(headerRouting) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // SetWeight provides a mock function with given fields: desiredWeight, additionalDestinations func (_m *TrafficRoutingReconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { _va := make([]interface{}, len(additionalDestinations)) diff --git a/rollout/trafficrouting.go b/rollout/trafficrouting.go index 2cc0a87c25..4e1ff4d305 100644 --- a/rollout/trafficrouting.go +++ b/rollout/trafficrouting.go @@ -126,6 +126,7 @@ func (c *rolloutContext) reconcileTrafficRouting() error { currentStep, index := replicasetutil.GetCurrentCanaryStep(c.rollout) desiredWeight := int32(0) + var setHeaderRouting *v1alpha1.SetHeaderRouting weightDestinations := make([]v1alpha1.WeightDestination, 0) var canaryHash, stableHash string @@ -164,6 +165,7 @@ func (c *rolloutContext) reconcileTrafficRouting() error { } } else if index != nil { atDesiredReplicaCount := replicasetutil.AtDesiredReplicaCountsForCanary(c.rollout, c.newRS, c.stableRS, c.otherRSs, nil) + setHeaderRouting = replicasetutil.GetCurrentSetHeaderRouting(c.rollout, *index) if !atDesiredReplicaCount && !c.rollout.Status.PromoteFull { // Use the previous weight since the new RS is not ready for a new weight for i := *index - 1; i >= 0; i-- { @@ -195,6 +197,11 @@ func (c *rolloutContext) reconcileTrafficRouting() error { c.recorder.Warnf(c.rollout, record.EventOptions{EventReason: "TrafficRoutingError"}, err.Error()) return err } + + if err = reconciler.SetHeaderRouting(setHeaderRouting); err != nil { + return err + } + if modified, newWeights := calculateWeightStatus(c.rollout, canaryHash, stableHash, desiredWeight, weightDestinations...); modified { c.log.Infof("Previous weights: %v", c.rollout.Status.Canary.Weights) c.log.Infof("New weights: %v", newWeights) diff --git a/rollout/trafficrouting/alb/alb.go b/rollout/trafficrouting/alb/alb.go index d88fd993e8..bc1f4c7de9 100644 --- a/rollout/trafficrouting/alb/alb.go +++ b/rollout/trafficrouting/alb/alb.go @@ -113,6 +113,10 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 return nil } +func (r *Reconciler) SetHeaderRouting(headerRouting *v1alpha1.SetHeaderRouting) error { + return nil +} + func (r *Reconciler) shouldVerifyWeight() bool { if r.cfg.VerifyWeight != nil { return *r.cfg.VerifyWeight diff --git a/rollout/trafficrouting/ambassador/ambassador.go b/rollout/trafficrouting/ambassador/ambassador.go index 97036449e8..6ed6c56743 100644 --- a/rollout/trafficrouting/ambassador/ambassador.go +++ b/rollout/trafficrouting/ambassador/ambassador.go @@ -115,6 +115,10 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 return formatErrors(errs) } +func (r *Reconciler) SetHeaderRouting(headerRouting *v1alpha1.SetHeaderRouting) error { + return nil +} + func formatErrors(errs []error) error { errorsCount := len(errs) if errorsCount == 0 { diff --git a/rollout/trafficrouting/appmesh/appmesh.go b/rollout/trafficrouting/appmesh/appmesh.go index 19d2100907..cbf2d589f6 100644 --- a/rollout/trafficrouting/appmesh/appmesh.go +++ b/rollout/trafficrouting/appmesh/appmesh.go @@ -5,14 +5,15 @@ import ( "errors" "fmt" - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" - logutil "github.com/argoproj/argo-rollouts/utils/log" - "github.com/argoproj/argo-rollouts/utils/record" "github.com/sirupsen/logrus" k8serrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/client-go/dynamic" + + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + logutil "github.com/argoproj/argo-rollouts/utils/log" + "github.com/argoproj/argo-rollouts/utils/record" ) const ( @@ -135,6 +136,10 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 return nil } +func (r *Reconciler) SetHeaderRouting(headerRouting *v1alpha1.SetHeaderRouting) error { + return nil +} + type routeReconcileContext struct { route map[string]interface{} routeIndex int diff --git a/rollout/trafficrouting/appmesh/appmesh_test.go b/rollout/trafficrouting/appmesh/appmesh_test.go index ae37aac64d..d64974bcc7 100644 --- a/rollout/trafficrouting/appmesh/appmesh_test.go +++ b/rollout/trafficrouting/appmesh/appmesh_test.go @@ -6,16 +6,17 @@ import ( "strings" "testing" - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" - testutil "github.com/argoproj/argo-rollouts/test/util" - "github.com/argoproj/argo-rollouts/utils/record" - unstructuredutil "github.com/argoproj/argo-rollouts/utils/unstructured" "github.com/tj/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" k8stesting "k8s.io/client-go/testing" + + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + testutil "github.com/argoproj/argo-rollouts/test/util" + "github.com/argoproj/argo-rollouts/utils/record" + unstructuredutil "github.com/argoproj/argo-rollouts/utils/unstructured" ) const ( diff --git a/rollout/trafficrouting/istio/istio.go b/rollout/trafficrouting/istio/istio.go index b4f3e75cdd..b6a63251dd 100644 --- a/rollout/trafficrouting/istio/istio.go +++ b/rollout/trafficrouting/istio/istio.go @@ -25,6 +25,7 @@ import ( const Http = "http" const Tls = "tls" const Type = "Istio" +const HeaderRouteName = "argo-rollouts-header-based-route" // NewReconciler returns a reconciler struct that brings the Virtual Service into the desired state func NewReconciler(r *v1alpha1.Rollout, client dynamic.Interface, recorder record.EventRecorder, virtualServiceLister, destinationRuleLister dynamiclister.Lister) *Reconciler { @@ -49,6 +50,22 @@ type Reconciler struct { destinationRuleLister dynamiclister.Lister } +type routePatchAction string + +const ( + DeleteRoute routePatchAction = "DeleteRoute" + InsertHeaderRoute routePatchAction = "InsertRoute" +) + +type virtualServiceRoutePatch struct { + routeIndex int + host string + subset string + patchAction routePatchAction +} + +type virtualServiceRoutePatches []virtualServiceRoutePatch + type virtualServicePatch struct { routeIndex int routeType string @@ -218,7 +235,7 @@ func (r *Reconciler) reconcileVirtualService(obj *unstructured.Unstructured, vsv var httpRoutes []VirtualServiceHTTPRoute httpRoutesI, err := GetHttpRoutesI(newObj) if err == nil { - routes, err := GetHttpRoutes(newObj, httpRoutesI) + routes, err := GetHttpRoutes(httpRoutesI) httpRoutes = routes if err != nil { return nil, false, err @@ -272,20 +289,7 @@ func (r *Reconciler) UpdateHash(canaryHash, stableHash string, additionalDestina ctx := context.TODO() client := r.client.Resource(istioutil.GetIstioDestinationRuleGVR()).Namespace(r.rollout.Namespace) - var dRuleUn *unstructured.Unstructured - var err error - if r.destinationRuleLister != nil { - dRuleUn, err = r.destinationRuleLister.Namespace(r.rollout.Namespace).Get(dRuleSpec.Name) - } else { - dRuleUn, err = client.Get(ctx, dRuleSpec.Name, metav1.GetOptions{}) - } - if err != nil { - if k8serrors.IsNotFound(err) { - r.recorder.Warnf(r.rollout, record.EventOptions{EventReason: "DestinationRuleNotFound"}, "DestinationRule `%s` not found", dRuleSpec.Name) - } - return err - } - origBytes, dRule, dRuleNew, err := unstructuredToDestinationRules(dRuleUn) + origBytes, dRule, dRuleNew, err := r.getDestinationRule(dRuleSpec, client, ctx) if err != nil { return err } @@ -378,6 +382,7 @@ func destinationRuleReplaceExtraMarshal(dRule *DestinationRule) []byte { } dRuleNew["spec"] = map[string]interface{}{ "subsets": subsets, + "host": dRule.Spec.Host, } dRuleNewBytes, _ := json.Marshal(dRuleNew) @@ -550,7 +555,7 @@ func GetTlsRoutesI(obj *unstructured.Unstructured) ([]interface{}, error) { return tlsRoutesI, nil } -func GetHttpRoutes(obj *unstructured.Unstructured, httpRoutesI []interface{}) ([]VirtualServiceHTTPRoute, error) { +func GetHttpRoutes(httpRoutesI []interface{}) ([]VirtualServiceHTTPRoute, error) { routeBytes, err := json.Marshal(httpRoutesI) if err != nil { return nil, err @@ -588,15 +593,103 @@ func (r *Reconciler) Type() string { // SetWeight modifies Istio resources to reach desired state func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { ctx := context.TODO() - var vsvc *unstructured.Unstructured - var virtualServices []v1alpha1.IstioVirtualService + virtualServices := r.getVirtualServices() + for _, virtualService := range virtualServices { + name := virtualService.Name + namespace, vsvcName := istioutil.GetVirtualServiceNamespaceName(name) + if namespace == "" { + namespace = r.rollout.Namespace + } + + client := r.client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(namespace) + vsvc, err := r.getVirtualService(namespace, vsvcName, client, ctx) + if err != nil { + return err + } + modifiedVirtualService, modified, err := r.reconcileVirtualService(vsvc, virtualService.Routes, virtualService.TLSRoutes, desiredWeight, additionalDestinations...) + if err != nil { + return err + } + if !modified { + continue + } + _, err = client.Update(ctx, modifiedVirtualService, metav1.UpdateOptions{}) + if err == nil { + r.log.Debugf("Updated VirtualService: %s", modifiedVirtualService) + r.recorder.Eventf(r.rollout, record.EventOptions{EventReason: "Updated VirtualService"}, "VirtualService `%s` set to desiredWeight '%d'", vsvcName, desiredWeight) + } else { + return err + } + } + return nil +} +func (r *Reconciler) getVirtualServices() []v1alpha1.IstioVirtualService { if istioutil.MultipleVirtualServiceConfigured(r.rollout) { - virtualServices = r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualServices + return r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualServices } else { - virtualServices = []v1alpha1.IstioVirtualService{*r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService} + return []v1alpha1.IstioVirtualService{*r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService} + } +} + +func (r *Reconciler) getVirtualService(namespace string, vsvcName string, client dynamic.ResourceInterface, ctx context.Context) (*unstructured.Unstructured, error) { + var vsvc *unstructured.Unstructured + var err error + if r.virtualServiceLister != nil { + vsvc, err = r.virtualServiceLister.Namespace(namespace).Get(vsvcName) + } else { + vsvc, err = client.Get(ctx, vsvcName, metav1.GetOptions{}) + } + if err != nil { + if k8serrors.IsNotFound(err) { + r.recorder.Warnf(r.rollout, record.EventOptions{EventReason: "VirtualServiceNotFound"}, "VirtualService `%s` not found", vsvcName) + } + return nil, err + } + return vsvc, err +} + +func (r *Reconciler) reconcileVirtualServiceRoutes(obj *unstructured.Unstructured, headerRouting *v1alpha1.SetHeaderRouting) (*unstructured.Unstructured, bool, error) { + newObj := obj.DeepCopy() + + // HTTP Routes + var httpRoutes []VirtualServiceHTTPRoute + httpRoutesI, err := GetHttpRoutesI(newObj) + if err == nil { + httpRoutes, err = GetHttpRoutes(httpRoutesI) + if err != nil { + return nil, false, err + } + } + destRuleHost, err := r.getDestinationRuleHost() + if err != nil { + return nil, false, err + } + + // Generate Patches + patches := r.generateHeaderBasedPatches(httpRoutes, headerRouting, destRuleHost) + for _, patch := range patches { + if patch.patchAction == InsertHeaderRoute { + httpRoutesI = append(httpRoutesI[:patch.routeIndex+1], httpRoutesI[patch.routeIndex:]...) + httpRoutesI[patch.routeIndex] = createHeaderRoute(headerRouting, patch) + } else if patch.patchAction == DeleteRoute { + httpRoutesI = append(httpRoutesI[:patch.routeIndex], httpRoutesI[patch.routeIndex+1:]...) + } + } + + // Set HTTP Route Slice + if len(httpRoutes) > 0 && len(patches) > 0 { + err = unstructured.SetNestedSlice(newObj.Object, httpRoutesI, "spec", Http) + if err != nil { + return newObj, len(patches) > 0, err + } } + return newObj, len(patches) > 0, err +} +func (r *Reconciler) SetHeaderRouting(headerRouting *v1alpha1.SetHeaderRouting) error { + ctx := context.TODO() + virtualServices := r.getVirtualServices() for _, virtualService := range virtualServices { name := virtualService.Name namespace, vsvcName := istioutil.GetVirtualServiceNamespaceName(name) @@ -604,20 +697,12 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 namespace = r.rollout.Namespace } - var err error client := r.client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(namespace) - if r.virtualServiceLister != nil { - vsvc, err = r.virtualServiceLister.Namespace(namespace).Get(vsvcName) - } else { - vsvc, err = client.Get(ctx, vsvcName, metav1.GetOptions{}) - } + vsvc, err := r.getVirtualService(namespace, vsvcName, client, ctx) if err != nil { - if k8serrors.IsNotFound(err) { - r.recorder.Warnf(r.rollout, record.EventOptions{EventReason: "VirtualServiceNotFound"}, "VirtualService `%s` not found", vsvcName) - } return err } - modifiedVirtualService, modified, err := r.reconcileVirtualService(vsvc, virtualService.Routes, virtualService.TLSRoutes, desiredWeight, additionalDestinations...) + modifiedVirtualService, modified, err := r.reconcileVirtualServiceRoutes(vsvc, headerRouting) if err != nil { return err } @@ -627,7 +712,7 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 _, err = client.Update(ctx, modifiedVirtualService, metav1.UpdateOptions{}) if err == nil { r.log.Debugf("Updated VirtualService: %s", modifiedVirtualService) - r.recorder.Eventf(r.rollout, record.EventOptions{EventReason: "Updated VirtualService"}, "VirtualService `%s` set to desiredWeight '%d'", vsvcName, desiredWeight) + r.recorder.Eventf(r.rollout, record.EventOptions{EventReason: "Updated VirtualService"}, "VirtualService `%s` set headerRouting '%v'", vsvcName, headerRouting) } else { return err } @@ -635,6 +720,137 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 return nil } +func (r *Reconciler) getDestinationRuleHost() (string, error) { + if r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.DestinationRule != nil { + ctx := context.TODO() + client := r.client.Resource(istioutil.GetIstioDestinationRuleGVR()).Namespace(r.rollout.Namespace) + _, dRule, _, err := r.getDestinationRule(r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.DestinationRule, client, ctx) + if err != nil { + return "", err + } + return dRule.Spec.Host, nil + } + return "", nil +} + +func (r *Reconciler) getDestinationRule(dRuleSpec *v1alpha1.IstioDestinationRule, client dynamic.ResourceInterface, ctx context.Context) ([]byte, *DestinationRule, *DestinationRule, error) { + var dRuleUn *unstructured.Unstructured + var err error + if r.destinationRuleLister != nil { + dRuleUn, err = r.destinationRuleLister.Namespace(r.rollout.Namespace).Get(dRuleSpec.Name) + } else { + dRuleUn, err = client.Get(ctx, dRuleSpec.Name, metav1.GetOptions{}) + } + if err != nil { + if k8serrors.IsNotFound(err) { + r.recorder.Warnf(r.rollout, record.EventOptions{EventReason: "DestinationRuleNotFound"}, "DestinationRule `%s` not found", dRuleSpec.Name) + } + return nil, nil, nil, err + } + origBytes, dRule, dRuleNew, err := unstructuredToDestinationRules(dRuleUn) + if err != nil { + return nil, nil, nil, err + } + return origBytes, dRule, dRuleNew, nil +} + +func (r *Reconciler) generateHeaderBasedPatches(httpRoutes []VirtualServiceHTTPRoute, headerRouting *v1alpha1.SetHeaderRouting, destRuleHost string) virtualServiceRoutePatches { + canarySvc := r.rollout.Spec.Strategy.Canary.CanaryService + if destRuleHost != "" { + canarySvc = destRuleHost + } + var canarySubset string + if r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.DestinationRule != nil { + canarySubset = r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.DestinationRule.CanarySubsetName + } + + patches := virtualServiceRoutePatches{} + headerRouteExist := hasHeaderRoute(httpRoutes) + + if headerRouteExist { + if headerRouting == nil || headerRouting.Match == nil { + deleteHeaderRoute(&patches) + } else { + deleteHeaderRoute(&patches) + insertHeaderRoute(&patches, canarySvc, canarySubset) + } + } else if headerRouting != nil && headerRouting.Match != nil { + insertHeaderRoute(&patches, canarySvc, canarySubset) + } + return patches +} + +func hasHeaderRoute(httpRoutes []VirtualServiceHTTPRoute) bool { + for _, route := range httpRoutes { + if route.Name == HeaderRouteName { + return true + } + } + return false +} + +func deleteHeaderRoute(patches *virtualServiceRoutePatches) { + patch := virtualServiceRoutePatch{ + routeIndex: 0, + patchAction: DeleteRoute, + } + *patches = append(*patches, patch) +} + +func insertHeaderRoute(patches *virtualServiceRoutePatches, host, subset string) { + insertPatch := virtualServiceRoutePatch{ + routeIndex: 0, + host: host, + subset: subset, + patchAction: InsertHeaderRoute, + } + *patches = append(*patches, insertPatch) +} + +func createHeaderRoute(headerRouting *v1alpha1.SetHeaderRouting, patch virtualServiceRoutePatch) map[string]interface{} { + var routeMatches []interface{} + for _, hrm := range headerRouting.Match { + routeMatches = append(routeMatches, createRouteMatch(hrm)) + } + canaryDestination := routeDestination(patch.host, patch.subset, 100) + return map[string]interface{}{ + "name": HeaderRouteName, + "match": routeMatches, + "route": []interface{}{canaryDestination}, + } +} + +func createRouteMatch(hrm v1alpha1.HeaderRoutingMatch) interface{} { + res := map[string]interface{}{} + value := hrm.HeaderValue + setMapValueIfNotEmpty(res, "exact", value.Exact) + setMapValueIfNotEmpty(res, "regex", value.Regex) + setMapValueIfNotEmpty(res, "prefix", value.Prefix) + return map[string]interface{}{ + "headers": map[string]interface{}{hrm.HeaderName: res}, + } +} + +func setMapValueIfNotEmpty(m map[string]interface{}, key string, value string) { + if value != "" { + m[key] = value + } +} + +func routeDestination(host, subset string, weight int64) map[string]interface{} { + dest := map[string]interface{}{ + "host": host, + } + if subset != "" { + dest["subset"] = subset + } + routeValue := map[string]interface{}{ + "weight": float64(weight), + "destination": dest, + } + return routeValue +} + func (r *Reconciler) VerifyWeight(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) (*bool, error) { return nil, nil } @@ -658,14 +874,12 @@ func getHttpRouteIndexesToPatch(routeNames []string, httpRoutes []VirtualService } func searchHttpRoute(routeName string, httpRoutes []VirtualServiceHTTPRoute) int { - routeIndex := -1 for i, route := range httpRoutes { if route.Name == routeName { - routeIndex = i - break + return i } } - return routeIndex + return -1 } // getTlsRouteIndexesToPatch returns array indices of the tlsRoutes which need to be patched when updating weights diff --git a/rollout/trafficrouting/istio/istio_test.go b/rollout/trafficrouting/istio/istio_test.go index bad150869a..939c16beb0 100644 --- a/rollout/trafficrouting/istio/istio_test.go +++ b/rollout/trafficrouting/istio/istio_test.go @@ -335,6 +335,27 @@ spec: host: canary weight: 0` +const singleRouteSubsetVsvc = `apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: vsvc + namespace: default +spec: + gateways: + - istio-rollout-gateway + hosts: + - istio-rollout.dev.argoproj.io + http: + - route: + - destination: + host: 'rollout-service' + subset: 'stable-subset' + weight: 100 + - destination: + host: rollout-service + subset: 'canary-subset' + weight: 0` + const singleRouteTlsVsvc = `apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: @@ -465,6 +486,92 @@ func TestHttpReconcileWeightsBaseCase(t *testing.T) { } } +func TestHttpReconcileHeaderRoute_HostBased(t *testing.T) { + r := &Reconciler{ + rollout: rolloutWithHttpRoutes("stable", "canary", "vsvc", []string{"primary"}), + } + + // Test for both the HTTP VS & Mixed VS + vsObj := unstructuredutil.StrToUnstructuredUnsafe(regularVsvc) + hr := &v1alpha1.SetHeaderRouting{ + Match: []v1alpha1.HeaderRoutingMatch{ + { + HeaderName: "agent", + HeaderValue: v1alpha1.StringMatch{Exact: "firefox"}, + }, + }, + } + modifiedVsObj, _, err := r.reconcileVirtualServiceRoutes(vsObj, hr) + assert.Nil(t, err) + assert.NotNil(t, modifiedVsObj) + + // HTTP Routes + httpRoutes := extractHttpRoutes(t, modifiedVsObj) + + // Assertions + assert.Equal(t, httpRoutes[0].Name, HeaderRouteName) + checkDestination(t, httpRoutes[0].Route, "canary", 100) + assert.Equal(t, len(httpRoutes[0].Route), 1) + assert.Equal(t, httpRoutes[1].Name, "primary") + checkDestination(t, httpRoutes[1].Route, "stable", 100) + assert.Equal(t, httpRoutes[2].Name, "secondary") + + // Reset header routing, expecting removing of the header route + + modifiedVsObj, _, err = r.reconcileVirtualServiceRoutes(vsObj, nil) + assert.Nil(t, err) + assert.NotNil(t, modifiedVsObj) + // HTTP Routes + httpRoutes = extractHttpRoutes(t, modifiedVsObj) + // Assertions + assert.Equal(t, httpRoutes[0].Name, "primary") + assert.Equal(t, httpRoutes[1].Name, "secondary") +} + +func TestHttpReconcileHeaderRoute_SubsetBased(t *testing.T) { + ro := rolloutWithDestinationRule() + obj := unstructuredutil.StrToUnstructuredUnsafe(` +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-destrule + namespace: default +spec: + host: root-service + subsets: + - name: stable + - name: canary +`) + + client := testutil.NewFakeDynamicClient(obj) + r := NewReconciler(ro, client, record.NewFakeEventRecorder(), nil, nil) + client.ClearActions() + + // Test for both the HTTP VS & Mixed VS + vsObj := unstructuredutil.StrToUnstructuredUnsafe(singleRouteSubsetVsvc) + hr := &v1alpha1.SetHeaderRouting{ + Match: []v1alpha1.HeaderRoutingMatch{ + { + HeaderName: "agent", + HeaderValue: v1alpha1.StringMatch{ + Regex: "firefox", + }, + }, + }, + } + modifiedVsObj, _, err := r.reconcileVirtualServiceRoutes(vsObj, hr) + assert.Nil(t, err) + assert.NotNil(t, modifiedVsObj) + + // HTTP Routes + httpRoutes := extractHttpRoutes(t, modifiedVsObj) + + // Assertions + assert.Equal(t, httpRoutes[0].Name, HeaderRouteName) + assert.Equal(t, httpRoutes[0].Route[0].Destination.Host, "root-service") + assert.Equal(t, httpRoutes[0].Route[0].Destination.Subset, "canary") +} + func TestTlsReconcileWeightsBaseCase(t *testing.T) { r := &Reconciler{ rollout: rolloutWithTlsRoutes("stable", "canary", "vsvc", @@ -1157,7 +1264,7 @@ spec: jsonBytes, err := json.Marshal(dRule) assert.NoError(t, err) - assert.Equal(t, `{"metadata":{"name":"istio-destrule","namespace":"default","creationTimestamp":null,"annotations":{"argo-rollouts.argoproj.io/managed-by-rollouts":"rollout"}},"spec":{"subsets":[{"name":"stable","labels":{"rollouts-pod-template-hash":"def456","version":"v3"}},{"name":"canary","labels":{"rollouts-pod-template-hash":"abc123"},"Extra":{"trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}}}]}}`, + assert.Equal(t, `{"metadata":{"name":"istio-destrule","namespace":"default","creationTimestamp":null,"annotations":{"argo-rollouts.argoproj.io/managed-by-rollouts":"rollout"}},"spec":{"host":"ratings.prod.svc.cluster.local","subsets":[{"name":"stable","labels":{"rollouts-pod-template-hash":"def456","version":"v3"}},{"name":"canary","labels":{"rollouts-pod-template-hash":"abc123"},"Extra":{"trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}}}]}}`, string(jsonBytes)) } @@ -1207,6 +1314,7 @@ metadata: annotations: argo-rollouts.argoproj.io/managed-by-rollouts: rollout spec: + host: ratings.prod.svc.cluster.local subsets: - name: stable labels: diff --git a/rollout/trafficrouting/istio/istio_types.go b/rollout/trafficrouting/istio/istio_types.go index 63d361f42e..4e14a60bdf 100644 --- a/rollout/trafficrouting/istio/istio_types.go +++ b/rollout/trafficrouting/istio/istio_types.go @@ -59,6 +59,7 @@ type DestinationRule struct { } type DestinationRuleSpec struct { + Host string `json:"host,omitempty"` Subsets []Subset `json:"subsets,omitempty"` } diff --git a/rollout/trafficrouting/nginx/nginx.go b/rollout/trafficrouting/nginx/nginx.go index 0892f7c175..a0d291c121 100644 --- a/rollout/trafficrouting/nginx/nginx.go +++ b/rollout/trafficrouting/nginx/nginx.go @@ -307,6 +307,10 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 return nil } +func (r *Reconciler) SetHeaderRouting(headerRouting *v1alpha1.SetHeaderRouting) error { + return nil +} + func (r *Reconciler) VerifyWeight(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) (*bool, error) { return nil, nil } diff --git a/rollout/trafficrouting/smi/smi.go b/rollout/trafficrouting/smi/smi.go index a1b6c5f7fe..8be3584abf 100644 --- a/rollout/trafficrouting/smi/smi.go +++ b/rollout/trafficrouting/smi/smi.go @@ -218,6 +218,10 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 return r.patchTrafficSplit(existingTrafficSplit, trafficSplits) } +func (r *Reconciler) SetHeaderRouting(headerRouting *v1alpha1.SetHeaderRouting) error { + return nil +} + func (r *Reconciler) generateTrafficSplits(trafficSplitName string, desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) VersionedTrafficSplits { // If root service not set, then set root service to be stable service rootSvc := r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.SMI.RootService diff --git a/rollout/trafficrouting/traefik/traefik.go b/rollout/trafficrouting/traefik/traefik.go index a2f9703726..22c3f56875 100644 --- a/rollout/trafficrouting/traefik/traefik.go +++ b/rollout/trafficrouting/traefik/traefik.go @@ -6,15 +6,15 @@ import ( "strings" "github.com/pkg/errors" - - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" - "github.com/argoproj/argo-rollouts/utils/defaults" - "github.com/argoproj/argo-rollouts/utils/record" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic" + + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + "github.com/argoproj/argo-rollouts/utils/defaults" + "github.com/argoproj/argo-rollouts/utils/record" ) // Type holds this controller type @@ -156,6 +156,10 @@ func getService(serviceName string, services []interface{}) (map[string]interfac return selectedService, nil } +func (r *Reconciler) SetHeaderRouting(headerRouting *v1alpha1.SetHeaderRouting) error { + return nil +} + func (r *Reconciler) VerifyWeight(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) (*bool, error) { return nil, nil } diff --git a/rollout/trafficrouting/trafficroutingutil.go b/rollout/trafficrouting/trafficroutingutil.go index 53c20ffd2b..08569c4a16 100644 --- a/rollout/trafficrouting/trafficroutingutil.go +++ b/rollout/trafficrouting/trafficroutingutil.go @@ -10,6 +10,8 @@ type TrafficRoutingReconciler interface { UpdateHash(canaryHash, stableHash string, additionalDestinations ...v1alpha1.WeightDestination) error // SetWeight sets the canary weight to the desired weight SetWeight(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error + // SetHeaderRouting sets the header routing step + SetHeaderRouting(headerRouting *v1alpha1.SetHeaderRouting) error // VerifyWeight returns true if the canary is at the desired weight and additionalDestinations are at the weights specified // Returns nil if weight verification is not supported or not applicable VerifyWeight(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) (*bool, error) diff --git a/rollout/trafficrouting_test.go b/rollout/trafficrouting_test.go index aff8b09060..11941a9aea 100644 --- a/rollout/trafficrouting_test.go +++ b/rollout/trafficrouting_test.go @@ -35,6 +35,7 @@ func newFakeSingleTrafficRoutingReconciler() *mocks.TrafficRoutingReconciler { trafficRoutingReconciler := mocks.TrafficRoutingReconciler{} trafficRoutingReconciler.On("Type").Return("fake") trafficRoutingReconciler.On("SetWeight", mock.Anything, mock.Anything).Return(nil) + trafficRoutingReconciler.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) trafficRoutingReconciler.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) trafficRoutingReconciler.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) return &trafficRoutingReconciler @@ -98,6 +99,7 @@ func TestReconcileTrafficRoutingVerifyWeightErr(t *testing.T) { f.fakeTrafficRouting = newUnmockedFakeTrafficRoutingReconciler() f.fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(false), errors.New("Error message")) f.expectPatchRolloutAction(ro) f.run(getKey(ro, t)) @@ -110,6 +112,7 @@ func TestReconcileTrafficRoutingVerifyWeightFalse(t *testing.T) { f.fakeTrafficRouting = newUnmockedFakeTrafficRoutingReconciler() f.fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(false), nil) c, i, k8sI := f.newController(noResyncPeriodFunc) enqueued := false @@ -171,6 +174,7 @@ func TestRolloutUseDesiredWeight(t *testing.T) { assert.Equal(t, int32(10), desiredWeight) return nil }) + f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(true, nil) f.run(getKey(r2, t)) } @@ -219,6 +223,7 @@ func TestRolloutUseDesiredWeight100(t *testing.T) { assert.Equal(t, int32(100), desiredWeight) return nil }) + f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(true, nil) f.run(getKey(r2, t)) } @@ -286,6 +291,7 @@ func TestRolloutWithExperimentStep(t *testing.T) { assert.Equal(t, ex.Status.TemplateStatuses[0].PodTemplateHash, weightDestinations[0].PodTemplateHash) return nil }) + f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(func(desiredWeight int32, weightDestinations ...v1alpha1.WeightDestination) error { assert.Equal(t, int32(10), desiredWeight) assert.Equal(t, int32(5), weightDestinations[0].Weight) @@ -306,6 +312,7 @@ func TestRolloutWithExperimentStep(t *testing.T) { assert.Len(t, weightDestinations, 0) return nil }) + f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(func(desiredWeight int32, weightDestinations ...v1alpha1.WeightDestination) error { assert.Equal(t, int32(10), desiredWeight) assert.Len(t, weightDestinations, 0) @@ -360,6 +367,7 @@ func TestRolloutUsePreviousSetWeight(t *testing.T) { assert.Equal(t, int32(10), desiredWeight) return nil }) + f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything, mock.Anything).Return(pointer.BoolPtr(true), nil) f.fakeTrafficRouting.On("error patching alb ingress", mock.Anything, mock.Anything).Return(true, nil) f.run(getKey(r2, t)) @@ -425,6 +433,7 @@ func TestRolloutUseDynamicWeightOnPromoteFull(t *testing.T) { assert.Equal(t, int32(50), desiredWeight) return nil }) + f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) f.run(getKey(r2, t)) }) @@ -437,6 +446,7 @@ func TestRolloutUseDynamicWeightOnPromoteFull(t *testing.T) { assert.Equal(t, int32(5), desiredWeight) return nil }) + f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) f.run(getKey(r2, t)) }) @@ -480,6 +490,7 @@ func TestRolloutSetWeightToZeroWhenFullyRolledOut(t *testing.T) { assert.Equal(t, int32(0), desiredWeight) return nil }) + f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) f.run(getKey(r1, t)) } @@ -852,6 +863,7 @@ func TestDynamicScalingDontIncreaseWeightWhenAborted(t *testing.T) { assert.Equal(t, int32(0), desiredWeight) return nil }) + f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) f.run(getKey(r1, t)) } @@ -921,6 +933,7 @@ func TestDynamicScalingDecreaseWeightAccordingToStableAvailabilityWhenAborted(t assert.Equal(t, int32(80), desiredWeight) return nil }) + f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) f.run(getKey(r1, t)) } diff --git a/test/e2e/header-routing/istio-hr-host.yaml b/test/e2e/header-routing/istio-hr-host.yaml new file mode 100644 index 0000000000..6c3fa050bb --- /dev/null +++ b/test/e2e/header-routing/istio-hr-host.yaml @@ -0,0 +1,115 @@ +apiVersion: v1 +kind: Service +metadata: + name: canary-service +spec: + selector: + app: rollouts-demo + ports: + - name: http + port: 80 + protocol: TCP + targetPort: http +--- +apiVersion: v1 +kind: Service +metadata: + name: stable-service +spec: + selector: + app: rollouts-demo + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + +--- +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +metadata: + name: rollouts-demo-vsvc +spec: + gateways: + - rollouts-demo-gateway + hosts: + - rollouts-demo.com + http: +# - name: argo-rollouts-header-route +# route: +# - destination: +# host: canary-service +# weight: 100 + - name: primary + route: + - destination: + host: stable-service + weight: 80 + - destination: + host: canary-service + weight: 20 + +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollouts-demo +spec: + replicas: 5 + selector: + matchLabels: + app: rollouts-demo + template: + metadata: + labels: + app: rollouts-demo + spec: + containers: + - name: rollouts-demo + image: "nginx:1.19-alpine" + ports: + - name: http + containerPort: 8080 + protocol: TCP + strategy: + canary: + canaryService: canary-service + stableService: stable-service + trafficRouting: + istio: + virtualService: + name: rollouts-demo-vsvc + routes: + - primary + steps: + - setWeight: 20 + - setHeaderRouting: + match: + - headerName: agent + headerValue: + regex: firefox(.*) + - pause: { } + - setHeaderRouting: + match: + - headerName: agent + headerValue: + regex: chrome(.*) + - pause: { } + - setWeight: 40 + - setHeaderRouting: {} + - pause: {} +--- +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: rollouts-demo-gateway +spec: + selector: + istio: ingressgateway + servers: + - hosts: + - '*' + port: + name: http + number: 80 + protocol: HTTP diff --git a/test/e2e/header_routing_test.go b/test/e2e/header_routing_test.go new file mode 100644 index 0000000000..a1aab16999 --- /dev/null +++ b/test/e2e/header_routing_test.go @@ -0,0 +1,91 @@ +//go:build e2e +// +build e2e + +package e2e + +import ( + "testing" + "time" + + "github.com/stretchr/testify/suite" + "github.com/tj/assert" + + "github.com/argoproj/argo-rollouts/rollout/trafficrouting/istio" + + "github.com/argoproj/argo-rollouts/test/fixtures" +) + +type HeaderRoutingSuite struct { + fixtures.E2ESuite +} + +func TestHeaderRoutingSuite(t *testing.T) { + suite.Run(t, new(HeaderRoutingSuite)) +} + +func (s *HeaderRoutingSuite) SetupSuite() { + s.E2ESuite.SetupSuite() + if !s.IstioEnabled { + s.T().SkipNow() + } +} + +func (s *HeaderRoutingSuite) TestIstioHostHeaderRoute() { + s.Given(). + RolloutObjects("@header-routing/istio-hr-host.yaml"). + When(). + ApplyManifests(). + WaitForRolloutStatus("Healthy"). + Then(). + Assert(func(t *fixtures.Then) { + vsvc := t.GetVirtualService() + assert.Equal(s.T(), "primary", vsvc.Spec.HTTP[0].Name) + }). + When(). + UpdateSpec(). + WaitForRolloutStatus("Paused"). + Sleep(1 * time.Second). + Then(). + Assert(func(t *fixtures.Then) { + vsvc := t.GetVirtualService() + assert.Equal(s.T(), istio.HeaderRouteName, vsvc.Spec.HTTP[0].Name) + assertDestination(s, vsvc.Spec.HTTP[0], "canary-service", int64(100)) + assertDestination(s, vsvc.Spec.HTTP[1], "stable-service", int64(80)) + assertDestination(s, vsvc.Spec.HTTP[1], "canary-service", int64(20)) + }). + When(). + PromoteRollout(). + WaitForRolloutStatus("Paused"). + Sleep(1 * time.Second). + Then(). + When(). + PromoteRollout(). + WaitForRolloutStatus("Paused"). + Sleep(1 * time.Second). + Then(). + Assert(func(t *fixtures.Then) { + vsvc := t.GetVirtualService() + assertDestination(s, vsvc.Spec.HTTP[0], "stable-service", int64(60)) + assertDestination(s, vsvc.Spec.HTTP[0], "canary-service", int64(40)) + }). + When(). + PromoteRolloutFull(). + WaitForRolloutStatus("Healthy"). + Sleep(1 * time.Second). + Then(). + Assert(func(t *fixtures.Then) { + vsvc := t.GetVirtualService() + assertDestination(s, vsvc.Spec.HTTP[0], "stable-service", int64(100)) + assertDestination(s, vsvc.Spec.HTTP[0], "canary-service", int64(0)) + }) +} + +func assertDestination(s *HeaderRoutingSuite, route istio.VirtualServiceHTTPRoute, service string, weight int64) { + for _, destination := range route.Route { + if destination.Destination.Host == service { + assert.Equal(s.T(), weight, destination.Weight) + return + } + } + assert.Fail(s.T(), "Could not find the destination for service: %s", service) +} diff --git a/utils/replicaset/canary.go b/utils/replicaset/canary.go index 88e78f86c6..8a015f7b7d 100644 --- a/utils/replicaset/canary.go +++ b/utils/replicaset/canary.go @@ -4,12 +4,12 @@ import ( "encoding/json" "math" + log "github.com/sirupsen/logrus" appsv1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/defaults" - log "github.com/sirupsen/logrus" ) const ( @@ -474,6 +474,19 @@ func GetCurrentSetWeight(rollout *v1alpha1.Rollout) int32 { return 0 } +func GetCurrentSetHeaderRouting(rollout *v1alpha1.Rollout, index int32) *v1alpha1.SetHeaderRouting { + if int32(len(rollout.Spec.Strategy.Canary.Steps)) == index { + index-- + } + for i := index; i >= 0; i-- { + step := rollout.Spec.Strategy.Canary.Steps[i] + if step.SetHeaderRouting != nil { + return step.SetHeaderRouting + } + } + return nil +} + // UseSetCanaryScale will return a SetCanaryScale if specified and should be used, returns nil otherwise. // TrafficRouting is required to be set for SetCanaryScale to be applicable. // If MatchTrafficWeight is set after a previous SetCanaryScale step, it will likewise be ignored. diff --git a/utils/replicaset/canary_test.go b/utils/replicaset/canary_test.go index b341bb06e6..e111043362 100644 --- a/utils/replicaset/canary_test.go +++ b/utils/replicaset/canary_test.go @@ -4,6 +4,7 @@ import ( "fmt" "testing" + "github.com/aws/smithy-go/ptr" "github.com/stretchr/testify/assert" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -1014,6 +1015,41 @@ func TestGetCurrentSetWeight(t *testing.T) { } +func TestGetCurrentSetHeaderRouting(t *testing.T) { + rollout := newRollout(10, 10, intstr.FromInt(0), intstr.FromInt(1), "", "", nil, nil) + setHeaderRoutingStep := v1alpha1.SetHeaderRouting{ + Match: []v1alpha1.HeaderRoutingMatch{ + { + HeaderName: "agent", + }, + { + HeaderName: "agent2", + HeaderValue: v1alpha1.StringMatch{Exact: "value"}, + }, + { + HeaderName: "agent3", + HeaderValue: v1alpha1.StringMatch{Regex: "regexValue(.*)"}, + }, + }, + } + rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{ + {SetWeight: ptr.Int32(20)}, + {Pause: &v1alpha1.RolloutPause{}}, + {SetHeaderRouting: &setHeaderRoutingStep}, + {SetWeight: ptr.Int32(40)}, + {Pause: &v1alpha1.RolloutPause{}}, + {SetHeaderRouting: &v1alpha1.SetHeaderRouting{}}, + } + + assert.Nil(t, GetCurrentSetHeaderRouting(rollout, 0)) + assert.Nil(t, GetCurrentSetHeaderRouting(rollout, 1)) + assert.Equal(t, &setHeaderRoutingStep, GetCurrentSetHeaderRouting(rollout, 2)) + assert.Equal(t, &setHeaderRoutingStep, GetCurrentSetHeaderRouting(rollout, 3)) + assert.Equal(t, &setHeaderRoutingStep, GetCurrentSetHeaderRouting(rollout, 4)) + assert.Nil(t, GetCurrentSetHeaderRouting(rollout, 5).Match) + assert.Nil(t, GetCurrentSetHeaderRouting(rollout, 6).Match) +} + func TestAtDesiredReplicaCountsForCanary(t *testing.T) { t.Run("we are at desired replica counts and availability", func(t *testing.T) { From 15df713909ce8b4b3f4145338a187d0a20b260a1 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Wed, 25 May 2022 14:54:11 -0500 Subject: [PATCH 129/175] feat: Ability for lint command to inspect referenced resources (#2030) Signed-off-by: zachaller --- .../validation/validation_references.go | 1 - pkg/kubectl-argo-rollouts/cmd/lint/lint.go | 259 +++++++++++++++--- .../cmd/lint/lint_test.go | 75 +++-- .../testdata/invalid-ingress-smi-multi.yml | 244 +++++++++++++++++ .../lint/testdata/invalid-nginx-canary.yml | 95 +++++++ .../cmd/lint/testdata/invalid-ping-pong.yml | 69 +++++ .../lint/testdata/invalid-service-labels.yml | 69 +++++ .../cmd/lint/testdata/invalid.json | 72 +++++ .../cmd/lint/testdata/valid-alb-canary.yml | 95 +++++++ .../cmd/lint/testdata/valid-blue-green.yml | 51 ++++ .../lint/testdata/valid-ingress-smi-multi.yml | 244 +++++++++++++++++ .../cmd/lint/testdata/valid-ingress-smi.yml | 115 ++++++++ .../lint/testdata/valid-istio-v1alpha3.yml | 88 ++++++ ...id-istio-v1beta1-mulitiple-virtualsvcs.yml | 110 ++++++++ .../cmd/lint/testdata/valid-istio-v1beta1.yml | 88 ++++++ .../cmd/lint/testdata/valid-nginx-canary.yml | 88 ++++++ .../cmd/lint/testdata/valid.json | 72 +++++ 17 files changed, 1773 insertions(+), 62 deletions(-) create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-ingress-smi-multi.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-nginx-canary.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-ping-pong.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-service-labels.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid.json create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-alb-canary.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-blue-green.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-ingress-smi-multi.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-ingress-smi.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1alpha3.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1beta1-mulitiple-virtualsvcs.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1beta1.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-nginx-canary.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid.json diff --git a/pkg/apis/rollouts/validation/validation_references.go b/pkg/apis/rollouts/validation/validation_references.go index 5869b6ce7f..a4d5561f4a 100644 --- a/pkg/apis/rollouts/validation/validation_references.go +++ b/pkg/apis/rollouts/validation/validation_references.go @@ -105,7 +105,6 @@ func ValidateService(svc ServiceWithType, rollout *v1alpha1.Rollout) field.Error } if v, ok := rollout.Spec.Template.Labels[svcLabelKey]; !ok || v != svcLabelValue { msg := fmt.Sprintf("Service %q has unmatch lable %q in rollout", service.Name, svcLabelKey) - fmt.Println(msg) allErrs = append(allErrs, field.Invalid(fldPath, service.Name, msg)) } } diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/lint.go b/pkg/kubectl-argo-rollouts/cmd/lint/lint.go index 1c50a9650d..2969b53034 100644 --- a/pkg/kubectl-argo-rollouts/cmd/lint/lint.go +++ b/pkg/kubectl-argo-rollouts/cmd/lint/lint.go @@ -2,19 +2,23 @@ package lint import ( "bytes" - "encoding/json" + "fmt" "io" "io/ioutil" - "unicode" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/validation" "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/options" + ingressutil "github.com/argoproj/argo-rollouts/utils/ingress" "github.com/ghodss/yaml" "github.com/spf13/cobra" goyaml "gopkg.in/yaml.v2" + v1 "k8s.io/api/core/v1" + extensionsv1beta1 "k8s.io/api/extensions/v1beta1" + networkingv1 "k8s.io/api/networking/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/util/validation/field" ) type LintOptions struct { @@ -22,6 +26,11 @@ type LintOptions struct { File string } +type roAndReferences struct { + Rollout v1alpha1.Rollout + References validation.ReferencedResources +} + const ( lintExample = ` # Lint a rollout @@ -56,42 +65,10 @@ func NewCmdLint(o *options.ArgoRolloutsOptions) *cobra.Command { return cmd } -// isJSON detects if the byte array looks like json, based on the first non-whitespace character -func isJSON(fileBytes []byte) bool { - for _, b := range fileBytes { - if !unicode.IsSpace(rune(b)) { - return b == '{' - } - } - return false -} - func unmarshal(fileBytes []byte, obj interface{}) error { - if isJSON(fileBytes) { - decoder := json.NewDecoder(bytes.NewReader(fileBytes)) - decoder.DisallowUnknownFields() - return decoder.Decode(&obj) - } return yaml.UnmarshalStrict(fileBytes, &obj, yaml.DisallowUnknownFields) } -func validate(fileBytes []byte, un *unstructured.Unstructured) error { - gvk := un.GroupVersionKind() - switch { - case gvk.Group == rollouts.Group && gvk.Kind == rollouts.RolloutKind: - var ro v1alpha1.Rollout - err := unmarshal(fileBytes, &ro) - if err != nil { - return err - } - errs := validation.ValidateRollout(&ro) - if 0 < len(errs) { - return errs[0] - } - } - return nil -} - func (l *LintOptions) lintResource(path string) error { fileBytes, err := ioutil.ReadFile(path) if err != nil { @@ -99,13 +76,8 @@ func (l *LintOptions) lintResource(path string) error { } var un unstructured.Unstructured - - if isJSON(fileBytes) { - if err = unmarshal(fileBytes, un); err != nil { - return err - } - return validate(fileBytes, &un) - } + var refResource validation.ReferencedResources + var fileRollouts []v1alpha1.Rollout decoder := goyaml.NewDecoder(bytes.NewReader(fileBytes)) for { @@ -128,10 +100,213 @@ func (l *LintOptions) lintResource(path string) error { return err } - if err = validate(valueBytes, &un); err != nil { + gvk := un.GroupVersionKind() + if gvk.Group == rollouts.Group && gvk.Kind == rollouts.RolloutKind { + var ro v1alpha1.Rollout + err := unmarshal(valueBytes, &ro) + if err != nil { + return err + } + fileRollouts = append(fileRollouts, ro) + } + err = buildAllReferencedResources(un, &refResource) + if err != nil { return err } } + setServiceTypeAndManagedAnnotation(fileRollouts, refResource) + setIngressManagedAnnotation(fileRollouts, refResource) + setVirtualServiceManagedAnnotation(fileRollouts, refResource) + + var errList field.ErrorList + for _, rollout := range fileRollouts { + roRef := matchRolloutToReferences(rollout, refResource) + + errList = append(errList, validation.ValidateRollout(&roRef.Rollout)...) + errList = append(errList, validation.ValidateRolloutReferencedResources(&roRef.Rollout, roRef.References)...) + } + + for _, e := range errList { + fmt.Println(e.ErrorBody()) + } + if len(errList) > 0 { + return errList[0] + } else { + return nil + } +} + +// buildAllReferencedResources This builds a ReferencedResources object that has all the external resources for every +// rollout resource in the manifest. We will need to later match each referenced resource to its own rollout resource +// before passing the rollout object and its managed reference on to validation. +func buildAllReferencedResources(un unstructured.Unstructured, refResource *validation.ReferencedResources) error { + + valueBytes, err := un.MarshalJSON() + if err != nil { + return err + } + + gvk := un.GroupVersionKind() + switch { + case gvk.Group == v1.GroupName && gvk.Kind == "Service": + var svc v1.Service + err := unmarshal(valueBytes, &svc) + if err != nil { + return err + } + refResource.ServiceWithType = append(refResource.ServiceWithType, validation.ServiceWithType{ + Service: &svc, + }) + + case gvk.Group == "networking.istio.io" && gvk.Kind == "VirtualService": + refResource.VirtualServices = append(refResource.VirtualServices, un) + + case (gvk.Group == networkingv1.GroupName || gvk.Group == extensionsv1beta1.GroupName) && gvk.Kind == "Ingress": + var ing networkingv1.Ingress + var ingv1beta1 extensionsv1beta1.Ingress + if gvk.Version == "v1" { + err := unmarshal(valueBytes, &ing) + if err != nil { + return err + } + refResource.Ingresses = append(refResource.Ingresses, *ingressutil.NewIngress(&ing)) + } else if gvk.Version == "v1beta1" { + err := unmarshal(valueBytes, &ingv1beta1) + if err != nil { + return err + } + refResource.Ingresses = append(refResource.Ingresses, *ingressutil.NewLegacyIngress(&ingv1beta1)) + } + + } return nil } + +// matchRolloutToReferences This function goes through the global list of all ReferencedResources in the manifest and matches +// them up with their respective rollout object so that we can latter have a mapping of a single rollout object and its +// referenced resources. +func matchRolloutToReferences(rollout v1alpha1.Rollout, refResource validation.ReferencedResources) roAndReferences { + matchedReferenceResources := roAndReferences{Rollout: rollout, References: validation.ReferencedResources{}} + + for _, service := range refResource.ServiceWithType { + if service.Service.Annotations[v1alpha1.ManagedByRolloutsKey] == rollout.Name { + matchedReferenceResources.References.ServiceWithType = append(matchedReferenceResources.References.ServiceWithType, service) + } + } + for _, ingress := range refResource.Ingresses { + if ingress.GetAnnotations()[v1alpha1.ManagedByRolloutsKey] == rollout.Name { + matchedReferenceResources.References.Ingresses = append(matchedReferenceResources.References.Ingresses, ingress) + } + } + for _, virtualService := range refResource.VirtualServices { + if virtualService.GetAnnotations()[v1alpha1.ManagedByRolloutsKey] == rollout.Name { + matchedReferenceResources.References.VirtualServices = append(matchedReferenceResources.References.VirtualServices, virtualService) + } + } + + return matchedReferenceResources +} + +// setServiceTypeAndManagedAnnotation This sets the managed annotation on each service as well as figures out what +// type of service its is by looking at the rollout and set's its service type accordingly. +func setServiceTypeAndManagedAnnotation(rollouts []v1alpha1.Rollout, refResource validation.ReferencedResources) { + for _, rollout := range rollouts { + for i := range refResource.ServiceWithType { + + if refResource.ServiceWithType[i].Service.Annotations == nil { + refResource.ServiceWithType[i].Service.Annotations = make(map[string]string) + } + + if rollout.Spec.Strategy.Canary != nil { + if rollout.Spec.Strategy.Canary.CanaryService == refResource.ServiceWithType[i].Service.Name { + refResource.ServiceWithType[i].Type = validation.CanaryService + refResource.ServiceWithType[i].Service.Annotations[v1alpha1.ManagedByRolloutsKey] = rollout.Name + } + if rollout.Spec.Strategy.Canary.StableService == refResource.ServiceWithType[i].Service.Name { + refResource.ServiceWithType[i].Type = validation.StableService + refResource.ServiceWithType[i].Service.Annotations[v1alpha1.ManagedByRolloutsKey] = rollout.Name + } + if rollout.Spec.Strategy.Canary.PingPong != nil { + if rollout.Spec.Strategy.Canary.PingPong.PingService == refResource.ServiceWithType[i].Service.Name { + refResource.ServiceWithType[i].Type = validation.PingService + refResource.ServiceWithType[i].Service.Annotations[v1alpha1.ManagedByRolloutsKey] = rollout.Name + } + if rollout.Spec.Strategy.Canary.PingPong.PongService == refResource.ServiceWithType[i].Service.Name { + refResource.ServiceWithType[i].Type = validation.PongService + refResource.ServiceWithType[i].Service.Annotations[v1alpha1.ManagedByRolloutsKey] = rollout.Name + } + } + } + + if rollout.Spec.Strategy.BlueGreen != nil { + if rollout.Spec.Strategy.BlueGreen.ActiveService == refResource.ServiceWithType[i].Service.Name { + refResource.ServiceWithType[i].Type = validation.ActiveService + refResource.ServiceWithType[i].Service.Annotations[v1alpha1.ManagedByRolloutsKey] = rollout.Name + } + if rollout.Spec.Strategy.BlueGreen.PreviewService == refResource.ServiceWithType[i].Service.Name { + refResource.ServiceWithType[i].Type = validation.PreviewService + refResource.ServiceWithType[i].Service.Annotations[v1alpha1.ManagedByRolloutsKey] = rollout.Name + } + } + + } + } +} + +// setIngressManagedAnnotation This tries to find ingresses that have matching services in the rollout resource and if so +// it will add the managed by annotations just for linting so that we can later match up resources to a rollout resources +// for the case when we have multiple rollout resources in a single manifest. +func setIngressManagedAnnotation(rollouts []v1alpha1.Rollout, refResource validation.ReferencedResources) { + for _, rollout := range rollouts { + for i := range refResource.Ingresses { + var serviceName string + if rollout.Spec.Strategy.Canary.TrafficRouting.Nginx != nil { + serviceName = rollout.Spec.Strategy.Canary.StableService + } else if rollout.Spec.Strategy.Canary.TrafficRouting.ALB != nil { + serviceName = rollout.Spec.Strategy.Canary.StableService + if rollout.Spec.Strategy.Canary.TrafficRouting.ALB.RootService != "" { + serviceName = rollout.Spec.Strategy.Canary.TrafficRouting.ALB.RootService + } + } else if rollout.Spec.Strategy.Canary.TrafficRouting.SMI != nil { + serviceName = rollout.Spec.Strategy.Canary.TrafficRouting.SMI.RootService + } + + if ingressutil.HasRuleWithService(&refResource.Ingresses[i], serviceName) { + annotations := refResource.Ingresses[i].GetAnnotations() + if annotations == nil { + annotations = make(map[string]string) + } + annotations[v1alpha1.ManagedByRolloutsKey] = rollout.Name + refResource.Ingresses[i].SetAnnotations(annotations) + } + } + } +} + +// setVirtualServiceManagedAnnotation This function finds virtual services that are listed in the rollout resources and +// adds the ManagedByRolloutsKey to the annotations of the virtual services. +func setVirtualServiceManagedAnnotation(ro []v1alpha1.Rollout, refResource validation.ReferencedResources) { + for _, rollout := range ro { + for i := range refResource.VirtualServices { + if rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService != nil && rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name == refResource.VirtualServices[i].GetName() { + annotations := refResource.VirtualServices[i].GetAnnotations() + if annotations == nil { + annotations = make(map[string]string) + } + annotations[v1alpha1.ManagedByRolloutsKey] = rollout.Name + refResource.VirtualServices[i].SetAnnotations(annotations) + } + for _, virtualService := range rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualServices { + if virtualService.Name == refResource.VirtualServices[i].GetName() { + annotations := refResource.VirtualServices[i].GetAnnotations() + if annotations == nil { + annotations = make(map[string]string) + } + annotations[v1alpha1.ManagedByRolloutsKey] = rollout.Name + refResource.VirtualServices[i].SetAnnotations(annotations) + } + } + } + } +} diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/lint_test.go b/pkg/kubectl-argo-rollouts/cmd/lint/lint_test.go index 1780dbcc8b..554c4820db 100644 --- a/pkg/kubectl-argo-rollouts/cmd/lint/lint_test.go +++ b/pkg/kubectl-argo-rollouts/cmd/lint/lint_test.go @@ -15,13 +15,30 @@ func TestLintValidRollout(t *testing.T) { cmd := NewCmdLint(o) cmd.PersistentPreRunE = o.PersistentPreRunE - for _, filename := range []string{"testdata/valid.yml", "testdata/valid-workload-ref.yaml", "testdata/valid-with-another-empty-object.yml"} { - cmd.SetArgs([]string{"-f", filename}) - err := cmd.Execute() - assert.NoError(t, err) + tests := []string{ + "testdata/valid.yml", + "testdata/valid.json", + "testdata/valid-workload-ref.yaml", + "testdata/valid-with-another-empty-object.yml", + "testdata/valid-istio-v1alpha3.yml", + "testdata/valid-istio-v1beta1.yml", + "testdata/valid-blue-green.yml", + "testdata/valid-ingress-smi.yml", + "testdata/valid-ingress-smi-multi.yml", + "testdata/valid-alb-canary.yml", + "testdata/valid-nginx-canary.yml", + "testdata/valid-istio-v1beta1-mulitiple-virtualsvcs.yml", + } + + for _, filename := range tests { + t.Run(filename, func(t *testing.T) { + cmd.SetArgs([]string{"-f", filename}) + err := cmd.Execute() + assert.NoError(t, err) - stdout := o.Out.(*bytes.Buffer).String() - assert.Empty(t, stdout) + stdout := o.Out.(*bytes.Buffer).String() + assert.Empty(t, stdout) + }) } } @@ -32,36 +49,56 @@ func TestLintInvalidRollout(t *testing.T) { filename string errmsg string }{ - { "testdata/invalid.yml", "Error: spec.strategy.maxSurge: Invalid value: intstr.IntOrString{Type:0, IntVal:0, StrVal:\"\"}: MaxSurge and MaxUnavailable both can not be zero\n", }, + { + "testdata/invalid.json", + "Error: spec.strategy.maxSurge: Invalid value: intstr.IntOrString{Type:0, IntVal:0, StrVal:\"\"}: MaxSurge and MaxUnavailable both can not be zero\n", + }, { "testdata/invalid-multiple-docs.yml", "Error: spec.strategy.maxSurge: Invalid value: intstr.IntOrString{Type:0, IntVal:0, StrVal:\"\"}: MaxSurge and MaxUnavailable both can not be zero\n", }, - { "testdata/invalid-unknown-field.yml", "Error: error unmarshaling JSON: while decoding JSON: json: unknown field \"unknown-strategy\"\n", }, + { + "testdata/invalid-service-labels.yml", + "Error: spec.strategy.canary.canaryService: Invalid value: \"istio-host-split-canary\": Service \"istio-host-split-canary\" has unmatch lable \"app\" in rollout\n", + }, + { + "testdata/invalid-ping-pong.yml", + "Error: spec.strategy.canary.pingPong.pingService: Invalid value: \"ping-service\": Service \"ping-service\" has unmatch lable \"app\" in rollout\n", + }, + { + "testdata/invalid-ingress-smi-multi.yml", + "Error: spec.strategy.canary.canaryService: Invalid value: \"rollout-smi-experiment-canary\": Service \"rollout-smi-experiment-canary\" has unmatch lable \"app\" in rollout\n", + }, + { + filename: "testdata/invalid-nginx-canary.yml", + errmsg: "Error: spec.strategy.steps[1].experiment.templates[0].weight: Invalid value: 20: Experiment template weight is only available for TrafficRouting with SMI, ALB, and Istio at this time\n", + }, } runCmd = func(filename string, errmsg string) { - tf, o := options.NewFakeArgoRolloutsOptions() - defer tf.Cleanup() + t.Run(filename, func(t *testing.T) { + tf, o := options.NewFakeArgoRolloutsOptions() + defer tf.Cleanup() - cmd := NewCmdLint(o) - cmd.PersistentPreRunE = o.PersistentPreRunE - cmd.SetArgs([]string{"-f", filename}) - err := cmd.Execute() - assert.Error(t, err) + cmd := NewCmdLint(o) + cmd.PersistentPreRunE = o.PersistentPreRunE + cmd.SetArgs([]string{"-f", filename}) + err := cmd.Execute() + assert.Error(t, err) - stdout := o.Out.(*bytes.Buffer).String() - stderr := o.ErrOut.(*bytes.Buffer).String() - assert.Empty(t, stdout) - assert.Equal(t, errmsg, stderr) + stdout := o.Out.(*bytes.Buffer).String() + stderr := o.ErrOut.(*bytes.Buffer).String() + assert.Empty(t, stdout) + assert.Equal(t, errmsg, stderr) + }) } for _, t := range tests { diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-ingress-smi-multi.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-ingress-smi-multi.yml new file mode 100644 index 0000000000..fc04b8deb7 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-ingress-smi-multi.yml @@ -0,0 +1,244 @@ +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-canary +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment-miss +--- +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-stable +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment-miss +--- +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-root +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment-miss +--- +apiVersion: split.smi-spec.io/v1alpha1 +kind: TrafficSplit +metadata: + name: rollout-smi-experiment-split +spec: + service: rollout-smi-experiment-root + backends: + - service: rollout-smi-experiment-stable + weight: 95 + - service: rollout-smi-experiment-canary + weight: 5 +--- +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: rollout-smi-experiment-stable + annotations: + kubernetes.io/ingress.class: nginx +spec: + rules: + - host: rollout-smi-experiment.local + http: + paths: + - path: / + backend: + serviceName: rollout-smi-experiment-stable + servicePort: 80 + - host: rollout-smi-experiment-root.local + http: + paths: + - path: / + backend: + serviceName: rollout-smi-experiment-root + servicePort: 80 +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollout-smi-experiment +spec: + replicas: 1 + strategy: + canary: + canaryService: rollout-smi-experiment-canary + stableService: rollout-smi-experiment-stable + trafficRouting: + smi: + trafficSplitName: rollout-smi-experiment-split + rootService: rollout-smi-experiment-root + steps: + - setWeight: 5 + - experiment: + templates: + - name: experiment-smi + specRef: canary + weight: 5 + revisionHistoryLimit: 2 + selector: + matchLabels: + app: rollout-smi-experiment + template: + metadata: + labels: + app: rollout-smi-experiment + spec: + containers: + - name: rollout-smi-experiment + image: argoproj/rollouts-demo:blue + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m + + + + + +--- + + + + +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-canary-1 +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment-1 +--- +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-stable-1 +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment-1 +--- +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-root-1 +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment-1 +--- +apiVersion: split.smi-spec.io/v1alpha1 +kind: TrafficSplit +metadata: + name: rollout-smi-experiment-split-1 +spec: + service: rollout-smi-experiment-root-1 + backends: + - service: rollout-smi-experiment-stable-1 + weight: 95 + - service: rollout-smi-experiment-canary-1 + weight: 5 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: rollout-smi-experiment-stable-1 + annotations: + kubernetes.io/ingress.class: nginx +spec: + rules: + - host: rollout-smi-experiment.local + http: + paths: + - path: / + backend: + service: + name: rollout-smi-experiment-stable-1 + port: + number: 80 + - host: rollout-smi-experiment-root.local + http: + paths: + - path: / + backend: + service: + name: rollout-smi-experiment-root-1 + port: + number: 80 +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollout-smi-experiment-1 +spec: + replicas: 1 + strategy: + canary: + canaryService: rollout-smi-experiment-canary-1 + stableService: rollout-smi-experiment-stable-1 + trafficRouting: + smi: + trafficSplitName: rollout-smi-experiment-split-1 + rootService: rollout-smi-experiment-root-1 + steps: + - setWeight: 5 + - experiment: + templates: + - name: experiment-smi + specRef: canary + weight: 5 + revisionHistoryLimit: 2 + selector: + matchLabels: + app: rollout-smi-experiment-1 + template: + metadata: + labels: + app: rollout-smi-experiment-1 + spec: + containers: + - name: rollout-smi-experiment + image: argoproj/rollouts-demo:blue + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m \ No newline at end of file diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-nginx-canary.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-nginx-canary.yml new file mode 100644 index 0000000000..ec90d8ad2d --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-nginx-canary.yml @@ -0,0 +1,95 @@ +apiVersion: v1 +kind: Service +metadata: + name: nginx-rollout-root +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: nginx-rollout +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx-rollout-canary +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: nginx-rollout +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx-rollout-stable +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: nginx-rollout +--- +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: nginx-rollout-ingress + annotations: + kubernetes.io/ingress.class: nginx +spec: + rules: + - http: + paths: + - path: /* + backend: + serviceName: nginx-rollout-root + servicePort: use-annotation +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: nginx-rollout +spec: + selector: + matchLabels: + app: nginx-rollout + template: + metadata: + labels: + app: nginx-rollout + spec: + containers: + - name: nginx-rollout + image: argoproj/rollouts-demo:blue + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m + strategy: + canary: + canaryService: nginx-rollout-canary + stableService: nginx-rollout-stable + trafficRouting: + nginx: + stableIngress: nginx-rollout-ingress + steps: + - setWeight: 10 + - experiment: + templates: + - name: experiment-nginx + specRef: canary + weight: 20 diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-ping-pong.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-ping-pong.yml new file mode 100644 index 0000000000..a0c908dce8 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-ping-pong.yml @@ -0,0 +1,69 @@ +# Miss matched labels on service +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: invalid-rollout +spec: + revisionHistoryLimit: 1 + replicas: 10 + strategy: + canary: + pingPong: #Indicates that the ping-pong services enabled + pingService: ping-service + pongService: pong-service + maxUnavailable: 0 + maxSurge: 1 + analysis: + templates: + - templateName: integrationtests + steps: + - setWeight: 10 + - setWeight: 20 + - setWeight: 40 + - setWeight: 80 + selector: + matchLabels: + app: invalid-rollout + template: + metadata: + labels: + app: invalid-rollout + spec: + containers: + - name: invalid-rollout + image: invalid-rollout:0.0.0 + ports: + - name: http + containerPort: 8080 + protocol: TCP + readinessProbe: + httpGet: + path: /ping + port: 8080 + periodSeconds: 5 +--- +apiVersion: v1 +kind: Service +metadata: + name: ping-service +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: invalid-rollout-miss-match +--- +apiVersion: v1 +kind: Service +metadata: + name: pong-service +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: invalid-rollout-miss-match \ No newline at end of file diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-service-labels.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-service-labels.yml new file mode 100644 index 0000000000..705597f927 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-service-labels.yml @@ -0,0 +1,69 @@ +# Miss matched labels on service +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: invalid-rollout +spec: + revisionHistoryLimit: 1 + replicas: 10 + strategy: + canary: + canaryService: istio-host-split-canary + stableService: istio-host-split-stable + maxUnavailable: 0 + maxSurge: 1 + analysis: + templates: + - templateName: integrationtests + steps: + - setWeight: 10 + - setWeight: 20 + - setWeight: 40 + - setWeight: 80 + selector: + matchLabels: + app: invalid-rollout + template: + metadata: + labels: + app: invalid-rollout + spec: + containers: + - name: invalid-rollout + image: invalid-rollout:0.0.0 + ports: + - name: http + containerPort: 8080 + protocol: TCP + readinessProbe: + httpGet: + path: /ping + port: 8080 + periodSeconds: 5 +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-canary +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-stable +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split \ No newline at end of file diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid.json b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid.json new file mode 100644 index 0000000000..09fbae6451 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid.json @@ -0,0 +1,72 @@ +{ + "apiVersion": "argoproj.io/v1alpha1", + "kind": "Rollout", + "metadata": { + "name": "invalid-rollout" + }, + "spec": { + "revisionHistoryLimit": 1, + "replicas": 1, + "strategy": { + "canary": { + "maxUnavailable": 0, + "maxSurge": 0, + "analysis": { + "templates": [ + { + "templateName": "integrationtests" + } + ] + }, + "steps": [ + { + "setWeight": 10 + }, + { + "setWeight": 20 + }, + { + "setWeight": 40 + }, + { + "setWeight": 80 + } + ] + } + }, + "selector": { + "matchLabels": { + "app": "invalid-rollout" + } + }, + "template": { + "metadata": { + "labels": { + "app": "invalid-rollout" + } + }, + "spec": { + "containers": [ + { + "name": "invalid-rollout", + "image": "invalid-rollout:0.0.0", + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + } + ], + "readinessProbe": { + "httpGet": { + "path": "/ping", + "port": 8080 + }, + "periodSeconds": 5 + } + } + ] + } + } + } +} diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-alb-canary.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-alb-canary.yml new file mode 100644 index 0000000000..c0b2131c74 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-alb-canary.yml @@ -0,0 +1,95 @@ +apiVersion: v1 +kind: Service +metadata: + name: alb-rollout-root +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: alb-rollout +--- +apiVersion: v1 +kind: Service +metadata: + name: alb-rollout-canary +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: alb-rollout +--- +apiVersion: v1 +kind: Service +metadata: + name: alb-rollout-stable +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: alb-rollout +--- +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: alb-rollout-ingress +spec: + rules: + - http: + paths: + - path: /* + backend: + serviceName: alb-rollout-root + servicePort: use-annotation +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: alb-rollout +spec: + selector: + matchLabels: + app: alb-rollout + template: + metadata: + labels: + app: alb-rollout + spec: + containers: + - name: alb-rollout + image: argoproj/rollouts-demo:blue + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m + strategy: + canary: + canaryService: alb-rollout-canary + stableService: alb-rollout-stable + trafficRouting: + alb: + ingress: alb-rollout-ingress + rootService: alb-rollout-root + servicePort: 80 + steps: + - setWeight: 10 + - experiment: + templates: + - name: experiment-alb + specRef: canary + weight: 20 diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-blue-green.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-blue-green.yml new file mode 100644 index 0000000000..ad93ae1c5e --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-blue-green.yml @@ -0,0 +1,51 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollout-bluegreen +spec: + replicas: 2 + revisionHistoryLimit: 2 + selector: + matchLabels: + app: rollout-bluegreen + template: + metadata: + labels: + app: rollout-bluegreen + spec: + containers: + - name: rollouts-demo + image: argoproj/rollouts-demo:blue + imagePullPolicy: Always + ports: + - containerPort: 8080 + strategy: + blueGreen: + activeService: rollout-bluegreen-active + previewService: rollout-bluegreen-preview + autoPromotionEnabled: false +--- +kind: Service +apiVersion: v1 +metadata: + name: rollout-bluegreen-active +spec: + selector: + app: rollout-bluegreen + ports: + - protocol: TCP + port: 80 + targetPort: 8080 + +--- +kind: Service +apiVersion: v1 +metadata: + name: rollout-bluegreen-preview +spec: + selector: + app: rollout-bluegreen + ports: + - protocol: TCP + port: 80 + targetPort: 8080 diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-ingress-smi-multi.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-ingress-smi-multi.yml new file mode 100644 index 0000000000..884eebf406 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-ingress-smi-multi.yml @@ -0,0 +1,244 @@ +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-canary +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment +--- +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-stable +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment +--- +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-root +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment +--- +apiVersion: split.smi-spec.io/v1alpha1 +kind: TrafficSplit +metadata: + name: rollout-smi-experiment-split +spec: + service: rollout-smi-experiment-root + backends: + - service: rollout-smi-experiment-stable + weight: 95 + - service: rollout-smi-experiment-canary + weight: 5 +--- +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: rollout-smi-experiment-stable + annotations: + kubernetes.io/ingress.class: nginx +spec: + rules: + - host: rollout-smi-experiment.local + http: + paths: + - path: / + backend: + serviceName: rollout-smi-experiment-stable + servicePort: 80 + - host: rollout-smi-experiment-root.local + http: + paths: + - path: / + backend: + serviceName: rollout-smi-experiment-root + servicePort: 80 +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollout-smi-experiment +spec: + replicas: 1 + strategy: + canary: + canaryService: rollout-smi-experiment-canary + stableService: rollout-smi-experiment-stable + trafficRouting: + smi: + trafficSplitName: rollout-smi-experiment-split + rootService: rollout-smi-experiment-root + steps: + - setWeight: 5 + - experiment: + templates: + - name: experiment-smi + specRef: canary + weight: 5 + revisionHistoryLimit: 2 + selector: + matchLabels: + app: rollout-smi-experiment + template: + metadata: + labels: + app: rollout-smi-experiment + spec: + containers: + - name: rollout-smi-experiment + image: argoproj/rollouts-demo:blue + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m + + + + + +--- + + + + +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-canary-1 +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment-1 +--- +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-stable-1 +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment-1 +--- +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-root-1 +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment-1 +--- +apiVersion: split.smi-spec.io/v1alpha1 +kind: TrafficSplit +metadata: + name: rollout-smi-experiment-split-1 +spec: + service: rollout-smi-experiment-root-1 + backends: + - service: rollout-smi-experiment-stable-1 + weight: 95 + - service: rollout-smi-experiment-canary-1 + weight: 5 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: rollout-smi-experiment-stable-1 + annotations: + kubernetes.io/ingress.class: nginx +spec: + rules: + - host: rollout-smi-experiment.local + http: + paths: + - path: / + backend: + service: + name: rollout-smi-experiment-stable-1 + port: + number: 80 + - host: rollout-smi-experiment-root.local + http: + paths: + - path: / + backend: + service: + name: rollout-smi-experiment-root-1 + port: + number: 80 +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollout-smi-experiment-1 +spec: + replicas: 1 + strategy: + canary: + canaryService: rollout-smi-experiment-canary-1 + stableService: rollout-smi-experiment-stable-1 + trafficRouting: + smi: + trafficSplitName: rollout-smi-experiment-split-1 + rootService: rollout-smi-experiment-root-1 + steps: + - setWeight: 5 + - experiment: + templates: + - name: experiment-smi + specRef: canary + weight: 5 + revisionHistoryLimit: 2 + selector: + matchLabels: + app: rollout-smi-experiment-1 + template: + metadata: + labels: + app: rollout-smi-experiment-1 + spec: + containers: + - name: rollout-smi-experiment + image: argoproj/rollouts-demo:blue + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m \ No newline at end of file diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-ingress-smi.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-ingress-smi.yml new file mode 100644 index 0000000000..63f9e6cddf --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-ingress-smi.yml @@ -0,0 +1,115 @@ +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-canary +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment +--- +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-stable +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment +--- +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-root +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment +--- +apiVersion: split.smi-spec.io/v1alpha1 +kind: TrafficSplit +metadata: + name: rollout-smi-experiment-split +spec: + service: rollout-smi-experiment-root + backends: + - service: rollout-smi-experiment-stable + weight: 95 + - service: rollout-smi-experiment-canary + weight: 5 +--- +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: rollout-smi-experiment-stable + annotations: + kubernetes.io/ingress.class: nginx +spec: + rules: + - host: rollout-smi-experiment.local + http: + paths: + - path: / + backend: + serviceName: rollout-smi-experiment-stable + servicePort: 80 + - host: rollout-smi-experiment-root.local + http: + paths: + - path: / + backend: + serviceName: rollout-smi-experiment-root + servicePort: 80 +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollout-smi-experiment +spec: + replicas: 1 + strategy: + canary: + canaryService: rollout-smi-experiment-canary + stableService: rollout-smi-experiment-stable + trafficRouting: + smi: + trafficSplitName: rollout-smi-experiment-split + rootService: rollout-smi-experiment-root + steps: + - setWeight: 5 + - experiment: + templates: + - name: experiment-smi + specRef: canary + weight: 5 + revisionHistoryLimit: 2 + selector: + matchLabels: + app: rollout-smi-experiment + template: + metadata: + labels: + app: rollout-smi-experiment + spec: + containers: + - name: rollout-smi-experiment + image: argoproj/rollouts-demo:blue + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1alpha3.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1alpha3.yml new file mode 100644 index 0000000000..1de296d451 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1alpha3.yml @@ -0,0 +1,88 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-canary +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-stable +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: istio-host-split-vsvc +spec: + hosts: + - istio-host-split.com + gateways: + - istio-host-split-gateway + http: + - name: primary + route: + - destination: + host: istio-host-split-stable + weight: 100 + - destination: + host: istio-host-split-canary + weight: 0 +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: istio-host-split +spec: + strategy: + canary: + canaryService: istio-host-split-canary + stableService: istio-host-split-stable + trafficRouting: + istio: + virtualService: + name: istio-host-split-vsvc + routes: + - primary + steps: + - setWeight: 10 + - experiment: + templates: + - name: experiment-istio + specRef: canary + weight: 20 + selector: + matchLabels: + app: istio-host-split + template: + metadata: + labels: + app: istio-host-split + spec: + containers: + - name: istio-host-split + image: argoproj/rollouts-demo:red + ports: + - name: http + containerPort: 8080 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m \ No newline at end of file diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1beta1-mulitiple-virtualsvcs.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1beta1-mulitiple-virtualsvcs.yml new file mode 100644 index 0000000000..346de2e287 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1beta1-mulitiple-virtualsvcs.yml @@ -0,0 +1,110 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-canary +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-stable +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +metadata: + name: istio-host-split-vsvc +spec: + hosts: + - istio-host-split.com + gateways: + - istio-host-split-gateway + http: + - name: primary + route: + - destination: + host: istio-host-split-stable + weight: 100 + - destination: + host: istio-host-split-canary + weight: 0 +--- +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +metadata: + name: istio-host-split-vsvc-1 +spec: + hosts: + - istio-host-split.com + gateways: + - istio-host-split-gateway + http: + - name: primary + route: + - destination: + host: istio-host-split-stable + weight: 100 + - destination: + host: istio-host-split-canary + weight: 0 +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: istio-host-split +spec: + strategy: + canary: + canaryService: istio-host-split-canary + stableService: istio-host-split-stable + trafficRouting: + istio: + virtualServices: + - name: istio-host-split-vsvc + routes: + - primary + - name: istio-host-split-vsvc-1 + routes: + - primary + steps: + - setWeight: 10 + - experiment: + templates: + - name: experiment-istio + specRef: canary + weight: 20 + selector: + matchLabels: + app: istio-host-split + template: + metadata: + labels: + app: istio-host-split + spec: + containers: + - name: istio-host-split + image: argoproj/rollouts-demo:red + ports: + - name: http + containerPort: 8080 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m \ No newline at end of file diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1beta1.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1beta1.yml new file mode 100644 index 0000000000..d793401a9f --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1beta1.yml @@ -0,0 +1,88 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-canary +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-stable +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +metadata: + name: istio-host-split-vsvc +spec: + hosts: + - istio-host-split.com + gateways: + - istio-host-split-gateway + http: + - name: primary + route: + - destination: + host: istio-host-split-stable + weight: 100 + - destination: + host: istio-host-split-canary + weight: 0 +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: istio-host-split +spec: + strategy: + canary: + canaryService: istio-host-split-canary + stableService: istio-host-split-stable + trafficRouting: + istio: + virtualService: + name: istio-host-split-vsvc + routes: + - primary + steps: + - setWeight: 10 + - experiment: + templates: + - name: experiment-istio + specRef: canary + weight: 20 + selector: + matchLabels: + app: istio-host-split + template: + metadata: + labels: + app: istio-host-split + spec: + containers: + - name: istio-host-split + image: argoproj/rollouts-demo:red + ports: + - name: http + containerPort: 8080 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m \ No newline at end of file diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-nginx-canary.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-nginx-canary.yml new file mode 100644 index 0000000000..30fe00ca12 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-nginx-canary.yml @@ -0,0 +1,88 @@ +apiVersion: v1 +kind: Service +metadata: + name: nginx-rollout-root +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: nginx-rollout +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx-rollout-canary +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: nginx-rollout +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx-rollout-stable +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: nginx-rollout +--- +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: nginx-rollout-ingress +spec: + rules: + - http: + paths: + - path: /* + backend: + serviceName: nginx-rollout-root + servicePort: use-annotation +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: nginx-rollout +spec: + selector: + matchLabels: + app: nginx-rollout + template: + metadata: + labels: + app: nginx-rollout + spec: + containers: + - name: nginx-rollout + image: argoproj/rollouts-demo:blue + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m + strategy: + canary: + canaryService: nginx-rollout-canary + stableService: nginx-rollout-stable + trafficRouting: + nginx: + stableIngress: nginx-rollout-ingress + steps: + - setWeight: 10 diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid.json b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid.json new file mode 100644 index 0000000000..df85628af7 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid.json @@ -0,0 +1,72 @@ +{ + "apiVersion": "argoproj.io/v1alpha1", + "kind": "Rollout", + "metadata": { + "name": "valid-rollout" + }, + "spec": { + "revisionHistoryLimit": 1, + "replicas": 10, + "strategy": { + "canary": { + "maxUnavailable": 0, + "maxSurge": 1, + "analysis": { + "templates": [ + { + "templateName": "integrationtests" + } + ] + }, + "steps": [ + { + "setWeight": 10 + }, + { + "setWeight": 20 + }, + { + "setWeight": 40 + }, + { + "setWeight": 80 + } + ] + } + }, + "selector": { + "matchLabels": { + "app": "valid-rollout" + } + }, + "template": { + "metadata": { + "labels": { + "app": "valid-rollout" + } + }, + "spec": { + "containers": [ + { + "name": "valid-rollout", + "image": "valid-rollout:0.0.0", + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + } + ], + "readinessProbe": { + "httpGet": { + "path": "/ping", + "port": 8080 + }, + "periodSeconds": 5 + } + } + ] + } + } + } +} From c5ee36139740223cf9ea19809ae5041ed59749fd Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Wed, 25 May 2022 14:59:46 -0500 Subject: [PATCH 130/175] docs: add selector to migrating page (#2039) Signed-off-by: zachaller --- docs/migrating.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/migrating.md b/docs/migrating.md index e0d9754df0..ee603a2999 100644 --- a/docs/migrating.md +++ b/docs/migrating.md @@ -66,6 +66,9 @@ metadata: name: rollout-ref-deployment spec: replicas: 5 + selector: + matchLabels: + app: rollout-ref-deployment workloadRef: # Reference an existing Deployment using workloadRef field apiVersion: apps/v1 kind: Deployment @@ -150,4 +153,4 @@ When a rollout is referencing to a deployment: 1. Scale-up the Deployment by changing `replicas` field of an existing Rollout to zero. 1. Scale-down existing Rollout by changing `replicas` field of an existing Rollout to zero. -Please refer to [Running Rollout and Deployment side-by-side](#running-rollout-and-deployment-side-by-side) and [Traffic Management During Migration](#traffic-management-during-migration) for caveats. \ No newline at end of file +Please refer to [Running Rollout and Deployment side-by-side](#running-rollout-and-deployment-side-by-side) and [Traffic Management During Migration](#traffic-management-during-migration) for caveats. From 94cdfd5aa4d316f1621167fef8c606befcaf78a6 Mon Sep 17 00:00:00 2001 From: schakrad <58915923+schakrad@users.noreply.github.com> Date: Thu, 26 May 2022 14:17:34 -0400 Subject: [PATCH 131/175] feature: Dashboard now displaying analysis details (#1910) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: “schakradari” Co-authored-by: Alexander Matyushentsev Co-authored-by: Daniel Helfand Co-authored-by: Michael Crenshaw Co-authored-by: Tomas Valasek <13797085+tvalasek@users.noreply.github.com> --- Makefile | 1 + hack/swagger-codegen.sh | 9 + pkg/apiclient/rollout/rollout.pb.go | 1153 +++++++++++++++-- pkg/apiclient/rollout/rollout.proto | 25 +- pkg/apiclient/rollout/rollout.swagger.json | 70 +- pkg/kubectl-argo-rollouts/cmd/get/get_test.go | 7 + .../info/analysisrun_info.go | 68 +- .../info/experiment_info.go | 2 +- .../info/replicaset_info.go | 2 +- .../info/rollout_info.go | 2 +- .../experiment-analysis/canary-analysis.yaml | 156 +-- ui/package.json | 4 +- ui/src/app/components/pods/pods.scss | 2 + ui/src/app/components/pods/pods.tsx | 81 +- ui/src/app/components/rollout/revision.tsx | 199 ++- ui/src/app/components/rollout/rollout.scss | 90 +- ui/src/app/components/rollout/rollout.tsx | 37 +- .../rollouts-list/rollouts-list.scss | 6 +- ui/src/models/rollout/generated/api.ts | 711 +++++++++- ui/yarn.lock | 2 +- utils/analysis/helpers.go | 8 + utils/analysis/helpers_test.go | 25 + 22 files changed, 2312 insertions(+), 348 deletions(-) create mode 100755 hack/swagger-codegen.sh diff --git a/Makefile b/Makefile index 5b67005c74..3302b41c1d 100644 --- a/Makefile +++ b/Makefile @@ -115,6 +115,7 @@ api-proto: go-mod-vendor k8s-proto # generates ui related proto files .PHONY: ui-proto +ui-proto: yarn --cwd ui run protogen # generates k8s client, informer, lister, deepcopy from types.go diff --git a/hack/swagger-codegen.sh b/hack/swagger-codegen.sh new file mode 100755 index 0000000000..8b5dc9c3d2 --- /dev/null +++ b/hack/swagger-codegen.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +export SWAGGER_CODEGEN_VERSION=3.0.25 +PROJECT_ROOT=$(cd $(dirname ${BASH_SOURCE})/..; pwd) + +test -f "/tmp/swagger-codegen-cli-${SWAGGER_CODEGEN_VERSION}.jar" || \ + curl https://repo1.maven.org/maven2/io/swagger/codegen/v3/swagger-codegen-cli/${SWAGGER_CODEGEN_VERSION}/swagger-codegen-cli-${SWAGGER_CODEGEN_VERSION}.jar -o "/tmp/swagger-codegen-cli-${SWAGGER_CODEGEN_VERSION}.jar" + +docker run --rm -v /tmp:/tmp -v $PROJECT_ROOT:/src -w /src/ui -t maven:3-jdk-8 java -jar /tmp/swagger-codegen-cli-${SWAGGER_CODEGEN_VERSION}.jar $@ \ No newline at end of file diff --git a/pkg/apiclient/rollout/rollout.pb.go b/pkg/apiclient/rollout/rollout.pb.go index 584dc967cd..4f36576290 100644 --- a/pkg/apiclient/rollout/rollout.pb.go +++ b/pkg/apiclient/rollout/rollout.pb.go @@ -908,7 +908,7 @@ func (m *RolloutInfo) GetSteps() []*v1alpha1.CanaryStep { type ExperimentInfo struct { ObjectMeta *v1.ObjectMeta `protobuf:"bytes,1,opt,name=objectMeta,proto3" json:"objectMeta,omitempty"` Icon string `protobuf:"bytes,2,opt,name=icon,proto3" json:"icon,omitempty"` - Revision int32 `protobuf:"varint,3,opt,name=revision,proto3" json:"revision,omitempty"` + Revision int64 `protobuf:"varint,3,opt,name=revision,proto3" json:"revision,omitempty"` Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` Message string `protobuf:"bytes,5,opt,name=message,proto3" json:"message,omitempty"` ReplicaSets []*ReplicaSetInfo `protobuf:"bytes,6,rep,name=replicaSets,proto3" json:"replicaSets,omitempty"` @@ -965,7 +965,7 @@ func (m *ExperimentInfo) GetIcon() string { return "" } -func (m *ExperimentInfo) GetRevision() int32 { +func (m *ExperimentInfo) GetRevision() int64 { if m != nil { return m.Revision } @@ -1004,7 +1004,7 @@ type ReplicaSetInfo struct { ObjectMeta *v1.ObjectMeta `protobuf:"bytes,1,opt,name=objectMeta,proto3" json:"objectMeta,omitempty"` Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` Icon string `protobuf:"bytes,3,opt,name=icon,proto3" json:"icon,omitempty"` - Revision int32 `protobuf:"varint,4,opt,name=revision,proto3" json:"revision,omitempty"` + Revision int64 `protobuf:"varint,4,opt,name=revision,proto3" json:"revision,omitempty"` Stable bool `protobuf:"varint,5,opt,name=stable,proto3" json:"stable,omitempty"` Canary bool `protobuf:"varint,6,opt,name=canary,proto3" json:"canary,omitempty"` Active bool `protobuf:"varint,7,opt,name=active,proto3" json:"active,omitempty"` @@ -1076,7 +1076,7 @@ func (m *ReplicaSetInfo) GetIcon() string { return "" } -func (m *ReplicaSetInfo) GetRevision() int32 { +func (m *ReplicaSetInfo) GetRevision() int64 { if m != nil { return m.Revision } @@ -1305,6 +1305,8 @@ type JobInfo struct { ObjectMeta *v1.ObjectMeta `protobuf:"bytes,1,opt,name=objectMeta,proto3" json:"objectMeta,omitempty"` Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` Icon string `protobuf:"bytes,3,opt,name=icon,proto3" json:"icon,omitempty"` + MetricName string `protobuf:"bytes,4,opt,name=metricName,proto3" json:"metricName,omitempty"` + StartedAt *v1.Time `protobuf:"bytes,5,opt,name=startedAt,proto3" json:"startedAt,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1364,16 +1366,32 @@ func (m *JobInfo) GetIcon() string { return "" } +func (m *JobInfo) GetMetricName() string { + if m != nil { + return m.MetricName + } + return "" +} + +func (m *JobInfo) GetStartedAt() *v1.Time { + if m != nil { + return m.StartedAt + } + return nil +} + type AnalysisRunInfo struct { ObjectMeta *v1.ObjectMeta `protobuf:"bytes,1,opt,name=objectMeta,proto3" json:"objectMeta,omitempty"` Icon string `protobuf:"bytes,2,opt,name=icon,proto3" json:"icon,omitempty"` - Revision int32 `protobuf:"varint,3,opt,name=revision,proto3" json:"revision,omitempty"` + Revision int64 `protobuf:"varint,3,opt,name=revision,proto3" json:"revision,omitempty"` Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` Successful int32 `protobuf:"varint,5,opt,name=successful,proto3" json:"successful,omitempty"` Failed int32 `protobuf:"varint,6,opt,name=failed,proto3" json:"failed,omitempty"` Inconclusive int32 `protobuf:"varint,7,opt,name=inconclusive,proto3" json:"inconclusive,omitempty"` Error int32 `protobuf:"varint,8,opt,name=error,proto3" json:"error,omitempty"` Jobs []*JobInfo `protobuf:"bytes,9,rep,name=jobs,proto3" json:"jobs,omitempty"` + NonJobInfo []*NonJobInfo `protobuf:"bytes,10,rep,name=nonJobInfo,proto3" json:"nonJobInfo,omitempty"` + Metrics []*Metrics `protobuf:"bytes,11,rep,name=metrics,proto3" json:"metrics,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1426,7 +1444,7 @@ func (m *AnalysisRunInfo) GetIcon() string { return "" } -func (m *AnalysisRunInfo) GetRevision() int32 { +func (m *AnalysisRunInfo) GetRevision() int64 { if m != nil { return m.Revision } @@ -1475,6 +1493,170 @@ func (m *AnalysisRunInfo) GetJobs() []*JobInfo { return nil } +func (m *AnalysisRunInfo) GetNonJobInfo() []*NonJobInfo { + if m != nil { + return m.NonJobInfo + } + return nil +} + +func (m *AnalysisRunInfo) GetMetrics() []*Metrics { + if m != nil { + return m.Metrics + } + return nil +} + +type NonJobInfo struct { + Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` + Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` + MetricName string `protobuf:"bytes,3,opt,name=metricName,proto3" json:"metricName,omitempty"` + StartedAt *v1.Time `protobuf:"bytes,4,opt,name=startedAt,proto3" json:"startedAt,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *NonJobInfo) Reset() { *m = NonJobInfo{} } +func (m *NonJobInfo) String() string { return proto.CompactTextString(m) } +func (*NonJobInfo) ProtoMessage() {} +func (*NonJobInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_99101d942e8912a7, []int{19} +} +func (m *NonJobInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *NonJobInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_NonJobInfo.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *NonJobInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_NonJobInfo.Merge(m, src) +} +func (m *NonJobInfo) XXX_Size() int { + return m.Size() +} +func (m *NonJobInfo) XXX_DiscardUnknown() { + xxx_messageInfo_NonJobInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_NonJobInfo proto.InternalMessageInfo + +func (m *NonJobInfo) GetValue() string { + if m != nil { + return m.Value + } + return "" +} + +func (m *NonJobInfo) GetStatus() string { + if m != nil { + return m.Status + } + return "" +} + +func (m *NonJobInfo) GetMetricName() string { + if m != nil { + return m.MetricName + } + return "" +} + +func (m *NonJobInfo) GetStartedAt() *v1.Time { + if m != nil { + return m.StartedAt + } + return nil +} + +type Metrics struct { + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + SuccessCondition string `protobuf:"bytes,2,opt,name=successCondition,proto3" json:"successCondition,omitempty"` + Count int32 `protobuf:"varint,3,opt,name=count,proto3" json:"count,omitempty"` + InconclusiveLimit int32 `protobuf:"varint,4,opt,name=inconclusiveLimit,proto3" json:"inconclusiveLimit,omitempty"` + FailureLimit int32 `protobuf:"varint,5,opt,name=failureLimit,proto3" json:"failureLimit,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Metrics) Reset() { *m = Metrics{} } +func (m *Metrics) String() string { return proto.CompactTextString(m) } +func (*Metrics) ProtoMessage() {} +func (*Metrics) Descriptor() ([]byte, []int) { + return fileDescriptor_99101d942e8912a7, []int{20} +} +func (m *Metrics) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Metrics) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Metrics.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Metrics) XXX_Merge(src proto.Message) { + xxx_messageInfo_Metrics.Merge(m, src) +} +func (m *Metrics) XXX_Size() int { + return m.Size() +} +func (m *Metrics) XXX_DiscardUnknown() { + xxx_messageInfo_Metrics.DiscardUnknown(m) +} + +var xxx_messageInfo_Metrics proto.InternalMessageInfo + +func (m *Metrics) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Metrics) GetSuccessCondition() string { + if m != nil { + return m.SuccessCondition + } + return "" +} + +func (m *Metrics) GetCount() int32 { + if m != nil { + return m.Count + } + return 0 +} + +func (m *Metrics) GetInconclusiveLimit() int32 { + if m != nil { + return m.InconclusiveLimit + } + return 0 +} + +func (m *Metrics) GetFailureLimit() int32 { + if m != nil { + return m.FailureLimit + } + return 0 +} + func init() { proto.RegisterType((*RolloutInfoQuery)(nil), "rollout.RolloutInfoQuery") proto.RegisterType((*RolloutInfoListQuery)(nil), "rollout.RolloutInfoListQuery") @@ -1495,6 +1677,8 @@ func init() { proto.RegisterType((*ContainerInfo)(nil), "rollout.ContainerInfo") proto.RegisterType((*JobInfo)(nil), "rollout.JobInfo") proto.RegisterType((*AnalysisRunInfo)(nil), "rollout.AnalysisRunInfo") + proto.RegisterType((*NonJobInfo)(nil), "rollout.NonJobInfo") + proto.RegisterType((*Metrics)(nil), "rollout.Metrics") } func init() { @@ -1502,107 +1686,117 @@ func init() { } var fileDescriptor_99101d942e8912a7 = []byte{ - // 1600 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0x4f, 0x6f, 0x1c, 0x45, - 0x16, 0x57, 0x7b, 0x3c, 0xf6, 0xb8, 0xc6, 0x7f, 0xcb, 0x4e, 0xd2, 0x99, 0x64, 0x2d, 0x6f, 0x67, - 0xa5, 0x75, 0xbc, 0xbb, 0xdd, 0x76, 0x36, 0x72, 0x36, 0xbb, 0xcb, 0xc1, 0x24, 0x96, 0x09, 0x0a, - 0x60, 0xda, 0x82, 0x08, 0x24, 0x88, 0x6a, 0x7a, 0xca, 0xed, 0x4e, 0x7a, 0xba, 0x9a, 0xae, 0xea, - 0x09, 0x23, 0x6b, 0x0e, 0x70, 0xe1, 0xc8, 0x81, 0x0f, 0x81, 0x38, 0x71, 0xe1, 0xc2, 0x81, 0x13, - 0x12, 0xe2, 0x88, 0xc4, 0x17, 0x40, 0x11, 0x17, 0xbe, 0x00, 0x67, 0x54, 0xaf, 0xab, 0xab, 0xbb, - 0xc7, 0xe3, 0xc4, 0x91, 0x0d, 0xe6, 0xd4, 0xf5, 0xde, 0xab, 0xf7, 0xde, 0xaf, 0xfa, 0xfd, 0xa9, - 0x3f, 0xe8, 0x5a, 0xfc, 0xd8, 0x77, 0x48, 0x1c, 0x78, 0x61, 0x40, 0x23, 0xe1, 0x24, 0x2c, 0x0c, - 0x59, 0xaa, 0xbf, 0x76, 0x9c, 0x30, 0xc1, 0xf0, 0xa4, 0x22, 0x5b, 0x57, 0x7d, 0xc6, 0xfc, 0x90, - 0x4a, 0x05, 0x87, 0x44, 0x11, 0x13, 0x44, 0x04, 0x2c, 0xe2, 0xd9, 0xb4, 0xd6, 0x7d, 0x3f, 0x10, - 0x07, 0x69, 0xdb, 0xf6, 0x58, 0xd7, 0x21, 0x89, 0xcf, 0xe2, 0x84, 0x3d, 0x82, 0xc1, 0xbf, 0x94, - 0x3e, 0x77, 0x94, 0x37, 0xee, 0x68, 0x4e, 0x6f, 0x83, 0x84, 0xf1, 0x01, 0xd9, 0x70, 0x7c, 0x1a, - 0xd1, 0x84, 0x08, 0xda, 0x51, 0xd6, 0x6e, 0x3e, 0xfe, 0x0f, 0xb7, 0x03, 0x26, 0xa7, 0x77, 0x89, - 0x77, 0x10, 0x44, 0x34, 0xe9, 0x17, 0xfa, 0x5d, 0x2a, 0x88, 0xd3, 0x3b, 0xaa, 0x75, 0x45, 0x21, - 0x04, 0xaa, 0x9d, 0xee, 0x3b, 0xb4, 0x1b, 0x8b, 0x7e, 0x26, 0xb4, 0xee, 0xa2, 0x79, 0x37, 0xf3, - 0x7b, 0x2f, 0xda, 0x67, 0x6f, 0xa6, 0x34, 0xe9, 0x63, 0x8c, 0xc6, 0x23, 0xd2, 0xa5, 0xa6, 0xb1, - 0x62, 0xac, 0x4e, 0xb9, 0x30, 0xc6, 0x57, 0xd1, 0x94, 0xfc, 0xf2, 0x98, 0x78, 0xd4, 0x1c, 0x03, - 0x41, 0xc1, 0xb0, 0x6e, 0xa2, 0xa5, 0x92, 0x95, 0xfb, 0x01, 0x17, 0x99, 0xa5, 0x8a, 0x96, 0x31, - 0xac, 0xf5, 0xa9, 0x81, 0xe6, 0xf6, 0xa8, 0xb8, 0xd7, 0x25, 0x3e, 0x75, 0xe9, 0x07, 0x29, 0xe5, - 0x02, 0x9b, 0x28, 0xff, 0xb3, 0x6a, 0x7e, 0x4e, 0x4a, 0x5b, 0x1e, 0x8b, 0x04, 0x91, 0xab, 0xce, - 0x11, 0x68, 0x06, 0x5e, 0x42, 0xf5, 0x40, 0xda, 0x31, 0x6b, 0x20, 0xc9, 0x08, 0x3c, 0x8f, 0x6a, - 0x82, 0xf8, 0xe6, 0x38, 0xf0, 0xe4, 0xb0, 0x8a, 0xa8, 0x3e, 0x8c, 0xe8, 0x00, 0xe1, 0xb7, 0xa2, - 0x0e, 0x53, 0x6b, 0x79, 0x3e, 0xa6, 0x16, 0x6a, 0x24, 0xb4, 0x17, 0xf0, 0x80, 0x45, 0x00, 0xa9, - 0xe6, 0x6a, 0xba, 0xea, 0xa9, 0x36, 0xec, 0xe9, 0x1e, 0xba, 0xe0, 0x52, 0x2e, 0x48, 0x22, 0x86, - 0x9c, 0xbd, 0xf8, 0xcf, 0x7f, 0x0f, 0x5d, 0xd8, 0x4d, 0x58, 0x97, 0x09, 0x7a, 0x5a, 0x53, 0x52, - 0x63, 0x3f, 0x0d, 0x43, 0x80, 0xdb, 0x70, 0x61, 0x6c, 0xed, 0xa0, 0xc5, 0xad, 0x36, 0x3b, 0x03, - 0x9c, 0x3b, 0x68, 0xd1, 0xa5, 0x22, 0xe9, 0x9f, 0xda, 0xd0, 0x43, 0xb4, 0xa0, 0x6c, 0x3c, 0x20, - 0xc2, 0x3b, 0xd8, 0xee, 0xd1, 0x08, 0xcc, 0x88, 0x7e, 0xac, 0xcd, 0xc8, 0x31, 0xde, 0x44, 0xcd, - 0xa4, 0x48, 0x4b, 0x30, 0xd4, 0xbc, 0xb1, 0x64, 0xe7, 0x95, 0x5c, 0x4a, 0x59, 0xb7, 0x3c, 0xd1, - 0x7a, 0x88, 0x66, 0x5e, 0xcf, 0xbd, 0x49, 0xc6, 0xb3, 0xf3, 0x18, 0xaf, 0xa3, 0x45, 0xd2, 0x23, - 0x41, 0x48, 0xda, 0x21, 0xd5, 0x7a, 0xdc, 0x1c, 0x5b, 0xa9, 0xad, 0x4e, 0xb9, 0xa3, 0x44, 0xd6, - 0x1d, 0x34, 0x37, 0x54, 0x2f, 0x78, 0x1d, 0x35, 0xf2, 0x06, 0x60, 0x1a, 0x2b, 0xb5, 0x63, 0x81, - 0xea, 0x59, 0xd6, 0x2d, 0xd4, 0x7c, 0x9b, 0x26, 0x32, 0xd7, 0x00, 0xe3, 0x2a, 0x9a, 0xcb, 0x45, - 0x8a, 0xad, 0x90, 0x0e, 0xb3, 0xad, 0xcf, 0x27, 0x50, 0xb3, 0x64, 0x12, 0xef, 0x22, 0xc4, 0xda, - 0x8f, 0xa8, 0x27, 0x5e, 0xa3, 0x82, 0x80, 0x52, 0xf3, 0xc6, 0xba, 0x9d, 0xf5, 0x1a, 0xbb, 0xdc, - 0x6b, 0xec, 0xf8, 0xb1, 0x2f, 0x19, 0xdc, 0x96, 0xbd, 0xc6, 0xee, 0x6d, 0xd8, 0x6f, 0x68, 0x3d, - 0xb7, 0x64, 0x03, 0x5f, 0x44, 0x13, 0x5c, 0x10, 0x91, 0x72, 0x15, 0x3c, 0x45, 0xc9, 0x4a, 0xea, - 0x52, 0xce, 0x8b, 0x3a, 0xcd, 0x49, 0x19, 0xbe, 0xc0, 0x63, 0x91, 0x2a, 0x55, 0x18, 0xcb, 0xea, - 0xe2, 0x42, 0x76, 0x32, 0xbf, 0xaf, 0x4a, 0x55, 0xd3, 0x72, 0x3e, 0x17, 0x34, 0x36, 0x27, 0xb2, - 0xf9, 0x72, 0x2c, 0xa3, 0xc4, 0xa9, 0x78, 0x40, 0x03, 0xff, 0x40, 0x98, 0x93, 0x59, 0x94, 0x34, - 0x03, 0x5b, 0x68, 0x9a, 0x78, 0x22, 0x25, 0xa1, 0x9a, 0xd0, 0x80, 0x09, 0x15, 0x9e, 0xec, 0x22, - 0x09, 0x25, 0x9d, 0xbe, 0x39, 0xb5, 0x62, 0xac, 0xd6, 0xdd, 0x8c, 0x90, 0xa8, 0xbd, 0x34, 0x49, - 0x68, 0x24, 0x4c, 0x04, 0xfc, 0x9c, 0x94, 0x92, 0x0e, 0xe5, 0x41, 0x42, 0x3b, 0x66, 0x33, 0x93, - 0x28, 0x52, 0x4a, 0xd2, 0xb8, 0x23, 0xbb, 0xb0, 0x39, 0x9d, 0x49, 0x14, 0x29, 0x51, 0xea, 0x94, - 0x30, 0x67, 0x40, 0x56, 0x30, 0xf0, 0x0a, 0x6a, 0x26, 0x59, 0x5f, 0xa0, 0x9d, 0x2d, 0x61, 0xce, - 0x02, 0xc8, 0x32, 0x0b, 0x2f, 0x23, 0xa4, 0x3a, 0xbc, 0x0c, 0xf1, 0x1c, 0x4c, 0x28, 0x71, 0xf0, - 0x6d, 0x69, 0x21, 0x0e, 0x03, 0x8f, 0xec, 0x51, 0xc1, 0xcd, 0x79, 0xc8, 0xa5, 0x4b, 0x45, 0x2e, - 0x69, 0x99, 0xca, 0xfb, 0x62, 0xae, 0x54, 0xa5, 0x1f, 0xc6, 0x34, 0x09, 0xba, 0x34, 0x12, 0xdc, - 0x5c, 0x18, 0x52, 0xdd, 0xd6, 0xb2, 0x4c, 0xb5, 0x34, 0x17, 0xff, 0x1f, 0x4d, 0x93, 0x88, 0x84, - 0x7d, 0x1e, 0x70, 0x37, 0x8d, 0xb8, 0x89, 0x41, 0xd7, 0xd4, 0xba, 0x5b, 0x85, 0x10, 0x94, 0x2b, - 0xb3, 0xf1, 0x26, 0x42, 0xba, 0x95, 0x73, 0x73, 0x11, 0x74, 0x2f, 0x6a, 0xdd, 0x3b, 0xb9, 0x08, - 0x34, 0x4b, 0x33, 0xf1, 0xfb, 0xa8, 0x2e, 0x23, 0xcf, 0xcd, 0x25, 0x50, 0x79, 0xc5, 0x2e, 0xb6, - 0x5b, 0x3b, 0xdf, 0x6e, 0x61, 0xf0, 0x30, 0xaf, 0x81, 0x22, 0x85, 0x35, 0x27, 0xdf, 0x6e, 0xed, - 0x3b, 0x24, 0x22, 0x49, 0x7f, 0x4f, 0xd0, 0xd8, 0xcd, 0xcc, 0x5a, 0xdf, 0x8c, 0xa1, 0xd9, 0xea, - 0xaa, 0x7f, 0x87, 0x62, 0xc9, 0x53, 0x7f, 0xac, 0x9a, 0xfa, 0x7a, 0x63, 0xa9, 0x41, 0x8e, 0x14, - 0x1b, 0x4b, 0x51, 0x5c, 0xe3, 0xc7, 0x15, 0x57, 0xbd, 0x5a, 0x5c, 0x43, 0x29, 0x31, 0xf1, 0x02, - 0x29, 0x31, 0x1c, 0xd7, 0xc9, 0x17, 0x89, 0xab, 0xf5, 0x6b, 0x0d, 0xcd, 0x56, 0xad, 0xff, 0x81, - 0xcd, 0x26, 0xff, 0xaf, 0xb5, 0x63, 0xfe, 0xeb, 0xf8, 0xc8, 0xff, 0x2a, 0xab, 0xb2, 0x0e, 0xdb, - 0x9f, 0xa2, 0x24, 0xdf, 0x83, 0xcc, 0x80, 0x66, 0xd3, 0x70, 0x15, 0x25, 0xf9, 0xc4, 0x13, 0x41, - 0x8f, 0x42, 0xaf, 0x69, 0xb8, 0x8a, 0x92, 0x71, 0x88, 0xa5, 0x51, 0xfa, 0x04, 0x7a, 0x4c, 0xc3, - 0xcd, 0xc9, 0xcc, 0x3b, 0xfc, 0x0d, 0xae, 0x3a, 0x8c, 0xa6, 0xab, 0x6d, 0x01, 0x0d, 0xb7, 0x85, - 0x16, 0x6a, 0x08, 0xda, 0x8d, 0x43, 0x22, 0x28, 0x74, 0x9a, 0x29, 0x57, 0xd3, 0xf8, 0x9f, 0x68, - 0x81, 0x7b, 0x24, 0xa4, 0x77, 0xd9, 0x93, 0xe8, 0x2e, 0x25, 0x9d, 0x30, 0x88, 0x28, 0x34, 0x9d, - 0x29, 0xf7, 0xa8, 0x40, 0xa2, 0x86, 0xb3, 0x11, 0x37, 0x67, 0x60, 0x7f, 0x52, 0x14, 0xfe, 0x1b, - 0x1a, 0x8f, 0x59, 0x87, 0x9b, 0xb3, 0x10, 0xe0, 0x79, 0x1d, 0xe0, 0x5d, 0xd6, 0x81, 0xc0, 0x82, - 0x54, 0xfe, 0xd3, 0x38, 0x88, 0x7c, 0x68, 0x3b, 0x0d, 0x17, 0xc6, 0xc0, 0x63, 0x91, 0x6f, 0xce, - 0x2b, 0x1e, 0x8b, 0x7c, 0xeb, 0x6b, 0x03, 0x4d, 0x2a, 0xcd, 0x73, 0x8e, 0xb8, 0x6e, 0xe9, 0x59, - 0xb1, 0xa8, 0x96, 0x0e, 0x91, 0x80, 0x9e, 0xca, 0x21, 0xda, 0x10, 0x89, 0x8c, 0xb6, 0x6e, 0xa3, - 0x99, 0x4a, 0xc7, 0x19, 0x79, 0x42, 0xd1, 0xe7, 0xcd, 0xb1, 0xd2, 0x79, 0xd3, 0xfa, 0xc4, 0x40, - 0x93, 0xaf, 0xb2, 0xf6, 0xf9, 0x2f, 0xdb, 0xfa, 0x76, 0x0c, 0xcd, 0x0d, 0xd5, 0xe6, 0x9f, 0xb8, - 0x75, 0x2d, 0x23, 0xc4, 0x53, 0xcf, 0xa3, 0x9c, 0xef, 0xa7, 0xa1, 0x0a, 0x48, 0x89, 0x23, 0xf5, - 0xf6, 0x49, 0x10, 0xd2, 0x0e, 0x94, 0x60, 0xdd, 0x55, 0x94, 0xdc, 0xd3, 0x83, 0xc8, 0x63, 0x91, - 0x17, 0xa6, 0x3c, 0x2f, 0xc4, 0xba, 0x5b, 0xe1, 0xc9, 0x48, 0xd1, 0x24, 0x61, 0x09, 0x14, 0x63, - 0xdd, 0xcd, 0x08, 0x99, 0xee, 0x8f, 0x58, 0x5b, 0x96, 0x61, 0x35, 0xdd, 0x55, 0xf4, 0x5c, 0x90, - 0xde, 0xf8, 0x65, 0x06, 0xcd, 0xaa, 0x93, 0xd2, 0x1e, 0x4d, 0x7a, 0x81, 0x47, 0x31, 0x47, 0xb3, - 0x3b, 0x54, 0x94, 0x8f, 0x4f, 0x97, 0x47, 0x9d, 0xd3, 0xe0, 0xfe, 0xd3, 0x1a, 0x79, 0x84, 0xb3, - 0xd6, 0x3f, 0xfe, 0xf1, 0xe7, 0xcf, 0xc6, 0xd6, 0xf0, 0x2a, 0x5c, 0x1a, 0x7b, 0x1b, 0xc5, 0xcd, - 0xef, 0x50, 0x1f, 0x2a, 0x07, 0xd9, 0x78, 0xe0, 0x04, 0xd2, 0xc5, 0x00, 0xcd, 0xc3, 0x51, 0xf7, - 0x54, 0x6e, 0x37, 0xc1, 0xed, 0x3a, 0xb6, 0x4f, 0xea, 0xd6, 0x79, 0x22, 0x7d, 0xae, 0x1b, 0xb8, - 0x87, 0xe6, 0xe5, 0x19, 0xb5, 0x64, 0x8c, 0xe3, 0xbf, 0x8c, 0xf2, 0xa1, 0x6f, 0x7e, 0x2d, 0xf3, - 0x38, 0xb1, 0x75, 0x1d, 0x60, 0x5c, 0xc3, 0x7f, 0x7d, 0x26, 0x0c, 0x58, 0xf6, 0x47, 0x06, 0x5a, - 0x18, 0x5e, 0xf7, 0x73, 0x3d, 0xb7, 0x86, 0xc5, 0xc5, 0x25, 0xc1, 0x72, 0xc0, 0xf7, 0x75, 0xfc, - 0xf7, 0xe7, 0xfa, 0xd6, 0x6b, 0x7f, 0x07, 0x4d, 0xef, 0x50, 0xa1, 0xcf, 0xee, 0xf8, 0xa2, 0x9d, - 0x5d, 0xa7, 0xed, 0xfc, 0x3a, 0x6d, 0x6f, 0xcb, 0xeb, 0x74, 0xab, 0x38, 0xae, 0x54, 0xae, 0x0e, - 0xd6, 0x65, 0x70, 0xb9, 0x88, 0x17, 0x72, 0x97, 0xc5, 0xbd, 0xe1, 0x4b, 0x43, 0xee, 0x8e, 0xe5, - 0x4b, 0x20, 0x5e, 0x2e, 0x6d, 0xca, 0x23, 0x6e, 0x87, 0xad, 0xed, 0xd3, 0x9d, 0x70, 0x94, 0xb5, - 0x3c, 0x15, 0x5a, 0xff, 0x38, 0x49, 0x2a, 0xa8, 0xc6, 0xf8, 0x5f, 0x63, 0x0d, 0x10, 0x57, 0xef, - 0x9a, 0x25, 0xc4, 0x23, 0x2f, 0xa1, 0xe7, 0x82, 0x38, 0xce, 0x90, 0x48, 0xc4, 0x5f, 0x18, 0x68, - 0xba, 0x7c, 0x7d, 0xc5, 0x57, 0x8b, 0xa3, 0xcb, 0xd1, 0x5b, 0xed, 0x59, 0xa1, 0xbd, 0x09, 0x68, - 0xed, 0xd6, 0xf5, 0x93, 0xa0, 0x25, 0x12, 0x87, 0xc4, 0xfa, 0x5d, 0xf6, 0x1e, 0x92, 0x67, 0x35, - 0xbc, 0x60, 0x14, 0x75, 0x34, 0xf4, 0x52, 0x72, 0x56, 0x50, 0x5d, 0x80, 0x7a, 0xbf, 0xb5, 0xf3, - 0x6c, 0xa8, 0x8a, 0x3b, 0x70, 0x38, 0x15, 0xce, 0xa1, 0x3e, 0x82, 0x0f, 0x9c, 0x43, 0xd8, 0xf9, - 0x5e, 0x5a, 0x5b, 0x1b, 0x38, 0x87, 0x82, 0xf8, 0x03, 0xb9, 0x90, 0xaf, 0x0c, 0xd4, 0x2c, 0xbd, - 0xa3, 0xe0, 0x2b, 0x7a, 0x11, 0x47, 0x5f, 0x57, 0xce, 0x6a, 0x1d, 0x5b, 0xb0, 0x8e, 0xff, 0xb5, - 0x36, 0x4f, 0xb8, 0x8e, 0x34, 0xea, 0x30, 0xe7, 0x30, 0xdf, 0x99, 0x06, 0x79, 0xae, 0x94, 0x5f, - 0x28, 0x4a, 0xb9, 0x32, 0xe2, 0xe1, 0xe2, 0x5c, 0x72, 0x25, 0x91, 0x38, 0x24, 0xd6, 0x5d, 0x34, - 0xa9, 0xae, 0xf3, 0xc7, 0x76, 0xa4, 0x62, 0x17, 0x28, 0x3d, 0x13, 0x58, 0x97, 0xc0, 0xdd, 0x02, - 0x9e, 0xcb, 0xdd, 0xf5, 0x32, 0xe1, 0xcb, 0xdb, 0xdf, 0x3f, 0x5d, 0x36, 0x7e, 0x78, 0xba, 0x6c, - 0xfc, 0xf4, 0x74, 0xd9, 0x78, 0xf7, 0xd6, 0x89, 0x1f, 0x2e, 0xab, 0xcf, 0xa4, 0xed, 0x09, 0x40, - 0xf1, 0xef, 0xdf, 0x02, 0x00, 0x00, 0xff, 0xff, 0xe8, 0x30, 0x8c, 0x5d, 0x46, 0x15, 0x00, 0x00, + // 1751 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0xcd, 0x6f, 0x1c, 0x49, + 0x15, 0x57, 0x7b, 0x3c, 0xf6, 0xf8, 0x8d, 0x3f, 0xc6, 0xe5, 0x6c, 0xb6, 0x77, 0x36, 0x58, 0xa6, + 0x17, 0x09, 0xc7, 0x40, 0xb7, 0x93, 0x8d, 0xb2, 0x2c, 0x1f, 0x87, 0x90, 0x58, 0xde, 0xa0, 0xec, + 0x12, 0x3a, 0xc0, 0x0a, 0x24, 0x88, 0x6a, 0x7a, 0xca, 0xe3, 0x4e, 0x7a, 0xba, 0x9a, 0xae, 0xea, + 0x09, 0x23, 0x6b, 0x0e, 0xf0, 0x0f, 0x70, 0xe0, 0x5f, 0x58, 0x09, 0x71, 0x42, 0x48, 0x5c, 0x38, + 0x70, 0x45, 0x1c, 0x91, 0xf8, 0x07, 0x50, 0xc4, 0x85, 0x23, 0x17, 0xce, 0xa8, 0x5e, 0x57, 0x57, + 0x7f, 0x78, 0xec, 0x38, 0xb2, 0x21, 0x7b, 0x9a, 0x7a, 0xef, 0xd5, 0x7b, 0xef, 0x57, 0xf3, 0x3e, + 0xaa, 0xfa, 0xc1, 0x7b, 0xc9, 0xf3, 0x91, 0x47, 0x93, 0x30, 0x88, 0x42, 0x16, 0x4b, 0x2f, 0xe5, + 0x51, 0xc4, 0x33, 0xf3, 0xeb, 0x26, 0x29, 0x97, 0x9c, 0x2c, 0x6b, 0xb2, 0x7f, 0x63, 0xc4, 0xf9, + 0x28, 0x62, 0x4a, 0xc1, 0xa3, 0x71, 0xcc, 0x25, 0x95, 0x21, 0x8f, 0x45, 0xbe, 0xad, 0xff, 0x68, + 0x14, 0xca, 0xe3, 0x6c, 0xe0, 0x06, 0x7c, 0xec, 0xd1, 0x74, 0xc4, 0x93, 0x94, 0x3f, 0xc3, 0xc5, + 0xd7, 0xb4, 0xbe, 0xf0, 0xb4, 0x37, 0xe1, 0x19, 0xce, 0xe4, 0x16, 0x8d, 0x92, 0x63, 0x7a, 0xcb, + 0x1b, 0xb1, 0x98, 0xa5, 0x54, 0xb2, 0xa1, 0xb6, 0x76, 0xe7, 0xf9, 0xd7, 0x85, 0x1b, 0x72, 0xb5, + 0x7d, 0x4c, 0x83, 0xe3, 0x30, 0x66, 0xe9, 0xb4, 0xd4, 0x1f, 0x33, 0x49, 0xbd, 0xc9, 0x69, 0xad, + 0x77, 0x35, 0x42, 0xa4, 0x06, 0xd9, 0x91, 0xc7, 0xc6, 0x89, 0x9c, 0xe6, 0x42, 0xe7, 0x01, 0xf4, + 0xfc, 0xdc, 0xef, 0xc3, 0xf8, 0x88, 0x7f, 0x3f, 0x63, 0xe9, 0x94, 0x10, 0x58, 0x8c, 0xe9, 0x98, + 0xd9, 0xd6, 0x8e, 0xb5, 0xbb, 0xe2, 0xe3, 0x9a, 0xdc, 0x80, 0x15, 0xf5, 0x2b, 0x12, 0x1a, 0x30, + 0x7b, 0x01, 0x05, 0x25, 0xc3, 0xb9, 0x03, 0xd7, 0x2a, 0x56, 0x1e, 0x85, 0x42, 0xe6, 0x96, 0x6a, + 0x5a, 0x56, 0x53, 0xeb, 0xd7, 0x16, 0x6c, 0x3c, 0x61, 0xf2, 0xe1, 0x98, 0x8e, 0x98, 0xcf, 0x7e, + 0x9e, 0x31, 0x21, 0x89, 0x0d, 0xc5, 0x3f, 0xab, 0xf7, 0x17, 0xa4, 0xb2, 0x15, 0xf0, 0x58, 0x52, + 0x75, 0xea, 0x02, 0x81, 0x61, 0x90, 0x6b, 0xd0, 0x0e, 0x95, 0x1d, 0xbb, 0x85, 0x92, 0x9c, 0x20, + 0x3d, 0x68, 0x49, 0x3a, 0xb2, 0x17, 0x91, 0xa7, 0x96, 0x75, 0x44, 0xed, 0x26, 0xa2, 0x63, 0x20, + 0x3f, 0x8c, 0x87, 0x5c, 0x9f, 0xe5, 0xd5, 0x98, 0xfa, 0xd0, 0x49, 0xd9, 0x24, 0x14, 0x21, 0x8f, + 0x11, 0x52, 0xcb, 0x37, 0x74, 0xdd, 0x53, 0xab, 0xe9, 0xe9, 0x21, 0xbc, 0xe5, 0x33, 0x21, 0x69, + 0x2a, 0x1b, 0xce, 0x5e, 0xff, 0xcf, 0xff, 0x29, 0xbc, 0xf5, 0x38, 0xe5, 0x63, 0x2e, 0xd9, 0x65, + 0x4d, 0x29, 0x8d, 0xa3, 0x2c, 0x8a, 0x10, 0x6e, 0xc7, 0xc7, 0xb5, 0x73, 0x08, 0x5b, 0xf7, 0x06, + 0xfc, 0x0a, 0x70, 0x1e, 0xc2, 0x96, 0xcf, 0x64, 0x3a, 0xbd, 0xb4, 0xa1, 0xa7, 0xb0, 0xa9, 0x6d, + 0x7c, 0x4a, 0x65, 0x70, 0x7c, 0x30, 0x61, 0x31, 0x9a, 0x91, 0xd3, 0xc4, 0x98, 0x51, 0x6b, 0x72, + 0x17, 0xba, 0x69, 0x99, 0x96, 0x68, 0xa8, 0x7b, 0xfb, 0x9a, 0x5b, 0x54, 0x72, 0x25, 0x65, 0xfd, + 0xea, 0x46, 0xe7, 0x29, 0xac, 0x7d, 0x52, 0x78, 0x53, 0x8c, 0xf3, 0xf3, 0x98, 0xec, 0xc3, 0x16, + 0x9d, 0xd0, 0x30, 0xa2, 0x83, 0x88, 0x19, 0x3d, 0x61, 0x2f, 0xec, 0xb4, 0x76, 0x57, 0xfc, 0x79, + 0x22, 0xe7, 0x3e, 0x6c, 0x34, 0xea, 0x85, 0xec, 0x43, 0xa7, 0x68, 0x00, 0xb6, 0xb5, 0xd3, 0x3a, + 0x13, 0xa8, 0xd9, 0xe5, 0x7c, 0x00, 0xdd, 0x1f, 0xb1, 0x54, 0xe5, 0x1a, 0x62, 0xdc, 0x85, 0x8d, + 0x42, 0xa4, 0xd9, 0x1a, 0x69, 0x93, 0xed, 0xfc, 0x76, 0x09, 0xba, 0x15, 0x93, 0xe4, 0x31, 0x00, + 0x1f, 0x3c, 0x63, 0x81, 0xfc, 0x98, 0x49, 0x8a, 0x4a, 0xdd, 0xdb, 0xfb, 0x6e, 0xde, 0x6b, 0xdc, + 0x6a, 0xaf, 0x71, 0x93, 0xe7, 0x23, 0xc5, 0x10, 0xae, 0xea, 0x35, 0xee, 0xe4, 0x96, 0xfb, 0x3d, + 0xa3, 0xe7, 0x57, 0x6c, 0x90, 0xeb, 0xb0, 0x24, 0x24, 0x95, 0x99, 0xd0, 0xc1, 0xd3, 0x94, 0xaa, + 0xa4, 0x31, 0x13, 0xa2, 0xac, 0xd3, 0x82, 0x54, 0xe1, 0x0b, 0x03, 0x1e, 0xeb, 0x52, 0xc5, 0xb5, + 0xaa, 0x2e, 0x21, 0x55, 0x27, 0x1b, 0x4d, 0x75, 0xa9, 0x1a, 0x5a, 0xed, 0x17, 0x92, 0x25, 0xf6, + 0x52, 0xbe, 0x5f, 0xad, 0x55, 0x94, 0x04, 0x93, 0x9f, 0xb2, 0x70, 0x74, 0x2c, 0xed, 0xe5, 0x3c, + 0x4a, 0x86, 0x41, 0x1c, 0x58, 0xa5, 0x81, 0xcc, 0x68, 0xa4, 0x37, 0x74, 0x70, 0x43, 0x8d, 0xa7, + 0xba, 0x48, 0xca, 0xe8, 0x70, 0x6a, 0xaf, 0xec, 0x58, 0xbb, 0x6d, 0x3f, 0x27, 0x14, 0xea, 0x20, + 0x4b, 0x53, 0x16, 0x4b, 0x1b, 0x90, 0x5f, 0x90, 0x4a, 0x32, 0x64, 0x22, 0x4c, 0xd9, 0xd0, 0xee, + 0xe6, 0x12, 0x4d, 0x2a, 0x49, 0x96, 0x0c, 0x55, 0x17, 0xb6, 0x57, 0x73, 0x89, 0x26, 0x15, 0x4a, + 0x93, 0x12, 0xf6, 0x1a, 0xca, 0x4a, 0x06, 0xd9, 0x81, 0x6e, 0x9a, 0xf7, 0x05, 0x36, 0xbc, 0x27, + 0xed, 0x75, 0x04, 0x59, 0x65, 0x91, 0x6d, 0x00, 0xdd, 0xe1, 0x55, 0x88, 0x37, 0x70, 0x43, 0x85, + 0x43, 0x3e, 0x54, 0x16, 0x92, 0x28, 0x0c, 0xe8, 0x13, 0x26, 0x85, 0xdd, 0xc3, 0x5c, 0x7a, 0xbb, + 0xcc, 0x25, 0x23, 0xd3, 0x79, 0x5f, 0xee, 0x55, 0xaa, 0xec, 0x17, 0x09, 0x4b, 0xc3, 0x31, 0x8b, + 0xa5, 0xb0, 0x37, 0x1b, 0xaa, 0x07, 0x46, 0x96, 0xab, 0x56, 0xf6, 0x92, 0x6f, 0xc1, 0x2a, 0x8d, + 0x69, 0x34, 0x15, 0xa1, 0xf0, 0xb3, 0x58, 0xd8, 0x04, 0x75, 0x6d, 0xa3, 0x7b, 0xaf, 0x14, 0xa2, + 0x72, 0x6d, 0x37, 0xb9, 0x0b, 0x60, 0x5a, 0xb9, 0xb0, 0xb7, 0x50, 0xf7, 0xba, 0xd1, 0xbd, 0x5f, + 0x88, 0x50, 0xb3, 0xb2, 0x93, 0xfc, 0x0c, 0xda, 0x2a, 0xf2, 0xc2, 0xbe, 0x86, 0x2a, 0x1f, 0xb9, + 0xe5, 0x75, 0xeb, 0x16, 0xd7, 0x2d, 0x2e, 0x9e, 0x16, 0x35, 0x50, 0xa6, 0xb0, 0xe1, 0x14, 0xd7, + 0xad, 0x7b, 0x9f, 0xc6, 0x34, 0x9d, 0x3e, 0x91, 0x2c, 0xf1, 0x73, 0xb3, 0xce, 0x9f, 0x17, 0x60, + 0xbd, 0x7e, 0xea, 0xff, 0x41, 0xb1, 0x14, 0xa9, 0xbf, 0x50, 0x4f, 0x7d, 0x73, 0xb1, 0xb4, 0x1a, + 0x17, 0x4b, 0x59, 0x5c, 0x8b, 0x67, 0x15, 0x57, 0xbb, 0x5e, 0x5c, 0x8d, 0x94, 0x58, 0x7a, 0x8d, + 0x94, 0x68, 0xc6, 0x75, 0xf9, 0x75, 0xe2, 0xea, 0xfc, 0xa7, 0x05, 0xeb, 0x75, 0xeb, 0xff, 0xc7, + 0x66, 0x53, 0xfc, 0xaf, 0xad, 0x33, 0xfe, 0xd7, 0xc5, 0xb9, 0xff, 0xab, 0xaa, 0xca, 0x36, 0x5e, + 0x7f, 0x9a, 0x52, 0xfc, 0x00, 0x33, 0x03, 0x9b, 0x4d, 0xc7, 0xd7, 0x94, 0xe2, 0xd3, 0x40, 0x86, + 0x13, 0x86, 0xbd, 0xa6, 0xe3, 0x6b, 0x4a, 0xc5, 0x21, 0x51, 0x46, 0xd9, 0x0b, 0xec, 0x31, 0x1d, + 0xbf, 0x20, 0x73, 0xef, 0xf8, 0x6f, 0x08, 0xdd, 0x61, 0x0c, 0x5d, 0x6f, 0x0b, 0xd0, 0x6c, 0x0b, + 0x7d, 0xe8, 0x48, 0x36, 0x4e, 0x22, 0x2a, 0x19, 0x76, 0x9a, 0x15, 0xdf, 0xd0, 0xe4, 0xab, 0xb0, + 0x29, 0x02, 0x1a, 0xb1, 0x07, 0xfc, 0x45, 0xfc, 0x80, 0xd1, 0x61, 0x14, 0xc6, 0x0c, 0x9b, 0xce, + 0x8a, 0x7f, 0x5a, 0xa0, 0x50, 0xe3, 0xdb, 0x48, 0xd8, 0x6b, 0x78, 0x3f, 0x69, 0x8a, 0x7c, 0x09, + 0x16, 0x13, 0x3e, 0x14, 0xf6, 0x3a, 0x06, 0xb8, 0x67, 0x02, 0xfc, 0x98, 0x0f, 0x31, 0xb0, 0x28, + 0x55, 0xff, 0x69, 0x12, 0xc6, 0x23, 0x6c, 0x3b, 0x1d, 0x1f, 0xd7, 0xc8, 0xe3, 0xf1, 0xc8, 0xee, + 0x69, 0x1e, 0x8f, 0x47, 0xce, 0x9f, 0x2c, 0x58, 0xd6, 0x9a, 0x6f, 0x38, 0xe2, 0xa6, 0xa5, 0xe7, + 0xc5, 0xa2, 0x5b, 0x3a, 0x46, 0x02, 0x7b, 0xaa, 0xc0, 0x68, 0x63, 0x24, 0x72, 0xda, 0xf9, 0x10, + 0xd6, 0x6a, 0x1d, 0x67, 0xee, 0x0b, 0xc5, 0xbc, 0x37, 0x17, 0x2a, 0xef, 0x4d, 0xe7, 0xdf, 0x16, + 0x2c, 0x7f, 0x97, 0x0f, 0x3e, 0x07, 0xc7, 0xde, 0x06, 0x18, 0x33, 0x99, 0x86, 0x81, 0x7a, 0x75, + 0xe8, 0xb3, 0x57, 0x38, 0xe4, 0x23, 0x58, 0x29, 0x6f, 0x99, 0x36, 0x82, 0xdb, 0xbb, 0x18, 0xb8, + 0x1f, 0x84, 0x63, 0xe6, 0x97, 0xca, 0xce, 0x67, 0x2d, 0xd8, 0x68, 0x74, 0x81, 0xcf, 0x71, 0x93, + 0xdc, 0x06, 0x10, 0x59, 0x10, 0x30, 0x21, 0x8e, 0xb2, 0x48, 0x87, 0xbe, 0xc2, 0x51, 0x7a, 0x47, + 0x34, 0x8c, 0xd8, 0x10, 0x8b, 0xbd, 0xed, 0x6b, 0x4a, 0xbd, 0x1e, 0xc2, 0x38, 0xe0, 0x71, 0x10, + 0x65, 0xa2, 0x28, 0xf9, 0xb6, 0x5f, 0xe3, 0xa9, 0x9c, 0x60, 0x69, 0xca, 0x53, 0x2c, 0xfb, 0xb6, + 0x9f, 0x13, 0xaa, 0xb0, 0x9e, 0xf1, 0x81, 0x2a, 0xf8, 0x7a, 0x61, 0xe9, 0x3c, 0xf1, 0x51, 0x4a, + 0xde, 0x07, 0x88, 0x79, 0xac, 0x79, 0x36, 0xe0, 0xde, 0x2d, 0xb3, 0xf7, 0x13, 0x23, 0xf2, 0x2b, + 0xdb, 0xc8, 0x9e, 0xea, 0xf8, 0x2a, 0xa4, 0xc2, 0xee, 0x36, 0xac, 0x7f, 0x9c, 0xf3, 0xfd, 0x62, + 0x83, 0xf3, 0x99, 0x05, 0x50, 0x9a, 0x51, 0x58, 0x27, 0x34, 0xca, 0x8a, 0xa4, 0xce, 0x89, 0x33, + 0x33, 0xac, 0x9e, 0x4d, 0xad, 0xf3, 0xb3, 0x69, 0xf1, 0x32, 0xd9, 0xf4, 0x07, 0x0b, 0x96, 0x35, + 0xf6, 0xb9, 0x75, 0xb7, 0x07, 0x3d, 0x1d, 0xad, 0xfb, 0x3c, 0x1e, 0x86, 0x32, 0x34, 0x39, 0x71, + 0x8a, 0xaf, 0xce, 0x18, 0xf0, 0x2c, 0x96, 0x08, 0xb8, 0xed, 0xe7, 0x84, 0x6a, 0x97, 0xd5, 0xa8, + 0x3d, 0x0a, 0xc7, 0x61, 0x8e, 0xb9, 0xed, 0x9f, 0x16, 0xa8, 0xb8, 0xab, 0x0c, 0xc8, 0x52, 0xbd, + 0x31, 0xcf, 0x98, 0x1a, 0xef, 0xf6, 0xbf, 0xd6, 0x60, 0x5d, 0xbf, 0xa7, 0x9f, 0xb0, 0x74, 0x12, + 0x06, 0x8c, 0x08, 0x58, 0x3f, 0x64, 0xb2, 0xfa, 0xc8, 0x7e, 0x67, 0xde, 0x6b, 0x1e, 0xbf, 0x92, + 0xfb, 0x73, 0x1f, 0xfa, 0xce, 0xfe, 0xaf, 0xfe, 0xfe, 0xcf, 0xdf, 0x2c, 0xec, 0x91, 0x5d, 0x1c, + 0x2d, 0x4c, 0x6e, 0x95, 0xf3, 0x81, 0x13, 0xf3, 0xe9, 0x31, 0xcb, 0xd7, 0x33, 0x2f, 0x54, 0x2e, + 0x66, 0xd0, 0xc3, 0x0f, 0xa2, 0x4b, 0xb9, 0xbd, 0x8b, 0x6e, 0xf7, 0x89, 0x7b, 0x51, 0xb7, 0xde, + 0x0b, 0xe5, 0x73, 0xdf, 0x22, 0x13, 0xe8, 0xa9, 0x2f, 0x99, 0x8a, 0x31, 0x41, 0xbe, 0x30, 0xcf, + 0x87, 0x99, 0x0f, 0xf4, 0xed, 0xb3, 0xc4, 0xce, 0x4d, 0x84, 0xf1, 0x1e, 0xf9, 0xe2, 0xb9, 0x30, + 0xf0, 0xd8, 0xbf, 0xb4, 0x60, 0xb3, 0x79, 0xee, 0x57, 0x7a, 0xee, 0x37, 0xc5, 0xe5, 0xa7, 0xa4, + 0xe3, 0xa1, 0xef, 0x9b, 0xe4, 0xcb, 0xaf, 0xf4, 0x6d, 0xce, 0xfe, 0x63, 0x58, 0x3d, 0x64, 0xd2, + 0x7c, 0xe1, 0x91, 0xeb, 0x6e, 0x3e, 0x74, 0x71, 0x8b, 0xa1, 0x8b, 0x7b, 0x30, 0x4e, 0xe4, 0xb4, + 0x5f, 0x3e, 0x6a, 0x6b, 0x1f, 0x98, 0xce, 0x3b, 0xe8, 0x72, 0x8b, 0x6c, 0x16, 0x2e, 0xcb, 0xaf, + 0xcb, 0xdf, 0x5b, 0xea, 0x0d, 0x55, 0x1d, 0x15, 0x90, 0xed, 0xca, 0xd3, 0x6d, 0xce, 0x0c, 0xa1, + 0x7f, 0x70, 0xb9, 0x77, 0xb0, 0xb6, 0x56, 0xa4, 0x42, 0xff, 0x2b, 0x17, 0x49, 0x05, 0x7d, 0x7d, + 0x7e, 0xc3, 0xda, 0x43, 0xc4, 0xf5, 0x89, 0x44, 0x05, 0xf1, 0xdc, 0x51, 0xc5, 0x1b, 0x41, 0x9c, + 0xe4, 0x48, 0x14, 0xe2, 0xdf, 0x59, 0xb0, 0x5a, 0x1d, 0x72, 0x90, 0x1b, 0xe5, 0x03, 0xf7, 0xf4, + 0xec, 0xe3, 0xaa, 0xd0, 0xde, 0x41, 0xb4, 0x6e, 0xff, 0xe6, 0x45, 0xd0, 0x52, 0x85, 0x43, 0x61, + 0xfd, 0x4b, 0x3e, 0x35, 0x2b, 0xb2, 0x1a, 0xe7, 0x5c, 0x65, 0x1d, 0x35, 0xe6, 0x69, 0x57, 0x05, + 0xd5, 0x47, 0xa8, 0x8f, 0xfa, 0x87, 0xe7, 0x43, 0xd5, 0xdc, 0x99, 0x27, 0x98, 0xf4, 0x4e, 0xcc, + 0x87, 0xda, 0xcc, 0x3b, 0xc1, 0xf7, 0xd1, 0xb7, 0xf7, 0xf6, 0x66, 0xde, 0x89, 0xa4, 0xa3, 0x99, + 0x3a, 0xc8, 0x1f, 0x2d, 0xe8, 0x56, 0xa6, 0x6d, 0xe4, 0x5d, 0x73, 0x88, 0xd3, 0x33, 0xb8, 0xab, + 0x3a, 0xc7, 0x3d, 0x3c, 0xc7, 0x37, 0xfb, 0x77, 0x2f, 0x78, 0x8e, 0x2c, 0x1e, 0x72, 0xef, 0xa4, + 0x78, 0x55, 0xcc, 0x8a, 0x5c, 0xa9, 0xce, 0xb1, 0x2a, 0xb9, 0x32, 0x67, 0xbc, 0xf5, 0x46, 0x72, + 0x25, 0x55, 0x38, 0x14, 0xd6, 0xc7, 0xb0, 0xac, 0x87, 0x3e, 0x67, 0x76, 0xa4, 0xf2, 0x16, 0xa8, + 0x0c, 0x93, 0x9c, 0xb7, 0xd1, 0xdd, 0x26, 0xd9, 0x28, 0xdc, 0x4d, 0x72, 0xe1, 0x77, 0x0e, 0xfe, + 0xfa, 0x72, 0xdb, 0xfa, 0xdb, 0xcb, 0x6d, 0xeb, 0x1f, 0x2f, 0xb7, 0xad, 0x9f, 0x7c, 0x70, 0xe1, + 0xf1, 0x76, 0x7d, 0x98, 0x3e, 0x58, 0x42, 0x14, 0xef, 0xff, 0x37, 0x00, 0x00, 0xff, 0xff, 0xa1, + 0x08, 0xa7, 0x61, 0x6c, 0x17, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -3254,6 +3448,25 @@ func (m *JobInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.StartedAt != nil { + { + size, err := m.StartedAt.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRollout(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + if len(m.MetricName) > 0 { + i -= len(m.MetricName) + copy(dAtA[i:], m.MetricName) + i = encodeVarintRollout(dAtA, i, uint64(len(m.MetricName))) + i-- + dAtA[i] = 0x22 + } if len(m.Icon) > 0 { i -= len(m.Icon) copy(dAtA[i:], m.Icon) @@ -3307,6 +3520,34 @@ func (m *AnalysisRunInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.Metrics) > 0 { + for iNdEx := len(m.Metrics) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Metrics[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRollout(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x5a + } + } + if len(m.NonJobInfo) > 0 { + for iNdEx := len(m.NonJobInfo) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.NonJobInfo[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRollout(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + } + } if len(m.Jobs) > 0 { for iNdEx := len(m.Jobs) - 1; iNdEx >= 0; iNdEx-- { { @@ -3375,6 +3616,122 @@ func (m *AnalysisRunInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *NonJobInfo) 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 *NonJobInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *NonJobInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.StartedAt != nil { + { + size, err := m.StartedAt.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRollout(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if len(m.MetricName) > 0 { + i -= len(m.MetricName) + copy(dAtA[i:], m.MetricName) + i = encodeVarintRollout(dAtA, i, uint64(len(m.MetricName))) + i-- + dAtA[i] = 0x1a + } + if len(m.Status) > 0 { + i -= len(m.Status) + copy(dAtA[i:], m.Status) + i = encodeVarintRollout(dAtA, i, uint64(len(m.Status))) + i-- + dAtA[i] = 0x12 + } + if len(m.Value) > 0 { + i -= len(m.Value) + copy(dAtA[i:], m.Value) + i = encodeVarintRollout(dAtA, i, uint64(len(m.Value))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Metrics) 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 *Metrics) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Metrics) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.FailureLimit != 0 { + i = encodeVarintRollout(dAtA, i, uint64(m.FailureLimit)) + i-- + dAtA[i] = 0x28 + } + if m.InconclusiveLimit != 0 { + i = encodeVarintRollout(dAtA, i, uint64(m.InconclusiveLimit)) + i-- + dAtA[i] = 0x20 + } + if m.Count != 0 { + i = encodeVarintRollout(dAtA, i, uint64(m.Count)) + i-- + dAtA[i] = 0x18 + } + if len(m.SuccessCondition) > 0 { + i -= len(m.SuccessCondition) + copy(dAtA[i:], m.SuccessCondition) + i = encodeVarintRollout(dAtA, i, uint64(len(m.SuccessCondition))) + i-- + dAtA[i] = 0x12 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintRollout(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintRollout(dAtA []byte, offset int, v uint64) int { offset -= sovRollout(v) base := offset @@ -3916,6 +4273,14 @@ func (m *JobInfo) Size() (n int) { if l > 0 { n += 1 + l + sovRollout(uint64(l)) } + l = len(m.MetricName) + if l > 0 { + n += 1 + l + sovRollout(uint64(l)) + } + if m.StartedAt != nil { + l = m.StartedAt.Size() + n += 1 + l + sovRollout(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -3961,16 +4326,85 @@ func (m *AnalysisRunInfo) Size() (n int) { n += 1 + l + sovRollout(uint64(l)) } } + if len(m.NonJobInfo) > 0 { + for _, e := range m.NonJobInfo { + l = e.Size() + n += 1 + l + sovRollout(uint64(l)) + } + } + if len(m.Metrics) > 0 { + for _, e := range m.Metrics { + l = e.Size() + n += 1 + l + sovRollout(uint64(l)) + } + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } return n } -func sovRollout(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozRollout(x uint64) (n int) { +func (m *NonJobInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Value) + if l > 0 { + n += 1 + l + sovRollout(uint64(l)) + } + l = len(m.Status) + if l > 0 { + n += 1 + l + sovRollout(uint64(l)) + } + l = len(m.MetricName) + if l > 0 { + n += 1 + l + sovRollout(uint64(l)) + } + if m.StartedAt != nil { + l = m.StartedAt.Size() + n += 1 + l + sovRollout(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *Metrics) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sovRollout(uint64(l)) + } + l = len(m.SuccessCondition) + if l > 0 { + n += 1 + l + sovRollout(uint64(l)) + } + if m.Count != 0 { + n += 1 + sovRollout(uint64(m.Count)) + } + if m.InconclusiveLimit != 0 { + n += 1 + sovRollout(uint64(m.InconclusiveLimit)) + } + if m.FailureLimit != 0 { + n += 1 + sovRollout(uint64(m.FailureLimit)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func sovRollout(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozRollout(x uint64) (n int) { return sovRollout(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } func (m *RolloutInfoQuery) Unmarshal(dAtA []byte) error { @@ -6149,7 +6583,7 @@ func (m *ExperimentInfo) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Revision |= int32(b&0x7F) << shift + m.Revision |= int64(b&0x7F) << shift if b < 0x80 { break } @@ -6451,7 +6885,7 @@ func (m *ReplicaSetInfo) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Revision |= int32(b&0x7F) << shift + m.Revision |= int64(b&0x7F) << shift if b < 0x80 { break } @@ -7212,6 +7646,74 @@ func (m *JobInfo) Unmarshal(dAtA []byte) error { } m.Icon = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MetricName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollout + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRollout + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRollout + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MetricName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StartedAt", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollout + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRollout + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRollout + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.StartedAt == nil { + m.StartedAt = &v1.Time{} + } + if err := m.StartedAt.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipRollout(dAtA[iNdEx:]) @@ -7345,7 +7847,7 @@ func (m *AnalysisRunInfo) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Revision |= int32(b&0x7F) << shift + m.Revision |= int64(b&0x7F) << shift if b < 0x80 { break } @@ -7492,6 +7994,429 @@ func (m *AnalysisRunInfo) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NonJobInfo", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollout + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRollout + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRollout + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NonJobInfo = append(m.NonJobInfo, &NonJobInfo{}) + if err := m.NonJobInfo[len(m.NonJobInfo)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Metrics", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollout + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRollout + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRollout + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Metrics = append(m.Metrics, &Metrics{}) + if err := m.Metrics[len(m.Metrics)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRollout(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRollout + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *NonJobInfo) 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 ErrIntOverflowRollout + } + 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: NonJobInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: NonJobInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollout + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRollout + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRollout + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Value = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollout + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRollout + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRollout + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Status = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MetricName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollout + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRollout + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRollout + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MetricName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StartedAt", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollout + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRollout + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRollout + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.StartedAt == nil { + m.StartedAt = &v1.Time{} + } + if err := m.StartedAt.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRollout(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRollout + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Metrics) 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 ErrIntOverflowRollout + } + 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: Metrics: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Metrics: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollout + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRollout + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRollout + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SuccessCondition", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollout + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRollout + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRollout + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SuccessCondition = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Count", wireType) + } + m.Count = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollout + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Count |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field InconclusiveLimit", wireType) + } + m.InconclusiveLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollout + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.InconclusiveLimit |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field FailureLimit", wireType) + } + m.FailureLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollout + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.FailureLimit |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipRollout(dAtA[iNdEx:]) diff --git a/pkg/apiclient/rollout/rollout.proto b/pkg/apiclient/rollout/rollout.proto index 27bd0337cd..0d21c5d9d6 100644 --- a/pkg/apiclient/rollout/rollout.proto +++ b/pkg/apiclient/rollout/rollout.proto @@ -101,7 +101,7 @@ message RolloutInfo { message ExperimentInfo { k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta objectMeta = 1; string icon = 2; - int32 revision = 3; + int64 revision = 3; string status = 4; string message = 5; repeated ReplicaSetInfo replicaSets = 6; @@ -112,7 +112,7 @@ message ReplicaSetInfo { k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta objectMeta = 1; string status = 2; string icon = 3; - int32 revision = 4; + int64 revision = 4; bool stable = 5; bool canary = 6; bool active = 7; @@ -144,20 +144,39 @@ message JobInfo { k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta objectMeta = 1; string status = 2; string icon = 3; + string metricName = 4; + k8s.io.apimachinery.pkg.apis.meta.v1.Time startedAt = 5; } message AnalysisRunInfo { k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta objectMeta = 1; string icon = 2; - int32 revision = 3; + int64 revision = 3; string status = 4; int32 successful = 5; int32 failed = 6; int32 inconclusive = 7; int32 error = 8; repeated JobInfo jobs = 9; + repeated NonJobInfo nonJobInfo = 10; + repeated Metrics metrics = 11; } +message NonJobInfo { + string value = 1; + string status = 2; + string metricName = 3; + k8s.io.apimachinery.pkg.apis.meta.v1.Time startedAt =4; +} + +message Metrics { + string name=1; + string successCondition = 2; + int32 count = 3; + int32 inconclusiveLimit = 4; + int32 failureLimit = 5; + } + service RolloutService { rpc GetRolloutInfo(RolloutInfoQuery) returns (RolloutInfo) { option (google.api.http).get = "/api/v1/rollouts/{namespace}/{name}/info"; diff --git a/pkg/apiclient/rollout/rollout.swagger.json b/pkg/apiclient/rollout/rollout.swagger.json index 140fb92856..384103913b 100644 --- a/pkg/apiclient/rollout/rollout.swagger.json +++ b/pkg/apiclient/rollout/rollout.swagger.json @@ -4456,8 +4456,8 @@ "type": "string" }, "revision": { - "type": "integer", - "format": "int32" + "type": "string", + "format": "int64" }, "status": { "type": "string" @@ -4483,6 +4483,18 @@ "items": { "$ref": "#/definitions/rollout.JobInfo" } + }, + "nonJobInfo": { + "type": "array", + "items": { + "$ref": "#/definitions/rollout.NonJobInfo" + } + }, + "metrics": { + "type": "array", + "items": { + "$ref": "#/definitions/rollout.Metrics" + } } } }, @@ -4507,8 +4519,8 @@ "type": "string" }, "revision": { - "type": "integer", - "format": "int32" + "type": "string", + "format": "int64" }, "status": { "type": "string" @@ -4541,6 +4553,35 @@ }, "icon": { "type": "string" + }, + "metricName": { + "type": "string" + }, + "startedAt": { + "$ref": "#/definitions/k8s.io.apimachinery.pkg.apis.meta.v1.Time" + } + } + }, + "rollout.Metrics": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "successCondition": { + "type": "string" + }, + "count": { + "type": "integer", + "format": "int32" + }, + "inconclusiveLimit": { + "type": "integer", + "format": "int32" + }, + "failureLimit": { + "type": "integer", + "format": "int32" } } }, @@ -4558,6 +4599,23 @@ } } }, + "rollout.NonJobInfo": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "status": { + "type": "string" + }, + "metricName": { + "type": "string" + }, + "startedAt": { + "$ref": "#/definitions/k8s.io.apimachinery.pkg.apis.meta.v1.Time" + } + } + }, "rollout.PodInfo": { "type": "object", "properties": { @@ -4606,8 +4664,8 @@ "type": "string" }, "revision": { - "type": "integer", - "format": "int32" + "type": "string", + "format": "int64" }, "stable": { "type": "boolean" diff --git a/pkg/kubectl-argo-rollouts/cmd/get/get_test.go b/pkg/kubectl-argo-rollouts/cmd/get/get_test.go index 6c89ca5b12..3f2f56468a 100644 --- a/pkg/kubectl-argo-rollouts/cmd/get/get_test.go +++ b/pkg/kubectl-argo-rollouts/cmd/get/get_test.go @@ -393,6 +393,13 @@ NAME K │ │ └──⧉ rollout-experiment-analysis-6f646bf7b7-1-vcv27-canary-7699dcf5d ReplicaSet ✔ Healthy 7d │ │ └──□ rollout-experiment-analysis-6f646bf7b7-1-vcv27-canary-7699vgr24 Pod ✔ Running 7d ready:1/1 │ └──α rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr AnalysisRun ? Inconclusive 7d ✔ 4,✖ 4,? 1,⚠ 1 +│ ├──⊞ rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-rzl6lt Job ✖ Failed 7d +│ ├──⊞ rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-r8lqpd Job ✔ Successful 7d +│ ├──⊞ rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-rjjsgg Job ✔ Successful 7d +│ ├──⊞ rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-rrnfj5 Job ✖ Failed 7d +│ ├──⊞ rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-rx5kqk Job ✖ Failed 7d +│ ├──⊞ rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-rp894b Job ✔ Successful 7d +│ ├──⊞ rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-rmngtj Job ✖ Failed 7d │ └──⊞ rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-rsxm69 Job ✔ Successful 7d └──# revision:1 └──⧉ rollout-experiment-analysis-f6db98dff ReplicaSet ✔ Healthy 7d stable diff --git a/pkg/kubectl-argo-rollouts/info/analysisrun_info.go b/pkg/kubectl-argo-rollouts/info/analysisrun_info.go index cecc3f2cd9..9c60ccad87 100644 --- a/pkg/kubectl-argo-rollouts/info/analysisrun_info.go +++ b/pkg/kubectl-argo-rollouts/info/analysisrun_info.go @@ -26,32 +26,72 @@ func getAnalysisRunInfo(ownerUID types.UID, allAnalysisRuns []*v1alpha1.Analysis UID: run.UID, }, } + if run.Spec.Metrics != nil { + for _, metric := range run.Spec.Metrics { + + metrics := rollout.Metrics{ + Name: metric.Name, + SuccessCondition: metric.SuccessCondition, + } + + if metric.InconclusiveLimit != nil { + metrics.InconclusiveLimit = metric.InconclusiveLimit.IntVal + } else { + metrics.InconclusiveLimit = 0 + } + + if metric.Count != nil { + metrics.Count = metric.Count.IntVal + } else { + metrics.Count = 0 + } + + if metric.FailureLimit != nil { + metrics.FailureLimit = metric.FailureLimit.IntVal + } else { + metrics.FailureLimit = 0 + } + + arInfo.Metrics = append(arInfo.Metrics, &metrics) + } + } arInfo.Status = string(run.Status.Phase) for _, mr := range run.Status.MetricResults { arInfo.Successful += mr.Successful arInfo.Failed += mr.Failed arInfo.Inconclusive += mr.Inconclusive arInfo.Error += mr.Error - lastMeasurement := analysisutil.LastMeasurement(run, mr.Name) - if lastMeasurement != nil && lastMeasurement.Metadata != nil { - if jobName, ok := lastMeasurement.Metadata[job.JobNameKey]; ok { - jobInfo := rollout.JobInfo{ - ObjectMeta: &v1.ObjectMeta{ - Name: jobName, - }, - Icon: analysisIcon(lastMeasurement.Phase), - Status: string(lastMeasurement.Phase), + for _, measurement := range analysisutil.ArrayMeasurement(run, mr.Name) { + if measurement.Metadata != nil { + if jobName, ok := measurement.Metadata[job.JobNameKey]; ok { + jobInfo := rollout.JobInfo{ + ObjectMeta: &v1.ObjectMeta{ + Name: jobName, + }, + Icon: analysisIcon(measurement.Phase), + Status: string(measurement.Phase), + StartedAt: measurement.StartedAt, + MetricName: mr.Name, + } + if measurement.StartedAt != nil { + jobInfo.ObjectMeta.CreationTimestamp = *measurement.StartedAt + } + arInfo.Jobs = append(arInfo.Jobs, &jobInfo) } - if lastMeasurement.StartedAt != nil { - jobInfo.ObjectMeta.CreationTimestamp = *lastMeasurement.StartedAt + } else { + nonJobInfo := rollout.NonJobInfo{ + Value: measurement.Value, + Status: string(measurement.Phase), + StartedAt: measurement.StartedAt, + MetricName: mr.Name, } - arInfo.Jobs = append(arInfo.Jobs, &jobInfo) + arInfo.NonJobInfo = append(arInfo.NonJobInfo, &nonJobInfo) } + } } arInfo.Icon = analysisIcon(run.Status.Phase) - arInfo.Revision = int32(parseRevision(run.ObjectMeta.Annotations)) - + arInfo.Revision = int64(parseRevision(run.ObjectMeta.Annotations)) arInfos = append(arInfos, &arInfo) } sort.Slice(arInfos[:], func(i, j int) bool { diff --git a/pkg/kubectl-argo-rollouts/info/experiment_info.go b/pkg/kubectl-argo-rollouts/info/experiment_info.go index 1799577cc1..e9f6ffb272 100644 --- a/pkg/kubectl-argo-rollouts/info/experiment_info.go +++ b/pkg/kubectl-argo-rollouts/info/experiment_info.go @@ -31,7 +31,7 @@ func NewExperimentInfo( Message: exp.Status.Message, } expInfo.Icon = analysisIcon(exp.Status.Phase) - expInfo.Revision = int32(parseRevision(exp.ObjectMeta.Annotations)) + expInfo.Revision = int64(parseRevision(exp.ObjectMeta.Annotations)) expInfo.ReplicaSets = GetReplicaSetInfo(exp.UID, nil, allReplicaSets, allPods) expInfo.AnalysisRuns = getAnalysisRunInfo(exp.UID, allAnalysisRuns) return &expInfo diff --git a/pkg/kubectl-argo-rollouts/info/replicaset_info.go b/pkg/kubectl-argo-rollouts/info/replicaset_info.go index d7d0655370..362261daef 100644 --- a/pkg/kubectl-argo-rollouts/info/replicaset_info.go +++ b/pkg/kubectl-argo-rollouts/info/replicaset_info.go @@ -36,7 +36,7 @@ func GetReplicaSetInfo(ownerUID types.UID, ro *v1alpha1.Rollout, allReplicaSets Available: rs.Status.AvailableReplicas, } rsInfo.Icon = replicaSetIcon(rsInfo.Status) - rsInfo.Revision = int32(parseRevision(rs.ObjectMeta.Annotations)) + rsInfo.Revision = int64(parseRevision(rs.ObjectMeta.Annotations)) rsInfo.Template = parseExperimentTemplateName(rs.ObjectMeta.Annotations) rsInfo.ScaleDownDeadline = parseScaleDownDeadline(rs.ObjectMeta.Annotations) diff --git a/pkg/kubectl-argo-rollouts/info/rollout_info.go b/pkg/kubectl-argo-rollouts/info/rollout_info.go index 98bfffb89c..59ee3f076a 100644 --- a/pkg/kubectl-argo-rollouts/info/rollout_info.go +++ b/pkg/kubectl-argo-rollouts/info/rollout_info.go @@ -229,7 +229,7 @@ func Revisions(r *rollout.RolloutInfo) []int { func ReplicaSetsByRevision(r *rollout.RolloutInfo, rev int) []*rollout.ReplicaSetInfo { var replicaSets []*rollout.ReplicaSetInfo for _, rs := range r.ReplicaSets { - if rs.Revision == int32(rev) { + if rs.Revision == int64(rev) { replicaSets = append(replicaSets, rs) } } diff --git a/pkg/kubectl-argo-rollouts/info/testdata/experiment-analysis/canary-analysis.yaml b/pkg/kubectl-argo-rollouts/info/testdata/experiment-analysis/canary-analysis.yaml index f27fa93e14..c792eca60d 100644 --- a/pkg/kubectl-argo-rollouts/info/testdata/experiment-analysis/canary-analysis.yaml +++ b/pkg/kubectl-argo-rollouts/info/testdata/experiment-analysis/canary-analysis.yaml @@ -12,88 +12,90 @@ metadata: name: rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr namespace: jesse-test ownerReferences: - - apiVersion: argoproj.io/v1alpha1 - blockOwnerDeletion: true - controller: true - kind: Rollout - name: rollout-experiment-analysis - uid: a17d1089-fae6-11e9-a15b-42010aa80033 + - apiVersion: argoproj.io/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: Rollout + name: rollout-experiment-analysis + uid: a17d1089-fae6-11e9-a15b-42010aa80033 resourceVersion: "29424124" selfLink: /apis/argoproj.io/v1alpha1/namespaces/jesse-test/analysisruns/rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr uid: e50bceec-fae6-11e9-a15b-42010aa80033 spec: metrics: - - interval: 10s - failureLimit: 5 - name: random-fail - provider: - job: - metadata: - creationTimestamp: null - spec: - backoffLimit: 0 - template: - metadata: - creationTimestamp: null - spec: - containers: - - args: - - FLIP=$(($(($RANDOM%10))%2)) && exit $FLIP - command: - - sh - - -c - image: alpine:3.8 - name: sleep - resources: {} - restartPolicy: Never + - interval: 10s + count: 10 + failureLimit: 5 + inconclusiveLimit: 1 + name: random-fail + provider: + job: + metadata: + creationTimestamp: null + spec: + backoffLimit: 0 + template: + metadata: + creationTimestamp: null + spec: + containers: + - args: + - FLIP=$(($(($RANDOM%10))%2)) && exit $FLIP + command: + - sh + - -c + image: alpine:3.8 + name: sleep + resources: {} + restartPolicy: Never status: metricResults: - - count: 8 - error: 1 - failed: 4 - inconclusive: 1 - measurements: - - finishedAt: "2019-10-30T07:28:40Z" - metadata: - job-name: rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-rzl6lt - startedAt: "2019-10-30T07:28:38Z" - phase: Failed - - finishedAt: "2019-10-30T07:28:53Z" - metadata: - job-name: rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-r8lqpd - startedAt: "2019-10-30T07:28:50Z" - phase: Successful - - finishedAt: "2019-10-30T07:29:05Z" - metadata: - job-name: rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-rjjsgg - startedAt: "2019-10-30T07:29:03Z" - phase: Successful - - finishedAt: "2019-10-30T07:29:17Z" - metadata: - job-name: rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-rrnfj5 - startedAt: "2019-10-30T07:29:15Z" - phase: Failed - - finishedAt: "2019-10-30T07:29:29Z" - metadata: - job-name: rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-rx5kqk - startedAt: "2019-10-30T07:29:27Z" - phase: Failed - - finishedAt: "2019-10-30T07:29:41Z" - metadata: - job-name: rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-rp894b - startedAt: "2019-10-30T07:29:39Z" - phase: Successful - - finishedAt: "2019-10-30T07:29:53Z" - metadata: - job-name: rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-rmngtj - startedAt: "2019-10-30T07:29:51Z" - phase: Failed - - finishedAt: "2019-10-30T16:13:40Z" - metadata: - job-name: rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-rsxm69 - startedAt: "2019-10-30T16:13:38Z" - phase: Successful - name: random-fail - phase: Inconclusive - successful: 4 + - count: 8 + error: 1 + failed: 4 + inconclusive: 1 + measurements: + - finishedAt: "2019-10-30T07:28:40Z" + metadata: + job-name: rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-rzl6lt + startedAt: "2019-10-30T07:28:38Z" + phase: Failed + - finishedAt: "2019-10-30T07:28:53Z" + metadata: + job-name: rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-r8lqpd + startedAt: "2019-10-30T07:28:50Z" + phase: Successful + - finishedAt: "2019-10-30T07:29:05Z" + metadata: + job-name: rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-rjjsgg + startedAt: "2019-10-30T07:29:03Z" + phase: Successful + - finishedAt: "2019-10-30T07:29:17Z" + metadata: + job-name: rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-rrnfj5 + startedAt: "2019-10-30T07:29:15Z" + phase: Failed + - finishedAt: "2019-10-30T07:29:29Z" + metadata: + job-name: rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-rx5kqk + startedAt: "2019-10-30T07:29:27Z" + phase: Failed + - finishedAt: "2019-10-30T07:29:41Z" + metadata: + job-name: rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-rp894b + startedAt: "2019-10-30T07:29:39Z" + phase: Successful + - finishedAt: "2019-10-30T07:29:53Z" + metadata: + job-name: rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-rmngtj + startedAt: "2019-10-30T07:29:51Z" + phase: Failed + - finishedAt: "2019-10-30T16:13:40Z" + metadata: + job-name: rollout-experiment-analysis-random-fail-6f646bf7b7-skqcr-rsxm69 + startedAt: "2019-10-30T16:13:38Z" + phase: Successful + name: random-fail + phase: Inconclusive + successful: 4 phase: Inconclusive diff --git a/ui/package.json b/ui/package.json index 234376cfce..898f96cf6b 100644 --- a/ui/package.json +++ b/ui/package.json @@ -23,7 +23,7 @@ "build": "rm -rf dist && webpack --config ./src/app/webpack.prod.js", "test": "react-scripts test", "eject": "react-scripts eject", - "protogen": "swagger-codegen generate -i ../pkg/apiclient/rollout/rollout.swagger.json -l typescript-fetch -o src/models/rollout/generated" + "protogen": "../hack/swagger-codegen.sh generate -i ../pkg/apiclient/rollout/rollout.swagger.json -l typescript-fetch -o src/models/rollout/generated" }, "eslintConfig": { "extends": [ @@ -68,4 +68,4 @@ "resolutions": { "@types/react": "16.9.3" } -} +} \ No newline at end of file diff --git a/ui/src/app/components/pods/pods.scss b/ui/src/app/components/pods/pods.scss index 29b72ac338..ee3121b111 100644 --- a/ui/src/app/components/pods/pods.scss +++ b/ui/src/app/components/pods/pods.scss @@ -32,6 +32,7 @@ $POD_SIZE: 30px; } } +/*This is used as an icon in pod, analysis job and analysis nonjob */ .pod-icon { width: $POD_SIZE; height: $POD_SIZE; @@ -42,6 +43,7 @@ $POD_SIZE: 30px; background-color: $fog; color: $shine; border-radius: 3px; + margin: 2px; cursor: pointer; &--success { diff --git a/ui/src/app/components/pods/pods.tsx b/ui/src/app/components/pods/pods.tsx index ae45adfef8..b45bd2e168 100644 --- a/ui/src/app/components/pods/pods.tsx +++ b/ui/src/app/components/pods/pods.tsx @@ -3,7 +3,6 @@ import * as React from 'react'; import * as moment from 'moment'; import {Duration, Ticker} from 'argo-ui'; import {RolloutReplicaSetInfo} from '../../../models/rollout/generated'; -import {Pod} from '../../../models/rollout/rollout'; import {ReplicaSetStatus, ReplicaSetStatusIcon} from '../status-icon/status-icon'; import './pods.scss'; @@ -23,6 +22,7 @@ export const ParsePodStatus = (status: string): PodStatus => { return PodStatus.Pending; case 'Running': case 'Completed': + case 'Successful': return PodStatus.Success; case 'Failed': case 'InvalidImageName': @@ -36,8 +36,8 @@ export const ParsePodStatus = (status: string): PodStatus => { } }; -export const PodIcon = (props: {status: string}) => { - const {status} = props; +export const PodIcon = (props: {status: string; customIcon?: string}) => { + const {status, customIcon} = props; let icon; let spin = false; if (status.startsWith('Init:')) { @@ -53,25 +53,27 @@ export const PodIcon = (props: {status: string}) => { const className = ParsePodStatus(status); - switch (className) { - case PodStatus.Pending: - icon = 'fa-circle-notch'; - spin = true; - break; - case PodStatus.Success: - icon = 'fa-check'; - break; - case PodStatus.Failed: - icon = 'fa-times'; - break; - case PodStatus.Warning: - icon = 'fa-exclamation-triangle'; - break; - default: - spin = false; - icon = 'fa-question-circle'; - break; - } + if (customIcon) icon = customIcon; + else + switch (className) { + case PodStatus.Pending: + icon = 'fa-circle-notch'; + spin = true; + break; + case PodStatus.Success: + icon = 'fa-check'; + break; + case PodStatus.Failed: + icon = 'fa-times'; + break; + case PodStatus.Warning: + icon = 'fa-exclamation-triangle'; + break; + default: + spin = false; + icon = 'fa-question-circle'; + break; + } return ( @@ -115,8 +117,13 @@ export const ReplicaSet = (props: {rs: RolloutReplicaSetInfo; showRevision?: boo {(now) => { const time = moment(props.rs.scaleDownDeadline).diff(now, 'second'); return time <= 0 ? null : ( - Scaledown in }> - as any} icon='fa fa-clock'> + + Scaledown in + + }> + ) as any} icon='fa fa-clock'> ); }} @@ -130,7 +137,17 @@ export const ReplicaSet = (props: {rs: RolloutReplicaSetInfo; showRevision?: boo {props.rs.pods.map((pod, i) => ( - + +
Status: {pod.status}
+
{pod.objectMeta?.name}
+
+ } + /> ))} @@ -139,16 +156,10 @@ export const ReplicaSet = (props: {rs: RolloutReplicaSetInfo; showRevision?: boo ); }; -export const PodWidget = (props: {pod: Pod}) => ( - navigator.clipboard.writeText(props.pod.objectMeta?.name), icon: 'fa-clipboard'}]}> - -
Status: {props.pod.status}
-
{props.pod.objectMeta?.name}
-
- }> - +export const PodWidget = ({name, status, tooltip, customIcon}: {name: string; status: string; tooltip: React.ReactNode; customIcon?: string}) => ( + navigator.clipboard.writeText(name), icon: 'fa-clipboard'}]}> + + ); diff --git a/ui/src/app/components/rollout/revision.tsx b/ui/src/app/components/rollout/revision.tsx index 014423cbfe..f61a9229c7 100644 --- a/ui/src/app/components/rollout/revision.tsx +++ b/ui/src/app/components/rollout/revision.tsx @@ -2,11 +2,13 @@ import {ActionButton, EffectDiv, formatTimestamp, InfoItemProps, InfoItemRow, Th import * as React from 'react'; import {RolloutAnalysisRunInfo, RolloutExperimentInfo, RolloutReplicaSetInfo} from '../../../models/rollout/generated'; import {IconForTag} from '../../shared/utils/utils'; -import {ReplicaSets} from '../pods/pods'; +import {PodWidget, ReplicaSets} from '../pods/pods'; import {ImageInfo, parseImages} from './rollout'; +import './rollout.scss'; +import '../pods/pods.scss'; export interface Revision { - number: number; + number: string; replicaSets: RolloutReplicaSetInfo[]; experiments: RolloutExperimentInfo[]; analysisRuns: RolloutAnalysisRunInfo[]; @@ -33,6 +35,7 @@ interface RevisionWidgetProps { initCollapsed?: boolean; rollback?: (revision: number) => void; current: boolean; + message: String; } export const RevisionWidget = (props: RevisionWidgetProps) => { @@ -46,7 +49,14 @@ export const RevisionWidget = (props: RevisionWidgetProps) => { Revision {revision.number}
{!props.current && props.rollback && ( - props.rollback(revision.number)} label='ROLLBACK' icon='fa-undo-alt' style={{fontSize: '13px'}} indicateLoading shouldConfirm /> + props.rollback(Number(revision.number))} + label='ROLLBACK' + icon='fa-undo-alt' + style={{fontSize: '13px'}} + indicateLoading + shouldConfirm + /> )} setCollapsed(!collapsed)}> @@ -75,22 +85,181 @@ export const RevisionWidget = (props: RevisionWidgetProps) => { const AnalysisRunWidget = (props: {analysisRuns: RolloutAnalysisRunInfo[]}) => { const {analysisRuns} = props; + const [selection, setSelection] = React.useState(null); + return ( -
Analysis Runs
+
Analysis Runs
- {analysisRuns.map((ar) => ( - -
{ar.objectMeta.name}
-
Created at {formatTimestamp(JSON.stringify(ar.objectMeta.creationTimestamp))}
- - }> - -
- ))} + {analysisRuns.map((ar) => { + let temp = ar.objectMeta.name.split('-'); + let len = temp.length; + return ( + +
+ Name: {ar.objectMeta.name} +
+
+ Created at: + {formatTimestamp(JSON.stringify(ar.objectMeta?.creationTimestamp))} +
+
+ Status: + {ar.status} +
+ + }> +
+ (selection?.objectMeta.name === ar.objectMeta.name ? setSelection(null) : setSelection(ar))} + label={`Analysis ${temp[len - 2] + '-' + temp[len - 1]}`} + /> +
+
+ ); + })}
+ + {selection && ( + +
+ {selection.objectMeta?.name} + +
+ {selection?.jobs && ( +
+
+ {selection.jobs.map((job) => { + return ( + +
job-name: {job.objectMeta?.name}
+
StartedAt: {formatTimestamp(JSON.stringify(job.startedAt))}
+
Status: {job.status}
+
MetricName: {job.metricName}
+
+ } + customIcon='fa-chart-bar' + /> + ); + })} +
+ metric.name === selection.jobs[0].metricName) + .map((metric) => { + return ( + + {metric?.name && ( +
+ MetricName: {metric.name} +
+ )} + {metric?.successCondition && ( +
+ SuccessCondition: + {metric.successCondition} +
+ )} + {metric?.failureLimit && ( +
+ FailureLimit: {metric.failureLimit} +
+ )} + {metric?.inconclusiveLimit && ( +
+ InconclusiveLimit: + {metric.inconclusiveLimit} +
+ )} + {metric?.count && ( +
+ Count: + {metric.count} +
+ )} +
+ ); + })}> + +
+
+ )} + {selection?.nonJobInfo && ( +
+
+ {selection.nonJobInfo.map((nonJob) => { + return ( + +
Value: {JSON.stringify(JSON.parse(nonJob.value), null, 2)}
+
StartedAt: {formatTimestamp(JSON.stringify(nonJob.startedAt))}
+
Status: {nonJob.status}
+
MetricName: {nonJob.metricName}
+
+ } + customIcon='fa-chart-bar' + /> + ); + })} +
+ metric.name === selection.nonJobInfo[0].metricName) + .map((metric) => { + return ( + + {metric?.name && ( +
+ MetricName: {metric.name} +
+ )} + {metric?.successCondition && ( +
+ SuccessCondition: + {metric.successCondition} +
+ )} + {metric?.failureLimit && ( +
+ FailureLimit: {metric.failureLimit} +
+ )} + {metric?.inconclusiveLimit && ( +
+ InconclusiveLimit: + {metric.inconclusiveLimit} +
+ )} + {metric?.count && ( +
+ Count: + {metric.count} +
+ )} +
+ ); + })}> + +
+ + )} + + )} ); }; diff --git a/ui/src/app/components/rollout/rollout.scss b/ui/src/app/components/rollout/rollout.scss index 6c2e6f020c..88819de47b 100644 --- a/ui/src/app/components/rollout/rollout.scss +++ b/ui/src/app/components/rollout/rollout.scss @@ -196,30 +196,110 @@ padding-top: 1em; border-top: 1px solid $argo-color-gray-4; &__runs { - margin-top: 1em; + margin: 12px 0px; display: flex; + flex-wrap: wrap; + + &-action { + &.analysis--pending .action-button__background { + background-color: $argo-color-gray-4; + border-color: $argo-color-gray-4; + } + + &.analysis--success .action-button__background { + background-color: $argo-success-color; + border-color: $argo-success-color; + } + + &.analysis--failure .action-button__background { + background-color: rgb(238, 111, 111); + border-color: rgb(238, 111, 111); + } + + .action-button { + font-size: '10px'; + line-height: 1; + border: '1px solid'; + padding: '8px 8px 8px 10px'; + border-radius: '12px'; + color: 'white'; + margin-top: 4px; + } + + &.analysis--success .action-button:hover { + .action-button__background { + background-color: seagreen; + border-color: seagreen; + } + } + + &.analysis--failure .action-button:hover { + .action-button__background { + background-color: red; + border-color: red; + } + } + } } &--dark { border-top: 1px solid $silver-lining; } + &-header { + font-size: 16px; + font-weight: 500; + display: flex; + align-items: center; + & i { + margin-left: 4px; + } + } &__run { width: 40px; + cursor: pointer; margin-right: 5px; + margin-bottom: 12px; height: 10px; - border-radius: 3px; + border-radius: 5px; background-color: $argo-color-gray-4; + &--successful { background-color: $argo-success-color; } - &--failed { background-color: $coral; } - &--running { - background-color: $sky; + &__jobs { + margin-top: 8px; + margin-bottom: 12px; + background-color: $argo-color-gray-3; + border-radius: 3px; + display: flex; + align-items: center; + padding: 7px; + + &-info { + font-size: 20px; + margin-left: 4px; + } + + &-list { + flex: 1 1 0; + display: flex; + align-items: center; + flex-wrap: wrap; + } } } + &--success { + color: $argo-success-color; + margin-left: 4px; + } + + &--failure { + color: $clay; + margin-left: 4px; + } } .containers { diff --git a/ui/src/app/components/rollout/rollout.tsx b/ui/src/app/components/rollout/rollout.tsx index b614968780..9b2a962244 100644 --- a/ui/src/app/components/rollout/rollout.tsx +++ b/ui/src/app/components/rollout/rollout.tsx @@ -151,6 +151,7 @@ export const RolloutWidget = (props: {rollout: RolloutRolloutInfo; interactive?: initCollapsed={false} rollback={interactive ? (r) => interactive.api.rolloutServiceUndoRollout({}, interactive.namespace, rollout.objectMeta.name, `${r}`) : null} current={i === 0} + message={rollout.message} /> ))} @@ -230,7 +231,7 @@ const ProcessRevisions = (ri: RolloutInfo): Revision[] => { if (!ri) { return; } - const map: {[key: number]: Revision} = {}; + const map: {[key: string]: Revision} = {}; const emptyRevision = {replicaSets: [], experiments: [], analysisRuns: []} as Revision; @@ -276,7 +277,8 @@ const parseDuration = (duration: string): string => { const Step = (props: {step: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStep; complete?: boolean; current?: boolean; last?: boolean}) => { const [openedTemplate, setOpenedTemplate] = React.useState(''); - const [open, setOpen] = React.useState(false); + const [openCanary, setOpenCanary] = React.useState(false); + const [openAnalysis, setOpenAnalysis] = React.useState(false); let icon: string; let content = ''; @@ -309,12 +311,20 @@ const Step = (props: {step: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1 return ( -
+
{icon && } {content} {unit} {props.step.setCanaryScale && ( - setOpen(!open)}> - + setOpenCanary(!openCanary)}> + + + )} + {props.step.analysis && ( + setOpenAnalysis(!openAnalysis)}> + )}
@@ -325,7 +335,22 @@ const Step = (props: {step: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1 })}
)} - {props.step?.setCanaryScale && open && } + + {props.step.analysis?.templates && openAnalysis && ( +
+
Templates
+
    + {props.step.analysis?.templates.map((template) => { + return ( +
    +
  • {template.templateName}
  • +
    + ); + })} +
+
+ )} + {props.step?.setCanaryScale && openCanary && }
{!props.last && }
diff --git a/ui/src/app/components/rollouts-list/rollouts-list.scss b/ui/src/app/components/rollouts-list/rollouts-list.scss index b5c58c61cd..3892e8cb9a 100644 --- a/ui/src/app/components/rollouts-list/rollouts-list.scss +++ b/ui/src/app/components/rollouts-list/rollouts-list.scss @@ -24,12 +24,12 @@ $colWidth: ($WIDGET_WIDTH + (2 * $widgetPadding)) + $widgetMarginRight; width: 3 * $colWidth; margin: 0 auto; - @media screen and (max-width: 3 * $colWidth) { + @media screen and (max-width: (3 * $colWidth)) { width: 2 * $colWidth; margin: 0 auto; } - @media screen and (max-width: 2 * $colWidth) { + @media screen and (max-width: (2 * $colWidth)) { width: $colWidth; .rollouts-list__widget { @@ -82,7 +82,7 @@ $colWidth: ($WIDGET_WIDTH + (2 * $widgetPadding)) + $widgetMarginRight; } } - @media screen and (max-width: 2 * $colWidth) { + @media screen and (max-width: (2 * $colWidth)) { width: 80%; } } diff --git a/ui/src/models/rollout/generated/api.ts b/ui/src/models/rollout/generated/api.ts index e0e6752792..fc2a6c7f4a 100644 --- a/ui/src/models/rollout/generated/api.ts +++ b/ui/src/models/rollout/generated/api.ts @@ -77,6 +77,31 @@ export class RequiredError extends Error { } } +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ALBStatus + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ALBStatus { + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AwsResourceRef} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ALBStatus + */ + loadBalancer?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AwsResourceRef; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AwsResourceRef} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ALBStatus + */ + canaryTargetGroup?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AwsResourceRef; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AwsResourceRef} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ALBStatus + */ + stableTargetGroup?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AwsResourceRef; +} /** * * @export @@ -101,6 +126,12 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ALBTrafficR * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ALBTrafficRouting */ rootService?: string; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StickinessConfig} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ALBTrafficRouting + */ + stickinessConfig?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StickinessConfig; /** * * @type {string} @@ -146,6 +177,25 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRun */ valueFrom?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ArgumentValueFrom; } +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunStrategy + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunStrategy { + /** + * + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunStrategy + */ + successfulRunHistoryLimit?: number; + /** + * + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunStrategy + */ + unsuccessfulRunHistoryLimit?: number; +} /** * * @export @@ -165,6 +215,76 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AntiAffinit */ requiredDuringSchedulingIgnoredDuringExecution?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RequiredDuringSchedulingIgnoredDuringExecution; } +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshTrafficRouting + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshTrafficRouting { + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshVirtualService} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshTrafficRouting + */ + virtualService?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshVirtualService; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshVirtualNodeGroup} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshTrafficRouting + */ + virtualNodeGroup?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshVirtualNodeGroup; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshVirtualNodeGroup + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshVirtualNodeGroup { + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshVirtualNodeReference} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshVirtualNodeGroup + */ + canaryVirtualNodeRef?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshVirtualNodeReference; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshVirtualNodeReference} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshVirtualNodeGroup + */ + stableVirtualNodeRef?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshVirtualNodeReference; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshVirtualNodeReference + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshVirtualNodeReference { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshVirtualNodeReference + */ + name?: string; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshVirtualService + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshVirtualService { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshVirtualService + */ + name?: string; + /** + * Routes is list of HTTP routes within virtual router associated with virtual service to edit. If omitted, virtual service must have a single route of this type. + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshVirtualService + */ + routes?: Array; +} /** * * @export @@ -184,6 +304,25 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ArgumentVal */ fieldRef?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1FieldRef; } +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AwsResourceRef + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AwsResourceRef { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AwsResourceRef + */ + name?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AwsResourceRef + */ + arn?: string; +} /** * * @export @@ -305,6 +444,12 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1BlueGreenSt * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1BlueGreenStrategy */ activeMetadata?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PodTemplateMetadata; + /** + * + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1BlueGreenStrategy + */ + abortScaleDownDelaySeconds?: number; } /** * @@ -330,6 +475,18 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStatu * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStatus */ currentExperiment?: string; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1TrafficWeights} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStatus + */ + weights?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1TrafficWeights; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStatus + */ + stablePingPong?: string; } /** * CanaryStep defines a step of a canary deployment. @@ -446,6 +603,37 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStrat * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStrategy */ scaleDownDelayRevisionLimit?: number; + /** + * + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStrategy + */ + abortScaleDownDelaySeconds?: number; + /** + * DynamicStableScale is a traffic routing feature which dynamically scales the stable ReplicaSet to minimize total pods which are running during an update. This is calculated by scaling down the stable as traffic is increased to canary. When disabled (the default behavior) the stable ReplicaSet remains fully scaled to support instantaneous aborts. + * @type {boolean} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStrategy + */ + dynamicStableScale?: boolean; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PingPongSpec} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStrategy + */ + pingPong?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PingPongSpec; +} +/** + * DryRun defines the settings for running the analysis in Dry-Run mode. + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1DryRun + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1DryRun { + /** + * Name of the metric which needs to be evaluated in the Dry-Run mode. Wildcard '*' is supported and denotes all the available metrics. + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1DryRun + */ + metricName?: string; } /** * @@ -503,6 +691,12 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioTraffi * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioTrafficRouting */ destinationRule?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioDestinationRule; + /** + * + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioTrafficRouting + */ + virtualServices?: Array; } /** * @@ -517,11 +711,36 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioVirtua */ name?: string; /** - * + * A list of HTTP routes within VirtualService to edit. If omitted, VirtualService must have a single route of this type. * @type {Array} * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioVirtualService */ routes?: Array; + /** + * A list of TLS/HTTPS routes within VirtualService to edit. If omitted, VirtualService must have a single route of this type. + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioVirtualService + */ + tlsRoutes?: Array; +} +/** + * MeasurementRetention defines the settings for retaining the number of measurements during the analysis. + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MeasurementRetention + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MeasurementRetention { + /** + * MetricName is the name of the metric on which this retention policy should be applied. + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MeasurementRetention + */ + metricName?: string; + /** + * Limit is the maximum number of measurements to be retained for this given metric. + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MeasurementRetention + */ + limit?: number; } /** * @@ -592,6 +811,25 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PauseCondit */ startTime?: K8sIoApimachineryPkgApisMetaV1Time; } +/** + * PingPongSpec holds the ping and pong service name. + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PingPongSpec + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PingPongSpec { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PingPongSpec + */ + pingService?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PingPongSpec + */ + pongService?: string; +} /** * * @export @@ -674,6 +912,18 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutAnal * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutAnalysis */ args?: Array; + /** + * + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutAnalysis + */ + dryRun?: Array; + /** + * + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutAnalysis + */ + measurementRetention?: Array; } /** * @@ -867,12 +1117,6 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutExpe * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutExperimentTemplate */ replicas?: number; - /** - * - * @type {number} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutExperimentTemplate - */ - weight?: number; /** * * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1PodTemplateMetadata} @@ -885,6 +1129,12 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutExpe * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutExperimentTemplate */ selector?: K8sIoApimachineryPkgApisMetaV1LabelSelector; + /** + * + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutExperimentTemplate + */ + weight?: number; } /** * @@ -959,12 +1209,24 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutSpec * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutSpec */ progressDeadlineSeconds?: number; + /** + * + * @type {boolean} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutSpec + */ + progressDeadlineAbort?: boolean; /** * * @type {K8sIoApimachineryPkgApisMetaV1Time} * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutSpec */ restartAt?: K8sIoApimachineryPkgApisMetaV1Time; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunStrategy} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutSpec + */ + analysis?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AnalysisRunStrategy; } /** * @@ -1098,6 +1360,30 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutStat * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutStatus */ promoteFull?: boolean; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutStatus + */ + phase?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutStatus + */ + message?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutStatus + */ + workloadObservedGeneration?: string; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ALBStatus} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutStatus + */ + alb?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1ALBStatus; } /** * @@ -1154,6 +1440,12 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutTraf * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutTrafficRouting */ ambassador?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AmbassadorTrafficRouting; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshTrafficRouting} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutTrafficRouting + */ + appMesh?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshTrafficRouting; } /** * @@ -1199,6 +1491,100 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetCanarySc */ matchTrafficWeight?: boolean; } +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StickinessConfig + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StickinessConfig { + /** + * + * @type {boolean} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StickinessConfig + */ + enabled?: boolean; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StickinessConfig + */ + durationSeconds?: string; +} +/** + * TLSRoute holds the information on the virtual service's TLS/HTTPS routes that are desired to be matched for changing weights. + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1TLSRoute + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1TLSRoute { + /** + * Port number of the TLS Route desired to be matched in the given Istio VirtualService. + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1TLSRoute + */ + port?: string; + /** + * A list of all the SNI Hosts of the TLS Route desired to be matched in the given Istio VirtualService. + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1TLSRoute + */ + sniHosts?: Array; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1TrafficWeights + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1TrafficWeights { + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WeightDestination} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1TrafficWeights + */ + canary?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WeightDestination; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WeightDestination} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1TrafficWeights + */ + stable?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WeightDestination; + /** + * + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1TrafficWeights + */ + additional?: Array; + /** + * + * @type {boolean} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1TrafficWeights + */ + verified?: boolean; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WeightDestination + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WeightDestination { + /** + * + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WeightDestination + */ + weight?: number; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WeightDestination + */ + serviceName?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1WeightDestination + */ + podTemplateHash?: string; +} /** * * @export @@ -1560,7 +1946,7 @@ export interface K8sIoApiCoreV1ConfigMapEnvSource { optional?: boolean; } /** - * Selects a key from a ConfigMap. + * * @export * @interface K8sIoApiCoreV1ConfigMapKeySelector */ @@ -1980,7 +2366,7 @@ export interface K8sIoApiCoreV1EnvVarSource { secretKeyRef?: K8sIoApiCoreV1SecretKeySelector; } /** - * An EphemeralContainer is a container that may be added temporarily to an existing pod for user-initiated activities such as debugging. Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a pod is removed or restarted. If an ephemeral container causes a pod to exceed its resource allocation, the pod may be evicted. Ephemeral containers may not be added by directly updating the pod spec. They must be added via the pod's ephemeralcontainers subresource, and they will appear in the pod spec once added. This is an alpha feature enabled by the EphemeralContainers feature flag. + * An EphemeralContainer is a temporary container that you may add to an existing Pod for user-initiated activities such as debugging. Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a Pod is removed or restarted. The kubelet may evict a Pod if an ephemeral container causes the Pod to exceed its resource allocation. To add an ephemeral container, use the ephemeralcontainers subresource of an existing Pod. Ephemeral containers may not be removed or restarted. This is a beta feature available on clusters that haven't disabled the EphemeralContainers feature gate. * @export * @interface K8sIoApiCoreV1EphemeralContainer */ @@ -1992,7 +2378,7 @@ export interface K8sIoApiCoreV1EphemeralContainer { */ ephemeralContainerCommon?: K8sIoApiCoreV1EphemeralContainerCommon; /** - * + * If set, the name of the container from PodSpec that this ephemeral container targets. The ephemeral container will be run in the namespaces (IPC, PID, etc) of this container. If not set then the ephemeral container uses the namespaces configured in the Pod spec. The container runtime must implement support for this feature. If the runtime does not support namespace targeting then the result of setting this field is undefined. +optional * @type {string} * @memberof K8sIoApiCoreV1EphemeralContainer */ @@ -2035,7 +2421,7 @@ export interface K8sIoApiCoreV1EphemeralContainerCommon { */ workingDir?: string; /** - * Ports are not allowed for ephemeral containers. + * * @type {Array} * @memberof K8sIoApiCoreV1EphemeralContainerCommon */ @@ -2149,12 +2535,6 @@ export interface K8sIoApiCoreV1EphemeralVolumeSource { * @memberof K8sIoApiCoreV1EphemeralVolumeSource */ volumeClaimTemplate?: K8sIoApiCoreV1PersistentVolumeClaimTemplate; - /** - * - * @type {boolean} - * @memberof K8sIoApiCoreV1EphemeralVolumeSource - */ - readOnly?: boolean; } /** * ExecAction describes a \"run in container\" action. @@ -2293,6 +2673,25 @@ export interface K8sIoApiCoreV1GCEPersistentDiskVolumeSource { */ readOnly?: boolean; } +/** + * + * @export + * @interface K8sIoApiCoreV1GRPCAction + */ +export interface K8sIoApiCoreV1GRPCAction { + /** + * Port number of the gRPC service. Number must be in the range 1 to 65535. + * @type {number} + * @memberof K8sIoApiCoreV1GRPCAction + */ + port?: number; + /** + * Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). If this is not specified, the default behavior is defined by gRPC. +optional +default=\"\" + * @type {string} + * @memberof K8sIoApiCoreV1GRPCAction + */ + service?: string; +} /** * Represents a volume that is populated with the contents of a git repository. Git repo volumes do not support ownership management. Git repo volumes support SELinux relabeling. DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir into the Pod's container. * @export @@ -2399,31 +2798,6 @@ export interface K8sIoApiCoreV1HTTPHeader { */ value?: string; } -/** - * Handler defines a specific action that should be taken TODO: pass structured data to these actions, and document that data here. - * @export - * @interface K8sIoApiCoreV1Handler - */ -export interface K8sIoApiCoreV1Handler { - /** - * - * @type {K8sIoApiCoreV1ExecAction} - * @memberof K8sIoApiCoreV1Handler - */ - exec?: K8sIoApiCoreV1ExecAction; - /** - * - * @type {K8sIoApiCoreV1HTTPGetAction} - * @memberof K8sIoApiCoreV1Handler - */ - httpGet?: K8sIoApiCoreV1HTTPGetAction; - /** - * - * @type {K8sIoApiCoreV1TCPSocketAction} - * @memberof K8sIoApiCoreV1Handler - */ - tcpSocket?: K8sIoApiCoreV1TCPSocketAction; -} /** * HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the pod's hosts file. * @export @@ -2568,19 +2942,44 @@ export interface K8sIoApiCoreV1KeyToPath { export interface K8sIoApiCoreV1Lifecycle { /** * - * @type {K8sIoApiCoreV1Handler} + * @type {K8sIoApiCoreV1LifecycleHandler} * @memberof K8sIoApiCoreV1Lifecycle */ - postStart?: K8sIoApiCoreV1Handler; + postStart?: K8sIoApiCoreV1LifecycleHandler; /** * - * @type {K8sIoApiCoreV1Handler} + * @type {K8sIoApiCoreV1LifecycleHandler} * @memberof K8sIoApiCoreV1Lifecycle */ - preStop?: K8sIoApiCoreV1Handler; + preStop?: K8sIoApiCoreV1LifecycleHandler; +} +/** + * LifecycleHandler defines a specific action that should be taken in a lifecycle hook. One and only one of the fields, except TCPSocket must be specified. + * @export + * @interface K8sIoApiCoreV1LifecycleHandler + */ +export interface K8sIoApiCoreV1LifecycleHandler { + /** + * + * @type {K8sIoApiCoreV1ExecAction} + * @memberof K8sIoApiCoreV1LifecycleHandler + */ + exec?: K8sIoApiCoreV1ExecAction; + /** + * + * @type {K8sIoApiCoreV1HTTPGetAction} + * @memberof K8sIoApiCoreV1LifecycleHandler + */ + httpGet?: K8sIoApiCoreV1HTTPGetAction; + /** + * + * @type {K8sIoApiCoreV1TCPSocketAction} + * @memberof K8sIoApiCoreV1LifecycleHandler + */ + tcpSocket?: K8sIoApiCoreV1TCPSocketAction; } /** - * LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace. + * * @export * @interface K8sIoApiCoreV1LocalObjectReference */ @@ -2637,7 +3036,7 @@ export interface K8sIoApiCoreV1NodeAffinity { preferredDuringSchedulingIgnoredDuringExecution?: Array; } /** - * A node selector represents the union of the results of one or more label queries over a set of nodes; that is, it represents the OR of the selectors represented by the node selector terms. + * * @export * @interface K8sIoApiCoreV1NodeSelector */ @@ -2675,7 +3074,7 @@ export interface K8sIoApiCoreV1NodeSelectorRequirement { values?: Array; } /** - * A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + * * @export * @interface K8sIoApiCoreV1NodeSelectorTerm */ @@ -2694,7 +3093,7 @@ export interface K8sIoApiCoreV1NodeSelectorTerm { matchFields?: Array; } /** - * ObjectFieldSelector selects an APIVersioned field of an object. + * * @export * @interface K8sIoApiCoreV1ObjectFieldSelector */ @@ -2760,6 +3159,12 @@ export interface K8sIoApiCoreV1PersistentVolumeClaimSpec { * @memberof K8sIoApiCoreV1PersistentVolumeClaimSpec */ dataSource?: K8sIoApiCoreV1TypedLocalObjectReference; + /** + * + * @type {K8sIoApiCoreV1TypedLocalObjectReference} + * @memberof K8sIoApiCoreV1PersistentVolumeClaimSpec + */ + dataSourceRef?: K8sIoApiCoreV1TypedLocalObjectReference; } /** * PersistentVolumeClaimTemplate is used to produce PersistentVolumeClaim objects as part of an EphemeralVolumeSource. @@ -2861,6 +3266,12 @@ export interface K8sIoApiCoreV1PodAffinityTerm { * @memberof K8sIoApiCoreV1PodAffinityTerm */ topologyKey?: string; + /** + * + * @type {K8sIoApimachineryPkgApisMetaV1LabelSelector} + * @memberof K8sIoApiCoreV1PodAffinityTerm + */ + namespaceSelector?: K8sIoApimachineryPkgApisMetaV1LabelSelector; } /** * Pod anti affinity is a group of inter pod anti affinity scheduling rules. @@ -2925,6 +3336,19 @@ export interface K8sIoApiCoreV1PodDNSConfigOption { */ value?: string; } +/** + * PodOS defines the OS parameters of a pod. + * @export + * @interface K8sIoApiCoreV1PodOS + */ +export interface K8sIoApiCoreV1PodOS { + /** + * + * @type {string} + * @memberof K8sIoApiCoreV1PodOS + */ + name?: string; +} /** * * @export @@ -2981,7 +3405,7 @@ export interface K8sIoApiCoreV1PodSecurityContext { */ supplementalGroups?: Array; /** - * 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- If unset, the Kubelet will not modify the ownership and permissions of any volume. +optional + * 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- If unset, the Kubelet will not modify the ownership and permissions of any volume. Note that this field cannot be set when spec.os.name is windows. +optional * @type {string} * @memberof K8sIoApiCoreV1PodSecurityContext */ @@ -3221,6 +3645,12 @@ export interface K8sIoApiCoreV1PodSpec { * @memberof K8sIoApiCoreV1PodSpec */ setHostnameAsFQDN?: boolean; + /** + * + * @type {K8sIoApiCoreV1PodOS} + * @memberof K8sIoApiCoreV1PodSpec + */ + os?: K8sIoApiCoreV1PodOS; } /** * @@ -3293,10 +3723,10 @@ export interface K8sIoApiCoreV1PreferredSchedulingTerm { export interface K8sIoApiCoreV1Probe { /** * - * @type {K8sIoApiCoreV1Handler} + * @type {K8sIoApiCoreV1ProbeHandler} * @memberof K8sIoApiCoreV1Probe */ - handler?: K8sIoApiCoreV1Handler; + handler?: K8sIoApiCoreV1ProbeHandler; /** * * @type {number} @@ -3327,6 +3757,43 @@ export interface K8sIoApiCoreV1Probe { * @memberof K8sIoApiCoreV1Probe */ failureThreshold?: number; + /** + * + * @type {string} + * @memberof K8sIoApiCoreV1Probe + */ + terminationGracePeriodSeconds?: string; +} +/** + * ProbeHandler defines a specific action that should be taken in a probe. One and only one of the fields must be specified. + * @export + * @interface K8sIoApiCoreV1ProbeHandler + */ +export interface K8sIoApiCoreV1ProbeHandler { + /** + * + * @type {K8sIoApiCoreV1ExecAction} + * @memberof K8sIoApiCoreV1ProbeHandler + */ + exec?: K8sIoApiCoreV1ExecAction; + /** + * + * @type {K8sIoApiCoreV1HTTPGetAction} + * @memberof K8sIoApiCoreV1ProbeHandler + */ + httpGet?: K8sIoApiCoreV1HTTPGetAction; + /** + * + * @type {K8sIoApiCoreV1TCPSocketAction} + * @memberof K8sIoApiCoreV1ProbeHandler + */ + tcpSocket?: K8sIoApiCoreV1TCPSocketAction; + /** + * + * @type {K8sIoApiCoreV1GRPCAction} + * @memberof K8sIoApiCoreV1ProbeHandler + */ + grpc?: K8sIoApiCoreV1GRPCAction; } /** * @@ -3626,7 +4093,7 @@ export interface K8sIoApiCoreV1SecretEnvSource { optional?: boolean; } /** - * SecretKeySelector selects a key of a Secret. + * * @export * @interface K8sIoApiCoreV1SecretKeySelector */ @@ -3935,7 +4402,7 @@ export interface K8sIoApiCoreV1TopologySpreadConstraint { */ topologyKey?: string; /** - * WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy the spread constraint. - DoNotSchedule (default) tells the scheduler not to schedule it. - ScheduleAnyway tells the scheduler to schedule the pod in any location, but giving higher precedence to topologies that would help reduce the skew. A constraint is considered \"Unsatisfiable\" for an incoming pod if and only if every possible node assigment for that pod would violate \"MaxSkew\" on some topology. For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same labelSelector spread as 3/1/1: +-------+-------+-------+ | zone1 | zone2 | zone3 | +-------+-------+-------+ | P P P | P | P | +-------+-------+-------+ If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler won't make it *more* imbalanced. It's a required field. + * WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy the spread constraint. - DoNotSchedule (default) tells the scheduler not to schedule it. - ScheduleAnyway tells the scheduler to schedule the pod in any location, but giving higher precedence to topologies that would help reduce the skew. A constraint is considered \"Unsatisfiable\" for an incoming pod if and only if every possible node assignment for that pod would violate \"MaxSkew\" on some topology. For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same labelSelector spread as 3/1/1: +-------+-------+-------+ | zone1 | zone2 | zone3 | +-------+-------+-------+ | P P P | P | P | +-------+-------+-------+ If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler won't make it *more* imbalanced. It's a required field. * @type {string} * @memberof K8sIoApiCoreV1TopologySpreadConstraint */ @@ -3948,7 +4415,7 @@ export interface K8sIoApiCoreV1TopologySpreadConstraint { labelSelector?: K8sIoApimachineryPkgApisMetaV1LabelSelector; } /** - * TypedLocalObjectReference contains enough information to let you locate the typed referenced object inside the same namespace. + * * @export * @interface K8sIoApiCoreV1TypedLocalObjectReference */ @@ -4339,6 +4806,12 @@ export interface K8sIoApiCoreV1WindowsSecurityContextOptions { * @memberof K8sIoApiCoreV1WindowsSecurityContextOptions */ runAsUserName?: string; + /** + * + * @type {boolean} + * @memberof K8sIoApiCoreV1WindowsSecurityContextOptions + */ + hostProcess?: boolean; } /** * Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and AsInt64() accessors. The serialization format is: ::= (Note that may be empty, from the \"\" case in .) ::= 0 | 1 | ... | 9 ::= | ::= | . | . | . ::= \"+\" | \"-\" ::= | ::= | | ::= Ki | Mi | Gi | Ti | Pi | Ei (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html) ::= m | \"\" | k | M | G | T | P | E (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.) ::= \"e\" | \"E\" No matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities. When a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized. Before serializing, Quantity will be put in \"canonical form\". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that: a. No precision is lost b. No fractional digits will be emitted c. The exponent (or suffix) is as large as possible. The sign will be omitted unless the number is negative. Examples: 1.5 will be serialized as \"1500m\" 1.5Gi will be serialized as \"1536Mi\" Note that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise. Non-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.) This format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation. +protobuf=true +protobuf.embed=string +protobuf.options.marshal=false +protobuf.options.(gogoproto.goproto_stringer)=false +k8s:deepcopy-gen=true +k8s:openapi-gen=true @@ -4452,6 +4925,12 @@ export interface K8sIoApimachineryPkgApisMetaV1ManagedFieldsEntry { * @memberof K8sIoApimachineryPkgApisMetaV1ManagedFieldsEntry */ fieldsV1?: K8sIoApimachineryPkgApisMetaV1FieldsV1; + /** + * Subresource is the name of the subresource used to update that object, or empty string if the object was updated through the main resource. The value of this field is used to distinguish between managers, even if they share the same name. For example, a status update will be distinct from a regular update using the same manager name. Note that the APIVersion field is not related to the Subresource field and it always corresponds to the version of the main resource. + * @type {string} + * @memberof K8sIoApimachineryPkgApisMetaV1ManagedFieldsEntry + */ + subresource?: string; } /** * ObjectMeta is metadata that all persisted resources must have, which includes all objects users must create. @@ -4557,7 +5036,7 @@ export interface K8sIoApimachineryPkgApisMetaV1ObjectMeta { managedFields?: Array; } /** - * OwnerReference contains enough information to let you identify an owning object. An owning object must be in the same namespace as the dependent, or be cluster-scoped, so there is no namespace field. + * * @export * @interface K8sIoApimachineryPkgApisMetaV1OwnerReference */ @@ -4682,10 +5161,10 @@ export interface RolloutAnalysisRunInfo { icon?: string; /** * - * @type {number} + * @type {string} * @memberof RolloutAnalysisRunInfo */ - revision?: number; + revision?: string; /** * * @type {string} @@ -4722,6 +5201,18 @@ export interface RolloutAnalysisRunInfo { * @memberof RolloutAnalysisRunInfo */ jobs?: Array; + /** + * + * @type {Array} + * @memberof RolloutAnalysisRunInfo + */ + nonJobInfo?: Array; + /** + * + * @type {Array} + * @memberof RolloutAnalysisRunInfo + */ + metrics?: Array; } /** * @@ -4762,10 +5253,10 @@ export interface RolloutExperimentInfo { icon?: string; /** * - * @type {number} + * @type {string} * @memberof RolloutExperimentInfo */ - revision?: number; + revision?: string; /** * * @type {string} @@ -4815,6 +5306,55 @@ export interface RolloutJobInfo { * @memberof RolloutJobInfo */ icon?: string; + /** + * + * @type {string} + * @memberof RolloutJobInfo + */ + metricName?: string; + /** + * + * @type {K8sIoApimachineryPkgApisMetaV1Time} + * @memberof RolloutJobInfo + */ + startedAt?: K8sIoApimachineryPkgApisMetaV1Time; +} +/** + * + * @export + * @interface RolloutMetrics + */ +export interface RolloutMetrics { + /** + * + * @type {string} + * @memberof RolloutMetrics + */ + name?: string; + /** + * + * @type {string} + * @memberof RolloutMetrics + */ + successCondition?: string; + /** + * + * @type {number} + * @memberof RolloutMetrics + */ + count?: number; + /** + * + * @type {number} + * @memberof RolloutMetrics + */ + inconclusiveLimit?: number; + /** + * + * @type {number} + * @memberof RolloutMetrics + */ + failureLimit?: number; } /** * @@ -4829,12 +5369,43 @@ export interface RolloutNamespaceInfo { */ namespace?: string; /** - * + * * @type {Array} * @memberof RolloutNamespaceInfo */ availableNamespaces?: Array; } +/** + * + * @export + * @interface RolloutNonJobInfo + */ +export interface RolloutNonJobInfo { + /** + * + * @type {string} + * @memberof RolloutNonJobInfo + */ + value?: string; + /** + * + * @type {string} + * @memberof RolloutNonJobInfo + */ + status?: string; + /** + * + * @type {string} + * @memberof RolloutNonJobInfo + */ + metricName?: string; + /** + * + * @type {K8sIoApimachineryPkgApisMetaV1Time} + * @memberof RolloutNonJobInfo + */ + startedAt?: K8sIoApimachineryPkgApisMetaV1Time; +} /** * * @export @@ -4923,10 +5494,10 @@ export interface RolloutReplicaSetInfo { icon?: string; /** * - * @type {number} + * @type {string} * @memberof RolloutReplicaSetInfo */ - revision?: number; + revision?: string; /** * * @type {boolean} @@ -4987,6 +5558,18 @@ export interface RolloutReplicaSetInfo { * @memberof RolloutReplicaSetInfo */ pods?: Array; + /** + * + * @type {boolean} + * @memberof RolloutReplicaSetInfo + */ + ping?: boolean; + /** + * + * @type {boolean} + * @memberof RolloutReplicaSetInfo + */ + pong?: boolean; } /** * diff --git a/ui/yarn.lock b/ui/yarn.lock index 89c94a9f4e..649423d763 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -12381,4 +12381,4 @@ yargs@^15.4.1: yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== \ No newline at end of file diff --git a/utils/analysis/helpers.go b/utils/analysis/helpers.go index 067950e776..64506ebae0 100644 --- a/utils/analysis/helpers.go +++ b/utils/analysis/helpers.go @@ -178,6 +178,14 @@ func LastMeasurement(run *v1alpha1.AnalysisRun, metricName string) *v1alpha1.Mea return nil } +func ArrayMeasurement(run *v1alpha1.AnalysisRun, metricName string) []v1alpha1.Measurement { + if result := GetResult(run, metricName); result != nil && len(result.Measurements) > 0 { + return result.Measurements + } + + return nil +} + // TerminateRun terminates an analysis run func TerminateRun(analysisRunIf argoprojclient.AnalysisRunInterface, name string) error { _, err := analysisRunIf.Patch(context.TODO(), name, patchtypes.MergePatchType, []byte(`{"spec":{"terminate":true}}`), metav1.PatchOptions{}) diff --git a/utils/analysis/helpers_test.go b/utils/analysis/helpers_test.go index 5568380e43..c7bd003c18 100644 --- a/utils/analysis/helpers_test.go +++ b/utils/analysis/helpers_test.go @@ -165,6 +165,31 @@ func TestLastMeasurement(t *testing.T) { assert.Nil(t, LastMeasurement(run, "success-rate")) } +func TestArrayMeasurement(t *testing.T) { + m1 := v1alpha1.Measurement{ + Phase: v1alpha1.AnalysisPhaseSuccessful, + Value: "99", + } + m2 := v1alpha1.Measurement{ + Phase: v1alpha1.AnalysisPhaseSuccessful, + Value: "98", + } + run := &v1alpha1.AnalysisRun{ + Status: v1alpha1.AnalysisRunStatus{ + Phase: v1alpha1.AnalysisPhaseRunning, + MetricResults: []v1alpha1.MetricResult{ + { + Name: "success-rate", + Phase: v1alpha1.AnalysisPhaseRunning, + Measurements: []v1alpha1.Measurement{m1, m2}, + }, + }, + }, + } + assert.Nil(t, ArrayMeasurement(run, "non-existent")) + assert.Equal(t, run.Status.MetricResults[0].Measurements, ArrayMeasurement(run, "success-rate")) +} + func TestIsTerminating(t *testing.T) { run := &v1alpha1.AnalysisRun{ Status: v1alpha1.AnalysisRunStatus{ From d93b043160ad97105dc16b987050177d67bbd6a8 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Fri, 3 Jun 2022 14:19:29 -0500 Subject: [PATCH 132/175] fix: UI codegen (#2072) Signed-off-by: zachaller --- ui/src/models/rollout/generated/api.ts | 82 ++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/ui/src/models/rollout/generated/api.ts b/ui/src/models/rollout/generated/api.ts index fc2a6c7f4a..1b4336be76 100644 --- a/ui/src/models/rollout/generated/api.ts +++ b/ui/src/models/rollout/generated/api.ts @@ -524,6 +524,12 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStep * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStep */ setCanaryScale?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetCanaryScale; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetHeaderRouting} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStep + */ + setHeaderRouting?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetHeaderRouting; } /** * @@ -648,6 +654,25 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1FieldRef { */ fieldPath?: string; } +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1HeaderRoutingMatch + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1HeaderRoutingMatch { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1HeaderRoutingMatch + */ + headerName?: string; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1HeaderRoutingMatch + */ + headerValue?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch; +} /** * * @export @@ -1446,6 +1471,12 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutTraf * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutTrafficRouting */ appMesh?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1AppMeshTrafficRouting; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1TraefikTrafficRouting} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutTrafficRouting + */ + traefik?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1TraefikTrafficRouting; } /** * @@ -1491,6 +1522,19 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetCanarySc */ matchTrafficWeight?: boolean; } +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetHeaderRouting + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetHeaderRouting { + /** + * + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetHeaderRouting + */ + match?: Array; +} /** * * @export @@ -1510,6 +1554,31 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StickinessC */ durationSeconds?: string; } +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch + */ + exact?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch + */ + prefix?: string; + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch + */ + regex?: string; +} /** * TLSRoute holds the information on the virtual service's TLS/HTTPS routes that are desired to be matched for changing weights. * @export @@ -1529,6 +1598,19 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1TLSRoute { */ sniHosts?: Array; } +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1TraefikTrafficRouting + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1TraefikTrafficRouting { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1TraefikTrafficRouting + */ + weightedTraefikServiceName?: string; +} /** * * @export From 3f5960efc21b5d8db44cbf20b779ab74d6fdaa99 Mon Sep 17 00:00:00 2001 From: RaviHari Date: Mon, 6 Jun 2022 22:45:51 +0530 Subject: [PATCH 133/175] fix: notifications when condition (#2066) * fix: notifications when condition Signed-off-by: Ravi Hari * fix: trigger check Signed-off-by: Ravi Hari --- utils/record/record.go | 19 +++++++++++--- utils/record/record_test.go | 52 +++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/utils/record/record.go b/utils/record/record.go index d6f00bd469..3ad05671b2 100644 --- a/utils/record/record.go +++ b/utils/record/record.go @@ -278,11 +278,22 @@ func (e *EventRecorderAdapter) sendNotifications(object runtime.Object, opts Eve return err } + res, err := notificationsAPI.RunTrigger(trigger, objMap) + if err != nil { + log.Errorf("Failed to execute condition of trigger %s: %v", trigger, err) + return err + } + log.Infof("Trigger %s result: %v", trigger, res) + for _, dest := range destinations { - err = notificationsAPI.Send(objMap, triggerActions[0].Send, dest) - if err != nil { - log.Errorf("notification error: %s", err.Error()) - return err + for _, c := range res { + if c.Triggered == true { + err = notificationsAPI.Send(objMap, triggerActions[0].Send, dest) + if err != nil { + log.Errorf("notification error: %s", err.Error()) + return err + } + } } } return nil diff --git a/utils/record/record_test.go b/utils/record/record_test.go index b3b34e7a3d..931ce42c9b 100644 --- a/utils/record/record_test.go +++ b/utils/record/record_test.go @@ -95,6 +95,12 @@ func TestSendNotifications(t *testing.T) { } mockCtrl := gomock.NewController(t) mockAPI := mocks.NewMockAPI(mockCtrl) + cr := []triggers.ConditionResult{{ + Key: "", + Triggered: true, + Templates: []string{"my-template"}, + }} + mockAPI.EXPECT().RunTrigger(gomock.Any(), gomock.Any()).Return(cr, nil).AnyTimes() mockAPI.EXPECT().Send(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() mockAPI.EXPECT().GetConfig().Return(api.Config{ Triggers: map[string][]triggers.Condition{"on-foo-reason": {triggers.Condition{Send: []string{"my-template"}}}}}).AnyTimes() @@ -194,6 +200,52 @@ func TestSendNotificationsFails(t *testing.T) { t.Run("SendError", func(t *testing.T) { mockCtrl := gomock.NewController(t) mockAPI := mocks.NewMockAPI(mockCtrl) + cr := []triggers.ConditionResult{{ + Key: "", + Triggered: true, + Templates: []string{"my-template"}, + }} + mockAPI.EXPECT().RunTrigger(gomock.Any(), gomock.Any()).Return(cr, nil).AnyTimes() + mockAPI.EXPECT().Send(gomock.Any(), gomock.Any(), gomock.Any()).Return(fmt.Errorf("failed to send")).AnyTimes() + mockAPI.EXPECT().GetConfig().Return(api.Config{ + Triggers: map[string][]triggers.Condition{"on-foo-reason": {triggers.Condition{Send: []string{"my-template"}}}}}).AnyTimes() + apiFactory := &mocks.FakeFactory{Api: mockAPI} + rec := NewFakeEventRecorder() + rec.EventRecorderAdapter.apiFactory = apiFactory + + err := rec.sendNotifications(&r, EventOptions{EventReason: "FooReason"}) + assert.Error(t, err) + }) + + t.Run("GetAPIError", func(t *testing.T) { + apiFactory := &mocks.FakeFactory{Err: errors.New("failed to get API")} + rec := NewFakeEventRecorder() + rec.EventRecorderAdapter.apiFactory = apiFactory + + err := rec.sendNotifications(&r, EventOptions{EventReason: "FooReason"}) + assert.Error(t, err) + }) + +} + +func TestSendNotificationsFailsWithRunTriggerError(t *testing.T) { + r := v1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Name: "guestbook", + Namespace: "default", + Annotations: map[string]string{"notifications.argoproj.io/subscribe.on-foo-reason.console": "console"}, + }, + } + + t.Run("SendError", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + mockAPI := mocks.NewMockAPI(mockCtrl) + cr := []triggers.ConditionResult{{ + Key: "", + Triggered: true, + Templates: []string{"my-template"}, + }} + mockAPI.EXPECT().RunTrigger(gomock.Any(), gomock.Any()).Return(cr, errors.New("fail")).AnyTimes() mockAPI.EXPECT().Send(gomock.Any(), gomock.Any(), gomock.Any()).Return(fmt.Errorf("failed to send")).AnyTimes() mockAPI.EXPECT().GetConfig().Return(api.Config{ Triggers: map[string][]triggers.Condition{"on-foo-reason": {triggers.Condition{Send: []string{"my-template"}}}}}).AnyTimes() From a6dbe0ec2db3f02cf695ba3c972db72cecabaefb Mon Sep 17 00:00:00 2001 From: schakrad <58915923+schakrad@users.noreply.github.com> Date: Mon, 13 Jun 2022 14:42:37 -0400 Subject: [PATCH 134/175] feat: ArgoRollouts dashboard now supporting rootpath (#2075) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: add workaround to fix 'stream terminated by RST_STREAM with error code: PROTOCOL_ERROR' Signed-off-by: Alexander Matyushentsev * ArgoRollouts dashboard should support rootpath Signed-off-by: “schakradari” * fixed camelCase naming Signed-off-by: “schakradari” * fixed Lint error Signed-off-by: “schakradari” Co-authored-by: Alexander Matyushentsev Co-authored-by: Remington Breeze --- .../cmd/dashboard/dashboard.go | 3 ++ server/server.go | 42 +++++++++++++++---- ui/src/app/App.tsx | 10 ++--- ui/src/app/components/header/header.tsx | 4 +- 4 files changed, 43 insertions(+), 16 deletions(-) diff --git a/pkg/kubectl-argo-rollouts/cmd/dashboard/dashboard.go b/pkg/kubectl-argo-rollouts/cmd/dashboard/dashboard.go index ce081a764c..b3acb06854 100644 --- a/pkg/kubectl-argo-rollouts/cmd/dashboard/dashboard.go +++ b/pkg/kubectl-argo-rollouts/cmd/dashboard/dashboard.go @@ -9,6 +9,7 @@ import ( ) func NewCmdDashboard(o *options.ArgoRolloutsOptions) *cobra.Command { + var rootPath string var cmd = &cobra.Command{ Use: "dashboard", Short: "Start UI dashboard", @@ -22,6 +23,7 @@ func NewCmdDashboard(o *options.ArgoRolloutsOptions) *cobra.Command { KubeClientset: kubeclientset, RolloutsClientset: rolloutclientset, DynamicClientset: o.DynamicClientset(), + RootPath: rootPath, } for { @@ -33,6 +35,7 @@ func NewCmdDashboard(o *options.ArgoRolloutsOptions) *cobra.Command { } }, } + cmd.Flags().StringVar(&rootPath, "rootPath", "rollouts", "renders the ui url with rootPath prefixed") return cmd } diff --git a/server/server.go b/server/server.go index 393cc97a08..a7bb7f298e 100644 --- a/server/server.go +++ b/server/server.go @@ -1,13 +1,14 @@ package server import ( + "bufio" "context" "embed" "fmt" - "io/fs" "net" "net/http" "os" + "regexp" "strings" "time" @@ -61,6 +62,7 @@ type ServerOptions struct { RolloutsClientset rolloutclientset.Interface DynamicClientset dynamic.Interface Namespace string + RootPath string } const ( @@ -91,6 +93,35 @@ func (fs *spaFileSystem) Open(name string) (http.File, error) { return f, err } +//This function helps in changing base href to point to rootpath as basepath, we are making modification in only server/static/index.html file +func withRootPath(rootpath string) { + inputFile, inputError := os.Open("./server/static/index.html") + if inputError != nil { + log.Error("An error occurred on opening the inputfile\n" + + "Does the file exist?\n" + + "Have you got access to it?\n") + panic(inputError) // exit on error + } + defer inputFile.Close() + inputReader := bufio.NewReader(inputFile) + inputString, _ := inputReader.ReadString('\n') + re := regexp.MustCompile(``) + var temp = re.ReplaceAllString(inputString, "") // href="/root/" + + outputFile, _ := os.OpenFile("./server/static/index.html", os.O_TRUNC|os.O_WRONLY, 0666) + defer outputFile.Close() + outputWriter := bufio.NewWriter(outputFile) + outputWriter.WriteString(temp) + outputWriter.Flush() + + //To make ui/dist/index.html file consistent with server/static/index.html + outputFileDist, _ := os.OpenFile("./ui/dist/app/index.html", os.O_TRUNC|os.O_WRONLY, 0666) + defer outputFileDist.Close() + outputWriterDist := bufio.NewWriter(outputFileDist) + outputWriterDist.WriteString(temp) + outputWriterDist.Flush() +} + func (s *ArgoRolloutsServer) newHTTPServer(ctx context.Context, port int) *http.Server { mux := http.NewServeMux() endpoint := fmt.Sprintf("0.0.0.0:%d", port) @@ -122,14 +153,11 @@ func (s *ArgoRolloutsServer) newHTTPServer(ctx context.Context, port int) *http. var handler http.Handler = gwmux - ui, err := fs.Sub(static, "static") - if err != nil { - log.Error("Could not load UI static files") - panic(err) - } + withRootPath(s.Options.RootPath) mux.Handle("/api/", handler) - mux.Handle("/", http.FileServer(&spaFileSystem{http.FS(ui)})) + + mux.Handle("/"+s.Options.RootPath+"/", http.StripPrefix("/"+s.Options.RootPath+"/", http.FileServer(http.Dir("./server/static")))) return &httpS } diff --git a/ui/src/app/App.tsx b/ui/src/app/App.tsx index 504878a683..644aa3b4e7 100644 --- a/ui/src/app/App.tsx +++ b/ui/src/app/App.tsx @@ -3,7 +3,7 @@ import {Header} from './components/header/header'; import {createBrowserHistory} from 'history'; import * as React from 'react'; import {Key, KeybindingContext, KeybindingProvider} from 'react-keyhooks'; -import {Redirect, Route, Router, Switch} from 'react-router-dom'; +import {Route, Router, Switch} from 'react-router-dom'; import './App.scss'; import {NamespaceContext, RolloutAPI} from './shared/context/api'; import {Modal} from './components/modal/modal'; @@ -90,11 +90,9 @@ const App = () => { - - } shortcuts={[ {key: '/', description: 'Search'}, @@ -105,8 +103,6 @@ const App = () => { changeNamespace={changeNamespace} /> } changeNamespace={changeNamespace} /> - - @@ -116,4 +112,4 @@ const App = () => { ); }; -export default App; +export default App; \ No newline at end of file diff --git a/ui/src/app/components/header/header.tsx b/ui/src/app/components/header/header.tsx index ff58a99114..90d51ee7c8 100644 --- a/ui/src/app/components/header/header.tsx +++ b/ui/src/app/components/header/header.tsx @@ -55,7 +55,7 @@ export const Header = (props: {pageHasShortcuts: boolean; changeNamespace: (val: onChange={(el) => setNsInput(el.target.value)} onItemClick={(val) => { props.changeNamespace(val ? val : nsInput); - history.push(`/rollouts`); + history.push(`/`); }} value={nsInput} /> @@ -65,4 +65,4 @@ export const Header = (props: {pageHasShortcuts: boolean; changeNamespace: (val: ); -}; +}; \ No newline at end of file From 1d0f9cf6bbc67580a60319c216e26a8dd5f5e824 Mon Sep 17 00:00:00 2001 From: Travis Perdue Date: Wed, 22 Jun 2022 10:36:16 -0500 Subject: [PATCH 135/175] add additionalStableIngresses datatype Signed-off-by: Travis Perdue --- manifests/crds/rollout-crd.yaml | 4 ++++ manifests/install.yaml | 4 ++++ manifests/namespace-install.yaml | 4 ++++ pkg/apiclient/rollout/rollout.swagger.json | 7 +++++++ pkg/apis/api-rules/violation_exceptions.list | 1 + pkg/apis/rollouts/v1alpha1/types.go | 3 +++ pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go | 5 +++++ ui/src/models/rollout/generated/api.ts | 6 ++++++ 8 files changed, 34 insertions(+) diff --git a/manifests/crds/rollout-crd.yaml b/manifests/crds/rollout-crd.yaml index bda1fdd4fc..a295f43046 100644 --- a/manifests/crds/rollout-crd.yaml +++ b/manifests/crds/rollout-crd.yaml @@ -761,6 +761,10 @@ spec: additionalProperties: type: string type: object + additionalStableIngresses: + items: + type: string + type: array annotationPrefix: type: string stableIngress: diff --git a/manifests/install.yaml b/manifests/install.yaml index 00ff531b5c..d9bdc9cad1 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -11729,6 +11729,10 @@ spec: additionalProperties: type: string type: object + additionalStableIngresses: + items: + type: string + type: array annotationPrefix: type: string stableIngress: diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 3edf1348e4..f900efb5eb 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -11729,6 +11729,10 @@ spec: additionalProperties: type: string type: object + additionalStableIngresses: + items: + type: string + type: array annotationPrefix: type: string stableIngress: diff --git a/pkg/apiclient/rollout/rollout.swagger.json b/pkg/apiclient/rollout/rollout.swagger.json index 384103913b..8028a3fbc5 100644 --- a/pkg/apiclient/rollout/rollout.swagger.json +++ b/pkg/apiclient/rollout/rollout.swagger.json @@ -1027,6 +1027,13 @@ "type": "string" }, "title": "+optional" + }, + "additionalStableIngresses": { + "type": "array", + "items": { + "type": "string" + }, + "title": "AdditionalStableIngresses refers to the names of `Ingress` resources in the same namespace as the `Rollout` in a multi ingress scenario\n+optional" } }, "title": "NginxTrafficRouting configuration for Nginx ingress controller to control traffic routing" diff --git a/pkg/apis/api-rules/violation_exceptions.list b/pkg/apis/api-rules/violation_exceptions.list index d9cc556c27..96ebd0bc27 100644 --- a/pkg/apis/api-rules/violation_exceptions.list +++ b/pkg/apis/api-rules/violation_exceptions.list @@ -25,6 +25,7 @@ API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,IstioVirtualService,TLSRoutes API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,KayentaMetric,Scopes API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,MetricResult,Measurements +API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,NginxTrafficRouting,AdditionalStableIngresses API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutAnalysis,Args API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutAnalysis,DryRun API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutAnalysis,MeasurementRetention diff --git a/pkg/apis/rollouts/v1alpha1/types.go b/pkg/apis/rollouts/v1alpha1/types.go index 04d45fddcd..f2fffbf9b8 100644 --- a/pkg/apis/rollouts/v1alpha1/types.go +++ b/pkg/apis/rollouts/v1alpha1/types.go @@ -398,6 +398,9 @@ type NginxTrafficRouting struct { StableIngress string `json:"stableIngress" protobuf:"bytes,2,opt,name=stableIngress"` // +optional AdditionalIngressAnnotations map[string]string `json:"additionalIngressAnnotations,omitempty" protobuf:"bytes,3,rep,name=additionalIngressAnnotations"` + // AdditionalStableIngresses refers to the names of `Ingress` resources in the same namespace as the `Rollout` in a multi ingress scenario + // +optional + AdditionalStableIngresses []string `json:"additionalStableIngresses,omitempty" protobuf:"bytes,4,rep,name=additionalStableIngresses"` } // IstioTrafficRouting configuration for Istio service mesh to enable fine grain configuration diff --git a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go index e45cf0dba6..5a3739b95d 100644 --- a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go @@ -1632,6 +1632,11 @@ func (in *NginxTrafficRouting) DeepCopyInto(out *NginxTrafficRouting) { (*out)[key] = val } } + if in.AdditionalStableIngresses != nil { + in, out := &in.AdditionalStableIngresses, &out.AdditionalStableIngresses + *out = make([]string, len(*in)) + copy(*out, *in) + } return } diff --git a/ui/src/models/rollout/generated/api.ts b/ui/src/models/rollout/generated/api.ts index 1b4336be76..8de7ed3865 100644 --- a/ui/src/models/rollout/generated/api.ts +++ b/ui/src/models/rollout/generated/api.ts @@ -791,6 +791,12 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1NginxTraffi * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1NginxTrafficRouting */ additionalIngressAnnotations?: { [key: string]: string; }; + /** + * + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1NginxTrafficRouting + */ + additionalStableIngresses?: Array; } /** * From 22845f2ca761afd103a05e2102de134dc8d0d603 Mon Sep 17 00:00:00 2001 From: Travis Perdue Date: Wed, 22 Jun 2022 10:50:18 -0500 Subject: [PATCH 136/175] add validation for additionalStableIngresses Signed-off-by: Travis Perdue --- .../validation/validation_references.go | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/pkg/apis/rollouts/validation/validation_references.go b/pkg/apis/rollouts/validation/validation_references.go index a4d5561f4a..55128f993b 100644 --- a/pkg/apis/rollouts/validation/validation_references.go +++ b/pkg/apis/rollouts/validation/validation_references.go @@ -218,23 +218,39 @@ func setArgValuePlaceHolder(Args []v1alpha1.Argument) { func ValidateIngress(rollout *v1alpha1.Rollout, ingress *ingressutil.Ingress) field.ErrorList { allErrs := field.ErrorList{} fldPath := field.NewPath("spec", "strategy", "canary", "trafficRouting") + canary := rollout.Spec.Strategy.Canary var ingressName string var serviceName string - if rollout.Spec.Strategy.Canary.TrafficRouting.Nginx != nil { + if canary.TrafficRouting.Nginx != nil { + // If there are additional stable ingresses + if len(canary.TrafficRouting.Nginx.AdditionalStableIngresses) > 0 { + // validate each ingress as valid + fldPath = fldPath.Child("nginx").Child("additionalStableIngresses") + serviceName = canary.StableService + for _, ing := range canary.TrafficRouting.Nginx.AdditionalStableIngresses { + ingressName = ing + allErrs = reportErrors(ingress, serviceName, ingressName, fldPath, allErrs) + } + } fldPath = fldPath.Child("nginx").Child("stableIngress") - serviceName = rollout.Spec.Strategy.Canary.StableService - ingressName = rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress - } else if rollout.Spec.Strategy.Canary.TrafficRouting.ALB != nil { + serviceName = canary.StableService + ingressName = canary.TrafficRouting.Nginx.StableIngress + + allErrs = reportErrors(ingress, serviceName, ingressName, fldPath, allErrs) + } else if canary.TrafficRouting.ALB != nil { fldPath = fldPath.Child("alb").Child("ingress") - ingressName = rollout.Spec.Strategy.Canary.TrafficRouting.ALB.Ingress - serviceName = rollout.Spec.Strategy.Canary.StableService - if rollout.Spec.Strategy.Canary.TrafficRouting.ALB.RootService != "" { - serviceName = rollout.Spec.Strategy.Canary.TrafficRouting.ALB.RootService + ingressName = canary.TrafficRouting.ALB.Ingress + serviceName = canary.StableService + if canary.TrafficRouting.ALB.RootService != "" { + serviceName = canary.TrafficRouting.ALB.RootService } - - } else { - return allErrs + allErrs = reportErrors(ingress, serviceName, ingressName, fldPath, allErrs) } + + return allErrs +} + +func reportErrors(ingress *ingressutil.Ingress, serviceName, ingressName string, fldPath *field.Path, allErrs field.ErrorList) field.ErrorList { if !ingressutil.HasRuleWithService(ingress, serviceName) { msg := fmt.Sprintf("ingress `%s` has no rules using service %s backend", ingress.GetName(), serviceName) allErrs = append(allErrs, field.Invalid(fldPath, ingressName, msg)) From 066ed1e2e00f562147c9f48748813bf10b222063 Mon Sep 17 00:00:00 2001 From: Travis Perdue Date: Wed, 22 Jun 2022 11:01:43 -0500 Subject: [PATCH 137/175] add rollout controller logic for additionalStableIngresses Signed-off-by: Travis Perdue --- rollout/controller.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/rollout/controller.go b/rollout/controller.go index 827c7a7a20..c0434e726a 100644 --- a/rollout/controller.go +++ b/rollout/controller.go @@ -780,6 +780,19 @@ func (c *rolloutContext) getReferencedIngresses() (*[]ingressutil.Ingress, error } ingresses = append(ingresses, *ingress) } else if canary.TrafficRouting.Nginx != nil { + // If the rollout resource manages more than 1 ingress + if len(canary.TrafficRouting.Nginx.AdditionalStableIngresses) > 0 { + for _, ing := range canary.TrafficRouting.Nginx.AdditionalStableIngresses { + ingress, err := c.ingressWrapper.GetCached(c.rollout.Namespace, ing) + if k8serrors.IsNotFound(err) { + return nil, field.Invalid(fldPath.Child("nginx", "AdditionalStableIngresses"), canary.TrafficRouting.Nginx.StableIngress, err.Error()) + } + if err != nil { + return nil, err + } + ingresses = append(ingresses, *ingress) + } + } ingress, err := c.ingressWrapper.GetCached(c.rollout.Namespace, canary.TrafficRouting.Nginx.StableIngress) if k8serrors.IsNotFound(err) { return nil, field.Invalid(fldPath.Child("nginx", "stableIngress"), canary.TrafficRouting.Nginx.StableIngress, err.Error()) From e3024292848d7ae304e7930a796eac0cd7229087 Mon Sep 17 00:00:00 2001 From: Travis Perdue Date: Wed, 22 Jun 2022 14:48:55 -0500 Subject: [PATCH 138/175] add nginx ingress logic for setting weight & fetching names for additionalStableIngresses Signed-off-by: Travis Perdue --- rollout/trafficrouting/nginx/nginx.go | 150 ++++++++++++++------------ utils/ingress/ingress.go | 32 ++++-- 2 files changed, 107 insertions(+), 75 deletions(-) diff --git a/rollout/trafficrouting/nginx/nginx.go b/rollout/trafficrouting/nginx/nginx.go index a0d291c121..b278a182ff 100644 --- a/rollout/trafficrouting/nginx/nginx.go +++ b/rollout/trafficrouting/nginx/nginx.go @@ -222,88 +222,106 @@ func (r *Reconciler) canaryIngress(stableIngress *ingressutil.Ingress, name stri // SetWeight modifies Nginx Ingress resources to reach desired state func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error { - ctx := context.TODO() - stableIngressName := r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress - canaryIngressName := ingressutil.GetCanaryIngressName(r.cfg.Rollout) - - // Check if stable ingress exists (from lister, which has a cache), error if it does not - stableIngress, err := r.cfg.IngressWrapper.GetCached(r.cfg.Rollout.Namespace, stableIngressName) - if err != nil { - r.log.WithField(logutil.IngressKey, stableIngressName).WithField("err", err.Error()).Error("error retrieving stableIngress") - return fmt.Errorf("error retrieving stableIngress `%s` from cache: %v", stableIngressName, err) - } - // Check if canary ingress exists (from lister which has a cache), determines whether we later call Create() or Update() - canaryIngress, err := r.cfg.IngressWrapper.GetCached(r.cfg.Rollout.Namespace, canaryIngressName) - - canaryIngressExists := true - if err != nil { - if !k8serrors.IsNotFound(err) { - // An error other than "not found" occurred - r.log.WithField(logutil.IngressKey, canaryIngressName).WithField("err", err.Error()).Error("error retrieving canary ingress") - return fmt.Errorf("error retrieving canary ingress `%s` from cache: %v", canaryIngressName, err) + // Set weight for additional ingresses if present + if ingresses := r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.AdditionalStableIngresses; ingresses != nil { + // Fail out if there is an issue setting weight on additional ingresesses. + // Fundamental assumption is that each additional Ingress is equal in importance + // as primary Ingress resource. + if err := r.SetWeightPerIngress(desiredWeight, ingresses); err != nil { + return err } - r.log.WithField(logutil.IngressKey, canaryIngressName).Infof("canary ingress not found") - canaryIngressExists = false - } - // Construct the desired canary Ingress resource - desiredCanaryIngress, err := r.canaryIngress(stableIngress, canaryIngressName, desiredWeight) - if err != nil { - r.log.WithField(logutil.IngressKey, canaryIngressName).Error(err.Error()) - return err } - if !canaryIngressExists { - r.cfg.Recorder.Eventf(r.cfg.Rollout, record.EventOptions{EventReason: "CreatingCanaryIngress"}, "Creating canary ingress `%s` with weight `%d`", canaryIngressName, desiredWeight) - _, err = r.cfg.IngressWrapper.Create(ctx, r.cfg.Rollout.Namespace, desiredCanaryIngress, metav1.CreateOptions{}) - if err == nil { - return nil + return r.SetWeightPerIngress(desiredWeight, []string{r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress}) +} + +// SetWeightMultiIngress modifies each Nginx Ingress resource to reach desired state in the scenario of a rollout +// having multiple Ngnix Ingress resources. +func (r *Reconciler) SetWeightPerIngress(desiredWeight int32, ingresses []string) error { + for _, ingress := range ingresses { + ctx := context.TODO() + stableIngressName := ingress + canaryIngressName := ingressutil.GetCanaryIngressName(r.cfg.Rollout.GetName(), stableIngressName) + + // Check if stable ingress exists (from lister, which has a cache), error if it does not + stableIngress, err := r.cfg.IngressWrapper.GetCached(r.cfg.Rollout.Namespace, stableIngressName) + if err != nil { + r.log.WithField(logutil.IngressKey, stableIngressName).WithField("err", err.Error()).Error("error retrieving stableIngress") + return fmt.Errorf("error retrieving stableIngress `%s` from cache: %v", stableIngressName, err) } - if !k8serrors.IsAlreadyExists(err) { - r.log.WithField(logutil.IngressKey, canaryIngressName).WithField("err", err.Error()).Error("error creating canary ingress") - return fmt.Errorf("error creating canary ingress `%s`: %v", canaryIngressName, err) + // Check if canary ingress exists (from lister which has a cache), determines whether we later call Create() or Update() + canaryIngress, err := r.cfg.IngressWrapper.GetCached(r.cfg.Rollout.Namespace, canaryIngressName) + + canaryIngressExists := true + if err != nil { + if !k8serrors.IsNotFound(err) { + // An error other than "not found" occurred + r.log.WithField(logutil.IngressKey, canaryIngressName).WithField("err", err.Error()).Error("error retrieving canary ingress") + return fmt.Errorf("error retrieving canary ingress `%s` from cache: %v", canaryIngressName, err) + } + r.log.WithField(logutil.IngressKey, canaryIngressName).Infof("canary ingress not found") + canaryIngressExists = false } - // Canary ingress was created by a different reconcile call before this one could complete (race) - // This means we just read it from the API now (instead of cache) and continue with the normal - // flow we take when the canary already existed. - canaryIngress, err = r.cfg.IngressWrapper.Get(ctx, r.cfg.Rollout.Namespace, canaryIngressName, metav1.GetOptions{}) + + // Construct the desired canary Ingress resource + desiredCanaryIngress, err := r.canaryIngress(stableIngress, canaryIngressName, desiredWeight) if err != nil { r.log.WithField(logutil.IngressKey, canaryIngressName).Error(err.Error()) - return fmt.Errorf("error retrieving canary ingress `%s` from api: %v", canaryIngressName, err) + return err + } + + if !canaryIngressExists { + r.cfg.Recorder.Eventf(r.cfg.Rollout, record.EventOptions{EventReason: "CreatingCanaryIngress"}, "Creating canary ingress `%s` with weight `%d`", canaryIngressName, desiredWeight) + _, err = r.cfg.IngressWrapper.Create(ctx, r.cfg.Rollout.Namespace, desiredCanaryIngress, metav1.CreateOptions{}) + if err == nil { + return nil + } + if !k8serrors.IsAlreadyExists(err) { + r.log.WithField(logutil.IngressKey, canaryIngressName).WithField("err", err.Error()).Error("error creating canary ingress") + return fmt.Errorf("error creating canary ingress `%s`: %v", canaryIngressName, err) + } + // Canary ingress was created by a different reconcile call before this one could complete (race) + // This means we just read it from the API now (instead of cache) and continue with the normal + // flow we take when the canary already existed. + canaryIngress, err = r.cfg.IngressWrapper.Get(ctx, r.cfg.Rollout.Namespace, canaryIngressName, metav1.GetOptions{}) + if err != nil { + r.log.WithField(logutil.IngressKey, canaryIngressName).Error(err.Error()) + return fmt.Errorf("error retrieving canary ingress `%s` from api: %v", canaryIngressName, err) + } } - } - // Canary Ingress already exists, apply a patch if needed + // Canary Ingress already exists, apply a patch if needed - // Only modify canaryIngress if it is controlled by this Rollout - if !metav1.IsControlledBy(canaryIngress.GetObjectMeta(), r.cfg.Rollout) { - r.log.WithField(logutil.IngressKey, canaryIngressName).Error("canary ingress controlled by different object") - return fmt.Errorf("canary ingress `%s` controlled by different object", canaryIngressName) - } + // Only modify canaryIngress if it is controlled by this Rollout + if !metav1.IsControlledBy(canaryIngress.GetObjectMeta(), r.cfg.Rollout) { + r.log.WithField(logutil.IngressKey, canaryIngressName).Error("canary ingress controlled by different object") + return fmt.Errorf("canary ingress `%s` controlled by different object", canaryIngressName) + } - // Make patches - patch, modified, err := ingressutil.BuildIngressPatch(canaryIngress.Mode(), canaryIngress, - desiredCanaryIngress, ingressutil.WithAnnotations(), ingressutil.WithLabels(), ingressutil.WithSpec()) + // Make patches + patch, modified, err := ingressutil.BuildIngressPatch(canaryIngress.Mode(), canaryIngress, + desiredCanaryIngress, ingressutil.WithAnnotations(), ingressutil.WithLabels(), ingressutil.WithSpec()) - if err != nil { - r.log.WithField(logutil.IngressKey, canaryIngressName).WithField("err", err.Error()).Error("error constructing canary ingress patch") - return fmt.Errorf("error constructing canary ingress patch for `%s`: %v", canaryIngressName, err) - } - if !modified { - r.log.WithField(logutil.IngressKey, canaryIngressName).Info("No changes to canary ingress - skipping patch") - return nil - } + if err != nil { + r.log.WithField(logutil.IngressKey, canaryIngressName).WithField("err", err.Error()).Error("error constructing canary ingress patch") + return fmt.Errorf("error constructing canary ingress patch for `%s`: %v", canaryIngressName, err) + } + if !modified { + r.log.WithField(logutil.IngressKey, canaryIngressName).Info("No changes to canary ingress - skipping patch") + return nil + } - r.log.WithField(logutil.IngressKey, canaryIngressName).WithField("patch", string(patch)).Debug("applying canary Ingress patch") - r.log.WithField(logutil.IngressKey, canaryIngressName).WithField("desiredWeight", desiredWeight).Info("updating canary Ingress") - r.cfg.Recorder.Eventf(r.cfg.Rollout, record.EventOptions{EventReason: "PatchingCanaryIngress"}, "Updating Ingress `%s` to desiredWeight '%d'", canaryIngressName, desiredWeight) + r.log.WithField(logutil.IngressKey, canaryIngressName).WithField("patch", string(patch)).Debug("applying canary Ingress patch") + r.log.WithField(logutil.IngressKey, canaryIngressName).WithField("desiredWeight", desiredWeight).Info("updating canary Ingress") + r.cfg.Recorder.Eventf(r.cfg.Rollout, record.EventOptions{EventReason: "PatchingCanaryIngress"}, "Updating Ingress `%s` to desiredWeight '%d'", canaryIngressName, desiredWeight) - _, err = r.cfg.IngressWrapper.Patch(ctx, r.cfg.Rollout.Namespace, canaryIngressName, types.MergePatchType, patch, metav1.PatchOptions{}) - if err != nil { - r.log.WithField(logutil.IngressKey, canaryIngressName).WithField("err", err.Error()).Error("error patching canary ingress") - return fmt.Errorf("error patching canary ingress `%s`: %v", canaryIngressName, err) + _, err = r.cfg.IngressWrapper.Patch(ctx, r.cfg.Rollout.Namespace, canaryIngressName, types.MergePatchType, patch, metav1.PatchOptions{}) + if err != nil { + r.log.WithField(logutil.IngressKey, canaryIngressName).WithField("err", err.Error()).Error("error patching canary ingress") + return fmt.Errorf("error patching canary ingress `%s`: %v", canaryIngressName, err) + } } - return nil } diff --git a/utils/ingress/ingress.go b/utils/ingress/ingress.go index 42dc61ca20..d5bcb99d4d 100644 --- a/utils/ingress/ingress.go +++ b/utils/ingress/ingress.go @@ -62,13 +62,31 @@ func GetRolloutIngressKeys(rollout *v1alpha1.Rollout) []string { rollout.Spec.Strategy.Canary.TrafficRouting.Nginx != nil && rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress != "" { + stableIngress := rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress // Also start watcher for `-canary` ingress which is created by the trafficmanagement controller ingresses = append( ingresses, - fmt.Sprintf("%s/%s", rollout.Namespace, rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress), - fmt.Sprintf("%s/%s", rollout.Namespace, GetCanaryIngressName(rollout)), + fmt.Sprintf("%s/%s", rollout.Namespace, stableIngress), + fmt.Sprintf("%s/%s", rollout.Namespace, GetCanaryIngressName(rollout.GetName(), stableIngress)), ) } + + // Scenario where one rollout is managing multiple Ngnix ingresses. + if rollout.Spec.Strategy.Canary != nil && + rollout.Spec.Strategy.Canary.TrafficRouting != nil && + rollout.Spec.Strategy.Canary.TrafficRouting.Nginx != nil && + len(rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.AdditionalStableIngresses) > 0 { + + for _, stableIngress := range rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.AdditionalStableIngresses { + // Also start watcher for `-canary` ingress which is created by the trafficmanagement controller + ingresses = append( + ingresses, + fmt.Sprintf("%s/%s", rollout.Namespace, stableIngress), + fmt.Sprintf("%s/%s", rollout.Namespace, GetCanaryIngressName(rollout.GetName(), stableIngress)), + ) + } + } + if rollout.Spec.Strategy.Canary != nil && rollout.Spec.Strategy.Canary.TrafficRouting != nil && rollout.Spec.Strategy.Canary.TrafficRouting.ALB != nil && @@ -83,14 +101,10 @@ func GetRolloutIngressKeys(rollout *v1alpha1.Rollout) []string { } // GetCanaryIngressName constructs the name to use for the canary ingress resource from a given Rollout -func GetCanaryIngressName(rollout *v1alpha1.Rollout) string { +func GetCanaryIngressName(rolloutName, stableIngressName string) string { // names limited to 253 characters - if rollout.Spec.Strategy.Canary != nil && - rollout.Spec.Strategy.Canary.TrafficRouting != nil && - rollout.Spec.Strategy.Canary.TrafficRouting.Nginx != nil && - rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress != "" { - - prefix := fmt.Sprintf("%s-%s", rollout.GetName(), rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress) + if stableIngressName != "" { + prefix := fmt.Sprintf("%s-%s", rolloutName, stableIngressName) if len(prefix) > 253-len(CanaryIngressSuffix) { // trim prefix prefix = prefix[0 : 253-len(CanaryIngressSuffix)] From 24c6aecfb926053aac92a966b81644197d723032 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Wed, 22 Jun 2022 15:15:09 -0500 Subject: [PATCH 139/175] Update membership permissions. (#2112) Add myself (zachaller) and Leo (leoluz) to OWNERS file. Signed-off-by: zachaller --- OWNERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OWNERS b/OWNERS index 4552f99648..eba5228bfd 100644 --- a/OWNERS +++ b/OWNERS @@ -7,6 +7,7 @@ approvers: - huikang - jessesuen - khhirani +- leoluz reviewers: - agrawroh @@ -14,3 +15,4 @@ reviewers: - harikrongali - kostis-codefresh - perenesenko +- zachaller From 31eb2e41a2d4e9d1c0bcf3edd6787d8f7688b363 Mon Sep 17 00:00:00 2001 From: Travis Perdue Date: Wed, 22 Jun 2022 16:20:42 -0500 Subject: [PATCH 140/175] add nginx testing for additionalStableIngresses Signed-off-by: Travis Perdue --- rollout/trafficrouting/nginx/nginx_test.go | 600 ++++++++++++++++++++- utils/ingress/ingress_test.go | 6 +- 2 files changed, 597 insertions(+), 9 deletions(-) diff --git a/rollout/trafficrouting/nginx/nginx_test.go b/rollout/trafficrouting/nginx/nginx_test.go index 2b3a7cf328..d0037574c9 100644 --- a/rollout/trafficrouting/nginx/nginx_test.go +++ b/rollout/trafficrouting/nginx/nginx_test.go @@ -137,6 +137,12 @@ func fakeRollout(stableSvc, canarySvc, stableIng string) *v1alpha1.Rollout { } } +func fakeRolloutWithMultiIngress(stableSvc, canarySvc, stableIng, addStableIng string) *v1alpha1.Rollout { + rollout := fakeRollout(stableSvc, canarySvc, stableIng) + rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.AdditionalStableIngresses = []string{addStableIng} + return rollout +} + func checkBackendService(t *testing.T, ing *ingressutil.Ingress, serviceName string) { t.Helper() switch ing.Mode() { @@ -188,7 +194,7 @@ func TestCanaryIngressCreate(t *testing.T) { stableIngress.Spec.IngressClassName = pointer.StringPtr("nginx-ext") i := ingressutil.NewLegacyIngress(stableIngress) - desiredCanaryIngress, err := r.canaryIngress(i, ingressutil.GetCanaryIngressName(r.cfg.Rollout), 10) + desiredCanaryIngress, err := r.canaryIngress(i, ingressutil.GetCanaryIngressName(r.cfg.Rollout.GetName(), r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress), 10) assert.Nil(t, err, "No error returned when calling canaryIngress") checkBackendService(t, desiredCanaryIngress, "canary-service") @@ -203,6 +209,45 @@ func TestCanaryIngressCreate(t *testing.T) { assert.Equal(t, "nginx-ext", *desired.Spec.IngressClassName) } +func TestCanaryIngressCreateMultiIngress(t *testing.T) { + r := Reconciler{ + cfg: ReconcilerConfig{ + Rollout: fakeRolloutWithMultiIngress("stable-service", "canary-service", "stable-ingress", "additional-stable-ingress"), + }, + } + stableIngress := extensionsIngress("stable-ingress", 80, "stable-service") + stableIngress.Spec.IngressClassName = pointer.StringPtr("nginx-ext") + i := ingressutil.NewLegacyIngress(stableIngress) + + desiredCanaryIngress, err := r.canaryIngress(i, ingressutil.GetCanaryIngressName(r.cfg.Rollout.GetName(), r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress), 10) + assert.Nil(t, err, "No error returned when calling canaryIngress") + + checkBackendService(t, desiredCanaryIngress, "canary-service") + desired, err := desiredCanaryIngress.GetExtensionsIngress() + if err != nil { + t.Error(err) + t.FailNow() + } + assert.Equal(t, "true", desired.Annotations["nginx.ingress.kubernetes.io/canary"], "canary annotation set to true") + assert.Equal(t, "10", desired.Annotations["nginx.ingress.kubernetes.io/canary-weight"], "canary-weight annotation set to expected value") + assert.NotNil(t, desired.Spec.IngressClassName) + assert.Equal(t, "nginx-ext", *desired.Spec.IngressClassName) + + additionalDesiredCanaryIngress, err := r.canaryIngress(i, ingressutil.GetCanaryIngressName(r.cfg.Rollout.GetName(), r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.AdditionalStableIngresses[0]), 10) + assert.Nil(t, err, "No error returned when calling canaryIngress") + + checkBackendService(t, additionalDesiredCanaryIngress, "canary-service") + desired, err = additionalDesiredCanaryIngress.GetExtensionsIngress() + if err != nil { + t.Error(err) + t.FailNow() + } + assert.Equal(t, "true", desired.Annotations["nginx.ingress.kubernetes.io/canary"], "canary annotation set to true") + assert.Equal(t, "10", desired.Annotations["nginx.ingress.kubernetes.io/canary-weight"], "canary-weight annotation set to expected value") + assert.NotNil(t, desired.Spec.IngressClassName) + assert.Equal(t, "nginx-ext", *desired.Spec.IngressClassName) +} + func TestCanaryIngressPatchWeight(t *testing.T) { r := Reconciler{ cfg: ReconcilerConfig{ @@ -218,7 +263,7 @@ func TestCanaryIngressPatchWeight(t *testing.T) { stableIngress := ingressutil.NewLegacyIngress(stable) canaryIngress := ingressutil.NewLegacyIngress(canary) - desiredCanaryIngress, err := r.canaryIngress(stableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout), 15) + desiredCanaryIngress, err := r.canaryIngress(stableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout.GetName(), r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress), 15) assert.Nil(t, err, "No error returned when calling canaryIngress") checkBackendService(t, desiredCanaryIngress, "canary-service") @@ -230,6 +275,53 @@ func TestCanaryIngressPatchWeight(t *testing.T) { assert.Equal(t, "{\"metadata\":{\"annotations\":{\"nginx.ingress.kubernetes.io/canary-weight\":\"15\"}}}", string(patch), "compareCanaryIngresses returns expected patch") } +func TestCanaryIngressPatchWeightMultiIngress(t *testing.T) { + r := Reconciler{ + cfg: ReconcilerConfig{ + Rollout: fakeRolloutWithMultiIngress("stable-service", "canary-service", "stable-ingress", "additional-stable-ingress"), + }, + } + stable := extensionsIngress("stable-ingress", 80, "stable-service") + canary := extensionsIngress("canary-ingress", 80, "canary-service") + canary.SetAnnotations(map[string]string{ + "nginx.ingress.kubernetes.io/canary": "true", + "nginx.ingress.kubernetes.io/canary-weight": "10", + }) + stableIngress := ingressutil.NewLegacyIngress(stable) + canaryIngress := ingressutil.NewLegacyIngress(canary) + + desiredCanaryIngress, err := r.canaryIngress(stableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout.GetName(), r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress), 15) + assert.Nil(t, err, "No error returned when calling canaryIngress") + + checkBackendService(t, desiredCanaryIngress, "canary-service") + + patch, modified, err := ingressutil.BuildIngressPatch(canaryIngress.Mode(), canaryIngress, desiredCanaryIngress, + ingressutil.WithAnnotations(), ingressutil.WithLabels(), ingressutil.WithSpec()) + assert.Nil(t, err, "compareCanaryIngresses returns no error") + assert.True(t, modified, "compareCanaryIngresses returns modified=true") + assert.Equal(t, "{\"metadata\":{\"annotations\":{\"nginx.ingress.kubernetes.io/canary-weight\":\"15\"}}}", string(patch), "compareCanaryIngresses returns expected patch") + + addStable := extensionsIngress("additional-stable-ingress", 80, "stable-service") + addCanary := extensionsIngress("additional-canary-ingress", 80, "canary-service") + addCanary.SetAnnotations(map[string]string{ + "nginx.ingress.kubernetes.io/canary": "true", + "nginx.ingress.kubernetes.io/canary-weight": "10", + }) + addStableIngress := ingressutil.NewLegacyIngress(addStable) + addCanaryIngress := ingressutil.NewLegacyIngress(addCanary) + + addDesiredCanaryIngress, err := r.canaryIngress(addStableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout.GetName(), r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.AdditionalStableIngresses[0]), 15) + assert.Nil(t, err, "No error returned when calling addCanaryIngress") + + checkBackendService(t, addDesiredCanaryIngress, "canary-service") + + patch, modified, err = ingressutil.BuildIngressPatch(addCanaryIngress.Mode(), addCanaryIngress, addDesiredCanaryIngress, + ingressutil.WithAnnotations(), ingressutil.WithLabels(), ingressutil.WithSpec()) + assert.Nil(t, err, "compareCanaryIngresses returns no error") + assert.True(t, modified, "compareCanaryIngresses returns modified=true") + assert.Equal(t, "{\"metadata\":{\"annotations\":{\"nginx.ingress.kubernetes.io/canary-weight\":\"15\"}}}", string(patch), "compareCanaryIngresses returns expected patch") +} + func TestCanaryIngressUpdatedRoute(t *testing.T) { r := Reconciler{ cfg: ReconcilerConfig{ @@ -246,7 +338,36 @@ func TestCanaryIngressUpdatedRoute(t *testing.T) { stableIngress := ingressutil.NewLegacyIngress(stable) canaryIngress := ingressutil.NewLegacyIngress(canary) - desiredCanaryIngress, err := r.canaryIngress(stableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout), 15) + desiredCanaryIngress, err := r.canaryIngress(stableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout.GetName(), r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress), 15) + assert.Nil(t, err, "No error returned when calling canaryIngress") + + checkBackendService(t, desiredCanaryIngress, "canary-service") + + patch, modified, err := ingressutil.BuildIngressPatch(canaryIngress.Mode(), canaryIngress, desiredCanaryIngress, + ingressutil.WithAnnotations(), ingressutil.WithLabels(), ingressutil.WithSpec()) + assert.Nil(t, err, "compareCanaryIngresses returns no error") + assert.True(t, modified, "compareCanaryIngresses returns modified=true") + assert.Equal(t, "{\"spec\":{\"rules\":[{\"host\":\"fakehost.example.com\",\"http\":{\"paths\":[{\"backend\":{\"serviceName\":\"canary-service\",\"servicePort\":80},\"path\":\"/bar\"}]}}]}}", string(patch), "compareCanaryIngresses returns expected patch") +} + +func TestCanaryIngressUpdatedRouteMultiIngress(t *testing.T) { + r := Reconciler{ + cfg: ReconcilerConfig{ + Rollout: fakeRolloutWithMultiIngress("stable-service", "canary-service", "stable-ingress", "additional-stable-ingress"), + }, + } + + stable := extensionsIngress("stable-ingress", 80, "stable-service") + stable.Spec.Rules[0].HTTP.Paths[0].Path = "/bar" + canary := extensionsIngress("canary-ingress", 80, "canary-service") + canary.SetAnnotations(map[string]string{ + "nginx.ingress.kubernetes.io/canary": "true", + "nginx.ingress.kubernetes.io/canary-weight": "15", + }) + stableIngress := ingressutil.NewLegacyIngress(stable) + canaryIngress := ingressutil.NewLegacyIngress(canary) + + desiredCanaryIngress, err := r.canaryIngress(stableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout.GetName(), r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress), 15) assert.Nil(t, err, "No error returned when calling canaryIngress") checkBackendService(t, desiredCanaryIngress, "canary-service") @@ -256,6 +377,27 @@ func TestCanaryIngressUpdatedRoute(t *testing.T) { assert.Nil(t, err, "compareCanaryIngresses returns no error") assert.True(t, modified, "compareCanaryIngresses returns modified=true") assert.Equal(t, "{\"spec\":{\"rules\":[{\"host\":\"fakehost.example.com\",\"http\":{\"paths\":[{\"backend\":{\"serviceName\":\"canary-service\",\"servicePort\":80},\"path\":\"/bar\"}]}}]}}", string(patch), "compareCanaryIngresses returns expected patch") + + addStable := extensionsIngress("stable-ingress", 80, "stable-service") + addStable.Spec.Rules[0].HTTP.Paths[0].Path = "/bar" + addCanary := extensionsIngress("canary-ingress", 80, "canary-service") + addCanary.SetAnnotations(map[string]string{ + "nginx.ingress.kubernetes.io/canary": "true", + "nginx.ingress.kubernetes.io/canary-weight": "15", + }) + addStableIngress := ingressutil.NewLegacyIngress(addStable) + addCanaryIngress := ingressutil.NewLegacyIngress(addCanary) + + addDesiredCanaryIngress, err := r.canaryIngress(addStableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout.GetName(), r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.AdditionalStableIngresses[0]), 15) + assert.Nil(t, err, "No error returned when calling canaryIngress") + + checkBackendService(t, addDesiredCanaryIngress, "canary-service") + + patch, modified, err = ingressutil.BuildIngressPatch(addCanaryIngress.Mode(), addCanaryIngress, addDesiredCanaryIngress, + ingressutil.WithAnnotations(), ingressutil.WithLabels(), ingressutil.WithSpec()) + assert.Nil(t, err, "compareCanaryIngresses returns no error") + assert.True(t, modified, "compareCanaryIngresses returns modified=true") + assert.Equal(t, "{\"spec\":{\"rules\":[{\"host\":\"fakehost.example.com\",\"http\":{\"paths\":[{\"backend\":{\"serviceName\":\"canary-service\",\"servicePort\":80},\"path\":\"/bar\"}]}}]}}", string(patch), "compareCanaryIngresses returns expected patch") } func TestCanaryIngressRetainIngressClass(t *testing.T) { @@ -270,7 +412,7 @@ func TestCanaryIngressRetainIngressClass(t *testing.T) { }) stableIngress := ingressutil.NewLegacyIngress(stable) - desiredCanaryIngress, err := r.canaryIngress(stableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout), 15) + desiredCanaryIngress, err := r.canaryIngress(stableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout.GetName(), r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress), 15) assert.Nil(t, err, "No error returned when calling canaryIngress") checkBackendService(t, desiredCanaryIngress, "canary-service") @@ -281,6 +423,45 @@ func TestCanaryIngressRetainIngressClass(t *testing.T) { assert.Equal(t, "nginx-foo", annotations["kubernetes.io/ingress.class"], "ingress-class annotation retained") } +func TestCanaryIngressRetainIngressClassMultiIngress(t *testing.T) { + r := Reconciler{ + cfg: ReconcilerConfig{ + Rollout: fakeRolloutWithMultiIngress("stable-service", "canary-service", "stable-ingress", "additional-stable-ingress"), + }, + } + stable := extensionsIngress("stable-ingress", 80, "stable-service") + stable.SetAnnotations(map[string]string{ + "kubernetes.io/ingress.class": "nginx-foo", + }) + stableIngress := ingressutil.NewLegacyIngress(stable) + + desiredCanaryIngress, err := r.canaryIngress(stableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout.GetName(), r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress), 15) + assert.Nil(t, err, "No error returned when calling canaryIngress") + + checkBackendService(t, desiredCanaryIngress, "canary-service") + + annotations := desiredCanaryIngress.GetAnnotations() + assert.Equal(t, "true", annotations["nginx.ingress.kubernetes.io/canary"], "canary annotation set to true") + assert.Equal(t, "15", annotations["nginx.ingress.kubernetes.io/canary-weight"], "canary-weight annotation set to expected value") + assert.Equal(t, "nginx-foo", annotations["kubernetes.io/ingress.class"], "ingress-class annotation retained") + + addStable := extensionsIngress("stable-ingress", 80, "stable-service") + addStable.SetAnnotations(map[string]string{ + "kubernetes.io/ingress.class": "nginx-foo", + }) + addStableIngress := ingressutil.NewLegacyIngress(addStable) + + addDesiredCanaryIngress, err := r.canaryIngress(addStableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout.GetName(), r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.AdditionalStableIngresses[0]), 15) + assert.Nil(t, err, "No error returned when calling canaryIngress") + + checkBackendService(t, addDesiredCanaryIngress, "canary-service") + + annotations = addDesiredCanaryIngress.GetAnnotations() + assert.Equal(t, "true", annotations["nginx.ingress.kubernetes.io/canary"], "canary annotation set to true") + assert.Equal(t, "15", annotations["nginx.ingress.kubernetes.io/canary-weight"], "canary-weight annotation set to expected value") + assert.Equal(t, "nginx-foo", annotations["kubernetes.io/ingress.class"], "ingress-class annotation retained") +} + func TestCanaryIngressAdditionalAnnotations(t *testing.T) { r := Reconciler{ cfg: ReconcilerConfig{ @@ -294,7 +475,33 @@ func TestCanaryIngressAdditionalAnnotations(t *testing.T) { stable := extensionsIngress("stable-ingress", 80, "stable-service") stableIngress := ingressutil.NewLegacyIngress(stable) - desiredCanaryIngress, err := r.canaryIngress(stableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout), 15) + desiredCanaryIngress, err := r.canaryIngress(stableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout.GetName(), r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress), 15) + assert.Nil(t, err, "No error returned when calling canaryIngress") + + checkBackendService(t, desiredCanaryIngress, "canary-service") + + annotations := desiredCanaryIngress.GetAnnotations() + assert.Equal(t, "true", annotations["nginx.ingress.kubernetes.io/canary"], "canary annotation set to true") + assert.Equal(t, "15", annotations["nginx.ingress.kubernetes.io/canary-weight"], "canary-weight annotation set to expected value") + assert.Equal(t, "X-Foo", annotations["nginx.ingress.kubernetes.io/canary-by-header"], "canary-by-header annotation set") + assert.Equal(t, "DoCanary", annotations["nginx.ingress.kubernetes.io/canary-by-header-value"], "canary-by-header-value annotation set") +} + +func TestCanaryIngressAdditionalAnnotationsMultiIngress(t *testing.T) { + r := Reconciler{ + cfg: ReconcilerConfig{ + Rollout: fakeRolloutWithMultiIngress("stable-service", "canary-service", "stable-ingress", "additional-stable-ingress"), + }, + } + r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.AdditionalIngressAnnotations = map[string]string{ + "canary-by-header": "X-Foo", + "canary-by-header-value": "DoCanary", + } + + stable := extensionsIngress("stable-ingress", 80, "stable-service") + stableIngress := ingressutil.NewLegacyIngress(stable) + + desiredCanaryIngress, err := r.canaryIngress(stableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout.GetName(), r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress), 15) assert.Nil(t, err, "No error returned when calling canaryIngress") checkBackendService(t, desiredCanaryIngress, "canary-service") @@ -304,6 +511,20 @@ func TestCanaryIngressAdditionalAnnotations(t *testing.T) { assert.Equal(t, "15", annotations["nginx.ingress.kubernetes.io/canary-weight"], "canary-weight annotation set to expected value") assert.Equal(t, "X-Foo", annotations["nginx.ingress.kubernetes.io/canary-by-header"], "canary-by-header annotation set") assert.Equal(t, "DoCanary", annotations["nginx.ingress.kubernetes.io/canary-by-header-value"], "canary-by-header-value annotation set") + + addStable := extensionsIngress("additional-stable-ingress", 80, "stable-service") + addStableIngress := ingressutil.NewLegacyIngress(addStable) + + addDesiredCanaryIngress, err := r.canaryIngress(addStableIngress, ingressutil.GetCanaryIngressName(r.cfg.Rollout.GetName(), r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.AdditionalStableIngresses[0]), 15) + assert.Nil(t, err, "No error returned when calling canaryIngress") + + checkBackendService(t, addDesiredCanaryIngress, "canary-service") + + annotations = addDesiredCanaryIngress.GetAnnotations() + assert.Equal(t, "true", annotations["nginx.ingress.kubernetes.io/canary"], "canary annotation set to true") + assert.Equal(t, "15", annotations["nginx.ingress.kubernetes.io/canary-weight"], "canary-weight annotation set to expected value") + assert.Equal(t, "X-Foo", annotations["nginx.ingress.kubernetes.io/canary-by-header"], "canary-by-header annotation set") + assert.Equal(t, "DoCanary", annotations["nginx.ingress.kubernetes.io/canary-by-header-value"], "canary-by-header-value annotation set") } func TestReconciler_canaryIngress(t *testing.T) { @@ -320,7 +541,38 @@ func TestReconciler_canaryIngress(t *testing.T) { i := ingressutil.NewIngress(stableIngress) // when - desiredCanaryIngress, err := r.canaryIngress(i, ingressutil.GetCanaryIngressName(r.cfg.Rollout), 10) + desiredCanaryIngress, err := r.canaryIngress(i, ingressutil.GetCanaryIngressName(r.cfg.Rollout.GetName(), r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress), 10) + + // then + assert.Nil(t, err, "No error returned when calling canaryIngress") + checkBackendService(t, desiredCanaryIngress, "canary-service") + desired, err := desiredCanaryIngress.GetNetworkingIngress() + if err != nil { + t.Fatal(err) + } + assert.Equal(t, "true", desired.Annotations["nginx.ingress.kubernetes.io/canary"], "canary annotation set to true") + assert.Equal(t, "10", desired.Annotations["nginx.ingress.kubernetes.io/canary-weight"], "canary-weight annotation set to expected value") + assert.NotNil(t, desired.Spec.IngressClassName) + assert.Equal(t, "nginx-ext", *desired.Spec.IngressClassName) + }) +} + +func TestReconciler_canaryIngressWithMultiIngress(t *testing.T) { + t.Run("will build desired networking ingress successfully", func(t *testing.T) { + // given + t.Parallel() + r := Reconciler{ + cfg: ReconcilerConfig{ + Rollout: fakeRolloutWithMultiIngress("stable-service", "canary-service", "stable-ingress", "additional-stable-ingress"), + }, + } + + stableIngress := networkingIngress("stable-ingress", 80, "stable-service") + stableIngress.Spec.IngressClassName = pointer.StringPtr("nginx-ext") + i := ingressutil.NewIngress(stableIngress) + + // when + desiredCanaryIngress, err := r.canaryIngress(i, ingressutil.GetCanaryIngressName(r.cfg.Rollout.GetName(), r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress), 10) // then assert.Nil(t, err, "No error returned when calling canaryIngress") @@ -333,6 +585,25 @@ func TestReconciler_canaryIngress(t *testing.T) { assert.Equal(t, "10", desired.Annotations["nginx.ingress.kubernetes.io/canary-weight"], "canary-weight annotation set to expected value") assert.NotNil(t, desired.Spec.IngressClassName) assert.Equal(t, "nginx-ext", *desired.Spec.IngressClassName) + + addStableIngress := networkingIngress("additional-stable-ingress", 80, "stable-service") + addStableIngress.Spec.IngressClassName = pointer.StringPtr("nginx-ext") + i = ingressutil.NewIngress(addStableIngress) + + // when + addDesiredCanaryIngress, err := r.canaryIngress(i, ingressutil.GetCanaryIngressName(r.cfg.Rollout.GetName(), r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.AdditionalStableIngresses[0]), 10) + + // then + assert.Nil(t, err, "No error returned when calling canaryIngress") + checkBackendService(t, desiredCanaryIngress, "canary-service") + desired, err = addDesiredCanaryIngress.GetNetworkingIngress() + if err != nil { + t.Fatal(err) + } + assert.Equal(t, "true", desired.Annotations["nginx.ingress.kubernetes.io/canary"], "canary annotation set to true") + assert.Equal(t, "10", desired.Annotations["nginx.ingress.kubernetes.io/canary-weight"], "canary-weight annotation set to expected value") + assert.NotNil(t, desired.Spec.IngressClassName) + assert.Equal(t, "nginx-ext", *desired.Spec.IngressClassName) }) } @@ -398,6 +669,41 @@ func TestReconcileStableIngressFound(t *testing.T) { } } +func TestReconcileStableIngressFoundMultiIngress(t *testing.T) { + rollout := fakeRolloutWithMultiIngress("stable-service", "canary-service", "stable-ingress", "additional-stable-ingress") + stableIngress := extensionsIngress("stable-ingress", 80, "stable-service") + addStableIngress := extensionsIngress("additional-stable-ingress", 80, "stable-service") + + client := fake.NewSimpleClientset() + k8sI := kubeinformers.NewSharedInformerFactory(client, 0) + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(stableIngress) + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(addStableIngress) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } + r := NewReconciler(ReconcilerConfig{ + Rollout: rollout, + Client: client, + Recorder: record.NewFakeEventRecorder(), + ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, + IngressWrapper: ingressWrapper, + }) + + err = r.SetWeight(10) + assert.Nil(t, err, "Reconcile returns no error") + actions := client.Actions() + assert.Len(t, actions, 2) + if !t.Failed() { + // Avoid "index out of range" errors + assert.Equal(t, "create", actions[0].GetVerb(), "action: create canary ingress") + assert.Equal(t, schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "ingresses"}, actions[0].GetResource(), "action: create canary ingress") + + assert.Equal(t, "create", actions[1].GetVerb(), "action: create canary ingress") + assert.Equal(t, schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "ingresses"}, actions[1].GetResource(), "action: create canary ingress") + } +} + func TestReconcileStableIngressFoundWrongBackend(t *testing.T) { rollout := fakeRollout("stable-service", "canary-service", "stable-ingress") stableIngress := extensionsIngress("stable-ingress", 80, "other-service") @@ -422,6 +728,34 @@ func TestReconcileStableIngressFoundWrongBackend(t *testing.T) { assert.Contains(t, err.Error(), "has no rules using service", "correct error is returned") } +func TestReconcileStableIngressFoundWrongBackendMultiIngress(t *testing.T) { + rollout := fakeRolloutWithMultiIngress("stable-service", "canary-service", "stable-ingress", "additional-stable-ingress") + // this one will work + stableIngress := extensionsIngress("stable-ingress", 80, "stable-service") + // This is the one that should error out + addStableIngress := extensionsIngress("additional-stable-ingress", 80, "other-service") + + client := fake.NewSimpleClientset() + k8sI := kubeinformers.NewSharedInformerFactory(client, 0) + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(stableIngress) + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(addStableIngress) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } + r := NewReconciler(ReconcilerConfig{ + Rollout: rollout, + Client: client, + Recorder: record.NewFakeEventRecorder(), + ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, + IngressWrapper: ingressWrapper, + }) + + err = r.SetWeight(10) + assert.NotNil(t, err, "Reconcile returns error") + assert.Contains(t, err.Error(), "has no rules using service", "correct error is returned") +} + func TestReconcileStableAndCanaryIngressFoundNoOwner(t *testing.T) { rollout := fakeRollout("stable-service", "canary-service", "stable-ingress") stableIngress := extensionsIngress("stable-ingress", 80, "stable-service") @@ -511,6 +845,54 @@ func TestReconcileStableAndCanaryIngressFoundPatch(t *testing.T) { } } +func TestReconcileStableAndCanaryIngressFoundPatchMultiIngress(t *testing.T) { + rollout := fakeRolloutWithMultiIngress("stable-service", "canary-service", "stable-ingress", "additional-stable-ingress") + stableIngress := extensionsIngress("stable-ingress", 80, "stable-service") + addStableIngress := extensionsIngress("additional-stable-ingress", 80, "stable-service") + canaryIngress := extensionsIngress("rollout-stable-ingress-canary", 80, "canary-service") + canaryIngress.SetAnnotations(map[string]string{ + "nginx.ingress.kubernetes.io/canary": "true", + "nginx.ingress.kubernetes.io/canary-weight": "15", + }) + addCanaryIngress := extensionsIngress("rollout-additional-stable-ingress-canary", 80, "canary-service") + addCanaryIngress.SetAnnotations(map[string]string{ + "nginx.ingress.kubernetes.io/canary": "true", + "nginx.ingress.kubernetes.io/canary-weight": "15", + }) + setIngressOwnerRef(canaryIngress, rollout) + setIngressOwnerRef(addCanaryIngress, rollout) + client := fake.NewSimpleClientset(canaryIngress, addCanaryIngress) + k8sI := kubeinformers.NewSharedInformerFactory(client, 0) + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(stableIngress) + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(canaryIngress) + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(addStableIngress) + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(addCanaryIngress) + + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } + r := NewReconciler(ReconcilerConfig{ + Rollout: rollout, + Client: client, + Recorder: record.NewFakeEventRecorder(), + ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, + IngressWrapper: ingressWrapper, + }) + + err = r.SetWeight(10) + assert.Nil(t, err, "Reconcile returns no error") + actions := client.Actions() + assert.Len(t, actions, 2) + if !t.Failed() { + // Avoid "index out of range" errors + assert.Equal(t, "patch", actions[0].GetVerb(), "action: patch canary ingress") + assert.Equal(t, schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "ingresses"}, actions[0].GetResource(), "action: patch canary ingress") + assert.Equal(t, "patch", actions[1].GetVerb(), "action: patch canary ingress") + assert.Equal(t, schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "ingresses"}, actions[1].GetResource(), "action: patch canary ingress") + } +} + func TestReconcileWillInvokeNetworkingIngress(t *testing.T) { // given rollout := fakeRollout("stable-service", "canary-service", "stable-ingress") @@ -551,6 +933,57 @@ func TestReconcileWillInvokeNetworkingIngress(t *testing.T) { } } +func TestReconcileWillInvokeNetworkingIngressMultiIngress(t *testing.T) { + // given + rollout := fakeRolloutWithMultiIngress("stable-service", "canary-service", "stable-ingress", "additional-stable-ingress") + stableIngress := networkingIngress("stable-ingress", 80, "stable-service") + addStableIngress := networkingIngress("additional-stable-ingress", 80, "stable-service") + canaryIngress := networkingIngress("rollout-stable-ingress-canary", 80, "canary-service") + canaryIngress.SetAnnotations(map[string]string{ + "nginx.ingress.kubernetes.io/canary": "true", + "nginx.ingress.kubernetes.io/canary-weight": "15", + }) + addCanaryIngress := networkingIngress("rollout-additional-stable-ingress-canary", 80, "canary-service") + addCanaryIngress.SetAnnotations(map[string]string{ + "nginx.ingress.kubernetes.io/canary": "true", + "nginx.ingress.kubernetes.io/canary-weight": "15", + }) + canaryIngress.SetOwnerReferences([]metav1.OwnerReference{*metav1.NewControllerRef(rollout, schema.GroupVersionKind{Group: "argoproj.io", Version: "v1alpha1", Kind: "Rollout"})}) + addCanaryIngress.SetOwnerReferences([]metav1.OwnerReference{*metav1.NewControllerRef(rollout, schema.GroupVersionKind{Group: "argoproj.io", Version: "v1alpha1", Kind: "Rollout"})}) + client := fake.NewSimpleClientset(stableIngress, canaryIngress, addStableIngress, addCanaryIngress) + k8sI := kubeinformers.NewSharedInformerFactory(client, 0) + k8sI.Networking().V1().Ingresses().Informer().GetIndexer().Add(stableIngress) + k8sI.Networking().V1().Ingresses().Informer().GetIndexer().Add(canaryIngress) + k8sI.Networking().V1().Ingresses().Informer().GetIndexer().Add(addStableIngress) + k8sI.Networking().V1().Ingresses().Informer().GetIndexer().Add(addCanaryIngress) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeNetworking, client, k8sI) + if err != nil { + t.Fatal(err) + } + r := NewReconciler(ReconcilerConfig{ + Rollout: rollout, + Client: client, + Recorder: record.NewFakeEventRecorder(), + ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, + IngressWrapper: ingressWrapper, + }) + + // when + err = r.SetWeight(10) + + // then + assert.Nil(t, err, "Reconcile returns no error") + actions := client.Actions() + assert.Len(t, actions, 2) + if !t.Failed() { + // Avoid "index out of range" errors + assert.Equal(t, "patch", actions[0].GetVerb(), "action: patch canary ingress") + assert.Equal(t, schema.GroupVersionResource{Group: "networking.k8s.io", Version: "v1", Resource: "ingresses"}, actions[0].GetResource(), "action: patch canary ingress") + assert.Equal(t, "patch", actions[1].GetVerb(), "action: patch canary ingress") + assert.Equal(t, schema.GroupVersionResource{Group: "networking.k8s.io", Version: "v1", Resource: "ingresses"}, actions[1].GetResource(), "action: patch canary ingress") + } +} + func TestReconcileStableAndCanaryIngressFoundNoChange(t *testing.T) { rollout := fakeRollout("stable-service", "canary-service", "stable-ingress") stableIngress := extensionsIngress("stable-ingress", 80, "stable-service") @@ -582,6 +1015,46 @@ func TestReconcileStableAndCanaryIngressFoundNoChange(t *testing.T) { assert.Len(t, actions, 0) } +func TestReconcileStableAndCanaryIngressFoundNoChangeMultiIngress(t *testing.T) { + rollout := fakeRolloutWithMultiIngress("stable-service", "canary-service", "stable-ingress", "additional-stable-ingress") + stableIngress := extensionsIngress("stable-ingress", 80, "stable-service") + addStableIngress := extensionsIngress("additional-stable-ingress", 80, "stable-service") + canaryIngress := extensionsIngress("rollout-stable-ingress-canary", 80, "canary-service") + addCanaryIngress := extensionsIngress("rollout-additional-stable-ingress-canary", 80, "canary-service") + setIngressOwnerRef(canaryIngress, rollout) + setIngressOwnerRef(addCanaryIngress, rollout) + canaryIngress.SetAnnotations(map[string]string{ + "nginx.ingress.kubernetes.io/canary": "true", + "nginx.ingress.kubernetes.io/canary-weight": "10", + }) + addCanaryIngress.SetAnnotations(map[string]string{ + "nginx.ingress.kubernetes.io/canary": "true", + "nginx.ingress.kubernetes.io/canary-weight": "10", + }) + client := fake.NewSimpleClientset() + k8sI := kubeinformers.NewSharedInformerFactory(client, 0) + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(stableIngress) + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(addStableIngress) + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(canaryIngress) + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(addCanaryIngress) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } + r := NewReconciler(ReconcilerConfig{ + Rollout: rollout, + Client: client, + Recorder: record.NewFakeEventRecorder(), + ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, + IngressWrapper: ingressWrapper, + }) + + err = r.SetWeight(10) + assert.Nil(t, err, "Reconcile returns no error") + actions := client.Actions() + assert.Len(t, actions, 0) +} + func TestReconcileCanaryCreateError(t *testing.T) { rollout := fakeRollout("stable-service", "canary-service", "stable-ingress") stableIngress := extensionsIngress("stable-ingress", 80, "stable-service") @@ -622,6 +1095,48 @@ func TestReconcileCanaryCreateError(t *testing.T) { } } +func TestReconcileCanaryCreateErrorMultiIngress(t *testing.T) { + rollout := fakeRolloutWithMultiIngress("stable-service", "canary-service", "stable-ingress", "additional-stable-ingress") + stableIngress := extensionsIngress("stable-ingress", 80, "stable-service") + addStableIngress := extensionsIngress("additional-stable-ingress", 80, "stable-service") + + client := fake.NewSimpleClientset() + client.ReactionChain = nil + k8sI := kubeinformers.NewSharedInformerFactory(client, 0) + + // stableIngress exists + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(stableIngress) + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(addStableIngress) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } + + r := NewReconciler(ReconcilerConfig{ + Rollout: rollout, + Client: client, + Recorder: record.NewFakeEventRecorder(), + ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, + IngressWrapper: ingressWrapper, + }) + + // Return with AlreadyExists error to create for canary + r.cfg.Client.(*fake.Clientset).Fake.AddReactor("create", "ingresses", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, errors.New("fake error") + }) + + err = r.SetWeight(10) + assert.NotNil(t, err, "Reconcile returns error") + assert.Equal(t, "error creating canary ingress `rollout-additional-stable-ingress-canary`: fake error", err.Error()) + actions := client.Actions() + assert.Len(t, actions, 1) + if !t.Failed() { + // Avoid "index out of range" errors + assert.Equal(t, "create", actions[0].GetVerb(), "action: create canary ingress") + assert.Equal(t, schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "ingresses"}, actions[0].GetResource(), "action: create canary ingress") + } +} + func TestReconcileCanaryCreateErrorAlreadyExistsPatch(t *testing.T) { rollout := fakeRollout("stable-service", "canary-service", "stable-ingress") stableIngress := extensionsIngress("stable-ingress", 80, "stable-service") @@ -678,3 +1193,76 @@ func TestReconcileCanaryCreateErrorAlreadyExistsPatch(t *testing.T) { assert.Equal(t, schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "ingresses"}, actions[2].GetResource(), "action: patch canary ingress") } } + +func TestReconcileCanaryCreateErrorAlreadyExistsPatchMultiIngress(t *testing.T) { + rollout := fakeRolloutWithMultiIngress("stable-service", "canary-service", "stable-ingress", "additional-stable-ingress") + stableIngress := extensionsIngress("stable-ingress", 80, "stable-service") + addStableIngress := extensionsIngress("additional-stable-ingress", 80, "stable-service") + canaryIngress := extensionsIngress("rollout-stable-ingress-canary", 80, "canary-service") + addCanaryIngress := extensionsIngress("rollout-additional-stable-ingress-canary", 80, "canary-service") + canaryIngress.SetAnnotations(map[string]string{ + "nginx.ingress.kubernetes.io/canary": "true", + "nginx.ingress.kubernetes.io/canary-weight": "15", + }) + addCanaryIngress.SetAnnotations(map[string]string{ + "nginx.ingress.kubernetes.io/canary": "true", + "nginx.ingress.kubernetes.io/canary-weight": "15", + }) + setIngressOwnerRef(canaryIngress, rollout) + setIngressOwnerRef(addCanaryIngress, rollout) + + client := fake.NewSimpleClientset() + client.ReactionChain = nil + k8sI := kubeinformers.NewSharedInformerFactory(client, 0) + + // stableIngress exists + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(stableIngress) + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(addStableIngress) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } + + r := NewReconciler(ReconcilerConfig{ + Rollout: rollout, + Client: client, + Recorder: record.NewFakeEventRecorder(), + ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, + IngressWrapper: ingressWrapper, + }) + + // Return with AlreadyExists error to create for canary + r.cfg.Client.(*fake.Clientset).Fake.AddReactor("create", "ingresses", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, k8serrors.NewAlreadyExists(schema.GroupResource{ + Group: "extensions", + Resource: "ingresses", + }, "rollout-stable-ingress-canary") + }) + + // Respond with canaryIngress on GET + r.cfg.Client.(*fake.Clientset).Fake.AddReactor("get", "ingresses", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { + return true, canaryIngress, nil + }) + + err = r.SetWeight(10) + assert.Nil(t, err, "Reconcile returns no error") + actions := client.Actions() + assert.Len(t, actions, 6) + if !t.Failed() { + // Avoid "index out of range" errors + // primary ingress + assert.Equal(t, "create", actions[0].GetVerb(), "action: create canary ingress") + assert.Equal(t, schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "ingresses"}, actions[0].GetResource(), "action: create canary ingress") + assert.Equal(t, "get", actions[1].GetVerb(), "action: get canary ingress") + assert.Equal(t, schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "ingresses"}, actions[1].GetResource(), "action: get canary ingress") + assert.Equal(t, "patch", actions[2].GetVerb(), "action: patch canary ingress") + assert.Equal(t, schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "ingresses"}, actions[2].GetResource(), "action: patch canary ingress") + // additional ingress + assert.Equal(t, "create", actions[3].GetVerb(), "action: create canary ingress") + assert.Equal(t, schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "ingresses"}, actions[0].GetResource(), "action: create canary ingress") + assert.Equal(t, "get", actions[4].GetVerb(), "action: get canary ingress") + assert.Equal(t, schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "ingresses"}, actions[1].GetResource(), "action: get canary ingress") + assert.Equal(t, "patch", actions[5].GetVerb(), "action: patch canary ingress") + assert.Equal(t, schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "ingresses"}, actions[2].GetResource(), "action: patch canary ingress") + } +} diff --git a/utils/ingress/ingress_test.go b/utils/ingress/ingress_test.go index eaca7e6a86..c545cd0b2d 100644 --- a/utils/ingress/ingress_test.go +++ b/utils/ingress/ingress_test.go @@ -84,18 +84,18 @@ func TestGetCanaryIngressName(t *testing.T) { t.Run("NoTrim", func(t *testing.T) { rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress = "stable-ingress" - canaryIngress := GetCanaryIngressName(rollout) + canaryIngress := GetCanaryIngressName(rollout.GetName(), rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress) assert.Equal(t, "myrollout-stable-ingress-canary", canaryIngress) }) t.Run("Trim", func(t *testing.T) { rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress = fmt.Sprintf("stable-ingress%s", strings.Repeat("a", 260)) - canaryIngress := GetCanaryIngressName(rollout) + canaryIngress := GetCanaryIngressName(rollout.GetName(), rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress) assert.Equal(t, 253, len(canaryIngress), "canary ingress truncated to 253") assert.Equal(t, true, strings.HasSuffix(canaryIngress, "-canary"), "canary ingress has -canary suffix") }) t.Run("NoStableIngress", func(t *testing.T) { rollout.Spec.Strategy.Canary.TrafficRouting.Nginx = nil - canaryIngress := GetCanaryIngressName(rollout) + canaryIngress := GetCanaryIngressName(rollout.GetName(), "") assert.Equal(t, "", canaryIngress, "canary ingress is empty") }) } From e53e889b15392fc27c92ed00f63c35de6998b1f3 Mon Sep 17 00:00:00 2001 From: Andrii Perenesenko Date: Thu, 23 Jun 2022 06:41:02 -0700 Subject: [PATCH 141/175] fix: High reconciliation activity and CPU load for invalid rollout (#2091) Signed-off-by: Andrii Perenesenko --- pkg/apis/rollouts/validation/validation.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/apis/rollouts/validation/validation.go b/pkg/apis/rollouts/validation/validation.go index d71af46ed4..15d10ea7c1 100644 --- a/pkg/apis/rollouts/validation/validation.go +++ b/pkg/apis/rollouts/validation/validation.go @@ -291,8 +291,8 @@ func ValidateRolloutStrategyCanary(rollout *v1alpha1.Rollout, fldPath *field.Pat if step.Pause != nil && step.Pause.DurationSeconds() < 0 { allErrs = append(allErrs, field.Invalid(stepFldPath.Child("pause").Child("duration"), step.Pause.DurationSeconds(), InvalidDurationMessage)) } - if rollout.Spec.Strategy.Canary != nil && rollout.Spec.Strategy.Canary.TrafficRouting == nil && step.SetCanaryScale != nil { - allErrs = append(allErrs, field.Invalid(stepFldPath.Child("setCanaryScale"), step.SetCanaryScale, InvalidSetCanaryScaleTrafficPolicy)) + if step.SetCanaryScale != nil && canary.TrafficRouting == nil { + allErrs = append(allErrs, field.Required(fldPath.Child("trafficRouting"), InvalidSetCanaryScaleTrafficPolicy)) } if step.SetHeaderRouting != nil { trafficRouting := rollout.Spec.Strategy.Canary.TrafficRouting From 9eef4e27d10f7fe229faf53b44f8ad093bbede3b Mon Sep 17 00:00:00 2001 From: Andrii Perenesenko Date: Thu, 23 Jun 2022 06:46:05 -0700 Subject: [PATCH 142/175] fix: argo-rollouts occasionally crashes in argoproj/pkg (#2111) * fix: argo-rollouts occasionally crashes in argoproj/pkg Signed-off-by: Andrii Perenesenko * fix: argo-rollouts occasionally crashes in argoproj/pkg Signed-off-by: Andrii Perenesenko --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 0a0e391e9b..37bebd331e 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.17 require ( github.com/antonmedv/expr v1.9.0 github.com/argoproj/notifications-engine v0.3.1-0.20220129012210-32519f8f68ec - github.com/argoproj/pkg v0.9.0 + github.com/argoproj/pkg v0.11.1-0.20211203175135-36c59d8fafe0 github.com/aws/aws-sdk-go-v2 v1.13.0 github.com/aws/aws-sdk-go-v2/config v1.13.1 github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.15.0 diff --git a/go.sum b/go.sum index f45bf974f5..146e68a910 100644 --- a/go.sum +++ b/go.sum @@ -114,8 +114,8 @@ github.com/antonmedv/expr v1.9.0/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmH github.com/appscode/go v0.0.0-20190808133642-1d4ef1f1c1e0/go.mod h1:iy07dV61Z7QQdCKJCIvUoDL21u6AIceRhZzyleh2ymc= github.com/argoproj/notifications-engine v0.3.1-0.20220129012210-32519f8f68ec h1:ulv8ieYQZLyQrTVR4za1ucLFnemS0Dksz8y5e91xxak= github.com/argoproj/notifications-engine v0.3.1-0.20220129012210-32519f8f68ec/go.mod h1:QF4tr3wfWOnhkKSaRpx7k/KEErQAh8iwKQ2pYFu/SfA= -github.com/argoproj/pkg v0.9.0 h1:PfWWYykfcEQdN0g41XLbVh/aonTjD+dPkvDp3hwpLYM= -github.com/argoproj/pkg v0.9.0/go.mod h1:ra+bQPmbVAoEL+gYSKesuigt4m49i3Qa3mE/xQcjCiA= +github.com/argoproj/pkg v0.11.1-0.20211203175135-36c59d8fafe0 h1:Cfp7rO/HpVxnwlRqJe0jHiBbZ77ZgXhB6HWlYD02Xdc= +github.com/argoproj/pkg v0.11.1-0.20211203175135-36c59d8fafe0/go.mod h1:ra+bQPmbVAoEL+gYSKesuigt4m49i3Qa3mE/xQcjCiA= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= From 5c32e84a06c597bb52e620dfae5ca787a83ed0e4 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Thu, 23 Jun 2022 08:49:03 -0500 Subject: [PATCH 143/175] Change bug template to bring inline with argocd (#2096) * Change bug template to bring inline with argocd? Signed-off-by: zachaller * add back maintainers note Signed-off-by: zachaller * Missed a bit Signed-off-by: zachaller * keep line Signed-off-by: zachaller --- .github/ISSUE_TEMPLATE/bug_report.md | 34 ++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 696e41272f..fd7d7aa972 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,15 +1,39 @@ --- name: Bug report about: Create a report to help us improve +title: '' labels: 'bug' +assignees: '' --- -## Summary -What happened/what you expected to happen? + -## Diagnostics +Checklist: -What version of Argo Rollouts are you running? +* [ ] I've included steps to reproduce the bug. +* [ ] I've inclued the version of argo rollouts. + +**Describe the bug** + + + +**To Reproduce** + + + +**Expected behavior** + + + +**Screenshots** + + + +**Version** + + + +**Logs** ``` # Paste the logs from the rollout controller @@ -18,7 +42,7 @@ What version of Argo Rollouts are you running? kubectl logs -n argo-rollouts deployment/argo-rollouts # Logs for a specific rollout: -kubectl logs -n argo-rollouts deployment/argo-rollouts | grep rollout= +kubectl logs -n argo-rollouts deployment/argo-rollouts | grep rollout= Date: Thu, 23 Jun 2022 10:19:37 -0500 Subject: [PATCH 144/175] add ingress & controller tests for additionalStableIngresses Signed-off-by: Travis Perdue --- ingress/ingress_test.go | 112 +++++++++++++++++- .../validation/validation_references_test.go | 18 +++ rollout/controller_test.go | 91 ++++++++++++++ 3 files changed, 219 insertions(+), 2 deletions(-) diff --git a/ingress/ingress_test.go b/ingress/ingress_test.go index b26b213e25..679eba81f6 100644 --- a/ingress/ingress_test.go +++ b/ingress/ingress_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/assert" extensionsv1beta1 "k8s.io/api/extensions/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" kubeinformers "k8s.io/client-go/informers" k8sfake "k8s.io/client-go/kubernetes/fake" @@ -54,7 +55,15 @@ func newNginxIngress(name string, port int, serviceName string) *extensionsv1bet } } +func newFakeIngressControllerMultiIngress(t *testing.T, ing []*extensionsv1beta1.Ingress, rollout *v1alpha1.Rollout) (*Controller, *k8sfake.Clientset, map[string]int) { + return underlyingControllerBuilder(t, ing, rollout) +} + func newFakeIngressController(t *testing.T, ing *extensionsv1beta1.Ingress, rollout *v1alpha1.Rollout) (*Controller, *k8sfake.Clientset, map[string]int) { + return underlyingControllerBuilder(t, []*extensionsv1beta1.Ingress{ing}, rollout) +} + +func underlyingControllerBuilder(t *testing.T, ing []*extensionsv1beta1.Ingress, rollout *v1alpha1.Rollout) (*Controller, *k8sfake.Clientset, map[string]int) { t.Helper() client := fake.NewSimpleClientset() if rollout != nil { @@ -62,7 +71,13 @@ func newFakeIngressController(t *testing.T, ing *extensionsv1beta1.Ingress, roll } kubeclient := k8sfake.NewSimpleClientset() if ing != nil { - kubeclient = k8sfake.NewSimpleClientset(ing) + var x []runtime.Object + for _, i := range ing { + if i != nil { + x = append(x, i) + } + } + kubeclient = k8sfake.NewSimpleClientset(x...) } i := informers.NewSharedInformerFactory(client, 0) k8sI := kubeinformers.NewSharedInformerFactory(kubeclient, 0) @@ -107,7 +122,11 @@ func newFakeIngressController(t *testing.T, ing *extensionsv1beta1.Ingress, roll } if ing != nil { - k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(ing) + for _, i := range ing { + if i != nil { + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) + } + } } if rollout != nil { i.Argoproj().V1alpha1().Rollouts().Informer().GetIndexer().Add(rollout) @@ -133,6 +152,20 @@ func TestSyncIngressNotReferencedByRollout(t *testing.T) { assert.Len(t, actions, 0) } +func TestSyncIngressNotReferencedByRolloutMultiIngress(t *testing.T) { + ings := []*extensionsv1beta1.Ingress{ + newNginxIngress("test-stable-ingress", 80, "stable-service"), + newNginxIngress("test-stable-ingress-additional", 80, "stable-service"), + } + + ctrl, kubeclient, _ := newFakeIngressControllerMultiIngress(t, ings, nil) + + err := ctrl.syncIngress("default/test-stable-ingress") + assert.NoError(t, err) + actions := kubeclient.Actions() + assert.Len(t, actions, 0) +} + func TestSyncIngressReferencedByRollout(t *testing.T) { ing := newNginxIngress("test-stable-ingress", 80, "stable-service") @@ -165,6 +198,42 @@ func TestSyncIngressReferencedByRollout(t *testing.T) { assert.Equal(t, 1, enqueuedObjects["default/rollout"]) } +func TestSyncIngressReferencedByRolloutMultiIngress(t *testing.T) { + ings := []*extensionsv1beta1.Ingress{ + newNginxIngress("test-stable-ingress", 80, "stable-service"), + newNginxIngress("test-stable-ingress-additional", 80, "stable-service"), + } + + rollout := &v1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rollout", + Namespace: metav1.NamespaceDefault, + }, + Spec: v1alpha1.RolloutSpec{ + Strategy: v1alpha1.RolloutStrategy{ + Canary: &v1alpha1.CanaryStrategy{ + StableService: "stable-service", + CanaryService: "canary-service", + TrafficRouting: &v1alpha1.RolloutTrafficRouting{ + Nginx: &v1alpha1.NginxTrafficRouting{ + StableIngress: "test-stable-ingress", + AdditionalStableIngresses: []string{"test-stable-ingress-additional"}, + }, + }, + }, + }, + }, + } + + ctrl, kubeclient, enqueuedObjects := newFakeIngressControllerMultiIngress(t, ings, rollout) + + err := ctrl.syncIngress("default/test-stable-ingress") + assert.NoError(t, err) + actions := kubeclient.Actions() + assert.Len(t, actions, 0) + assert.Equal(t, 1, enqueuedObjects["default/rollout"]) +} + func TestSkipIngressWithNoAnnotations(t *testing.T) { ing := newNginxIngress("test-stable-ingress", 80, "stable-service") ing.Annotations = nil @@ -196,3 +265,42 @@ func TestSkipIngressWithNoAnnotations(t *testing.T) { assert.Len(t, actions, 0) assert.Len(t, enqueuedObjects, 0) } + +func TestSkipIngressWithNoAnnotationsMultiIngress(t *testing.T) { + ings := []*extensionsv1beta1.Ingress{ + newNginxIngress("test-stable-ingress", 80, "stable-service"), + newNginxIngress("test-stable-ingress-additional", 80, "stable-service"), + } + for _, i := range ings { + i.Annotations = nil + } + + rollout := &v1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rollout", + Namespace: metav1.NamespaceDefault, + }, + Spec: v1alpha1.RolloutSpec{ + Strategy: v1alpha1.RolloutStrategy{ + Canary: &v1alpha1.CanaryStrategy{ + StableService: "stable-service", + CanaryService: "canary-service", + TrafficRouting: &v1alpha1.RolloutTrafficRouting{ + Nginx: &v1alpha1.NginxTrafficRouting{ + StableIngress: "test-stable-ingress", + AdditionalStableIngresses: []string{"test-stable-ingress-additional"}, + }, + }, + }, + }, + }, + } + + ctrl, kubeclient, enqueuedObjects := newFakeIngressControllerMultiIngress(t, ings, rollout) + + err := ctrl.syncIngress("default/test-stable-ingress") + assert.NoError(t, err) + actions := kubeclient.Actions() + assert.Len(t, actions, 0) + assert.Len(t, enqueuedObjects, 0) +} diff --git a/pkg/apis/rollouts/validation/validation_references_test.go b/pkg/apis/rollouts/validation/validation_references_test.go index 7b14dd7483..1df7d45b25 100644 --- a/pkg/apis/rollouts/validation/validation_references_test.go +++ b/pkg/apis/rollouts/validation/validation_references_test.go @@ -181,6 +181,24 @@ func getRollout() *v1alpha1.Rollout { } } +func getRolloutMultiIngress() *v1alpha1.Rollout { + return &v1alpha1.Rollout{ + Spec: v1alpha1.RolloutSpec{ + Strategy: v1alpha1.RolloutStrategy{ + Canary: &v1alpha1.CanaryStrategy{ + StableService: "stable-service-name", + TrafficRouting: &v1alpha1.RolloutTrafficRouting{ + Nginx: &v1alpha1.NginxTrafficRouting{ + StableIngress: "test-stable-ingress", + AdditionalStableIngresses: []string{"test-stable-ingress-additional"}, + }, + }, + }, + }, + }, + } +} + func getIngress() *v1beta1.Ingress { return &v1beta1.Ingress{ ObjectMeta: metav1.ObjectMeta{ diff --git a/rollout/controller_test.go b/rollout/controller_test.go index 7f324ea10b..04424f491b 100644 --- a/rollout/controller_test.go +++ b/rollout/controller_test.go @@ -1660,6 +1660,8 @@ func TestGetReferencedIngressesNginx(t *testing.T) { defer f.Close() t.Run("get referenced Nginx ingress - fail", func(t *testing.T) { + // clear fixture + f.ingressLister = []*ingressutil.Ingress{} c, _, _ := f.newController(noResyncPeriodFunc) roCtx, err := c.newRolloutContext(r) assert.NoError(t, err) @@ -1669,6 +1671,8 @@ func TestGetReferencedIngressesNginx(t *testing.T) { }) t.Run("get referenced Nginx ingress - success", func(t *testing.T) { + // clear fixture + f.ingressLister = []*ingressutil.Ingress{} ingress := &extensionsv1beta1.Ingress{ ObjectMeta: metav1.ObjectMeta{ Name: "nginx-ingress-name", @@ -1683,6 +1687,93 @@ func TestGetReferencedIngressesNginx(t *testing.T) { assert.NoError(t, err) }) } +func TestGetReferencedIngressesNginxMultiIngress(t *testing.T) { + f := newFixture(t) + defer f.Close() + r := newCanaryRollout("rollout", 1, nil, nil, nil, intstr.FromInt(0), intstr.FromInt(1)) + r.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{ + Nginx: &v1alpha1.NginxTrafficRouting{ + StableIngress: "nginx-ingress-name", + AdditionalStableIngresses: []string{"nginx-ingress-additional"}, + }, + } + r.Namespace = metav1.NamespaceDefault + defer f.Close() + + t.Run("get referenced Nginx ingress - fail on secondary when both missing", func(t *testing.T) { + // clear fixture + f.ingressLister = []*ingressutil.Ingress{} + c, _, _ := f.newController(noResyncPeriodFunc) + roCtx, err := c.newRolloutContext(r) + assert.NoError(t, err) + _, err = roCtx.getReferencedIngresses() + expectedErr := field.Invalid(field.NewPath("spec", "strategy", "canary", "trafficRouting", "nginx", "AdditionalStableIngresses"), "nginx-ingress-name", "ingress.extensions \"nginx-ingress-additional\" not found") + assert.Equal(t, expectedErr.Error(), err.Error()) + }) + + t.Run("get referenced Nginx ingress - fail on primary when additional present", func(t *testing.T) { + // clear fixture + f.ingressLister = []*ingressutil.Ingress{} + ingressAdditional := &extensionsv1beta1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx-ingress-additional", + Namespace: metav1.NamespaceDefault, + }, + } + f.ingressLister = append(f.ingressLister, ingressutil.NewLegacyIngress(ingressAdditional)) + c, _, _ := f.newController(noResyncPeriodFunc) + roCtx, err := c.newRolloutContext(r) + assert.NoError(t, err) + _, err = roCtx.getReferencedIngresses() + expectedErr := field.Invalid(field.NewPath("spec", "strategy", "canary", "trafficRouting", "nginx", "stableIngress"), "nginx-ingress-name", "ingress.extensions \"nginx-ingress-name\" not found") + assert.Equal(t, expectedErr.Error(), err.Error()) + }) + + t.Run("get referenced Nginx ingress - fail on secondary when only secondary missing", func(t *testing.T) { + // clear fixture + f.ingressLister = []*ingressutil.Ingress{} + ingress := &extensionsv1beta1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx-ingress-name", + Namespace: metav1.NamespaceDefault, + }, + } + f.ingressLister = append(f.ingressLister, ingressutil.NewLegacyIngress(ingress)) + c, _, _ := f.newController(noResyncPeriodFunc) + roCtx, err := c.newRolloutContext(r) + assert.NoError(t, err) + _, err = roCtx.getReferencedIngresses() + if err == nil { + fmt.Println("ERROR IS NIL") + } + expectedErr := field.Invalid(field.NewPath("spec", "strategy", "canary", "trafficRouting", "nginx", "AdditionalStableIngresses"), "nginx-ingress-name", "ingress.extensions \"nginx-ingress-additional\" not found") + assert.Equal(t, expectedErr.Error(), err.Error()) + }) + + t.Run("get referenced Nginx ingress - success", func(t *testing.T) { + // clear fixture + f.ingressLister = []*ingressutil.Ingress{} + ingress := &extensionsv1beta1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx-ingress-name", + Namespace: metav1.NamespaceDefault, + }, + } + ingressAdditional := &extensionsv1beta1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: "nginx-ingress-additional", + Namespace: metav1.NamespaceDefault, + }, + } + f.ingressLister = append(f.ingressLister, ingressutil.NewLegacyIngress(ingress)) + f.ingressLister = append(f.ingressLister, ingressutil.NewLegacyIngress(ingressAdditional)) + c, _, _ := f.newController(noResyncPeriodFunc) + roCtx, err := c.newRolloutContext(r) + assert.NoError(t, err) + _, err = roCtx.getReferencedIngresses() + assert.NoError(t, err) + }) +} func TestGetReferencedAppMeshResources(t *testing.T) { r := newCanaryRollout("rollout", 1, nil, nil, nil, intstr.FromInt(0), intstr.FromInt(1)) From 1c45c187677e32d702d6b80a6fb8a25f968d9f87 Mon Sep 17 00:00:00 2001 From: Travis Perdue Date: Thu, 23 Jun 2022 10:20:57 -0500 Subject: [PATCH 145/175] remove validation_references_test.go snafu Signed-off-by: Travis Perdue --- .../validation/validation_references_test.go | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/pkg/apis/rollouts/validation/validation_references_test.go b/pkg/apis/rollouts/validation/validation_references_test.go index 1df7d45b25..7b14dd7483 100644 --- a/pkg/apis/rollouts/validation/validation_references_test.go +++ b/pkg/apis/rollouts/validation/validation_references_test.go @@ -181,24 +181,6 @@ func getRollout() *v1alpha1.Rollout { } } -func getRolloutMultiIngress() *v1alpha1.Rollout { - return &v1alpha1.Rollout{ - Spec: v1alpha1.RolloutSpec{ - Strategy: v1alpha1.RolloutStrategy{ - Canary: &v1alpha1.CanaryStrategy{ - StableService: "stable-service-name", - TrafficRouting: &v1alpha1.RolloutTrafficRouting{ - Nginx: &v1alpha1.NginxTrafficRouting{ - StableIngress: "test-stable-ingress", - AdditionalStableIngresses: []string{"test-stable-ingress-additional"}, - }, - }, - }, - }, - }, - } -} - func getIngress() *v1beta1.Ingress { return &v1beta1.Ingress{ ObjectMeta: metav1.ObjectMeta{ From 427576ce8d653aaeffd8295faa91699e3a7d2c44 Mon Sep 17 00:00:00 2001 From: Travis Perdue Date: Thu, 23 Jun 2022 10:43:06 -0500 Subject: [PATCH 146/175] add ingress util testing for additionalStableIngresses Signed-off-by: Travis Perdue --- utils/ingress/ingress_test.go | 46 +++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/utils/ingress/ingress_test.go b/utils/ingress/ingress_test.go index c545cd0b2d..eb82a4f967 100644 --- a/utils/ingress/ingress_test.go +++ b/utils/ingress/ingress_test.go @@ -61,6 +61,33 @@ func TestGetRolloutIngressKeysForCanaryWithTrafficRouting(t *testing.T) { assert.ElementsMatch(t, keys, []string{"default/stable-ingress", "default/myrollout-stable-ingress-canary", "default/alb-ingress"}) } +func TestGetRolloutIngressKeysForCanaryWithTrafficRoutingMultiIngress(t *testing.T) { + keys := GetRolloutIngressKeys(&v1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Name: "myrollout", + Namespace: "default", + }, + Spec: v1alpha1.RolloutSpec{ + Strategy: v1alpha1.RolloutStrategy{ + Canary: &v1alpha1.CanaryStrategy{ + CanaryService: "canary-service", + StableService: "stable-service", + TrafficRouting: &v1alpha1.RolloutTrafficRouting{ + Nginx: &v1alpha1.NginxTrafficRouting{ + StableIngress: "stable-ingress", + AdditionalStableIngresses: []string{"stable-ingress-additional"}, + }, + ALB: &v1alpha1.ALBTrafficRouting{ + Ingress: "alb-ingress", + }, + }, + }, + }, + }, + }) + assert.ElementsMatch(t, keys, []string{"default/stable-ingress", "default/myrollout-stable-ingress-canary", "default/stable-ingress-additional", "default/myrollout-stable-ingress-additional-canary", "default/alb-ingress"}) +} + func TestGetCanaryIngressName(t *testing.T) { rollout := &v1alpha1.Rollout{ ObjectMeta: metav1.ObjectMeta{ @@ -75,6 +102,7 @@ func TestGetCanaryIngressName(t *testing.T) { TrafficRouting: &v1alpha1.RolloutTrafficRouting{ Nginx: &v1alpha1.NginxTrafficRouting{ StableIngress: "stable-ingress", + AdditionalStableIngresses: []string{"stable-ingress-additional"}, }, }, }, @@ -82,17 +110,31 @@ func TestGetCanaryIngressName(t *testing.T) { }, } - t.Run("NoTrim", func(t *testing.T) { + t.Run("StableIngress - NoTrim", func(t *testing.T) { rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress = "stable-ingress" canaryIngress := GetCanaryIngressName(rollout.GetName(), rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress) assert.Equal(t, "myrollout-stable-ingress-canary", canaryIngress) }) - t.Run("Trim", func(t *testing.T) { + t.Run("StableIngress - Trim", func(t *testing.T) { rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress = fmt.Sprintf("stable-ingress%s", strings.Repeat("a", 260)) canaryIngress := GetCanaryIngressName(rollout.GetName(), rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.StableIngress) assert.Equal(t, 253, len(canaryIngress), "canary ingress truncated to 253") assert.Equal(t, true, strings.HasSuffix(canaryIngress, "-canary"), "canary ingress has -canary suffix") }) + t.Run("AdditionalStableIngresses - NoTrim", func(t *testing.T) { + for _, ing := range rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.AdditionalStableIngresses { + canaryIngress := GetCanaryIngressName(rollout.GetName(), ing) + assert.Equal(t, "myrollout-stable-ingress-additional-canary", canaryIngress) + } + }) + t.Run("AdditionalStableIngresses - Trim", func(t *testing.T) { + rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.AdditionalStableIngresses = []string{fmt.Sprintf("stable-ingress%s", strings.Repeat("a", 260))} + for _, ing := range rollout.Spec.Strategy.Canary.TrafficRouting.Nginx.AdditionalStableIngresses { + canaryIngress := GetCanaryIngressName(rollout.GetName(), ing) + assert.Equal(t, 253, len(canaryIngress), "canary ingress truncated to 253") + assert.Equal(t, true, strings.HasSuffix(canaryIngress, "-canary"), "canary ingress has -canary suffix") + } + }) t.Run("NoStableIngress", func(t *testing.T) { rollout.Spec.Strategy.Canary.TrafficRouting.Nginx = nil canaryIngress := GetCanaryIngressName(rollout.GetName(), "") From e3c33d86b02ac4779ade8ccfbe195fb5bb071b86 Mon Sep 17 00:00:00 2001 From: jaymebrd Date: Thu, 23 Jun 2022 22:07:39 +0100 Subject: [PATCH 147/175] feat: add support for influxdb as a metrics provider (#1839) * feat: add InfluxDB metric provider implementation Signed-off-by: Jayme Bird * feat: add influx to metric provider util count, add missing graphite Signed-off-by: Jayme Bird * feat: add protobuf definitions for InfluxdbMetric Signed-off-by: Jayme Bird * feat: add docs for the Influxdb metrics provider Signed-off-by: Jayme Bird * feat: add tests for influxdb metrics provider Signed-off-by: Jayme Bird * feat: add go mod replace for version of moq due to security issue Signed-off-by: Jayme Bird * feat: update error message to distinguish failed cases - review feedback Signed-off-by: Jayme Bird * feat: update tests to simplify mocking of QueryTableResult An upstream change to the influx go client makes it easier to mock QueryTableResult in tests. This removes a lot of boilerplate duplication in the tests. Signed-off-by: Jayme Bird * feat: re-run codegen Signed-off-by: Jayme Bird --- README.md | 2 +- docs/analysis/influxdb.md | 41 + docs/index.md | 2 +- go.mod | 9 +- go.sum | 80 +- manifests/crds/analysis-run-crd.yaml | 7 + manifests/crds/analysis-template-crd.yaml | 7 + .../crds/cluster-analysis-template-crd.yaml | 7 + manifests/install.yaml | 21 + manifests/namespace-install.yaml | 21 + metricproviders/influxdb/influxdb.go | 136 ++ metricproviders/influxdb/influxdb_test.go | 249 ++++ metricproviders/influxdb/mock_test.go | 32 + metricproviders/metricproviders.go | 17 +- mkdocs.yml | 1 + pkg/apis/rollouts/v1alpha1/analysis_types.go | 10 + pkg/apis/rollouts/v1alpha1/generated.pb.go | 1282 ++++++++++------- pkg/apis/rollouts/v1alpha1/generated.proto | 12 + .../rollouts/v1alpha1/openapi_generated.go | 36 +- .../v1alpha1/zz_generated.deepcopy.go | 21 + utils/analysis/factory.go | 6 + utils/analysis/factory_test.go | 2 + 22 files changed, 1475 insertions(+), 526 deletions(-) create mode 100644 docs/analysis/influxdb.md create mode 100644 metricproviders/influxdb/influxdb.go create mode 100644 metricproviders/influxdb/influxdb_test.go create mode 100644 metricproviders/influxdb/mock_test.go diff --git a/README.md b/README.md index 94931ac5b5..f044877ab3 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ For these reasons, in large scale high-volume production environments, a rolling * Customizable metric queries and analysis of business KPIs * Ingress controller integration: NGINX, ALB * Service Mesh integration: Istio, Linkerd, SMI -* Metric provider integration: Prometheus, Wavefront, Kayenta, Web, Kubernetes Jobs, Datadog, New Relic +* Metric provider integration: Prometheus, Wavefront, Kayenta, Web, Kubernetes Jobs, Datadog, New Relic, InfluxDB ## Documentation To learn more about Argo Rollouts go to the [complete documentation](https://argoproj.github.io/argo-rollouts/). diff --git a/docs/analysis/influxdb.md b/docs/analysis/influxdb.md new file mode 100644 index 0000000000..f4bd95345e --- /dev/null +++ b/docs/analysis/influxdb.md @@ -0,0 +1,41 @@ +# InfluxDB Metrics + +An [InfluxDB](https://www.influxdata.com/) query using [Flux](https://docs.influxdata.com/influxdb/cloud/query-data/get-started/query-influxdb/) can be used to obtain measurements for analysis. + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: AnalysisTemplate +metadata: + name: error-rate +spec: + args: + - name: application-name + metrics: + - name: error-rate + # NOTE: To be consistent with the prometheus metrics provider InfluxDB query results are returned as an array. + # In the example we're looking at index 0 of the returned array to obtain the value we're using for the success condition + successCondition: result[0] <= 0.01 + provider: + influxdb: + profile: my-influxdb-secret # optional, defaults to 'influxdb' + query: | + from(bucket: "app_istio") + |> range(start: -15m) + |> filter(fn: (r) => r["destination_workload"] == "{{ args.application-name }}") + |> filter(fn: (r) => r["_measurement"] == "istio:istio_requests_errors_percentage:rate1m:5xx") + +``` + +An InfluxDB access profile can be configured using a Kubernetes secret in the `argo-rollouts` namespace. Alternate accounts can be used by creating more secrets of the same format and specifying which secret to use in the metric provider configuration using the `profile` field. + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: influxdb +type: Opaque +data: + address: + authToken: + org: +``` diff --git a/docs/index.md b/docs/index.md index 0174ed9f48..2614a51e08 100644 --- a/docs/index.md +++ b/docs/index.md @@ -30,7 +30,7 @@ For these reasons, in large scale high-volume production environments, a rolling * Ingress controller integration: NGINX, ALB * Service Mesh integration: Istio, Linkerd, SMI * Simultaneous usage of multiple providers: SMI + NGINX, Istio + ALB, etc. -* Metric provider integration: Prometheus, Wavefront, Kayenta, Web, Kubernetes Jobs, Datadog, New Relic, Graphite +* Metric provider integration: Prometheus, Wavefront, Kayenta, Web, Kubernetes Jobs, Datadog, New Relic, Graphite, InfluxDB ## Quick Start diff --git a/go.mod b/go.mod index 37bebd331e..e78e3ee333 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.2 github.com/grpc-ecosystem/grpc-gateway v1.16.0 + github.com/influxdata/influxdb-client-go/v2 v2.8.1 github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a github.com/mitchellh/mapstructure v1.4.3 github.com/newrelic/newrelic-client-go v0.72.0 @@ -82,6 +83,7 @@ require ( github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect github.com/cyphar/filepath-securejoin v0.2.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/deepmap/oapi-codegen v1.9.1 // indirect github.com/docker/distribution v2.7.1+incompatible // indirect github.com/emicklei/go-restful v2.9.5+incompatible // indirect github.com/evanphx/json-patch v4.12.0+incompatible // indirect @@ -113,6 +115,7 @@ require ( github.com/huandu/xstrings v1.3.2 // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -145,9 +148,9 @@ require ( github.com/whilp/git-urls v0.0.0-20191001220047-6db9661140c0 // indirect github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect - golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect + golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect golang.org/x/mod v0.5.1 // indirect - golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba // indirect + golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 // indirect golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect @@ -204,3 +207,5 @@ replace ( k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.23.1 k8s.io/sample-controller => k8s.io/sample-controller v0.23.1 ) + +replace github.com/matryer/moq => github.com/matryer/moq v0.1.6 diff --git a/go.sum b/go.sum index 146e68a910..2a1b73ff4c 100644 --- a/go.sum +++ b/go.sum @@ -238,6 +238,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -246,6 +247,11 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= +github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= +github.com/deepmap/oapi-codegen v1.9.1 h1:yHmEnA7jSTUMQgV+uN02WpZtwHnz2CBW3mZRIxr1vtI= +github.com/deepmap/oapi-codegen v1.9.1/go.mod h1:PLqNAhdedP8ttRpBBkzLKU3bp+Fpy+tTgeAMlztR2cw= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= @@ -306,12 +312,17 @@ github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5 github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM= +github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= +github.com/getkin/kin-openapi v0.87.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew= github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -339,6 +350,13 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.4.0 h1:Mr3JcvBjQEhCN9wld6OHKHuHxWaoXTaQfYKmj7QwP18= @@ -346,6 +364,7 @@ github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.4.0/go.mod h1:A2S0CWkNylc2 github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/goccy/go-json v0.7.8/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -354,6 +373,8 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.0.0 h1:RAqyYixv1p7uEnocuy8P1nru5wprCh/MH2BIlW5z5/o= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= @@ -395,6 +416,7 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -535,6 +557,11 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb-client-go/v2 v2.8.1 h1:DahMl2iYvr9hEtGZcV4Ud8Z7AQ8cQVbPlX6gEOBBCrE= +github.com/influxdata/influxdb-client-go/v2 v2.8.1/go.mod h1:x7Jo5UHHl+w8wu8UnGiNobDDHygojXwJX4mx7rXGKMk= +github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= +github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf h1:7JTmneyiNEwVBOHSjoMxiWAqB992atOeepeFYegn5RU= +github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= github.com/ishidawataru/sctp v0.0.0-20190723014705-7c296d48a2b5/go.mod h1:DM4VvS+hD/kDi1U1QsX2fnZowwBhqD0Dk3bRPKF/Oc8= github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -581,10 +608,25 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= +github.com/labstack/echo/v4 v4.6.3/go.mod h1:Hk5OiHj0kDqmFq7aHe7eDqI7CUhuCrfpupQtLGGLm7A= +github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= +github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= +github.com/lestrrat-go/blackmagic v1.0.0/go.mod h1:TNgH//0vYSs8VXDCfkZLgIrVTTXQELZffUV0tz3MtdQ= +github.com/lestrrat-go/codegen v1.0.2/go.mod h1:JhJw6OQAuPEfVKUCLItpaVLumDGWQznd1VaXrBk9TdM= +github.com/lestrrat-go/httpcc v1.0.0/go.mod h1:tGS/u00Vh5N6FHNkExqGGNId8e0Big+++0Gf8MBnAvE= +github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc= +github.com/lestrrat-go/jwx v1.2.7/go.mod h1:bw24IXWbavc0R2RsOtpXL7RtMyP589yZ1+L7kd09ZGA= +github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/libopenstorage/openstorage v1.0.0/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= @@ -606,15 +648,20 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/matryer/moq v0.1.6/go.mod h1:9RtPYjTnH1bSBIkpvtHkFN7nbWAnO7oRpdJkEIn6UtE= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= @@ -682,7 +729,6 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/newrelic/newrelic-client-go v0.72.0 h1:7dv4V+Wq4cKqZ1vq2OkspF9j08Q65D9A19LB6FWn9XM= github.com/newrelic/newrelic-client-go v0.72.0/go.mod h1:VXjhsfui0rvhM9cVwnKwlidF8NbXlHZvh63ZKi6fImA= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nlopes/slack v0.5.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= @@ -723,6 +769,7 @@ github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -775,6 +822,9 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rubiojr/go-vhd v0.0.0-20200706105327-02e210299021/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -861,11 +911,16 @@ github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJ github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= @@ -938,9 +993,14 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= +golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1042,10 +1102,11 @@ golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba h1:6u6sik+bn/y7vILcYkK3iwTBWN7WtBvB0+SZswQnbf8= -golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 h1:EN5+DfgmRMvRUrMGERW2gQl3Vc+Z7ZMnI/xdEpPSf0c= +golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1098,6 +1159,7 @@ golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1131,6 +1193,7 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1168,11 +1231,13 @@ golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= @@ -1190,6 +1255,7 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1244,13 +1310,16 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200815165600-90abf76919f3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= @@ -1437,8 +1506,9 @@ gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= diff --git a/manifests/crds/analysis-run-crd.yaml b/manifests/crds/analysis-run-crd.yaml index 29b474072e..b5a2dcc4a8 100644 --- a/manifests/crds/analysis-run-crd.yaml +++ b/manifests/crds/analysis-run-crd.yaml @@ -192,6 +192,13 @@ spec: query: type: string type: object + influxdb: + properties: + profile: + type: string + query: + type: string + type: object job: properties: metadata: diff --git a/manifests/crds/analysis-template-crd.yaml b/manifests/crds/analysis-template-crd.yaml index f1a2574030..df7cfe08f5 100644 --- a/manifests/crds/analysis-template-crd.yaml +++ b/manifests/crds/analysis-template-crd.yaml @@ -188,6 +188,13 @@ spec: query: type: string type: object + influxdb: + properties: + profile: + type: string + query: + type: string + type: object job: properties: metadata: diff --git a/manifests/crds/cluster-analysis-template-crd.yaml b/manifests/crds/cluster-analysis-template-crd.yaml index 8afa62eebc..919c0c5fc5 100644 --- a/manifests/crds/cluster-analysis-template-crd.yaml +++ b/manifests/crds/cluster-analysis-template-crd.yaml @@ -188,6 +188,13 @@ spec: query: type: string type: object + influxdb: + properties: + profile: + type: string + query: + type: string + type: object job: properties: metadata: diff --git a/manifests/install.yaml b/manifests/install.yaml index 00ff531b5c..4238f06eef 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -193,6 +193,13 @@ spec: query: type: string type: object + influxdb: + properties: + profile: + type: string + query: + type: string + type: object job: properties: metadata: @@ -3057,6 +3064,13 @@ spec: query: type: string type: object + influxdb: + properties: + profile: + type: string + query: + type: string + type: object job: properties: metadata: @@ -5807,6 +5821,13 @@ spec: query: type: string type: object + influxdb: + properties: + profile: + type: string + query: + type: string + type: object job: properties: metadata: diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 3edf1348e4..f10bf17255 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -193,6 +193,13 @@ spec: query: type: string type: object + influxdb: + properties: + profile: + type: string + query: + type: string + type: object job: properties: metadata: @@ -3057,6 +3064,13 @@ spec: query: type: string type: object + influxdb: + properties: + profile: + type: string + query: + type: string + type: object job: properties: metadata: @@ -5807,6 +5821,13 @@ spec: query: type: string type: object + influxdb: + properties: + profile: + type: string + query: + type: string + type: object job: properties: metadata: diff --git a/metricproviders/influxdb/influxdb.go b/metricproviders/influxdb/influxdb.go new file mode 100644 index 0000000000..f67c8d5f94 --- /dev/null +++ b/metricproviders/influxdb/influxdb.go @@ -0,0 +1,136 @@ +package influxdb + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/argoproj/argo-rollouts/utils/defaults" + "github.com/argoproj/argo-rollouts/utils/evaluate" + influxdb2 "github.com/influxdata/influxdb-client-go/v2" + influxapi "github.com/influxdata/influxdb-client-go/v2/api" + log "github.com/sirupsen/logrus" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + metricutil "github.com/argoproj/argo-rollouts/utils/metric" +) + +const ( + //ProviderType indicates the provider is InfluxDB + ProviderType = "Influxdb" + //DefaultInfluxdbTokensSecretName is the k8s secret that has InfluxDB api token, org and address + DefaultInfluxdbTokensSecretName = "influxdb" + influxdbToken = "authToken" + influxdbOrg = "org" + influxdbAddress = "address" + defaultQueryTimeout = 30 * time.Second +) + +// Provider contains all the required components to run a influxdb flux query +type Provider struct { + api influxapi.QueryAPI + logCtx log.Entry +} + +// Type indicates provider is a influxdb provider +func (p *Provider) Type() string { + return ProviderType +} + +// GetMetadata returns any additional metadata which needs to be stored & displayed as part of the metrics result. +func (p *Provider) GetMetadata(metric v1alpha1.Metric) map[string]string { + return nil +} + +// Run queries influxdb for the metric +func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alpha1.Measurement { + startTime := metav1.Now() + newMeasurement := v1alpha1.Measurement{ + StartedAt: &startTime, + } + ctx, cancel := context.WithTimeout(context.Background(), defaultQueryTimeout) + defer cancel() + result, err := p.api.Query(ctx, metric.Provider.Influxdb.Query) + if err != nil { + return metricutil.MarkMeasurementError(newMeasurement, err) + } + newValue, newStatus, err := p.processResponse(metric, result) + if err != nil { + return metricutil.MarkMeasurementError(newMeasurement, err) + } + newMeasurement.Value = newValue + + newMeasurement.Phase = newStatus + finishedTime := metav1.Now() + newMeasurement.FinishedAt = &finishedTime + return newMeasurement +} + +// Resume should not be used by the influxdb provider since all the work should occur in the Run method. +func (p *Provider) Resume(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric, measurement v1alpha1.Measurement) v1alpha1.Measurement { + p.logCtx.Warn("Influxdb provider should not execute the Resume method") + return measurement +} + +// Terminate should not be used by the influxdb provider since all the work should occur in the Run method. +func (p *Provider) Terminate(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric, measurement v1alpha1.Measurement) v1alpha1.Measurement { + p.logCtx.Warn("Influxdb provider should not execute the Terminate method") + return measurement +} + +// GarbageCollect is a no-op for the influxdb provider +func (p *Provider) GarbageCollect(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric, limit int) error { + return nil +} + +func (p *Provider) processResponse(metric v1alpha1.Metric, result *influxapi.QueryTableResult) (string, v1alpha1.AnalysisPhase, error) { + var res []interface{} + if result == nil { + return "", v1alpha1.AnalysisPhaseError, fmt.Errorf("no QueryTableResult returned from flux query") + } + for result.Next() { + res = append(res, result.Record().Value()) + } + if len(res) == 0 { + return "", v1alpha1.AnalysisPhaseError, fmt.Errorf("no results returned from flux query") + } + status, err := evaluate.EvaluateResult(res, metric, p.logCtx) + if err != nil { + return "", v1alpha1.AnalysisPhaseError, err + } + return fmt.Sprint(res), status, err +} + +// NewInfluxdbProvider Creates a new Influxdb client +func NewInfluxdbProvider(api influxapi.QueryAPI, logCtx log.Entry) *Provider { + return &Provider{ + logCtx: logCtx, + api: api, + } +} + +// NewInfluxdbAPI generates a Influx API from the metric configuration +func NewInfluxdbAPI(metric v1alpha1.Metric, kubeclientset kubernetes.Interface) (influxapi.QueryAPI, error) { + profileSecret := DefaultInfluxdbTokensSecretName + if metric.Provider.Influxdb.Profile != "" { + profileSecret = metric.Provider.Influxdb.Profile + } + ns := defaults.Namespace() + secret, err := kubeclientset.CoreV1().Secrets(ns).Get(context.TODO(), profileSecret, metav1.GetOptions{}) + if err != nil { + return nil, err + } + authToken := string(secret.Data[influxdbToken]) + address := string(secret.Data[influxdbAddress]) + org := string(secret.Data[influxdbOrg]) + + if authToken != "" && address != "" && org != "" { + influxClient := influxdb2.NewClient(address, authToken) + return influxClient.QueryAPI(org), nil + } + + return nil, errors.New("authToken, org, or address not found") +} diff --git a/metricproviders/influxdb/influxdb_test.go b/metricproviders/influxdb/influxdb_test.go new file mode 100644 index 0000000000..d4f1512e54 --- /dev/null +++ b/metricproviders/influxdb/influxdb_test.go @@ -0,0 +1,249 @@ +package influxdb + +import ( + "errors" + "fmt" + "io/ioutil" + "strings" + "testing" + + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + influxdb2 "github.com/influxdata/influxdb-client-go/v2/api" + log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + k8sfake "k8s.io/client-go/kubernetes/fake" + kubetesting "k8s.io/client-go/testing" +) + +func newAnalysisRun() *v1alpha1.AnalysisRun { + return &v1alpha1.AnalysisRun{} +} + +func TestType(t *testing.T) { + e := log.Entry{} + mock := &mockAPI{} + p := NewInfluxdbProvider(mock, e) + assert.Equal(t, ProviderType, p.Type()) +} + +func TestRunSuccessfully(t *testing.T) { + e := log.Entry{} + csvTable := `#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string,string,string,string +#group,false,false,true,true,false,false,true,true,true,true +#default,_result,,,,,,,,, +,result,table,_start,_stop,_time,_value,_field,_measurement,a,b +,,0,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T10:34:08.135814545Z,1.0,f,test,1,adsfasdf +,,0,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T22:08:44.850214724Z,6.6,f,test,1,adsfasdf +` + reader := strings.NewReader(csvTable) + result := influxdb2.NewQueryTableResult(ioutil.NopCloser(reader)) + mock := &mockAPI{response: result} + p := NewInfluxdbProvider(mock, e) + metric := v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result[0] == 1", + FailureCondition: "result[0] != 1", + Provider: v1alpha1.MetricProvider{ + Influxdb: &v1alpha1.InfluxdbMetric{ + Query: "test", + }, + }, + } + measurement := p.Run(newAnalysisRun(), metric) + metricsMetadata := p.GetMetadata(metric) + assert.Nil(t, metricsMetadata) + assert.NotNil(t, measurement.StartedAt) + assert.Equal(t, `[1 6.6]`, measurement.Value) + assert.NotNil(t, measurement.FinishedAt) + assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, measurement.Phase) +} + +func TestRunWithTimeseries(t *testing.T) { + e := log.Entry{} + csvTable := `#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string,string,string,string +#group,false,false,true,true,false,false,true,true,true,true +#default,_result,,,,,,,,, +,result,table,_start,_stop,_time,_value,_field,_measurement,a,b +,,0,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T10:34:08.135814545Z,10,f,test,1,adsfasdf +,,0,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T22:08:44.850214724Z,20,f,test,1,adsfasdf +` + reader := strings.NewReader(csvTable) + result := influxdb2.NewQueryTableResult(ioutil.NopCloser(reader)) + mock := &mockAPI{response: result} + p := NewInfluxdbProvider(mock, e) + metric := v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result[0] == 10", + FailureCondition: "result[1] < 20", + Provider: v1alpha1.MetricProvider{ + Influxdb: &v1alpha1.InfluxdbMetric{ + Query: "test", + }, + }, + } + measurement := p.Run(newAnalysisRun(), metric) + metricsMetadata := p.GetMetadata(metric) + assert.Nil(t, metricsMetadata) + assert.NotNil(t, measurement.StartedAt) + assert.Equal(t, `[10 20]`, measurement.Value) + assert.NotNil(t, measurement.FinishedAt) + assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, measurement.Phase) +} + +func TestRunWithEmptyResult(t *testing.T) { + e := log.NewEntry(log.New()) + expectedErr := fmt.Errorf("no results returned from flux query") + csvTable := `#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string,string,string,string +#group,false,false,true,true,false,false,true,true,true,true +#default,_result,,,,,,,,, +,result,table,_start,_stop,_time,_value,_field,_measurement,a,b +` + reader := strings.NewReader(csvTable) + result := influxdb2.NewQueryTableResult(ioutil.NopCloser(reader)) + mock := &mockAPI{response: result} + p := NewInfluxdbProvider(mock, *e) + metric := v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result[0] == 10", + FailureCondition: "result[0] != 10", + Provider: v1alpha1.MetricProvider{ + Influxdb: &v1alpha1.InfluxdbMetric{ + Query: "test", + }, + }, + } + measurement := p.Run(newAnalysisRun(), metric) + metricsMetadata := p.GetMetadata(metric) + assert.Nil(t, metricsMetadata) + assert.Equal(t, expectedErr.Error(), measurement.Message) + assert.NotNil(t, measurement.StartedAt) + assert.Equal(t, "", measurement.Value) + assert.NotNil(t, measurement.FinishedAt) + assert.Equal(t, v1alpha1.AnalysisPhaseError, measurement.Phase) +} + +func TestRunWithEvaluationError(t *testing.T) { + e := log.WithField("", "") + mock := &mockAPI{} + p := NewInfluxdbProvider(mock, *e) + metric := v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result == 10", + FailureCondition: "result != 10", + Provider: v1alpha1.MetricProvider{ + Influxdb: &v1alpha1.InfluxdbMetric{ + Query: "test", + }, + }, + } + measurement := p.Run(newAnalysisRun(), metric) + metricsMetadata := p.GetMetadata(metric) + assert.Nil(t, metricsMetadata) + assert.Equal(t, "no QueryTableResult returned from flux query", measurement.Message) + assert.NotNil(t, measurement.StartedAt) + assert.Equal(t, "", measurement.Value) + assert.NotNil(t, measurement.FinishedAt) + assert.Equal(t, v1alpha1.AnalysisPhaseError, measurement.Phase) +} + +func TestResume(t *testing.T) { + e := log.WithField("", "") + mock := &mockAPI{} + p := NewInfluxdbProvider(mock, *e) + metric := v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result == 10", + FailureCondition: "result != 10", + Provider: v1alpha1.MetricProvider{ + Influxdb: &v1alpha1.InfluxdbMetric{ + Query: "test", + }, + }, + } + now := metav1.Now() + previousMeasurement := v1alpha1.Measurement{ + StartedAt: &now, + Phase: v1alpha1.AnalysisPhaseInconclusive, + } + measurement := p.Resume(newAnalysisRun(), metric, previousMeasurement) + assert.Equal(t, previousMeasurement, measurement) +} + +func TestTerminate(t *testing.T) { + e := log.NewEntry(log.New()) + mock := &mockAPI{} + p := NewInfluxdbProvider(mock, *e) + metric := v1alpha1.Metric{} + now := metav1.Now() + previousMeasurement := v1alpha1.Measurement{ + StartedAt: &now, + Phase: v1alpha1.AnalysisPhaseRunning, + } + measurement := p.Terminate(newAnalysisRun(), metric, previousMeasurement) + assert.Equal(t, previousMeasurement, measurement) +} + +func TestGarbageCollect(t *testing.T) { + e := log.NewEntry(log.New()) + mock := &mockAPI{} + p := NewInfluxdbProvider(mock, *e) + err := p.GarbageCollect(nil, v1alpha1.Metric{}, 0) + assert.NoError(t, err) +} + +func TestNewInfluxdbAPI(t *testing.T) { + metric := v1alpha1.Metric{ + Provider: v1alpha1.MetricProvider{ + Influxdb: &v1alpha1.InfluxdbMetric{}, + }, + } + tokenSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: DefaultInfluxdbTokensSecretName, + }, + } + fakeClient := k8sfake.NewSimpleClientset() + fakeClient.PrependReactor("get", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { + return true, tokenSecret, nil + }) + + t.Run("with default settings", func(t *testing.T) { + tokenSecret.Data = map[string][]byte{ + influxdbToken: []byte("ABCDEFG01234"), + influxdbOrg: []byte("test-org"), + influxdbAddress: []byte("http://localhost:8086"), + } + _, err := NewInfluxdbAPI(metric, fakeClient) + assert.Nil(t, err) + }) + + t.Run("with authToken, org, or address missing", func(t *testing.T) { + tokenSecret.Data = map[string][]byte{ + influxdbToken: []byte("ABCDEFG01234"), + } + _, err := NewInfluxdbAPI(metric, fakeClient) + assert.EqualError(t, err, "authToken, org, or address not found") + }) + + t.Run("when secretName is specified by the metric", func(t *testing.T) { + metric.Provider.Influxdb.Profile = "my-influx-token-secret" + tokenSecret.Name = "my-influx-token-secret" + tokenSecret.Data = map[string][]byte{ + influxdbToken: []byte("ABCDEFG01234"), + influxdbOrg: []byte("test-org"), + influxdbAddress: []byte("http://localhost:8086"), + } + _, err := NewInfluxdbAPI(metric, fakeClient) + assert.Nil(t, err) + }) + t.Run("when the secret is not found", func(t *testing.T) { + fakeClient.PrependReactor("get", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, errors.New("secret not found") + }) + _, err := NewInfluxdbAPI(metric, fakeClient) + assert.NotNil(t, err) + }) +} diff --git a/metricproviders/influxdb/mock_test.go b/metricproviders/influxdb/mock_test.go new file mode 100644 index 0000000000..3aff084802 --- /dev/null +++ b/metricproviders/influxdb/mock_test.go @@ -0,0 +1,32 @@ +package influxdb + +import ( + "context" + + influxapi "github.com/influxdata/influxdb-client-go/v2/api" + "github.com/influxdata/influxdb-client-go/v2/domain" +) + +type mockAPI struct { + response *influxapi.QueryTableResult + err error +} + +func (m mockAPI) Query(ctx context.Context, query string) (*influxapi.QueryTableResult, error) { + if m.err != nil { + return nil, m.err + } + return m.response, nil +} + +func (m mockAPI) QueryRaw(context.Context, string, *domain.Dialect) (string, error) { + panic("Not used") +} + +func (m mockAPI) QueryRawWithParams(ctx context.Context, query string, dialect *domain.Dialect, params interface{}) (string, error) { + panic("Not used") +} + +func (m mockAPI) QueryWithParams(ctx context.Context, query string, params interface{}) (*influxapi.QueryTableResult, error) { + panic("Not used") +} diff --git a/metricproviders/metricproviders.go b/metricproviders/metricproviders.go index c963a0c245..d8a1637acf 100644 --- a/metricproviders/metricproviders.go +++ b/metricproviders/metricproviders.go @@ -3,6 +3,8 @@ package metricproviders import ( "fmt" + "github.com/argoproj/argo-rollouts/metricproviders/influxdb" + "github.com/argoproj/argo-rollouts/metricproviders/cloudwatch" "github.com/argoproj/argo-rollouts/metricproviders/datadog" "github.com/argoproj/argo-rollouts/metricproviders/graphite" @@ -88,11 +90,17 @@ func (f *ProviderFactory) NewProvider(logCtx log.Entry, metric v1alpha1.Metric) } return graphite.NewGraphiteProvider(client, logCtx), nil case cloudwatch.ProviderType: - clinet, err := cloudwatch.NewCloudWatchAPIClient(metric) + client, err := cloudwatch.NewCloudWatchAPIClient(metric) if err != nil { return nil, err } - return cloudwatch.NewCloudWatchProvider(clinet, logCtx), nil + return cloudwatch.NewCloudWatchProvider(client, logCtx), nil + case influxdb.ProviderType: + client, err := influxdb.NewInfluxdbAPI(metric, f.KubeClient) + if err != nil { + return nil, err + } + return influxdb.NewInfluxdbProvider(client, logCtx), nil default: return nil, fmt.Errorf("no valid provider in metric '%s'", metric.Name) } @@ -115,6 +123,11 @@ func Type(metric v1alpha1.Metric) string { return newrelic.ProviderType } else if metric.Provider.CloudWatch != nil { return cloudwatch.ProviderType + } else if metric.Provider.Graphite != nil { + return graphite.ProviderType + } else if metric.Provider.Influxdb != nil { + return influxdb.ProviderType } + return "Unknown Provider" } diff --git a/mkdocs.yml b/mkdocs.yml index 2e32bd682d..fbe3dcca09 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -55,6 +55,7 @@ nav: - Web: analysis/web.md - Kayenta: analysis/kayenta.md - CloudWatch: analysis/cloudwatch.md + - InfluxDB: analysis/influxdb.md - Experiments: features/experiment.md - Notifications: - Overview: features/notifications.md diff --git a/pkg/apis/rollouts/v1alpha1/analysis_types.go b/pkg/apis/rollouts/v1alpha1/analysis_types.go index 7b6b8e87c4..c22fef2572 100644 --- a/pkg/apis/rollouts/v1alpha1/analysis_types.go +++ b/pkg/apis/rollouts/v1alpha1/analysis_types.go @@ -170,6 +170,8 @@ type MetricProvider struct { CloudWatch *CloudWatchMetric `json:"cloudWatch,omitempty" protobuf:"bytes,8,opt,name=cloudWatch"` // Graphite specifies the Graphite metric to query Graphite *GraphiteMetric `json:"graphite,omitempty" protobuf:"bytes,9,opt,name=graphite"` + // Influxdb specifies the influxdb metric to query + Influxdb *InfluxdbMetric `json:"influxdb,omitempty" protobuf:"bytes,10,opt,name=influxdb"` } // AnalysisPhase is the overall phase of an AnalysisRun, MetricResult, or Measurement @@ -232,6 +234,14 @@ type GraphiteMetric struct { Query string `json:"query,omitempty" protobuf:"bytes,2,opt,name=query"` } +// InfluxdbMetric defines the InfluxDB Flux query to perform canary analysis +type InfluxdbMetric struct { + // Profile is the name of the secret holding InfluxDB account configuration + Profile string `json:"profile,omitempty" protobuf:"bytes,1,opt,name=profile"` + // Query is a raw InfluxDB flux query to perform + Query string `json:"query,omitempty" protobuf:"bytes,2,opt,name=query"` +} + // CloudWatchMetric defines the cloudwatch query to perform canary analysis type CloudWatchMetric struct { Interval DurationString `json:"interval,omitempty" protobuf:"bytes,1,opt,name=interval,casttype=DurationString"` diff --git a/pkg/apis/rollouts/v1alpha1/generated.pb.go b/pkg/apis/rollouts/v1alpha1/generated.pb.go index ae221882a7..8f9b715371 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.pb.go +++ b/pkg/apis/rollouts/v1alpha1/generated.pb.go @@ -1280,10 +1280,38 @@ func (m *HeaderRoutingMatch) XXX_DiscardUnknown() { var xxx_messageInfo_HeaderRoutingMatch proto.InternalMessageInfo +func (m *InfluxdbMetric) Reset() { *m = InfluxdbMetric{} } +func (*InfluxdbMetric) ProtoMessage() {} +func (*InfluxdbMetric) Descriptor() ([]byte, []int) { + return fileDescriptor_e0e705f843545fab, []int{44} +} +func (m *InfluxdbMetric) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *InfluxdbMetric) 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 *InfluxdbMetric) XXX_Merge(src proto.Message) { + xxx_messageInfo_InfluxdbMetric.Merge(m, src) +} +func (m *InfluxdbMetric) XXX_Size() int { + return m.Size() +} +func (m *InfluxdbMetric) XXX_DiscardUnknown() { + xxx_messageInfo_InfluxdbMetric.DiscardUnknown(m) +} + +var xxx_messageInfo_InfluxdbMetric proto.InternalMessageInfo + func (m *IstioDestinationRule) Reset() { *m = IstioDestinationRule{} } func (*IstioDestinationRule) ProtoMessage() {} func (*IstioDestinationRule) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{44} + return fileDescriptor_e0e705f843545fab, []int{45} } func (m *IstioDestinationRule) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1311,7 +1339,7 @@ var xxx_messageInfo_IstioDestinationRule proto.InternalMessageInfo func (m *IstioTrafficRouting) Reset() { *m = IstioTrafficRouting{} } func (*IstioTrafficRouting) ProtoMessage() {} func (*IstioTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{45} + return fileDescriptor_e0e705f843545fab, []int{46} } func (m *IstioTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1339,7 +1367,7 @@ var xxx_messageInfo_IstioTrafficRouting proto.InternalMessageInfo func (m *IstioVirtualService) Reset() { *m = IstioVirtualService{} } func (*IstioVirtualService) ProtoMessage() {} func (*IstioVirtualService) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{46} + return fileDescriptor_e0e705f843545fab, []int{47} } func (m *IstioVirtualService) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1367,7 +1395,7 @@ var xxx_messageInfo_IstioVirtualService proto.InternalMessageInfo func (m *JobMetric) Reset() { *m = JobMetric{} } func (*JobMetric) ProtoMessage() {} func (*JobMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{47} + return fileDescriptor_e0e705f843545fab, []int{48} } func (m *JobMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1395,7 +1423,7 @@ var xxx_messageInfo_JobMetric proto.InternalMessageInfo func (m *KayentaMetric) Reset() { *m = KayentaMetric{} } func (*KayentaMetric) ProtoMessage() {} func (*KayentaMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{48} + return fileDescriptor_e0e705f843545fab, []int{49} } func (m *KayentaMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1423,7 +1451,7 @@ var xxx_messageInfo_KayentaMetric proto.InternalMessageInfo func (m *KayentaScope) Reset() { *m = KayentaScope{} } func (*KayentaScope) ProtoMessage() {} func (*KayentaScope) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{49} + return fileDescriptor_e0e705f843545fab, []int{50} } func (m *KayentaScope) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1451,7 +1479,7 @@ var xxx_messageInfo_KayentaScope proto.InternalMessageInfo func (m *KayentaThreshold) Reset() { *m = KayentaThreshold{} } func (*KayentaThreshold) ProtoMessage() {} func (*KayentaThreshold) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{50} + return fileDescriptor_e0e705f843545fab, []int{51} } func (m *KayentaThreshold) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1479,7 +1507,7 @@ var xxx_messageInfo_KayentaThreshold proto.InternalMessageInfo func (m *Measurement) Reset() { *m = Measurement{} } func (*Measurement) ProtoMessage() {} func (*Measurement) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{51} + return fileDescriptor_e0e705f843545fab, []int{52} } func (m *Measurement) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1507,7 +1535,7 @@ var xxx_messageInfo_Measurement proto.InternalMessageInfo func (m *MeasurementRetention) Reset() { *m = MeasurementRetention{} } func (*MeasurementRetention) ProtoMessage() {} func (*MeasurementRetention) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{52} + return fileDescriptor_e0e705f843545fab, []int{53} } func (m *MeasurementRetention) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1535,7 +1563,7 @@ var xxx_messageInfo_MeasurementRetention proto.InternalMessageInfo func (m *Metric) Reset() { *m = Metric{} } func (*Metric) ProtoMessage() {} func (*Metric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{53} + return fileDescriptor_e0e705f843545fab, []int{54} } func (m *Metric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1563,7 +1591,7 @@ var xxx_messageInfo_Metric proto.InternalMessageInfo func (m *MetricProvider) Reset() { *m = MetricProvider{} } func (*MetricProvider) ProtoMessage() {} func (*MetricProvider) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{54} + return fileDescriptor_e0e705f843545fab, []int{55} } func (m *MetricProvider) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1591,7 +1619,7 @@ var xxx_messageInfo_MetricProvider proto.InternalMessageInfo func (m *MetricResult) Reset() { *m = MetricResult{} } func (*MetricResult) ProtoMessage() {} func (*MetricResult) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{55} + return fileDescriptor_e0e705f843545fab, []int{56} } func (m *MetricResult) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1619,7 +1647,7 @@ var xxx_messageInfo_MetricResult proto.InternalMessageInfo func (m *NewRelicMetric) Reset() { *m = NewRelicMetric{} } func (*NewRelicMetric) ProtoMessage() {} func (*NewRelicMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{56} + return fileDescriptor_e0e705f843545fab, []int{57} } func (m *NewRelicMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1647,7 +1675,7 @@ var xxx_messageInfo_NewRelicMetric proto.InternalMessageInfo func (m *NginxTrafficRouting) Reset() { *m = NginxTrafficRouting{} } func (*NginxTrafficRouting) ProtoMessage() {} func (*NginxTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{57} + return fileDescriptor_e0e705f843545fab, []int{58} } func (m *NginxTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1675,7 +1703,7 @@ var xxx_messageInfo_NginxTrafficRouting proto.InternalMessageInfo func (m *ObjectRef) Reset() { *m = ObjectRef{} } func (*ObjectRef) ProtoMessage() {} func (*ObjectRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{58} + return fileDescriptor_e0e705f843545fab, []int{59} } func (m *ObjectRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1703,7 +1731,7 @@ var xxx_messageInfo_ObjectRef proto.InternalMessageInfo func (m *PauseCondition) Reset() { *m = PauseCondition{} } func (*PauseCondition) ProtoMessage() {} func (*PauseCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{59} + return fileDescriptor_e0e705f843545fab, []int{60} } func (m *PauseCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1731,7 +1759,7 @@ var xxx_messageInfo_PauseCondition proto.InternalMessageInfo func (m *PingPongSpec) Reset() { *m = PingPongSpec{} } func (*PingPongSpec) ProtoMessage() {} func (*PingPongSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{60} + return fileDescriptor_e0e705f843545fab, []int{61} } func (m *PingPongSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1759,7 +1787,7 @@ var xxx_messageInfo_PingPongSpec proto.InternalMessageInfo func (m *PodTemplateMetadata) Reset() { *m = PodTemplateMetadata{} } func (*PodTemplateMetadata) ProtoMessage() {} func (*PodTemplateMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{61} + return fileDescriptor_e0e705f843545fab, []int{62} } func (m *PodTemplateMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1789,7 +1817,7 @@ func (m *PreferredDuringSchedulingIgnoredDuringExecution) Reset() { } func (*PreferredDuringSchedulingIgnoredDuringExecution) ProtoMessage() {} func (*PreferredDuringSchedulingIgnoredDuringExecution) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{62} + return fileDescriptor_e0e705f843545fab, []int{63} } func (m *PreferredDuringSchedulingIgnoredDuringExecution) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1817,7 +1845,7 @@ var xxx_messageInfo_PreferredDuringSchedulingIgnoredDuringExecution proto.Intern func (m *PrometheusMetric) Reset() { *m = PrometheusMetric{} } func (*PrometheusMetric) ProtoMessage() {} func (*PrometheusMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{63} + return fileDescriptor_e0e705f843545fab, []int{64} } func (m *PrometheusMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1847,7 +1875,7 @@ func (m *RequiredDuringSchedulingIgnoredDuringExecution) Reset() { } func (*RequiredDuringSchedulingIgnoredDuringExecution) ProtoMessage() {} func (*RequiredDuringSchedulingIgnoredDuringExecution) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{64} + return fileDescriptor_e0e705f843545fab, []int{65} } func (m *RequiredDuringSchedulingIgnoredDuringExecution) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1875,7 +1903,7 @@ var xxx_messageInfo_RequiredDuringSchedulingIgnoredDuringExecution proto.Interna func (m *Rollout) Reset() { *m = Rollout{} } func (*Rollout) ProtoMessage() {} func (*Rollout) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{65} + return fileDescriptor_e0e705f843545fab, []int{66} } func (m *Rollout) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1903,7 +1931,7 @@ var xxx_messageInfo_Rollout proto.InternalMessageInfo func (m *RolloutAnalysis) Reset() { *m = RolloutAnalysis{} } func (*RolloutAnalysis) ProtoMessage() {} func (*RolloutAnalysis) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{66} + return fileDescriptor_e0e705f843545fab, []int{67} } func (m *RolloutAnalysis) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1931,7 +1959,7 @@ var xxx_messageInfo_RolloutAnalysis proto.InternalMessageInfo func (m *RolloutAnalysisBackground) Reset() { *m = RolloutAnalysisBackground{} } func (*RolloutAnalysisBackground) ProtoMessage() {} func (*RolloutAnalysisBackground) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{67} + return fileDescriptor_e0e705f843545fab, []int{68} } func (m *RolloutAnalysisBackground) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1959,7 +1987,7 @@ var xxx_messageInfo_RolloutAnalysisBackground proto.InternalMessageInfo func (m *RolloutAnalysisRunStatus) Reset() { *m = RolloutAnalysisRunStatus{} } func (*RolloutAnalysisRunStatus) ProtoMessage() {} func (*RolloutAnalysisRunStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{68} + return fileDescriptor_e0e705f843545fab, []int{69} } func (m *RolloutAnalysisRunStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1987,7 +2015,7 @@ var xxx_messageInfo_RolloutAnalysisRunStatus proto.InternalMessageInfo func (m *RolloutAnalysisTemplate) Reset() { *m = RolloutAnalysisTemplate{} } func (*RolloutAnalysisTemplate) ProtoMessage() {} func (*RolloutAnalysisTemplate) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{69} + return fileDescriptor_e0e705f843545fab, []int{70} } func (m *RolloutAnalysisTemplate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2015,7 +2043,7 @@ var xxx_messageInfo_RolloutAnalysisTemplate proto.InternalMessageInfo func (m *RolloutCondition) Reset() { *m = RolloutCondition{} } func (*RolloutCondition) ProtoMessage() {} func (*RolloutCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{70} + return fileDescriptor_e0e705f843545fab, []int{71} } func (m *RolloutCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2043,7 +2071,7 @@ var xxx_messageInfo_RolloutCondition proto.InternalMessageInfo func (m *RolloutExperimentStep) Reset() { *m = RolloutExperimentStep{} } func (*RolloutExperimentStep) ProtoMessage() {} func (*RolloutExperimentStep) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{71} + return fileDescriptor_e0e705f843545fab, []int{72} } func (m *RolloutExperimentStep) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2073,7 +2101,7 @@ func (m *RolloutExperimentStepAnalysisTemplateRef) Reset() { } func (*RolloutExperimentStepAnalysisTemplateRef) ProtoMessage() {} func (*RolloutExperimentStepAnalysisTemplateRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{72} + return fileDescriptor_e0e705f843545fab, []int{73} } func (m *RolloutExperimentStepAnalysisTemplateRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2101,7 +2129,7 @@ var xxx_messageInfo_RolloutExperimentStepAnalysisTemplateRef proto.InternalMessa func (m *RolloutExperimentTemplate) Reset() { *m = RolloutExperimentTemplate{} } func (*RolloutExperimentTemplate) ProtoMessage() {} func (*RolloutExperimentTemplate) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{73} + return fileDescriptor_e0e705f843545fab, []int{74} } func (m *RolloutExperimentTemplate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2129,7 +2157,7 @@ var xxx_messageInfo_RolloutExperimentTemplate proto.InternalMessageInfo func (m *RolloutList) Reset() { *m = RolloutList{} } func (*RolloutList) ProtoMessage() {} func (*RolloutList) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{74} + return fileDescriptor_e0e705f843545fab, []int{75} } func (m *RolloutList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2157,7 +2185,7 @@ var xxx_messageInfo_RolloutList proto.InternalMessageInfo func (m *RolloutPause) Reset() { *m = RolloutPause{} } func (*RolloutPause) ProtoMessage() {} func (*RolloutPause) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{75} + return fileDescriptor_e0e705f843545fab, []int{76} } func (m *RolloutPause) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2185,7 +2213,7 @@ var xxx_messageInfo_RolloutPause proto.InternalMessageInfo func (m *RolloutSpec) Reset() { *m = RolloutSpec{} } func (*RolloutSpec) ProtoMessage() {} func (*RolloutSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{76} + return fileDescriptor_e0e705f843545fab, []int{77} } func (m *RolloutSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2213,7 +2241,7 @@ var xxx_messageInfo_RolloutSpec proto.InternalMessageInfo func (m *RolloutStatus) Reset() { *m = RolloutStatus{} } func (*RolloutStatus) ProtoMessage() {} func (*RolloutStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{77} + return fileDescriptor_e0e705f843545fab, []int{78} } func (m *RolloutStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2241,7 +2269,7 @@ var xxx_messageInfo_RolloutStatus proto.InternalMessageInfo func (m *RolloutStrategy) Reset() { *m = RolloutStrategy{} } func (*RolloutStrategy) ProtoMessage() {} func (*RolloutStrategy) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{78} + return fileDescriptor_e0e705f843545fab, []int{79} } func (m *RolloutStrategy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2269,7 +2297,7 @@ var xxx_messageInfo_RolloutStrategy proto.InternalMessageInfo func (m *RolloutTrafficRouting) Reset() { *m = RolloutTrafficRouting{} } func (*RolloutTrafficRouting) ProtoMessage() {} func (*RolloutTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{79} + return fileDescriptor_e0e705f843545fab, []int{80} } func (m *RolloutTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2297,7 +2325,7 @@ var xxx_messageInfo_RolloutTrafficRouting proto.InternalMessageInfo func (m *RunSummary) Reset() { *m = RunSummary{} } func (*RunSummary) ProtoMessage() {} func (*RunSummary) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{80} + return fileDescriptor_e0e705f843545fab, []int{81} } func (m *RunSummary) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2325,7 +2353,7 @@ var xxx_messageInfo_RunSummary proto.InternalMessageInfo func (m *SMITrafficRouting) Reset() { *m = SMITrafficRouting{} } func (*SMITrafficRouting) ProtoMessage() {} func (*SMITrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{81} + return fileDescriptor_e0e705f843545fab, []int{82} } func (m *SMITrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2353,7 +2381,7 @@ var xxx_messageInfo_SMITrafficRouting proto.InternalMessageInfo func (m *ScopeDetail) Reset() { *m = ScopeDetail{} } func (*ScopeDetail) ProtoMessage() {} func (*ScopeDetail) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{82} + return fileDescriptor_e0e705f843545fab, []int{83} } func (m *ScopeDetail) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2381,7 +2409,7 @@ var xxx_messageInfo_ScopeDetail proto.InternalMessageInfo func (m *SecretKeyRef) Reset() { *m = SecretKeyRef{} } func (*SecretKeyRef) ProtoMessage() {} func (*SecretKeyRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{83} + return fileDescriptor_e0e705f843545fab, []int{84} } func (m *SecretKeyRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2409,7 +2437,7 @@ var xxx_messageInfo_SecretKeyRef proto.InternalMessageInfo func (m *SetCanaryScale) Reset() { *m = SetCanaryScale{} } func (*SetCanaryScale) ProtoMessage() {} func (*SetCanaryScale) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{84} + return fileDescriptor_e0e705f843545fab, []int{85} } func (m *SetCanaryScale) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2437,7 +2465,7 @@ var xxx_messageInfo_SetCanaryScale proto.InternalMessageInfo func (m *SetHeaderRouting) Reset() { *m = SetHeaderRouting{} } func (*SetHeaderRouting) ProtoMessage() {} func (*SetHeaderRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{85} + return fileDescriptor_e0e705f843545fab, []int{86} } func (m *SetHeaderRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2465,7 +2493,7 @@ var xxx_messageInfo_SetHeaderRouting proto.InternalMessageInfo func (m *StickinessConfig) Reset() { *m = StickinessConfig{} } func (*StickinessConfig) ProtoMessage() {} func (*StickinessConfig) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{86} + return fileDescriptor_e0e705f843545fab, []int{87} } func (m *StickinessConfig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2493,7 +2521,7 @@ var xxx_messageInfo_StickinessConfig proto.InternalMessageInfo func (m *StringMatch) Reset() { *m = StringMatch{} } func (*StringMatch) ProtoMessage() {} func (*StringMatch) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{87} + return fileDescriptor_e0e705f843545fab, []int{88} } func (m *StringMatch) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2521,7 +2549,7 @@ var xxx_messageInfo_StringMatch proto.InternalMessageInfo func (m *TLSRoute) Reset() { *m = TLSRoute{} } func (*TLSRoute) ProtoMessage() {} func (*TLSRoute) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{88} + return fileDescriptor_e0e705f843545fab, []int{89} } func (m *TLSRoute) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2549,7 +2577,7 @@ var xxx_messageInfo_TLSRoute proto.InternalMessageInfo func (m *TemplateService) Reset() { *m = TemplateService{} } func (*TemplateService) ProtoMessage() {} func (*TemplateService) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{89} + return fileDescriptor_e0e705f843545fab, []int{90} } func (m *TemplateService) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2577,7 +2605,7 @@ var xxx_messageInfo_TemplateService proto.InternalMessageInfo func (m *TemplateSpec) Reset() { *m = TemplateSpec{} } func (*TemplateSpec) ProtoMessage() {} func (*TemplateSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{90} + return fileDescriptor_e0e705f843545fab, []int{91} } func (m *TemplateSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2605,7 +2633,7 @@ var xxx_messageInfo_TemplateSpec proto.InternalMessageInfo func (m *TemplateStatus) Reset() { *m = TemplateStatus{} } func (*TemplateStatus) ProtoMessage() {} func (*TemplateStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{91} + return fileDescriptor_e0e705f843545fab, []int{92} } func (m *TemplateStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2633,7 +2661,7 @@ var xxx_messageInfo_TemplateStatus proto.InternalMessageInfo func (m *TraefikTrafficRouting) Reset() { *m = TraefikTrafficRouting{} } func (*TraefikTrafficRouting) ProtoMessage() {} func (*TraefikTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{92} + return fileDescriptor_e0e705f843545fab, []int{93} } func (m *TraefikTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2661,7 +2689,7 @@ var xxx_messageInfo_TraefikTrafficRouting proto.InternalMessageInfo func (m *TrafficWeights) Reset() { *m = TrafficWeights{} } func (*TrafficWeights) ProtoMessage() {} func (*TrafficWeights) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{93} + return fileDescriptor_e0e705f843545fab, []int{94} } func (m *TrafficWeights) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2689,7 +2717,7 @@ var xxx_messageInfo_TrafficWeights proto.InternalMessageInfo func (m *ValueFrom) Reset() { *m = ValueFrom{} } func (*ValueFrom) ProtoMessage() {} func (*ValueFrom) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{94} + return fileDescriptor_e0e705f843545fab, []int{95} } func (m *ValueFrom) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2717,7 +2745,7 @@ var xxx_messageInfo_ValueFrom proto.InternalMessageInfo func (m *WavefrontMetric) Reset() { *m = WavefrontMetric{} } func (*WavefrontMetric) ProtoMessage() {} func (*WavefrontMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{95} + return fileDescriptor_e0e705f843545fab, []int{96} } func (m *WavefrontMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2745,7 +2773,7 @@ var xxx_messageInfo_WavefrontMetric proto.InternalMessageInfo func (m *WebMetric) Reset() { *m = WebMetric{} } func (*WebMetric) ProtoMessage() {} func (*WebMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{96} + return fileDescriptor_e0e705f843545fab, []int{97} } func (m *WebMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2773,7 +2801,7 @@ var xxx_messageInfo_WebMetric proto.InternalMessageInfo func (m *WebMetricHeader) Reset() { *m = WebMetricHeader{} } func (*WebMetricHeader) ProtoMessage() {} func (*WebMetricHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{97} + return fileDescriptor_e0e705f843545fab, []int{98} } func (m *WebMetricHeader) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2801,7 +2829,7 @@ var xxx_messageInfo_WebMetricHeader proto.InternalMessageInfo func (m *WeightDestination) Reset() { *m = WeightDestination{} } func (*WeightDestination) ProtoMessage() {} func (*WeightDestination) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{98} + return fileDescriptor_e0e705f843545fab, []int{99} } func (m *WeightDestination) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2871,6 +2899,7 @@ func init() { proto.RegisterType((*FieldRef)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.FieldRef") proto.RegisterType((*GraphiteMetric)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.GraphiteMetric") proto.RegisterType((*HeaderRoutingMatch)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.HeaderRoutingMatch") + proto.RegisterType((*InfluxdbMetric)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.InfluxdbMetric") proto.RegisterType((*IstioDestinationRule)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.IstioDestinationRule") proto.RegisterType((*IstioTrafficRouting)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.IstioTrafficRouting") proto.RegisterType((*IstioVirtualService)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.IstioVirtualService") @@ -2938,465 +2967,466 @@ func init() { } var fileDescriptor_e0e705f843545fab = []byte{ - // 7317 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x5d, 0x6c, 0x24, 0x59, - 0x75, 0xf0, 0x56, 0xb7, 0xdb, 0x6e, 0x1f, 0x7b, 0xfc, 0x73, 0xc7, 0xc3, 0x78, 0xbd, 0x3b, 0xd3, - 0x4b, 0x2d, 0xda, 0x6f, 0xf9, 0x3e, 0xf0, 0xc0, 0xfe, 0x7c, 0x59, 0x58, 0xb4, 0x49, 0xb7, 0x3d, - 0xb3, 0xe3, 0x59, 0xdb, 0xd3, 0x73, 0xdb, 0x33, 0x03, 0x0b, 0x4b, 0x28, 0x77, 0x5f, 0xb7, 0x6b, - 0xa6, 0xbb, 0xaa, 0xa9, 0xaa, 0xf6, 0x8c, 0x97, 0x15, 0xec, 0x06, 0xed, 0x06, 0x22, 0x10, 0x9b, - 0x00, 0x8a, 0xa2, 0x88, 0x08, 0x45, 0x48, 0x89, 0x02, 0x4f, 0x28, 0x51, 0x5e, 0x90, 0x12, 0x05, - 0x50, 0x88, 0xa2, 0x44, 0x24, 0x4a, 0x02, 0x44, 0xa2, 0x93, 0x35, 0x79, 0x49, 0x94, 0x28, 0x8a, - 0x44, 0x14, 0x31, 0x4f, 0xd1, 0xfd, 0xad, 0x5b, 0x3f, 0xed, 0xe9, 0x76, 0x97, 0x87, 0x55, 0xc2, - 0x5b, 0xf7, 0x39, 0xe7, 0x9e, 0x73, 0xff, 0xcf, 0xb9, 0xe7, 0x9e, 0x7b, 0x0a, 0xd6, 0x9b, 0x76, - 0xb0, 0xdb, 0xdd, 0x5e, 0xae, 0xbb, 0xed, 0x73, 0x96, 0xd7, 0x74, 0x3b, 0x9e, 0x7b, 0x83, 0xfd, - 0x78, 0xa7, 0xe7, 0xb6, 0x5a, 0x6e, 0x37, 0xf0, 0xcf, 0x75, 0x6e, 0x36, 0xcf, 0x59, 0x1d, 0xdb, - 0x3f, 0xa7, 0x20, 0x7b, 0xef, 0xb6, 0x5a, 0x9d, 0x5d, 0xeb, 0xdd, 0xe7, 0x9a, 0xc4, 0x21, 0x9e, - 0x15, 0x90, 0xc6, 0x72, 0xc7, 0x73, 0x03, 0x17, 0xbd, 0x2f, 0xe4, 0xb6, 0x2c, 0xb9, 0xb1, 0x1f, - 0xbf, 0x28, 0xcb, 0x2e, 0x77, 0x6e, 0x36, 0x97, 0x29, 0xb7, 0x65, 0x05, 0x91, 0xdc, 0x96, 0xde, - 0xa9, 0xd5, 0xa5, 0xe9, 0x36, 0xdd, 0x73, 0x8c, 0xe9, 0x76, 0x77, 0x87, 0xfd, 0x63, 0x7f, 0xd8, - 0x2f, 0x2e, 0x6c, 0xe9, 0xe1, 0x9b, 0x4f, 0xf9, 0xcb, 0xb6, 0x4b, 0xeb, 0x76, 0x6e, 0xdb, 0x0a, - 0xea, 0xbb, 0xe7, 0xf6, 0x12, 0x35, 0x5a, 0x32, 0x35, 0xa2, 0xba, 0xeb, 0x91, 0x34, 0x9a, 0x27, - 0x42, 0x9a, 0xb6, 0x55, 0xdf, 0xb5, 0x1d, 0xe2, 0xed, 0x87, 0xad, 0x6e, 0x93, 0xc0, 0x4a, 0x2b, - 0x75, 0xae, 0x5f, 0x29, 0xaf, 0xeb, 0x04, 0x76, 0x9b, 0x24, 0x0a, 0xfc, 0xff, 0xbb, 0x15, 0xf0, - 0xeb, 0xbb, 0xa4, 0x6d, 0x25, 0xca, 0x3d, 0xde, 0xaf, 0x5c, 0x37, 0xb0, 0x5b, 0xe7, 0x6c, 0x27, - 0xf0, 0x03, 0x2f, 0x5e, 0xc8, 0xfc, 0x56, 0x1e, 0x26, 0xcb, 0xeb, 0x95, 0x5a, 0x60, 0x05, 0x5d, - 0x1f, 0xbd, 0x66, 0xc0, 0x74, 0xcb, 0xb5, 0x1a, 0x15, 0xab, 0x65, 0x39, 0x75, 0xe2, 0x2d, 0x1a, - 0x0f, 0x19, 0x8f, 0x4e, 0x3d, 0xb6, 0xbe, 0x3c, 0xca, 0x78, 0x2d, 0x97, 0x6f, 0xf9, 0x98, 0xf8, - 0x6e, 0xd7, 0xab, 0x13, 0x4c, 0x76, 0x2a, 0x0b, 0xdf, 0xe9, 0x95, 0xee, 0x3b, 0xe8, 0x95, 0xa6, - 0xd7, 0x35, 0x49, 0x38, 0x22, 0x17, 0x7d, 0xd1, 0x80, 0xf9, 0xba, 0xe5, 0x58, 0xde, 0xfe, 0x96, - 0xe5, 0x35, 0x49, 0xf0, 0xac, 0xe7, 0x76, 0x3b, 0x8b, 0xb9, 0x63, 0xa8, 0xcd, 0xfd, 0xa2, 0x36, - 0xf3, 0x2b, 0x71, 0x71, 0x38, 0x59, 0x03, 0x56, 0x2f, 0x3f, 0xb0, 0xb6, 0x5b, 0x44, 0xaf, 0x57, - 0xfe, 0x38, 0xeb, 0x55, 0x8b, 0x8b, 0xc3, 0xc9, 0x1a, 0x98, 0xaf, 0xe6, 0x61, 0xbe, 0xbc, 0x5e, - 0xd9, 0xf2, 0xac, 0x9d, 0x1d, 0xbb, 0x8e, 0xdd, 0x6e, 0x60, 0x3b, 0x4d, 0xf4, 0x76, 0x98, 0xb0, - 0x9d, 0xa6, 0x47, 0x7c, 0x9f, 0x0d, 0xe4, 0x64, 0x65, 0x56, 0x30, 0x9d, 0x58, 0xe3, 0x60, 0x2c, - 0xf1, 0xe8, 0x49, 0x98, 0xf2, 0x89, 0xb7, 0x67, 0xd7, 0x49, 0xd5, 0xf5, 0x02, 0xd6, 0xd3, 0x85, - 0xca, 0x49, 0x41, 0x3e, 0x55, 0x0b, 0x51, 0x58, 0xa7, 0xa3, 0xc5, 0x3c, 0xd7, 0x0d, 0x04, 0x9e, - 0x75, 0xc4, 0x64, 0x58, 0x0c, 0x87, 0x28, 0xac, 0xd3, 0xa1, 0xd7, 0x0d, 0x98, 0xf3, 0x03, 0xbb, - 0x7e, 0xd3, 0x76, 0x88, 0xef, 0xaf, 0xb8, 0xce, 0x8e, 0xdd, 0x5c, 0x2c, 0xb0, 0x5e, 0xdc, 0x1c, - 0xad, 0x17, 0x6b, 0x31, 0xae, 0x95, 0x85, 0x83, 0x5e, 0x69, 0x2e, 0x0e, 0xc5, 0x09, 0xe9, 0x68, - 0x15, 0xe6, 0x2c, 0xc7, 0x71, 0x03, 0x2b, 0xb0, 0x5d, 0xa7, 0xea, 0x91, 0x1d, 0xfb, 0xf6, 0xe2, - 0x18, 0x6b, 0xce, 0xa2, 0x68, 0xce, 0x5c, 0x39, 0x86, 0xc7, 0x89, 0x12, 0xe6, 0x2a, 0x2c, 0x96, - 0xdb, 0xdb, 0x96, 0xef, 0x5b, 0x0d, 0xd7, 0x8b, 0x8d, 0xc6, 0xa3, 0x50, 0x6c, 0x5b, 0x9d, 0x8e, - 0xed, 0x34, 0xe9, 0x70, 0xe4, 0x1f, 0x9d, 0xac, 0x4c, 0x1f, 0xf4, 0x4a, 0xc5, 0x0d, 0x01, 0xc3, - 0x0a, 0x6b, 0xfe, 0x20, 0x07, 0x53, 0x65, 0xc7, 0x6a, 0xed, 0xfb, 0xb6, 0x8f, 0xbb, 0x0e, 0xfa, - 0x08, 0x14, 0xe9, 0xee, 0xd2, 0xb0, 0x02, 0x4b, 0xac, 0xc8, 0x77, 0x2d, 0xf3, 0xc5, 0xbe, 0xac, - 0x2f, 0xf6, 0xb0, 0x5f, 0x28, 0xf5, 0xf2, 0xde, 0xbb, 0x97, 0x2f, 0x6f, 0xdf, 0x20, 0xf5, 0x60, - 0x83, 0x04, 0x56, 0x05, 0x89, 0x56, 0x40, 0x08, 0xc3, 0x8a, 0x2b, 0x72, 0x61, 0xcc, 0xef, 0x90, - 0xba, 0x58, 0x61, 0x1b, 0x23, 0xce, 0xe4, 0xb0, 0xea, 0xb5, 0x0e, 0xa9, 0x57, 0xa6, 0x85, 0xe8, - 0x31, 0xfa, 0x0f, 0x33, 0x41, 0xe8, 0x16, 0x8c, 0xfb, 0x6c, 0xcf, 0x11, 0x8b, 0xe7, 0x72, 0x76, - 0x22, 0x19, 0xdb, 0xca, 0x8c, 0x10, 0x3a, 0xce, 0xff, 0x63, 0x21, 0xce, 0xfc, 0x7b, 0x03, 0x4e, - 0x6a, 0xd4, 0x65, 0xaf, 0xd9, 0x6d, 0x13, 0x27, 0x40, 0x0f, 0xc1, 0x98, 0x63, 0xb5, 0x89, 0x58, - 0x28, 0xaa, 0xca, 0x9b, 0x56, 0x9b, 0x60, 0x86, 0x41, 0x0f, 0x43, 0x61, 0xcf, 0x6a, 0x75, 0x09, - 0xeb, 0xa4, 0xc9, 0xca, 0x09, 0x41, 0x52, 0xb8, 0x46, 0x81, 0x98, 0xe3, 0xd0, 0x4b, 0x30, 0xc9, - 0x7e, 0x5c, 0xf0, 0xdc, 0x76, 0x46, 0x4d, 0x13, 0x35, 0xbc, 0x26, 0xd9, 0x56, 0x4e, 0x1c, 0xf4, - 0x4a, 0x93, 0xea, 0x2f, 0x0e, 0x05, 0x9a, 0xff, 0x60, 0xc0, 0xac, 0xd6, 0xb8, 0x75, 0xdb, 0x0f, - 0xd0, 0x87, 0x12, 0x93, 0x67, 0x79, 0xb0, 0xc9, 0x43, 0x4b, 0xb3, 0xa9, 0x33, 0x27, 0x5a, 0x5a, - 0x94, 0x10, 0x6d, 0xe2, 0x38, 0x50, 0xb0, 0x03, 0xd2, 0xf6, 0x17, 0x73, 0x0f, 0xe5, 0x1f, 0x9d, - 0x7a, 0x6c, 0x2d, 0xb3, 0x61, 0x0c, 0xfb, 0x77, 0x8d, 0xf2, 0xc7, 0x5c, 0x8c, 0xf9, 0xf5, 0xb1, - 0x48, 0x0b, 0xe9, 0x8c, 0x42, 0x2e, 0x4c, 0xb4, 0x49, 0xe0, 0xd9, 0x75, 0xbe, 0xae, 0xa6, 0x1e, - 0x5b, 0x1d, 0xad, 0x16, 0x1b, 0x8c, 0x59, 0xb8, 0x59, 0xf2, 0xff, 0x3e, 0x96, 0x52, 0xd0, 0x2e, - 0x8c, 0x59, 0x5e, 0x53, 0xb6, 0xf9, 0x42, 0x36, 0xe3, 0x1b, 0xce, 0xb9, 0xb2, 0xd7, 0xf4, 0x31, - 0x93, 0x80, 0xce, 0xc1, 0x64, 0x40, 0xbc, 0xb6, 0xed, 0x58, 0x01, 0xdf, 0x5d, 0x8b, 0x95, 0x79, - 0x41, 0x36, 0xb9, 0x25, 0x11, 0x38, 0xa4, 0x41, 0x2d, 0x18, 0x6f, 0x78, 0xfb, 0xb8, 0xeb, 0x2c, - 0x8e, 0x65, 0xd1, 0x15, 0xab, 0x8c, 0x57, 0xb8, 0x98, 0xf8, 0x7f, 0x2c, 0x64, 0xa0, 0xaf, 0x18, - 0xb0, 0xd0, 0x26, 0x96, 0xdf, 0xf5, 0x08, 0x6d, 0x02, 0x26, 0x01, 0x71, 0xe8, 0x6e, 0xb8, 0x58, - 0x60, 0xc2, 0xf1, 0xa8, 0xe3, 0x90, 0xe4, 0x5c, 0x79, 0x50, 0x54, 0x65, 0x21, 0x0d, 0x8b, 0x53, - 0x6b, 0x63, 0xfe, 0x60, 0x0c, 0xe6, 0x13, 0x3b, 0x04, 0x7a, 0x02, 0x0a, 0x9d, 0x5d, 0xcb, 0x97, - 0x4b, 0xfe, 0xac, 0x9c, 0x6f, 0x55, 0x0a, 0xbc, 0xd3, 0x2b, 0x9d, 0x90, 0x45, 0x18, 0x00, 0x73, - 0x62, 0xaa, 0x53, 0xdb, 0xc4, 0xf7, 0xad, 0xa6, 0xdc, 0x07, 0xb4, 0x69, 0xc2, 0xc0, 0x58, 0xe2, - 0xd1, 0x2f, 0x1b, 0x70, 0x82, 0x4f, 0x19, 0x4c, 0xfc, 0x6e, 0x2b, 0xa0, 0x7b, 0x1d, 0xed, 0x96, - 0x4b, 0x59, 0x4c, 0x4f, 0xce, 0xb2, 0x72, 0x4a, 0x48, 0x3f, 0xa1, 0x43, 0x7d, 0x1c, 0x95, 0x8b, - 0xae, 0xc3, 0xa4, 0x1f, 0x58, 0x5e, 0x40, 0x1a, 0xe5, 0x80, 0x69, 0xb5, 0xa9, 0xc7, 0xfe, 0xef, - 0x60, 0x9b, 0xc0, 0x96, 0xdd, 0x26, 0x7c, 0xc3, 0xa9, 0x49, 0x06, 0x38, 0xe4, 0x85, 0x5e, 0x02, - 0xf0, 0xba, 0x4e, 0xad, 0xdb, 0x6e, 0x5b, 0xde, 0xbe, 0xd0, 0xe0, 0x17, 0x47, 0x6b, 0x1e, 0x56, - 0xfc, 0x42, 0x9d, 0x15, 0xc2, 0xb0, 0x26, 0x0f, 0xbd, 0x62, 0xc0, 0x09, 0x3e, 0x13, 0x65, 0x0d, - 0xc6, 0x33, 0xae, 0xc1, 0x3c, 0xed, 0xda, 0x55, 0x5d, 0x04, 0x8e, 0x4a, 0x34, 0xff, 0x36, 0xaa, - 0x4f, 0x6a, 0x01, 0xb5, 0xae, 0x9b, 0xfb, 0xe8, 0x83, 0x70, 0xbf, 0xdf, 0xad, 0xd7, 0x89, 0xef, - 0xef, 0x74, 0x5b, 0xb8, 0xeb, 0x5c, 0xb4, 0xfd, 0xc0, 0xf5, 0xf6, 0xd7, 0xed, 0xb6, 0x1d, 0xb0, - 0x19, 0x57, 0xa8, 0x9c, 0x39, 0xe8, 0x95, 0xee, 0xaf, 0xf5, 0x23, 0xc2, 0xfd, 0xcb, 0x23, 0x0b, - 0x1e, 0xe8, 0x3a, 0xfd, 0xd9, 0x73, 0xeb, 0xad, 0x74, 0xd0, 0x2b, 0x3d, 0x70, 0xb5, 0x3f, 0x19, - 0x3e, 0x8c, 0x87, 0xf9, 0x2f, 0x06, 0xcc, 0xc9, 0x76, 0x6d, 0x91, 0x76, 0xa7, 0x45, 0x77, 0x97, - 0xe3, 0x37, 0x44, 0x82, 0x88, 0x21, 0x82, 0xb3, 0x51, 0x27, 0xb2, 0xfe, 0xfd, 0xac, 0x11, 0xf3, - 0x9f, 0x0d, 0x58, 0x88, 0x13, 0xdf, 0x03, 0xe5, 0xe9, 0x47, 0x95, 0xe7, 0x66, 0xb6, 0xad, 0xed, - 0xa3, 0x41, 0x5f, 0x1b, 0x4b, 0xb6, 0xf5, 0x7f, 0xba, 0x1a, 0x0d, 0xb5, 0x62, 0xfe, 0xa7, 0xa9, - 0x15, 0xc7, 0xde, 0x54, 0x5a, 0xf1, 0x77, 0xc7, 0x60, 0xba, 0xec, 0x04, 0x76, 0x79, 0x67, 0xc7, - 0x76, 0xec, 0x60, 0x1f, 0x7d, 0x26, 0x07, 0xe7, 0x3a, 0x1e, 0xd9, 0x21, 0x9e, 0x47, 0x1a, 0xab, - 0x5d, 0xcf, 0x76, 0x9a, 0xb5, 0xfa, 0x2e, 0x69, 0x74, 0x5b, 0xb6, 0xd3, 0x5c, 0x6b, 0x3a, 0xae, - 0x02, 0x9f, 0xbf, 0x4d, 0xea, 0x5d, 0xd6, 0x24, 0xbe, 0x28, 0xda, 0xa3, 0x35, 0xa9, 0x3a, 0x9c, - 0xd0, 0xca, 0xe3, 0x07, 0xbd, 0xd2, 0xb9, 0x21, 0x0b, 0xe1, 0x61, 0x9b, 0x86, 0x3e, 0x95, 0x83, - 0x65, 0x8f, 0x7c, 0xb4, 0x6b, 0x0f, 0xde, 0x1b, 0x7c, 0xd7, 0x6a, 0x8d, 0xa8, 0x7e, 0x86, 0x92, - 0x59, 0x79, 0xec, 0xa0, 0x57, 0x1a, 0xb2, 0x0c, 0x1e, 0xb2, 0x5d, 0xe6, 0x37, 0x73, 0x70, 0xaa, - 0xdc, 0xe9, 0x6c, 0x10, 0x7f, 0x37, 0x76, 0xa8, 0xfd, 0x9c, 0x01, 0x33, 0x7b, 0xb6, 0x17, 0x74, - 0xad, 0x96, 0x74, 0x02, 0xf0, 0x29, 0x51, 0x1b, 0x71, 0x39, 0x73, 0x69, 0xd7, 0x22, 0xac, 0x2b, - 0xe8, 0xa0, 0x57, 0x9a, 0x89, 0xc2, 0x70, 0x4c, 0x3c, 0xfa, 0x75, 0x03, 0xe6, 0x04, 0x68, 0xd3, - 0x6d, 0x10, 0xdd, 0x73, 0x74, 0x35, 0xcb, 0x3a, 0x29, 0xe6, 0xdc, 0xc5, 0x10, 0x87, 0xe2, 0x44, - 0x25, 0xcc, 0x7f, 0xcb, 0xc1, 0xe9, 0x3e, 0x3c, 0xd0, 0xef, 0x18, 0xb0, 0xc0, 0xdd, 0x4d, 0x1a, - 0x0a, 0x93, 0x1d, 0xd1, 0x9b, 0x1f, 0xc8, 0xba, 0xe6, 0x98, 0xae, 0x05, 0xe2, 0xd4, 0x49, 0x65, - 0x91, 0x6e, 0x1b, 0x2b, 0x29, 0xa2, 0x71, 0x6a, 0x85, 0x58, 0x4d, 0xb9, 0x03, 0x2a, 0x56, 0xd3, - 0xdc, 0x3d, 0xa9, 0x69, 0x2d, 0x45, 0x34, 0x4e, 0xad, 0x90, 0xf9, 0xf3, 0xf0, 0xc0, 0x21, 0xec, - 0xee, 0x7e, 0xe2, 0x37, 0x5f, 0x50, 0xb3, 0x3e, 0x3a, 0xe7, 0x06, 0x70, 0x16, 0x98, 0x30, 0xee, - 0xb9, 0xdd, 0x80, 0x70, 0xed, 0x36, 0x59, 0x01, 0xaa, 0x27, 0x30, 0x83, 0x60, 0x81, 0x31, 0xbf, - 0x69, 0x40, 0x71, 0x08, 0xff, 0x43, 0x29, 0xea, 0x7f, 0x98, 0x4c, 0xf8, 0x1e, 0x82, 0xa4, 0xef, - 0xe1, 0xd9, 0xd1, 0x46, 0x63, 0x10, 0x9f, 0xc3, 0xbf, 0x1b, 0x30, 0x9f, 0xf0, 0x51, 0xa0, 0x5d, - 0x58, 0xe8, 0xb8, 0x0d, 0x69, 0x5f, 0x5c, 0xb4, 0xfc, 0x5d, 0x86, 0x13, 0xcd, 0x7b, 0x82, 0x8e, - 0x64, 0x35, 0x05, 0x7f, 0xa7, 0x57, 0x5a, 0x54, 0x4c, 0x62, 0x04, 0x38, 0x95, 0x23, 0xea, 0x40, - 0x71, 0xc7, 0x26, 0xad, 0x46, 0x38, 0x05, 0x47, 0xb4, 0x24, 0x2e, 0x08, 0x6e, 0xdc, 0x3d, 0x27, - 0xff, 0x61, 0x25, 0xc5, 0xbc, 0x02, 0x33, 0x51, 0x67, 0xed, 0x00, 0x83, 0x77, 0x06, 0xf2, 0x96, - 0xe7, 0x88, 0xa1, 0x9b, 0x12, 0x04, 0xf9, 0x32, 0xde, 0xc4, 0x14, 0x6e, 0xfe, 0x64, 0x0c, 0x66, - 0x2b, 0xad, 0x2e, 0x79, 0xd6, 0x23, 0x44, 0x9e, 0x4f, 0xcb, 0x30, 0xdb, 0xf1, 0xc8, 0x9e, 0x4d, - 0x6e, 0xd5, 0x48, 0x8b, 0xd4, 0x03, 0xd7, 0x13, 0xfc, 0x4f, 0x8b, 0xe2, 0xb3, 0xd5, 0x28, 0x1a, - 0xc7, 0xe9, 0xd1, 0x33, 0x30, 0x63, 0xd5, 0x03, 0x7b, 0x8f, 0x28, 0x0e, 0xbc, 0x02, 0x6f, 0x11, - 0x1c, 0x66, 0xca, 0x11, 0x2c, 0x8e, 0x51, 0xa3, 0x0f, 0xc1, 0xa2, 0x5f, 0xb7, 0x5a, 0xe4, 0x6a, - 0x47, 0x88, 0x5a, 0xd9, 0x25, 0xf5, 0x9b, 0x55, 0xd7, 0x76, 0x02, 0xe1, 0x8d, 0x78, 0x48, 0x70, - 0x5a, 0xac, 0xf5, 0xa1, 0xc3, 0x7d, 0x39, 0xa0, 0x3f, 0x32, 0xe0, 0x4c, 0xc7, 0x23, 0x55, 0xcf, - 0x6d, 0xbb, 0x54, 0xcd, 0x24, 0x8e, 0xe8, 0xe2, 0xa8, 0x7a, 0x6d, 0x44, 0x7d, 0xca, 0x21, 0x49, - 0x17, 0xe1, 0x5b, 0x0f, 0x7a, 0xa5, 0x33, 0xd5, 0xc3, 0x2a, 0x80, 0x0f, 0xaf, 0x1f, 0xfa, 0x13, - 0x03, 0xce, 0x76, 0x5c, 0x3f, 0x38, 0xa4, 0x09, 0x85, 0x63, 0x6d, 0x82, 0x79, 0xd0, 0x2b, 0x9d, - 0xad, 0x1e, 0x5a, 0x03, 0x7c, 0x97, 0x1a, 0x9a, 0x07, 0x53, 0x30, 0xaf, 0xcd, 0x3d, 0x71, 0x7e, - 0x7d, 0x1a, 0x4e, 0xc8, 0xc9, 0x10, 0xaa, 0xf5, 0xc9, 0xd0, 0xdf, 0x50, 0xd6, 0x91, 0x38, 0x4a, - 0x4b, 0xe7, 0x9d, 0x9a, 0x8a, 0xbc, 0x74, 0x6c, 0xde, 0x55, 0x23, 0x58, 0x1c, 0xa3, 0x46, 0x6b, - 0x70, 0x52, 0x40, 0x30, 0xe9, 0xb4, 0xec, 0xba, 0xb5, 0xe2, 0x76, 0xc5, 0x94, 0x2b, 0x54, 0x4e, - 0x1f, 0xf4, 0x4a, 0x27, 0xab, 0x49, 0x34, 0x4e, 0x2b, 0x83, 0xd6, 0x61, 0xc1, 0xea, 0x06, 0xae, - 0x6a, 0xff, 0x79, 0x87, 0x6a, 0x8a, 0x06, 0x9b, 0x5a, 0x45, 0xae, 0x52, 0xca, 0x29, 0x78, 0x9c, - 0x5a, 0x0a, 0x55, 0x63, 0xdc, 0x6a, 0xa4, 0xee, 0x3a, 0x0d, 0x3e, 0xca, 0x85, 0xd0, 0x0a, 0x2f, - 0xa7, 0xd0, 0xe0, 0xd4, 0x92, 0xa8, 0x05, 0x33, 0x6d, 0xeb, 0xf6, 0x55, 0xc7, 0xda, 0xb3, 0xec, - 0x16, 0x15, 0x22, 0x7c, 0x18, 0xfd, 0x0f, 0xd6, 0xdd, 0xc0, 0x6e, 0x2d, 0xf3, 0xeb, 0xbc, 0xe5, - 0x35, 0x27, 0xb8, 0xec, 0xd5, 0x02, 0x6a, 0xad, 0x71, 0xe3, 0x68, 0x23, 0xc2, 0x0b, 0xc7, 0x78, - 0xa3, 0xcb, 0x70, 0x8a, 0x2d, 0xc7, 0x55, 0xf7, 0x96, 0xb3, 0x4a, 0x5a, 0xd6, 0xbe, 0x6c, 0xc0, - 0x04, 0x6b, 0xc0, 0xfd, 0x07, 0xbd, 0xd2, 0xa9, 0x5a, 0x1a, 0x01, 0x4e, 0x2f, 0x87, 0x2c, 0x78, - 0x20, 0x8a, 0xc0, 0x64, 0xcf, 0xf6, 0x6d, 0xd7, 0xe1, 0x9e, 0x88, 0x62, 0xe8, 0x89, 0xa8, 0xf5, - 0x27, 0xc3, 0x87, 0xf1, 0x40, 0xbf, 0x69, 0xc0, 0x42, 0xda, 0x32, 0x5c, 0x9c, 0xcc, 0xe2, 0xb2, - 0x22, 0xb6, 0xb4, 0xf8, 0x8c, 0x48, 0xdd, 0x14, 0x52, 0x2b, 0x81, 0x5e, 0x36, 0x60, 0xda, 0xd2, - 0x4e, 0x51, 0x8b, 0xc0, 0x6a, 0x75, 0x69, 0xd4, 0xb3, 0x7c, 0xc8, 0xb1, 0x32, 0x77, 0xd0, 0x2b, - 0x45, 0x4e, 0x6a, 0x38, 0x22, 0x11, 0xfd, 0x96, 0x01, 0xa7, 0x52, 0xd7, 0xf8, 0xe2, 0xd4, 0x71, - 0xf4, 0x10, 0x9b, 0x24, 0xe9, 0x7b, 0x4e, 0x7a, 0x35, 0xd0, 0xeb, 0x86, 0x52, 0x65, 0x1b, 0xd2, - 0x9b, 0x32, 0xcd, 0xaa, 0x76, 0x65, 0xc4, 0x83, 0x63, 0x68, 0x10, 0x48, 0xc6, 0x95, 0x93, 0x9a, - 0x66, 0x94, 0x40, 0x1c, 0x17, 0x8f, 0x3e, 0x6b, 0x48, 0xd5, 0xa8, 0x6a, 0x74, 0xe2, 0xb8, 0x6a, - 0x84, 0x42, 0x4d, 0xab, 0x2a, 0x14, 0x13, 0x8e, 0x3e, 0x0c, 0x4b, 0xd6, 0xb6, 0xeb, 0x05, 0xa9, - 0x8b, 0x6f, 0x71, 0x86, 0x2d, 0xa3, 0xb3, 0x07, 0xbd, 0xd2, 0x52, 0xb9, 0x2f, 0x15, 0x3e, 0x84, - 0x83, 0xf9, 0xb5, 0x02, 0x4c, 0x73, 0x23, 0x5f, 0xa8, 0xae, 0x6f, 0x18, 0xf0, 0x60, 0xbd, 0xeb, - 0x79, 0xc4, 0x09, 0x6a, 0x01, 0xe9, 0x24, 0x15, 0x97, 0x71, 0xac, 0x8a, 0xeb, 0xa1, 0x83, 0x5e, - 0xe9, 0xc1, 0x95, 0x43, 0xe4, 0xe3, 0x43, 0x6b, 0x87, 0xfe, 0xd2, 0x00, 0x53, 0x10, 0x54, 0xac, - 0xfa, 0xcd, 0xa6, 0xe7, 0x76, 0x9d, 0x46, 0xb2, 0x11, 0xb9, 0x63, 0x6d, 0xc4, 0x23, 0x07, 0xbd, - 0x92, 0xb9, 0x72, 0xd7, 0x5a, 0xe0, 0x01, 0x6a, 0x8a, 0x9e, 0x85, 0x79, 0x41, 0x75, 0xfe, 0x76, - 0x87, 0x78, 0x36, 0x35, 0xa7, 0xc5, 0x7d, 0x7a, 0x18, 0xa2, 0x10, 0x27, 0xc0, 0xc9, 0x32, 0xc8, - 0x87, 0x89, 0x5b, 0xc4, 0x6e, 0xee, 0x06, 0xd2, 0x7c, 0x1a, 0x31, 0x2e, 0x41, 0x1c, 0xf8, 0xaf, - 0x73, 0x9e, 0x95, 0xa9, 0x83, 0x5e, 0x69, 0x42, 0xfc, 0xc1, 0x52, 0x12, 0xda, 0x84, 0x19, 0x7e, - 0x04, 0xab, 0xda, 0x4e, 0xb3, 0xea, 0x3a, 0xfc, 0x36, 0x7f, 0xb2, 0xf2, 0x88, 0x54, 0xf8, 0xb5, - 0x08, 0xf6, 0x4e, 0xaf, 0x34, 0x2d, 0x7f, 0x6f, 0xed, 0x77, 0x08, 0x8e, 0x95, 0x36, 0xbf, 0x59, - 0x00, 0x90, 0xd3, 0x95, 0x74, 0xd0, 0xff, 0x83, 0x49, 0x9f, 0x04, 0x5c, 0xaa, 0x70, 0x9e, 0xf3, - 0x3b, 0x09, 0x09, 0xc4, 0x21, 0x1e, 0xdd, 0x84, 0x42, 0xc7, 0xea, 0xfa, 0x44, 0x0c, 0xfe, 0xa5, - 0x4c, 0x06, 0xbf, 0x4a, 0x39, 0xf2, 0x33, 0x17, 0xfb, 0x89, 0xb9, 0x0c, 0xf4, 0x49, 0x03, 0x80, - 0x44, 0x07, 0x6c, 0x64, 0xdf, 0x87, 0x10, 0x19, 0x8e, 0x29, 0xed, 0x83, 0xca, 0xcc, 0x41, 0xaf, - 0x04, 0xda, 0xd0, 0x6b, 0x62, 0xd1, 0x2d, 0x28, 0x5a, 0x72, 0xcf, 0x1f, 0x3b, 0x8e, 0x3d, 0x9f, - 0x1d, 0x85, 0xd4, 0xa4, 0x55, 0xc2, 0xd0, 0xa7, 0x0c, 0x98, 0xf1, 0x49, 0x20, 0x86, 0x8a, 0xee, - 0x3c, 0xc2, 0xe0, 0x1d, 0x71, 0xd2, 0xd5, 0x22, 0x3c, 0xf9, 0x0e, 0x1a, 0x85, 0xe1, 0x98, 0x5c, - 0x1e, 0x53, 0x42, 0x82, 0x8b, 0xc4, 0x6a, 0x10, 0x4f, 0xb8, 0xa7, 0x84, 0x2d, 0xb5, 0x39, 0x72, - 0x65, 0x22, 0x5c, 0x45, 0x4c, 0x49, 0x0c, 0x8a, 0x13, 0xd2, 0xcd, 0xbf, 0x9e, 0x86, 0x19, 0x39, - 0x8b, 0x43, 0xb3, 0x9a, 0x7b, 0x55, 0xfa, 0x98, 0xd5, 0x2b, 0x3a, 0x12, 0x47, 0x69, 0x69, 0x61, - 0xbe, 0x4e, 0xa2, 0x56, 0xb5, 0x2a, 0x5c, 0xd3, 0x91, 0x38, 0x4a, 0x8b, 0xda, 0x50, 0xf0, 0x03, - 0xd2, 0x91, 0x97, 0x90, 0x23, 0xde, 0x91, 0x85, 0x8b, 0x33, 0xbc, 0x66, 0xa0, 0xff, 0x7c, 0xcc, - 0xa5, 0x30, 0xc7, 0x60, 0x10, 0xf1, 0x15, 0x8a, 0x99, 0x99, 0xcd, 0xe2, 0x88, 0xba, 0x21, 0xf9, - 0x04, 0x89, 0xc2, 0x70, 0x4c, 0x7c, 0x8a, 0xa5, 0x5d, 0x38, 0x46, 0x4b, 0xfb, 0x79, 0x28, 0xb6, - 0xad, 0xdb, 0xb5, 0xae, 0xd7, 0x3c, 0xba, 0x45, 0x2f, 0xe2, 0x83, 0x38, 0x17, 0xac, 0xf8, 0xa1, - 0x57, 0x0c, 0x6d, 0xbd, 0x4f, 0x30, 0xe6, 0xd7, 0xb3, 0x5d, 0xef, 0x4a, 0x51, 0xf5, 0x5d, 0xf9, - 0x09, 0xbb, 0xb7, 0x78, 0xcf, 0xed, 0x5e, 0x6a, 0xc3, 0xf1, 0x05, 0xa2, 0x6c, 0xb8, 0xc9, 0x63, - 0xb5, 0xe1, 0x56, 0x22, 0xc2, 0x70, 0x4c, 0x38, 0xab, 0x0f, 0x5f, 0x73, 0xaa, 0x3e, 0x70, 0xac, - 0xf5, 0xa9, 0x45, 0x84, 0xe1, 0x98, 0xf0, 0xfe, 0x87, 0xbd, 0xa9, 0xe3, 0x39, 0xec, 0x4d, 0x67, - 0x70, 0xd8, 0x3b, 0xdc, 0x0e, 0x3e, 0x31, 0xaa, 0x1d, 0x8c, 0x2e, 0x01, 0x6a, 0xec, 0x3b, 0x56, - 0xdb, 0xae, 0x8b, 0xcd, 0x92, 0xe9, 0xac, 0x19, 0xe6, 0x0c, 0x58, 0x12, 0x1b, 0x19, 0x5a, 0x4d, - 0x50, 0xe0, 0x94, 0x52, 0x28, 0x80, 0x62, 0x47, 0x9a, 0x3b, 0xb3, 0x59, 0xcc, 0x7e, 0x69, 0xfe, - 0xf0, 0x7b, 0x6a, 0xba, 0xf0, 0x24, 0x04, 0x2b, 0x49, 0xe6, 0x7f, 0x1a, 0x30, 0xb7, 0xd2, 0x72, - 0xbb, 0x8d, 0xeb, 0x56, 0x50, 0xdf, 0xe5, 0x97, 0xaa, 0xe8, 0x19, 0x28, 0xda, 0x4e, 0x40, 0xbc, - 0x3d, 0xab, 0x25, 0x34, 0x8a, 0x29, 0xef, 0x9d, 0xd7, 0x04, 0xfc, 0x4e, 0xaf, 0x34, 0xb3, 0xda, - 0xf5, 0x58, 0xb4, 0x22, 0xdf, 0x5f, 0xb0, 0x2a, 0x83, 0xbe, 0x6c, 0xc0, 0x3c, 0xbf, 0x96, 0x5d, - 0xb5, 0x02, 0xeb, 0x4a, 0x97, 0x78, 0x36, 0x91, 0x17, 0xb3, 0x23, 0x6e, 0x2d, 0xf1, 0xba, 0x4a, - 0x01, 0xfb, 0xa1, 0x5d, 0xbb, 0x11, 0x97, 0x8c, 0x93, 0x95, 0x31, 0x3f, 0x9f, 0x87, 0xfb, 0xfb, - 0xf2, 0x42, 0x4b, 0x90, 0xb3, 0x1b, 0xa2, 0xe9, 0x20, 0xf8, 0xe6, 0xd6, 0x1a, 0x38, 0x67, 0x37, - 0xd0, 0x32, 0x33, 0xd1, 0x3c, 0xe2, 0xfb, 0xf2, 0x8e, 0x6e, 0x52, 0x59, 0x53, 0x02, 0x8a, 0x35, - 0x0a, 0x54, 0x82, 0x42, 0xcb, 0xda, 0x26, 0x2d, 0x61, 0x7e, 0x33, 0xa3, 0x6f, 0x9d, 0x02, 0x30, - 0x87, 0xa3, 0x5f, 0x32, 0x00, 0x78, 0x05, 0xa9, 0xf1, 0x2e, 0xf4, 0x1a, 0xce, 0xb6, 0x9b, 0x28, - 0x67, 0x5e, 0xcb, 0xf0, 0x3f, 0xd6, 0xa4, 0xa2, 0x2d, 0x18, 0xa7, 0xf6, 0x9f, 0xdb, 0x38, 0xb2, - 0x1a, 0x63, 0x77, 0x12, 0x55, 0xc6, 0x03, 0x0b, 0x5e, 0xb4, 0xaf, 0x3c, 0x12, 0x74, 0x3d, 0x87, - 0x76, 0x2d, 0x53, 0x5c, 0x45, 0x5e, 0x0b, 0xac, 0xa0, 0x58, 0xa3, 0x30, 0xff, 0x30, 0x07, 0x0b, - 0x69, 0x55, 0xa7, 0xfa, 0x61, 0x9c, 0xd7, 0x56, 0x9c, 0x24, 0xdf, 0x9f, 0x7d, 0xff, 0x88, 0x08, - 0x03, 0x75, 0x0f, 0x2f, 0x62, 0xa0, 0x84, 0x5c, 0xf4, 0x7e, 0xd5, 0x43, 0xb9, 0x23, 0xf6, 0x90, - 0xe2, 0x1c, 0xeb, 0xa5, 0x87, 0x60, 0xcc, 0xa7, 0x23, 0x9f, 0x8f, 0xfa, 0xfb, 0xd9, 0x18, 0x31, - 0x0c, 0xa5, 0xe8, 0x3a, 0x76, 0x20, 0x42, 0x88, 0x15, 0xc5, 0x55, 0xc7, 0x0e, 0x30, 0xc3, 0x98, - 0x5f, 0xcc, 0xc1, 0x52, 0xff, 0x46, 0xa1, 0x2f, 0x1a, 0x00, 0x0d, 0x6a, 0xdd, 0xd3, 0x29, 0x29, - 0x23, 0x32, 0xac, 0xe3, 0xea, 0xc3, 0x55, 0x29, 0x29, 0x0c, 0xcf, 0x51, 0x20, 0x1f, 0x6b, 0x15, - 0x41, 0x8f, 0xc9, 0xa9, 0xbf, 0x69, 0xb5, 0xa5, 0x01, 0xaa, 0xca, 0x6c, 0x28, 0x0c, 0xd6, 0xa8, - 0xe8, 0xf1, 0xcd, 0xb1, 0xda, 0xc4, 0xef, 0x58, 0x2a, 0x46, 0x9c, 0x1d, 0xdf, 0x36, 0x25, 0x10, - 0x87, 0x78, 0xb3, 0x05, 0x0f, 0x0f, 0x50, 0xcf, 0x8c, 0xe2, 0x75, 0xcd, 0xff, 0x30, 0xe0, 0xf4, - 0x4a, 0xab, 0xeb, 0x07, 0xc4, 0xfb, 0x5f, 0x13, 0xed, 0xf4, 0x5f, 0x06, 0x3c, 0xd0, 0xa7, 0xcd, - 0xf7, 0x20, 0xe8, 0xe9, 0xc5, 0x68, 0xd0, 0xd3, 0xd5, 0x51, 0xa7, 0x74, 0x6a, 0x3b, 0xfa, 0xc4, - 0x3e, 0x05, 0x70, 0x82, 0xee, 0x5a, 0x0d, 0xb7, 0x99, 0x91, 0xde, 0x7c, 0x18, 0x0a, 0x1f, 0xa5, - 0xfa, 0x27, 0x3e, 0xc7, 0x98, 0x52, 0xc2, 0x1c, 0x67, 0xbe, 0x0f, 0x44, 0x84, 0x50, 0x6c, 0xf1, - 0x18, 0x83, 0x2c, 0x1e, 0xf3, 0xef, 0x72, 0xa0, 0x1d, 0xfb, 0xef, 0xc1, 0xa4, 0x74, 0x22, 0x93, - 0x72, 0xc4, 0x83, 0xbc, 0xe6, 0xc4, 0xe8, 0xf7, 0x14, 0x60, 0x2f, 0xf6, 0x14, 0x60, 0x33, 0x33, - 0x89, 0x87, 0xbf, 0x04, 0xf8, 0x9e, 0x01, 0x0f, 0x84, 0xc4, 0x49, 0x8f, 0xdc, 0xdd, 0x77, 0x98, - 0x27, 0x61, 0xca, 0x0a, 0x8b, 0x89, 0x39, 0xa0, 0x5e, 0xbf, 0x68, 0x1c, 0xb1, 0x4e, 0x17, 0x06, - 0x1e, 0xe7, 0x8f, 0x18, 0x78, 0x3c, 0x76, 0x78, 0xe0, 0xb1, 0xf9, 0xe3, 0x1c, 0x9c, 0x49, 0xb6, - 0x4c, 0xae, 0x8d, 0xc1, 0x2e, 0xac, 0x9f, 0x82, 0xe9, 0x40, 0x14, 0xd0, 0x76, 0x7a, 0xf5, 0x76, - 0x6b, 0x4b, 0xc3, 0xe1, 0x08, 0x25, 0x2d, 0x59, 0xe7, 0xab, 0xb2, 0x56, 0x77, 0x3b, 0x32, 0x6c, - 0x5d, 0x95, 0x5c, 0xd1, 0x70, 0x38, 0x42, 0xa9, 0x02, 0x02, 0xc7, 0x8e, 0x3d, 0x20, 0xb0, 0x06, - 0xa7, 0x64, 0x08, 0xd4, 0x05, 0xd7, 0x5b, 0x71, 0xdb, 0x9d, 0x16, 0x11, 0x81, 0xeb, 0xb4, 0xb2, - 0x67, 0x44, 0x91, 0x53, 0x38, 0x8d, 0x08, 0xa7, 0x97, 0x35, 0xbf, 0x97, 0x87, 0x93, 0x61, 0xb7, - 0xaf, 0xb8, 0x4e, 0xc3, 0x66, 0x81, 0x64, 0x4f, 0xc3, 0x58, 0xb0, 0xdf, 0x91, 0x9d, 0xfd, 0x7f, - 0x64, 0x75, 0xb6, 0xf6, 0x3b, 0x74, 0xb4, 0x4f, 0xa7, 0x14, 0x61, 0x3e, 0x51, 0x56, 0x08, 0xad, - 0xab, 0xd5, 0xc1, 0x47, 0xe0, 0x89, 0xe8, 0x6c, 0xbe, 0xd3, 0x2b, 0xa5, 0x3c, 0x5d, 0x5c, 0x56, - 0x9c, 0xa2, 0x73, 0x1e, 0xdd, 0x80, 0x99, 0x96, 0xe5, 0x07, 0x57, 0x3b, 0x0d, 0x2b, 0x20, 0x5b, - 0x76, 0x9b, 0x88, 0x35, 0x37, 0x4c, 0x34, 0xb8, 0xba, 0xc4, 0x5d, 0x8f, 0x70, 0xc2, 0x31, 0xce, - 0x68, 0x0f, 0x10, 0x85, 0x6c, 0x79, 0x96, 0xe3, 0xf3, 0x56, 0x51, 0x79, 0xc3, 0x47, 0x9f, 0xab, - 0x63, 0xd9, 0x7a, 0x82, 0x1b, 0x4e, 0x91, 0x80, 0x1e, 0x81, 0x71, 0x8f, 0x58, 0xbe, 0x18, 0xcc, - 0xc9, 0x70, 0xfd, 0x63, 0x06, 0xc5, 0x02, 0xab, 0x2f, 0xa8, 0xf1, 0xbb, 0x2c, 0xa8, 0x1f, 0x1a, - 0x30, 0x13, 0x0e, 0xd3, 0x3d, 0x50, 0x92, 0xed, 0xa8, 0x92, 0xbc, 0x98, 0xd5, 0x96, 0xd8, 0x47, - 0x2f, 0xfe, 0xe9, 0xb8, 0xde, 0x3e, 0x16, 0x0d, 0xfc, 0x31, 0x98, 0x94, 0xab, 0x5a, 0x5a, 0x9f, - 0x23, 0x9e, 0x6e, 0x23, 0x76, 0x89, 0xf6, 0x8a, 0x45, 0x08, 0xc1, 0xa1, 0x3c, 0xaa, 0x96, 0x1b, - 0x42, 0xe5, 0x8a, 0x69, 0xaf, 0xd4, 0xb2, 0x54, 0xc5, 0x69, 0x6a, 0x59, 0x96, 0x41, 0x57, 0xe1, - 0x74, 0xc7, 0x73, 0xd9, 0xcb, 0xc6, 0x55, 0x62, 0x35, 0x5a, 0xb6, 0x43, 0xa4, 0x0b, 0x81, 0xc7, - 0x10, 0x3c, 0x70, 0xd0, 0x2b, 0x9d, 0xae, 0xa6, 0x93, 0xe0, 0x7e, 0x65, 0xa3, 0xaf, 0x71, 0xc6, - 0x06, 0x78, 0x8d, 0xf3, 0x69, 0xe5, 0xa8, 0x23, 0xbe, 0x78, 0x13, 0xf3, 0xc1, 0xac, 0x86, 0x32, - 0x65, 0x5b, 0x0f, 0xa7, 0x54, 0x59, 0x08, 0xc5, 0x4a, 0x7c, 0x7f, 0x6f, 0xd0, 0xf8, 0x11, 0xbd, - 0x41, 0x61, 0x50, 0xf5, 0xc4, 0x4f, 0x33, 0xa8, 0xba, 0xf8, 0xa6, 0x0a, 0xaa, 0x7e, 0xb5, 0x00, - 0x73, 0x71, 0x0b, 0xe4, 0xf8, 0x5f, 0x1a, 0xfd, 0x9a, 0x01, 0x73, 0x72, 0xf5, 0x70, 0x99, 0x44, - 0xfa, 0xf9, 0xd7, 0x33, 0x5a, 0xb4, 0xdc, 0x96, 0x52, 0x6f, 0x61, 0xb7, 0x62, 0xd2, 0x70, 0x42, - 0x3e, 0x7a, 0x01, 0xa6, 0x94, 0x3b, 0xfc, 0x48, 0xcf, 0x8e, 0x66, 0x99, 0x15, 0x15, 0xb2, 0xc0, - 0x3a, 0x3f, 0xf4, 0xaa, 0x01, 0x50, 0x97, 0x6a, 0x4e, 0xae, 0xae, 0x2b, 0x59, 0xad, 0x2e, 0xa5, - 0x40, 0x43, 0x63, 0x59, 0x81, 0x7c, 0xac, 0x09, 0x46, 0x9f, 0x67, 0x8e, 0x70, 0x65, 0xdd, 0xd1, - 0xf5, 0x94, 0x1f, 0x3d, 0x0e, 0xf6, 0x10, 0xc3, 0x34, 0x34, 0xa5, 0x34, 0x94, 0x8f, 0x23, 0x95, - 0x30, 0x9f, 0x06, 0x15, 0xb9, 0x48, 0xb7, 0x2d, 0x16, 0xbb, 0x58, 0xb5, 0x82, 0x5d, 0x31, 0x05, - 0xd5, 0xb6, 0x75, 0x41, 0x22, 0x70, 0x48, 0x63, 0x7e, 0x04, 0x66, 0x9e, 0xf5, 0xac, 0xce, 0xae, - 0xcd, 0x1c, 0xce, 0xf4, 0x9c, 0xf4, 0x76, 0x98, 0xb0, 0x1a, 0x8d, 0xb4, 0x97, 0xe4, 0x65, 0x0e, - 0xc6, 0x12, 0x3f, 0xd8, 0x91, 0xe8, 0xcf, 0x0d, 0x40, 0x91, 0xbb, 0xb2, 0x0d, 0x7a, 0xda, 0xa7, - 0xe7, 0xa3, 0x5d, 0x06, 0x4d, 0x3b, 0x1f, 0x5d, 0x54, 0x18, 0xac, 0x51, 0xa1, 0x97, 0x0d, 0x98, - 0xe2, 0x7f, 0xaf, 0xa9, 0xd3, 0xfe, 0xc8, 0x0f, 0x51, 0xb9, 0x46, 0x61, 0x95, 0x0a, 0x0d, 0xfa, - 0x8b, 0xa1, 0x14, 0xac, 0x8b, 0x34, 0xbf, 0x65, 0xc0, 0xc2, 0x9a, 0x1f, 0xd8, 0xee, 0x2a, 0xf1, - 0x03, 0xba, 0xf3, 0xd3, 0xfd, 0xa1, 0xdb, 0x1a, 0x24, 0x4e, 0x78, 0x15, 0xe6, 0xc4, 0x1d, 0x5f, - 0x77, 0xdb, 0x27, 0x81, 0x66, 0x6a, 0xab, 0xa5, 0xb6, 0x12, 0xc3, 0xe3, 0x44, 0x09, 0xca, 0x45, - 0x5c, 0xf6, 0x85, 0x5c, 0xf2, 0x51, 0x2e, 0xb5, 0x18, 0x1e, 0x27, 0x4a, 0x98, 0xdf, 0xcd, 0xc3, - 0x49, 0xd6, 0x8c, 0x58, 0x8c, 0xff, 0x67, 0xfb, 0xc5, 0xf8, 0x8f, 0xb8, 0xda, 0x98, 0xac, 0x23, - 0x44, 0xf8, 0xff, 0xaa, 0x01, 0xb3, 0x8d, 0x68, 0x4f, 0x67, 0xe3, 0x41, 0x49, 0x1b, 0x43, 0x1e, - 0x4f, 0x14, 0x03, 0xe2, 0xb8, 0x7c, 0xf4, 0x05, 0x03, 0x66, 0xa3, 0xd5, 0x94, 0x1b, 0xf0, 0x31, - 0x74, 0x92, 0x0a, 0x00, 0x8e, 0xc2, 0x7d, 0x1c, 0xaf, 0x82, 0xf9, 0x37, 0x86, 0x18, 0xd2, 0xe3, - 0x08, 0x60, 0x47, 0xb7, 0x60, 0x32, 0x68, 0xf9, 0x1c, 0x28, 0x5a, 0x3b, 0xe2, 0xa1, 0x6d, 0x6b, - 0xbd, 0xc6, 0xd8, 0x69, 0x76, 0x95, 0x80, 0x50, 0xfb, 0x50, 0xca, 0x32, 0xbf, 0x6a, 0xc0, 0xe4, - 0x25, 0x77, 0x5b, 0x6c, 0x4e, 0x1f, 0xce, 0xc0, 0x25, 0xa2, 0x2c, 0x27, 0x75, 0x9b, 0x16, 0x1a, - 0xe3, 0xcf, 0x44, 0x1c, 0x22, 0x0f, 0x6a, 0xbc, 0x97, 0x59, 0x3e, 0x19, 0xca, 0xea, 0x92, 0xbb, - 0xdd, 0xd7, 0xdf, 0xf6, 0xdb, 0x05, 0x38, 0xf1, 0x9c, 0xb5, 0x4f, 0x9c, 0xc0, 0x1a, 0x7e, 0x3b, - 0x7d, 0x12, 0xa6, 0xac, 0x0e, 0x8b, 0x67, 0xd5, 0xac, 0xe1, 0xd0, 0xc7, 0x10, 0xa2, 0xb0, 0x4e, - 0x17, 0xee, 0x2b, 0x3c, 0xbd, 0x45, 0xda, 0x8e, 0xb0, 0x12, 0xc3, 0xe3, 0x44, 0x09, 0x74, 0x09, - 0x90, 0x78, 0xac, 0x57, 0xae, 0xd7, 0xdd, 0xae, 0xc3, 0x77, 0x16, 0xee, 0x7e, 0x50, 0xc7, 0xb2, - 0x8d, 0x04, 0x05, 0x4e, 0x29, 0x85, 0x3e, 0x04, 0x8b, 0x75, 0xc6, 0x59, 0x18, 0xe9, 0x3a, 0x47, - 0x7e, 0x50, 0x53, 0xb1, 0xe4, 0x2b, 0x7d, 0xe8, 0x70, 0x5f, 0x0e, 0xb4, 0xa6, 0x7e, 0xe0, 0x7a, - 0x56, 0x93, 0xe8, 0x7c, 0xc7, 0xa3, 0x35, 0xad, 0x25, 0x28, 0x70, 0x4a, 0x29, 0xf4, 0x09, 0x98, - 0x0c, 0x76, 0x3d, 0xe2, 0xef, 0xba, 0xad, 0x86, 0xb8, 0x5e, 0x1f, 0xd1, 0x27, 0x25, 0x46, 0x7f, - 0x4b, 0x72, 0xd5, 0xa6, 0xb7, 0x04, 0xe1, 0x50, 0x26, 0xf2, 0x60, 0xdc, 0xaf, 0xbb, 0x1d, 0xe2, - 0x0b, 0xe3, 0xf6, 0x52, 0x26, 0xd2, 0x99, 0x8f, 0x45, 0xf3, 0x86, 0x31, 0x09, 0x58, 0x48, 0x32, - 0xbf, 0x9d, 0x83, 0x69, 0x9d, 0x70, 0x80, 0x2d, 0xe2, 0x93, 0x06, 0x4c, 0xd7, 0x5d, 0x27, 0xf0, - 0xdc, 0x16, 0xf7, 0xf4, 0x64, 0xa3, 0x7a, 0x29, 0xab, 0x55, 0x12, 0x58, 0x76, 0x4b, 0x73, 0x1a, - 0x69, 0x62, 0x70, 0x44, 0x28, 0xfa, 0x8c, 0x01, 0xb3, 0x61, 0x28, 0x54, 0xe8, 0x72, 0xca, 0xb4, - 0x22, 0x6a, 0xc7, 0x3d, 0x1f, 0x95, 0x84, 0xe3, 0xa2, 0xcd, 0x6d, 0x98, 0x8b, 0x8f, 0x36, 0xed, - 0xca, 0x8e, 0x25, 0xd6, 0x7a, 0x3e, 0xec, 0xca, 0xaa, 0xe5, 0xfb, 0x98, 0x61, 0xd0, 0x3b, 0xa0, - 0xd8, 0xb6, 0xbc, 0xa6, 0xed, 0x58, 0x2d, 0xd6, 0x8b, 0x79, 0x6d, 0x43, 0x12, 0x70, 0xac, 0x28, - 0xcc, 0x1f, 0x8d, 0xc1, 0x94, 0x76, 0x26, 0x39, 0xfe, 0xf3, 0x45, 0x24, 0x7f, 0x40, 0x3e, 0xc3, - 0xfc, 0x01, 0xcf, 0x03, 0xec, 0xd8, 0x8e, 0xed, 0xef, 0x1e, 0x31, 0x33, 0x01, 0xbb, 0x9a, 0xbc, - 0xa0, 0x38, 0x60, 0x8d, 0x5b, 0x78, 0xff, 0x53, 0x38, 0x24, 0x5f, 0xcb, 0xab, 0x86, 0xa6, 0x3c, - 0xc6, 0xb3, 0xb8, 0xef, 0xd6, 0x06, 0x66, 0x59, 0x2a, 0x93, 0xf3, 0x4e, 0xe0, 0xed, 0x1f, 0xaa, - 0x63, 0xb6, 0xa0, 0xe8, 0x11, 0xbf, 0xdb, 0xa6, 0x27, 0xa5, 0x89, 0xa1, 0xbb, 0x81, 0xc5, 0x0a, - 0x60, 0x51, 0x1e, 0x2b, 0x4e, 0x4b, 0x4f, 0xc3, 0x89, 0x48, 0x15, 0xd0, 0x1c, 0xe4, 0x6f, 0x92, - 0x7d, 0x3e, 0x4f, 0x30, 0xfd, 0x89, 0x16, 0x22, 0xb7, 0x64, 0xa2, 0x5b, 0xde, 0x9b, 0x7b, 0xca, - 0x30, 0x5d, 0x48, 0x3d, 0xf8, 0x1e, 0xe5, 0x12, 0x83, 0x8e, 0x45, 0x4b, 0x4b, 0x4d, 0xa0, 0xc6, - 0x82, 0x47, 0x84, 0x70, 0x9c, 0xf9, 0xe3, 0x71, 0x10, 0x57, 0xb8, 0x03, 0x6c, 0x3e, 0xfa, 0xcd, - 0x4d, 0xee, 0x08, 0x37, 0x37, 0x97, 0x60, 0xda, 0x76, 0xec, 0xc0, 0xb6, 0x5a, 0xcc, 0xa9, 0x21, - 0x94, 0xa3, 0x8c, 0x57, 0x9d, 0x5e, 0xd3, 0x70, 0x29, 0x7c, 0x22, 0x65, 0xd1, 0x15, 0x28, 0x30, - 0xed, 0x21, 0x26, 0xf0, 0xf0, 0xf7, 0xcc, 0x2c, 0xc4, 0x80, 0x3f, 0x62, 0xe1, 0x9c, 0x98, 0x45, - 0xcf, 0x73, 0x33, 0xa8, 0x63, 0xa7, 0x98, 0xc7, 0xa1, 0x45, 0x1f, 0xc3, 0xe3, 0x44, 0x09, 0xca, - 0x65, 0xc7, 0xb2, 0x5b, 0x5d, 0x8f, 0x84, 0x5c, 0xc6, 0xa3, 0x5c, 0x2e, 0xc4, 0xf0, 0x38, 0x51, - 0x02, 0xed, 0xc0, 0xb4, 0x80, 0xf1, 0x38, 0x9f, 0x89, 0x23, 0xb6, 0x92, 0xc5, 0x73, 0x5d, 0xd0, - 0x38, 0xe1, 0x08, 0x5f, 0xd4, 0x85, 0x79, 0xdb, 0xa9, 0xbb, 0x4e, 0xbd, 0xd5, 0xf5, 0xed, 0x3d, - 0x12, 0xbe, 0x20, 0x39, 0x8a, 0xb0, 0x53, 0x07, 0xbd, 0xd2, 0xfc, 0x5a, 0x9c, 0x1d, 0x4e, 0x4a, - 0x40, 0xaf, 0x18, 0x70, 0xaa, 0xee, 0x3a, 0x3e, 0x7b, 0xec, 0xbc, 0x47, 0xce, 0x7b, 0x9e, 0xeb, - 0x71, 0xd9, 0x93, 0x47, 0x94, 0xcd, 0x7c, 0x69, 0x2b, 0x69, 0x2c, 0x71, 0xba, 0x24, 0xf4, 0x22, - 0x14, 0x3b, 0x9e, 0xbb, 0x67, 0x37, 0x88, 0x27, 0x62, 0xc6, 0xd6, 0xb3, 0x48, 0xbe, 0x50, 0x15, - 0x3c, 0xc3, 0xad, 0x47, 0x42, 0xb0, 0x92, 0x67, 0x7e, 0xad, 0x08, 0x33, 0x51, 0x72, 0xf4, 0x71, - 0x80, 0x8e, 0xe7, 0xb6, 0x49, 0xb0, 0x4b, 0xd4, 0x4b, 0x80, 0xcd, 0x51, 0xdf, 0xf8, 0x4b, 0x7e, - 0x32, 0x6a, 0x83, 0x6e, 0x17, 0x21, 0x14, 0x6b, 0x12, 0x91, 0x07, 0x13, 0x37, 0xb9, 0x12, 0x15, - 0x36, 0xc5, 0x73, 0x99, 0x58, 0x40, 0x42, 0x32, 0x0b, 0x61, 0x17, 0x20, 0x2c, 0x05, 0xa1, 0x6d, - 0xc8, 0xdf, 0x22, 0xdb, 0xd9, 0xbc, 0x9b, 0xbd, 0x4e, 0xc4, 0xd9, 0xa4, 0x32, 0x71, 0xd0, 0x2b, - 0xe5, 0xaf, 0x93, 0x6d, 0x4c, 0x99, 0xd3, 0x76, 0x35, 0xf8, 0xfd, 0xb3, 0xd8, 0x2a, 0x46, 0x6c, - 0x57, 0xe4, 0x32, 0x9b, 0xb7, 0x4b, 0x80, 0xb0, 0x14, 0x84, 0x5e, 0x84, 0xc9, 0x5b, 0xd6, 0x1e, - 0xd9, 0xf1, 0x5c, 0x27, 0x10, 0xa1, 0x42, 0x23, 0x06, 0x87, 0x5f, 0x97, 0xec, 0x84, 0x5c, 0xa6, - 0xde, 0x15, 0x10, 0x87, 0xe2, 0xd0, 0x1e, 0x14, 0x1d, 0x72, 0x0b, 0x93, 0x96, 0x5d, 0x17, 0x41, - 0xb0, 0x23, 0x4e, 0xeb, 0x4d, 0xc1, 0x4d, 0x48, 0x66, 0x7a, 0x4f, 0xc2, 0xb0, 0x92, 0x45, 0xc7, - 0xf2, 0x86, 0xbb, 0x2d, 0x36, 0xaa, 0x11, 0xc7, 0x52, 0x9d, 0x33, 0xf9, 0x58, 0x5e, 0x72, 0xb7, - 0x31, 0x65, 0x4e, 0xd7, 0x48, 0x5d, 0xc5, 0xa9, 0x88, 0x6d, 0x6a, 0x33, 0xdb, 0xf8, 0x1c, 0xbe, - 0x46, 0x42, 0x28, 0xd6, 0x24, 0xd2, 0xbe, 0x6d, 0x0a, 0x27, 0x9d, 0xd8, 0xa8, 0x46, 0xec, 0xdb, - 0xa8, 0xcb, 0x8f, 0xf7, 0xad, 0x84, 0x61, 0x25, 0xcb, 0xfc, 0xea, 0x38, 0x4c, 0xeb, 0xc9, 0xa6, - 0x06, 0xd0, 0xd5, 0xca, 0x3e, 0xcd, 0x0d, 0x63, 0x9f, 0xd2, 0xe3, 0x85, 0xe6, 0x63, 0x97, 0x1e, - 0x86, 0xb5, 0xcc, 0xcc, 0xb3, 0xf0, 0x78, 0xa1, 0x01, 0x7d, 0x1c, 0x11, 0x3a, 0xc4, 0xb5, 0x3b, - 0x35, 0x72, 0xb8, 0x19, 0x50, 0x88, 0x1a, 0x39, 0x11, 0xc5, 0xfe, 0x18, 0x40, 0x98, 0x74, 0x49, - 0xdc, 0xbd, 0x28, 0xeb, 0x49, 0x4b, 0x06, 0xa5, 0x51, 0xa1, 0x47, 0x60, 0x9c, 0x2a, 0x4a, 0xd2, - 0x10, 0xcf, 0x34, 0xd5, 0x19, 0xee, 0x02, 0x83, 0x62, 0x81, 0x45, 0x4f, 0x51, 0x9b, 0x26, 0x54, - 0x6f, 0xe2, 0xf5, 0xe5, 0x42, 0x68, 0xd3, 0x84, 0x38, 0x1c, 0xa1, 0xa4, 0x55, 0x27, 0x54, 0x1b, - 0xb1, 0x99, 0xa4, 0x55, 0x9d, 0xa9, 0x28, 0xcc, 0x71, 0xcc, 0xa7, 0x10, 0xd3, 0x5e, 0x4c, 0x59, - 0x15, 0x34, 0x9f, 0x42, 0x0c, 0x8f, 0x13, 0x25, 0x68, 0x63, 0xc4, 0xb5, 0xd1, 0x14, 0x8f, 0x2e, - 0xec, 0x73, 0xe1, 0xf3, 0x9a, 0x6e, 0x99, 0x4f, 0xb3, 0xa1, 0x7f, 0x7f, 0x76, 0x89, 0xd3, 0x06, - 0x37, 0xcd, 0x47, 0x33, 0xa2, 0x3f, 0x02, 0x33, 0xd1, 0x3d, 0x8b, 0x4e, 0xa8, 0x8e, 0xe7, 0xee, - 0xd8, 0x2d, 0x12, 0xf7, 0xfd, 0x54, 0x39, 0x18, 0x4b, 0xfc, 0x60, 0xae, 0xf4, 0x3f, 0xcb, 0xc3, - 0xc9, 0xcd, 0xa6, 0xed, 0xdc, 0x8e, 0x79, 0x6d, 0xd3, 0x12, 0x9a, 0x1a, 0xc3, 0x26, 0x34, 0x0d, - 0x9f, 0x9c, 0x88, 0x8c, 0xb1, 0xe9, 0x4f, 0x4e, 0x64, 0x3a, 0xd9, 0x28, 0x2d, 0xfa, 0xa1, 0x01, - 0x0f, 0x5a, 0x0d, 0x6e, 0x45, 0x5a, 0x2d, 0x01, 0x0d, 0x85, 0xca, 0x15, 0xed, 0x8f, 0xa8, 0x13, - 0x92, 0x8d, 0x5f, 0x2e, 0x1f, 0x22, 0x95, 0x8f, 0xf8, 0xdb, 0x44, 0x0b, 0x1e, 0x3c, 0x8c, 0x14, - 0x1f, 0x5a, 0xfd, 0xa5, 0xcb, 0xf0, 0xd6, 0xbb, 0x0a, 0x1a, 0x6a, 0xb6, 0x7c, 0xd2, 0x80, 0x49, - 0xee, 0x94, 0xc4, 0x64, 0x87, 0x6e, 0x15, 0x56, 0xc7, 0xbe, 0x46, 0x3c, 0x5f, 0x66, 0x5a, 0xd2, - 0x0e, 0x5a, 0xe5, 0xea, 0x9a, 0xc0, 0x60, 0x8d, 0x8a, 0x6e, 0xc6, 0x37, 0x6d, 0xa7, 0x21, 0x86, - 0x49, 0x6d, 0xc6, 0xcf, 0xd9, 0x4e, 0x03, 0x33, 0x8c, 0xda, 0xae, 0xf3, 0x7d, 0xd3, 0x9e, 0x7c, - 0xc5, 0x80, 0x19, 0xf6, 0xc8, 0x2d, 0x3c, 0x02, 0x3c, 0xa9, 0x62, 0x2a, 0x78, 0x35, 0xce, 0x44, - 0x63, 0x2a, 0xee, 0xf4, 0x4a, 0x53, 0xfc, 0x59, 0x5c, 0x34, 0xc4, 0xe2, 0x83, 0xc2, 0x6f, 0xc0, - 0x22, 0x3f, 0x72, 0x43, 0x1f, 0x6b, 0x95, 0x97, 0xac, 0x26, 0x99, 0xe0, 0x90, 0x9f, 0xf9, 0x12, - 0x4c, 0xeb, 0x01, 0xf3, 0xe8, 0x49, 0x98, 0xea, 0xd8, 0x4e, 0x33, 0xfa, 0xb0, 0x4a, 0x79, 0x4a, - 0xab, 0x21, 0x0a, 0xeb, 0x74, 0xac, 0x98, 0x1b, 0x16, 0x8b, 0x39, 0x58, 0xab, 0xae, 0x5e, 0x2c, - 0xfc, 0x63, 0xfe, 0x7e, 0x1e, 0x4e, 0xa6, 0x3c, 0xcc, 0x40, 0xaf, 0x1a, 0x30, 0xce, 0xa2, 0xc4, - 0x65, 0xd4, 0xc4, 0x0b, 0x99, 0x3f, 0xfe, 0x58, 0x66, 0xc1, 0xe8, 0x62, 0x1e, 0xab, 0xed, 0x93, - 0x03, 0xb1, 0x10, 0x8e, 0x7e, 0xc3, 0x80, 0x29, 0x4b, 0x5b, 0x6a, 0x3c, 0x90, 0x64, 0x3b, 0xfb, - 0xca, 0x24, 0x56, 0x96, 0x16, 0x00, 0x17, 0x2e, 0x24, 0xbd, 0x2e, 0x4b, 0xef, 0x81, 0x29, 0xad, - 0x09, 0xc3, 0xac, 0x90, 0xa5, 0x67, 0x60, 0x6e, 0xa4, 0x15, 0xf6, 0x01, 0x18, 0x36, 0x71, 0x18, - 0x55, 0x58, 0xb7, 0xf4, 0x97, 0xa7, 0xaa, 0xc7, 0xc5, 0xd3, 0x53, 0x81, 0x35, 0xb7, 0x61, 0x2e, - 0x7e, 0xc8, 0xc9, 0xfc, 0xde, 0xf4, 0x5d, 0x30, 0x64, 0xaa, 0x2f, 0xf3, 0x2f, 0x72, 0x30, 0x21, - 0x5e, 0x77, 0xdd, 0x83, 0xd8, 0xd1, 0x9b, 0x91, 0xab, 0x92, 0xb5, 0x4c, 0x1e, 0xa5, 0xf5, 0x0d, - 0x1c, 0xf5, 0x63, 0x81, 0xa3, 0xcf, 0x65, 0x23, 0xee, 0xf0, 0xa8, 0xd1, 0xaf, 0x8c, 0xc1, 0x6c, - 0xec, 0xb5, 0x1c, 0x35, 0x55, 0x12, 0xc1, 0x52, 0x57, 0x33, 0x7d, 0x90, 0xa7, 0xe2, 0x9a, 0x0f, - 0x8f, 0x9b, 0xf2, 0x23, 0x19, 0x15, 0xaf, 0x64, 0x96, 0x8c, 0xf9, 0x67, 0xc9, 0x15, 0x87, 0x8d, - 0x03, 0xfa, 0x27, 0x03, 0xee, 0xef, 0xfb, 0xa8, 0x92, 0x25, 0xc4, 0xf0, 0xa2, 0x58, 0xb1, 0x20, - 0x33, 0x7e, 0xb7, 0xad, 0xee, 0x2d, 0xe2, 0x39, 0x0c, 0xe2, 0xe2, 0xd1, 0x13, 0x30, 0xcd, 0x54, - 0x2b, 0xdd, 0x53, 0x02, 0xd2, 0x11, 0x8e, 0x5a, 0xe6, 0xb2, 0xab, 0x69, 0x70, 0x1c, 0xa1, 0x32, - 0xbf, 0x6c, 0xc0, 0x62, 0xbf, 0xf4, 0x08, 0x03, 0x1c, 0x0c, 0x7f, 0x2e, 0x16, 0xdc, 0x5a, 0x4a, - 0x04, 0xb7, 0xc6, 0x8e, 0x86, 0x32, 0x8e, 0x55, 0x3b, 0x95, 0xe5, 0xef, 0x12, 0xbb, 0xf9, 0x59, - 0x03, 0x4e, 0xf7, 0x59, 0x4d, 0x89, 0x20, 0x67, 0xe3, 0xc8, 0x41, 0xce, 0xb9, 0x41, 0x83, 0x9c, - 0xcd, 0xbf, 0xca, 0xc3, 0x9c, 0xa8, 0x4f, 0x68, 0x5f, 0x3d, 0x15, 0x09, 0x11, 0x7e, 0x5b, 0x2c, - 0x44, 0x78, 0x21, 0x4e, 0xff, 0xb3, 0xf8, 0xe0, 0x37, 0x57, 0x7c, 0xf0, 0x4f, 0x72, 0x70, 0x2a, - 0x35, 0x6b, 0x03, 0xfa, 0x54, 0x8a, 0x6a, 0xb8, 0x9e, 0x71, 0x7a, 0x88, 0x01, 0x95, 0xc3, 0xa8, - 0x41, 0xb5, 0x5f, 0xd0, 0x83, 0x59, 0xf9, 0x56, 0xbf, 0x73, 0x0c, 0x89, 0x2e, 0x86, 0x8c, 0x6b, - 0x35, 0x7f, 0x25, 0x0f, 0x8f, 0x0e, 0xca, 0xe8, 0x4d, 0xfa, 0xee, 0xc1, 0x8f, 0xbc, 0x7b, 0xb8, - 0x47, 0x6a, 0xfb, 0x58, 0x9e, 0x40, 0x7c, 0x35, 0xaf, 0xd4, 0x5e, 0x72, 0x7e, 0x0e, 0x74, 0xab, - 0x37, 0x41, 0x4d, 0x3b, 0x99, 0xcb, 0x31, 0xdc, 0x0a, 0x27, 0x6a, 0x1c, 0x7c, 0xa7, 0x57, 0x9a, - 0x17, 0xf9, 0xdd, 0x6a, 0x24, 0x10, 0x40, 0x2c, 0x0b, 0xa1, 0x47, 0xa1, 0xe8, 0x71, 0xac, 0x8c, - 0xf4, 0x16, 0x57, 0xa3, 0x1c, 0x86, 0x15, 0x16, 0x7d, 0x42, 0xb3, 0x85, 0xc7, 0x8e, 0xeb, 0x95, - 0xfe, 0x61, 0x37, 0xbe, 0x2f, 0x40, 0xd1, 0x97, 0x59, 0x19, 0xb9, 0x5b, 0xfe, 0xf1, 0x01, 0x1f, - 0x10, 0xd0, 0xa3, 0x93, 0x4c, 0xd1, 0xc8, 0xdb, 0xa7, 0x12, 0x38, 0x2a, 0x96, 0xc8, 0x54, 0xa7, - 0x16, 0xee, 0x63, 0x84, 0x94, 0x13, 0xcb, 0xf7, 0x0c, 0x98, 0x12, 0xa3, 0x75, 0x0f, 0xde, 0x34, - 0xdc, 0x88, 0xbe, 0x69, 0x38, 0x9f, 0xc9, 0xde, 0xd1, 0xe7, 0x41, 0xc3, 0x0d, 0x98, 0xd6, 0x13, - 0xf7, 0xa0, 0xe7, 0xb5, 0xbd, 0xcf, 0x18, 0x25, 0x1b, 0x87, 0xdc, 0x1d, 0xc3, 0x7d, 0xd1, 0xfc, - 0x52, 0x51, 0xf5, 0x22, 0xf3, 0x43, 0xe8, 0x73, 0xd0, 0x38, 0x74, 0x0e, 0xea, 0x53, 0x20, 0x97, - 0xfd, 0x14, 0xb8, 0x02, 0x45, 0xb9, 0x41, 0x09, 0x35, 0xfe, 0xb0, 0x1e, 0xbb, 0x46, 0x6d, 0x01, - 0xca, 0x4c, 0x9b, 0xb8, 0xec, 0xa8, 0xa5, 0xc6, 0x50, 0x6d, 0x9c, 0x8a, 0x0d, 0x7a, 0x11, 0xa6, - 0x6e, 0xb9, 0xde, 0xcd, 0x96, 0x6b, 0xb1, 0x7c, 0xab, 0x90, 0xc5, 0x05, 0x8b, 0x72, 0x78, 0xf1, - 0x80, 0xef, 0xeb, 0x21, 0x7f, 0xac, 0x0b, 0x43, 0x65, 0x98, 0x6d, 0xdb, 0x0e, 0x26, 0x56, 0x43, - 0x3d, 0x5d, 0x18, 0xe3, 0x09, 0x21, 0xa5, 0x91, 0xbb, 0x11, 0x45, 0xe3, 0x38, 0x3d, 0xfa, 0x18, - 0x14, 0x7d, 0x91, 0x89, 0x27, 0x9b, 0xab, 0x30, 0x75, 0x66, 0xe4, 0x4c, 0xc3, 0xbe, 0x93, 0x10, - 0xac, 0x04, 0xa2, 0x75, 0x58, 0xf0, 0x44, 0xae, 0x8b, 0xc8, 0xd7, 0x1a, 0xf8, 0xfa, 0x64, 0x79, - 0x07, 0x71, 0x0a, 0x1e, 0xa7, 0x96, 0xa2, 0x56, 0x0c, 0xcb, 0x40, 0xc5, 0xef, 0x04, 0x34, 0x37, - 0x3a, 0x9b, 0xf0, 0x0d, 0x2c, 0xb0, 0x87, 0x3d, 0x85, 0x29, 0x8e, 0xf0, 0x14, 0xa6, 0x06, 0xa7, - 0xe2, 0x28, 0x96, 0x91, 0x83, 0x25, 0x01, 0xd1, 0xb4, 0x47, 0x35, 0x8d, 0x08, 0xa7, 0x97, 0x45, - 0xd7, 0x61, 0xd2, 0x23, 0xec, 0x7c, 0x51, 0x96, 0x97, 0xef, 0x43, 0x87, 0x19, 0x61, 0xc9, 0x00, - 0x87, 0xbc, 0xe8, 0xb8, 0x5b, 0xd1, 0x9c, 0x88, 0x57, 0x32, 0xfc, 0xde, 0x94, 0x18, 0xfb, 0x3e, - 0x99, 0x72, 0xcc, 0x37, 0x66, 0xe0, 0x44, 0xc4, 0xb7, 0x80, 0x1e, 0x86, 0x02, 0x4b, 0x51, 0xc2, - 0xb6, 0x87, 0x62, 0xb8, 0x85, 0xf1, 0xce, 0xe1, 0x38, 0xf4, 0x39, 0x03, 0x66, 0x3b, 0x11, 0x2f, - 0xac, 0xdc, 0x39, 0x47, 0xbc, 0xe7, 0x8b, 0xba, 0x76, 0xb5, 0x6c, 0xc2, 0x51, 0x61, 0x38, 0x2e, - 0x9d, 0x2e, 0x40, 0x11, 0x79, 0xd7, 0x22, 0x1e, 0xa3, 0x16, 0x36, 0x8e, 0x62, 0xb1, 0x12, 0x45, - 0xe3, 0x38, 0x3d, 0x1d, 0x61, 0xd6, 0xba, 0x51, 0x3e, 0x44, 0x53, 0x96, 0x0c, 0x70, 0xc8, 0x0b, - 0x3d, 0x03, 0x33, 0x22, 0x15, 0x5e, 0xd5, 0x6d, 0x5c, 0xb4, 0xfc, 0x5d, 0x61, 0xdc, 0xab, 0xc3, - 0xc8, 0x4a, 0x04, 0x8b, 0x63, 0xd4, 0xac, 0x6d, 0x61, 0xbe, 0x41, 0xc6, 0x60, 0x3c, 0x9a, 0x6c, - 0x79, 0x25, 0x8a, 0xc6, 0x71, 0x7a, 0xf4, 0x0e, 0x6d, 0xdf, 0xe7, 0xf7, 0x74, 0x6a, 0x37, 0x48, - 0xd9, 0xfb, 0xcb, 0x30, 0xdb, 0x65, 0x67, 0xa1, 0x86, 0x44, 0x8a, 0xf5, 0xa8, 0x04, 0x5e, 0x8d, - 0xa2, 0x71, 0x9c, 0x1e, 0x3d, 0x0d, 0x27, 0x3c, 0xba, 0xbb, 0x29, 0x06, 0xfc, 0xf2, 0x4e, 0xdd, - 0xcd, 0x60, 0x1d, 0x89, 0xa3, 0xb4, 0xe8, 0x59, 0x98, 0x0f, 0x93, 0x57, 0x49, 0x06, 0xfc, 0x36, - 0x4f, 0xe5, 0x65, 0x29, 0xc7, 0x09, 0x70, 0xb2, 0x0c, 0xfa, 0x05, 0x98, 0xd3, 0x7a, 0x62, 0xcd, - 0x69, 0x90, 0xdb, 0x22, 0xc1, 0x10, 0x4b, 0x93, 0xb6, 0x12, 0xc3, 0xe1, 0x04, 0x35, 0x7a, 0x2f, - 0xcc, 0xd4, 0xdd, 0x56, 0x8b, 0xed, 0x71, 0x3c, 0xd1, 0x2f, 0xcf, 0x24, 0xc4, 0x73, 0x2e, 0x45, - 0x30, 0x38, 0x46, 0x89, 0x2e, 0x01, 0x72, 0xb7, 0x7d, 0xe2, 0xed, 0x91, 0xc6, 0xb3, 0xfc, 0xd3, - 0x96, 0x54, 0xc5, 0x9f, 0x88, 0xc6, 0xfd, 0x5e, 0x4e, 0x50, 0xe0, 0x94, 0x52, 0x2c, 0xad, 0x8b, - 0xf6, 0xa2, 0x68, 0x26, 0x8b, 0x8f, 0xb2, 0xc4, 0x4f, 0xee, 0x77, 0x7d, 0x4e, 0xe4, 0xc1, 0x38, - 0x0f, 0xc3, 0xce, 0x26, 0xa5, 0x90, 0x9e, 0xf3, 0x33, 0xd4, 0x11, 0x1c, 0x8a, 0x85, 0x24, 0xf4, - 0x71, 0x98, 0xdc, 0x96, 0x09, 0xa0, 0x17, 0xe7, 0xb2, 0xd0, 0x8b, 0xb1, 0x5c, 0xe6, 0xe1, 0xc9, - 0x54, 0x21, 0x70, 0x28, 0x12, 0x3d, 0x02, 0x53, 0x17, 0xab, 0x65, 0x35, 0x0b, 0xe7, 0xd9, 0xe8, - 0x8f, 0xd1, 0x22, 0x58, 0x47, 0xd0, 0x15, 0xa6, 0xec, 0x25, 0xc4, 0x86, 0x38, 0xd4, 0xb7, 0x49, - 0xf3, 0x87, 0x52, 0xb3, 0xeb, 0x48, 0x5c, 0x5b, 0x3c, 0x19, 0xa3, 0x16, 0x70, 0xac, 0x28, 0xd0, - 0x0b, 0x30, 0x25, 0xf4, 0x05, 0xdb, 0x9b, 0x16, 0x8e, 0xf6, 0x5a, 0x0d, 0x87, 0x2c, 0xb0, 0xce, - 0x8f, 0xdd, 0x32, 0xb1, 0xbc, 0xb8, 0xe4, 0x42, 0xb7, 0xd5, 0x5a, 0x3c, 0xc5, 0xf6, 0xcd, 0xf0, - 0x96, 0x29, 0x44, 0x61, 0x9d, 0x0e, 0x3d, 0x2e, 0x23, 0x27, 0xde, 0x12, 0xb9, 0x76, 0x53, 0x91, - 0x13, 0xca, 0xca, 0xed, 0x13, 0xd8, 0x7b, 0xfa, 0x2e, 0x21, 0x0b, 0xdb, 0xb0, 0x24, 0x4d, 0xac, - 0xe4, 0x22, 0x59, 0x5c, 0x8c, 0x78, 0x09, 0x96, 0xae, 0xf7, 0xa5, 0xc4, 0x87, 0x70, 0x41, 0xdb, - 0x90, 0xb7, 0x5a, 0xdb, 0x8b, 0xf7, 0x67, 0x61, 0x2b, 0xaa, 0x4f, 0xd5, 0xf2, 0x60, 0x9c, 0xf2, - 0x7a, 0x05, 0x53, 0xe6, 0xe6, 0x2b, 0x39, 0xe5, 0x95, 0x57, 0xa9, 0x16, 0x5f, 0xd2, 0x67, 0xb5, - 0x91, 0xc5, 0xa7, 0x18, 0x13, 0x59, 0xd2, 0xb9, 0x42, 0x4a, 0x9d, 0xd3, 0x1d, 0xb5, 0x8e, 0x33, - 0xc9, 0xa3, 0x11, 0x4d, 0x23, 0xc9, 0x4f, 0x73, 0xd1, 0x55, 0x6c, 0x7e, 0x7f, 0x5c, 0x39, 0xa1, - 0x62, 0xa1, 0x00, 0x1e, 0x14, 0x6c, 0x3f, 0xb0, 0xdd, 0x0c, 0x9f, 0x6d, 0xc5, 0xf2, 0x2f, 0xb2, - 0x00, 0x56, 0x86, 0xc0, 0x5c, 0x14, 0x95, 0xe9, 0x34, 0x6d, 0xe7, 0xb6, 0x68, 0xfe, 0x95, 0xcc, - 0xef, 0xf8, 0xb9, 0x4c, 0x86, 0xc0, 0x5c, 0x14, 0xba, 0xc1, 0x67, 0x5a, 0x36, 0x9f, 0xdd, 0x8c, - 0x7f, 0x4d, 0x37, 0x3a, 0xe3, 0xa8, 0x2c, 0xbf, 0x6d, 0x0b, 0x1b, 0x66, 0x44, 0x59, 0xb5, 0x8d, - 0xb5, 0x34, 0x59, 0xb5, 0x8d, 0x35, 0x4c, 0x85, 0xa0, 0xd7, 0x0c, 0x00, 0x4b, 0x7d, 0x56, 0x36, - 0x9b, 0x4f, 0x0a, 0xf4, 0xfb, 0x4c, 0x2d, 0x8f, 0x39, 0x0b, 0xb1, 0x58, 0x93, 0x8c, 0x5e, 0x84, - 0x09, 0x8b, 0x7f, 0x10, 0x45, 0x84, 0xf3, 0x65, 0xf3, 0x95, 0x9f, 0x58, 0x0d, 0x58, 0x1c, 0xa3, - 0x40, 0x61, 0x29, 0x90, 0xca, 0x0e, 0x3c, 0x8b, 0xec, 0xd8, 0x37, 0x45, 0x5c, 0x5f, 0x6d, 0xe4, - 0xbc, 0xc6, 0x94, 0x59, 0x9a, 0x6c, 0x81, 0xc2, 0x52, 0xa0, 0xf9, 0xaf, 0x06, 0x68, 0xdf, 0x20, - 0x0c, 0x03, 0xbd, 0x8c, 0x81, 0x03, 0xbd, 0x72, 0x43, 0x06, 0x7a, 0xe5, 0x87, 0x0a, 0xf4, 0x1a, - 0x1b, 0x3e, 0xd0, 0xab, 0xd0, 0x3f, 0xd0, 0xcb, 0x7c, 0xdd, 0x80, 0xf9, 0xc4, 0x9c, 0x8c, 0x7f, - 0xeb, 0xd9, 0x18, 0xf0, 0x5b, 0xcf, 0xab, 0x30, 0x27, 0x12, 0xb1, 0xd6, 0x3a, 0x2d, 0x3b, 0xf5, - 0x85, 0xeb, 0x56, 0x0c, 0x8f, 0x13, 0x25, 0xcc, 0x3f, 0x36, 0x60, 0x4a, 0x7b, 0x90, 0x43, 0xdb, - 0xc1, 0x1e, 0x2e, 0x89, 0x6a, 0x84, 0x39, 0x68, 0x99, 0x7b, 0x95, 0xe3, 0xb8, 0xa7, 0xbf, 0xa9, - 0x25, 0xfd, 0x0b, 0x3d, 0xfd, 0x14, 0x8a, 0x05, 0x96, 0xa7, 0x73, 0x23, 0xfc, 0x3b, 0xde, 0x79, - 0x3d, 0x9d, 0x1b, 0xe9, 0x60, 0x86, 0x61, 0xe2, 0xa8, 0x2e, 0x17, 0x31, 0x80, 0x5a, 0xca, 0x5b, - 0x8b, 0x9e, 0xd8, 0x18, 0x0e, 0x9d, 0x81, 0x3c, 0x71, 0x1a, 0xe2, 0xe0, 0xa1, 0xbe, 0xf1, 0x72, - 0xde, 0x69, 0x60, 0x0a, 0x37, 0x2f, 0xc3, 0x74, 0x8d, 0xd4, 0x3d, 0x12, 0x3c, 0x47, 0xf6, 0x07, - 0xfe, 0x68, 0xcc, 0x4d, 0xb2, 0x1f, 0xff, 0x68, 0x0c, 0x2d, 0x4e, 0xe1, 0xe6, 0xef, 0x19, 0x10, - 0x4b, 0x8a, 0xac, 0x79, 0xfd, 0x8c, 0x7e, 0x5e, 0xbf, 0x88, 0x7f, 0x2a, 0x77, 0xa8, 0x7f, 0xea, - 0x12, 0xa0, 0xb6, 0x15, 0xd4, 0x77, 0x23, 0x29, 0xc0, 0xc5, 0x99, 0x2f, 0x7c, 0xfe, 0x97, 0xa0, - 0xc0, 0x29, 0xa5, 0xcc, 0x4f, 0x1b, 0x90, 0x48, 0x99, 0x8c, 0xba, 0x50, 0x60, 0xa4, 0xe2, 0x62, - 0xa4, 0x3a, 0xda, 0x8a, 0x4e, 0x3e, 0x28, 0x0f, 0x07, 0x8a, 0xfd, 0xc5, 0x5c, 0x9a, 0xf9, 0x32, - 0xad, 0x4b, 0xfc, 0x03, 0xe0, 0x6f, 0x87, 0x09, 0x22, 0xbe, 0x0d, 0xc2, 0x8f, 0xe5, 0xca, 0x6a, - 0x92, 0x9f, 0x04, 0x91, 0x78, 0x7a, 0x76, 0x93, 0xde, 0x3f, 0xe9, 0x4b, 0xe1, 0x8f, 0xb6, 0xd4, - 0xd9, 0x6d, 0x35, 0x8a, 0xc6, 0x71, 0x7a, 0xf3, 0x13, 0x30, 0xa5, 0xbd, 0x31, 0x67, 0xcb, 0xf2, - 0xb6, 0x55, 0x0f, 0xe2, 0xd3, 0xf9, 0x3c, 0x05, 0x62, 0x8e, 0x63, 0x2e, 0x1f, 0x1e, 0xc7, 0x17, - 0x9b, 0xce, 0x22, 0x7a, 0x4f, 0x60, 0x29, 0x33, 0x8f, 0x34, 0xc9, 0x6d, 0x99, 0x6a, 0x4f, 0x32, - 0xc3, 0x14, 0x88, 0x39, 0xce, 0xbc, 0x06, 0x45, 0xf9, 0xb4, 0x96, 0xbd, 0x4f, 0x93, 0xee, 0x08, - 0xfd, 0x7d, 0x9a, 0xeb, 0x05, 0x98, 0x61, 0xe8, 0x9c, 0xf1, 0x1d, 0xfb, 0xa2, 0xeb, 0x07, 0xf2, - 0x3d, 0x30, 0x77, 0x3a, 0x6e, 0xae, 0x31, 0x18, 0x56, 0x58, 0x73, 0x1e, 0x66, 0x95, 0x37, 0x51, - 0x84, 0x4a, 0x7d, 0x3b, 0x0f, 0xd3, 0x91, 0x2f, 0x4d, 0xde, 0x7d, 0xe6, 0x0f, 0x3e, 0x47, 0x53, - 0xbc, 0x82, 0xf9, 0x21, 0xbd, 0x82, 0xba, 0x1b, 0x76, 0xec, 0x78, 0xdd, 0xb0, 0x85, 0x6c, 0xdc, - 0xb0, 0x01, 0x4c, 0x88, 0xaf, 0xf0, 0x0b, 0x3d, 0xbc, 0x91, 0x51, 0x96, 0x0f, 0xf1, 0xc0, 0x9c, - 0x69, 0x41, 0xb9, 0x9b, 0x4b, 0x51, 0xe6, 0x37, 0x0a, 0x30, 0x13, 0xcd, 0xfb, 0x31, 0xc0, 0x48, - 0xbe, 0x23, 0x31, 0x92, 0x43, 0x7a, 0x45, 0xf2, 0xa3, 0x7a, 0x45, 0xc6, 0x46, 0xf5, 0x8a, 0x14, - 0x8e, 0xe0, 0x15, 0x49, 0xfa, 0x34, 0xc6, 0x07, 0xf6, 0x69, 0xbc, 0x4f, 0x5d, 0xe9, 0x4f, 0x44, - 0xee, 0xc0, 0xc2, 0x2b, 0x7d, 0x14, 0x1d, 0x86, 0x15, 0xb7, 0x91, 0x1a, 0x1a, 0x51, 0xbc, 0xcb, - 0xe9, 0xcf, 0x4b, 0xbd, 0x81, 0x1f, 0xde, 0xf1, 0xfa, 0x96, 0x21, 0x6e, 0xdf, 0x9f, 0x84, 0x29, - 0x31, 0x9f, 0x98, 0x25, 0x00, 0x51, 0x2b, 0xa2, 0x16, 0xa2, 0xb0, 0x4e, 0xc7, 0x3e, 0x86, 0x16, - 0xfd, 0xfa, 0x1b, 0x73, 0x32, 0xe9, 0x1f, 0x43, 0x8b, 0x7d, 0x2d, 0x2e, 0x4e, 0x6f, 0x7e, 0x0c, - 0x4e, 0xa5, 0xda, 0x7c, 0xec, 0x10, 0xcc, 0x94, 0x14, 0x69, 0x08, 0x02, 0xad, 0x1a, 0xb1, 0xb4, - 0x90, 0x4b, 0xd7, 0xfb, 0x52, 0xe2, 0x43, 0xb8, 0x98, 0x5f, 0xcf, 0xc3, 0x4c, 0xf4, 0x4b, 0x1a, - 0xe8, 0x96, 0x3a, 0x21, 0x66, 0x72, 0x38, 0xe5, 0x6c, 0xb5, 0x44, 0x15, 0x7d, 0xdd, 0x3d, 0xb7, - 0xd8, 0xfc, 0xda, 0x56, 0x59, 0x33, 0x8e, 0x4f, 0xb0, 0xf0, 0xb3, 0x08, 0x71, 0xec, 0x63, 0x19, - 0x61, 0x40, 0xb5, 0x88, 0x21, 0xc8, 0x5c, 0x7a, 0x18, 0x22, 0xad, 0x44, 0x61, 0x4d, 0x2c, 0xd5, - 0x2d, 0x7b, 0xc4, 0xb3, 0x77, 0x6c, 0xf5, 0x15, 0x30, 0xb6, 0x73, 0x5f, 0x13, 0x30, 0xac, 0xb0, - 0xe6, 0xcb, 0x39, 0x08, 0xbf, 0x79, 0xc8, 0x32, 0xde, 0xfb, 0x9a, 0x01, 0x27, 0x86, 0xed, 0xd2, - 0xa8, 0x1f, 0x97, 0x08, 0x39, 0x8a, 0x70, 0x2b, 0x0d, 0x82, 0x23, 0x12, 0x7f, 0x0a, 0xdf, 0x3a, - 0xb4, 0x60, 0x36, 0xf6, 0xdc, 0x2b, 0xf3, 0x98, 0xd6, 0x2f, 0xe5, 0x61, 0x52, 0x3d, 0x98, 0x43, - 0xef, 0x61, 0x69, 0xa3, 0x77, 0x5d, 0x99, 0xcc, 0xfb, 0xad, 0x5a, 0x72, 0xe7, 0x5d, 0xb7, 0x71, - 0xa7, 0x57, 0x9a, 0x55, 0xc4, 0x1c, 0x84, 0x45, 0x01, 0x6a, 0x2e, 0x77, 0xbd, 0x56, 0xdc, 0x5c, - 0xbe, 0x8a, 0xd7, 0x31, 0x85, 0xa3, 0xdb, 0x30, 0xc1, 0x93, 0xf6, 0xc8, 0xe8, 0x95, 0x8d, 0x8c, - 0x1e, 0xf9, 0x71, 0xbb, 0x33, 0xec, 0x06, 0xfe, 0xdf, 0xc7, 0x52, 0x1c, 0xd5, 0x92, 0xdb, 0x6e, - 0x63, 0x3f, 0x9e, 0x0c, 0xba, 0xe2, 0x36, 0xf6, 0x31, 0xc3, 0xa0, 0x67, 0x60, 0x26, 0xb0, 0xdb, - 0xc4, 0xed, 0x06, 0xfa, 0x17, 0xe5, 0xf2, 0xe1, 0xf5, 0xc5, 0x56, 0x04, 0x8b, 0x63, 0xd4, 0x54, - 0xcb, 0xde, 0xf0, 0x5d, 0x87, 0x65, 0x78, 0x1a, 0x8f, 0xfa, 0x3a, 0x2f, 0xd5, 0x2e, 0x6f, 0xb2, - 0x04, 0x4f, 0x8a, 0x82, 0x52, 0xdb, 0xec, 0x55, 0x8e, 0x47, 0xc4, 0xed, 0xe1, 0x5c, 0xf8, 0x76, - 0x9a, 0xc3, 0xb1, 0xa2, 0x30, 0xaf, 0xc2, 0x6c, 0xac, 0xa9, 0xf2, 0x60, 0x62, 0xa4, 0x1f, 0x4c, - 0x06, 0xcb, 0xbc, 0xfc, 0x07, 0x06, 0xcc, 0x27, 0x16, 0xef, 0xa0, 0xc1, 0xd6, 0x71, 0x35, 0x92, - 0x3b, 0xba, 0x1a, 0xc9, 0x0f, 0xa7, 0x46, 0x2a, 0xcb, 0xdf, 0x79, 0xe3, 0xec, 0x7d, 0xdf, 0x7d, - 0xe3, 0xec, 0x7d, 0xdf, 0x7f, 0xe3, 0xec, 0x7d, 0x2f, 0x1f, 0x9c, 0x35, 0xbe, 0x73, 0x70, 0xd6, - 0xf8, 0xee, 0xc1, 0x59, 0xe3, 0xfb, 0x07, 0x67, 0x8d, 0x7f, 0x3c, 0x38, 0x6b, 0xbc, 0xfe, 0xa3, - 0xb3, 0xf7, 0x3d, 0x5f, 0x94, 0xd3, 0xe4, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0x1a, 0x88, 0xc5, - 0xd7, 0x3a, 0x8d, 0x00, 0x00, + // 7342 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x6b, 0x6c, 0x24, 0x59, + 0x75, 0xf0, 0x56, 0xb7, 0xdb, 0xee, 0x3e, 0xf6, 0xf8, 0x71, 0xc7, 0xc3, 0x78, 0xbd, 0x3b, 0xd3, + 0x4b, 0x2d, 0xda, 0x6f, 0xf9, 0x3e, 0xf0, 0xc0, 0x3e, 0xbe, 0x6f, 0x61, 0xd1, 0x7e, 0xe9, 0xb6, + 0x67, 0x76, 0x3c, 0x6b, 0x7b, 0x3c, 0xb7, 0x3d, 0x33, 0xb0, 0xb0, 0x84, 0x72, 0xf7, 0x75, 0xbb, + 0x66, 0xba, 0xab, 0x9a, 0xaa, 0x6a, 0xcf, 0x78, 0x59, 0xc1, 0x6e, 0xd0, 0x6e, 0x20, 0x02, 0xb1, + 0x09, 0xa0, 0x28, 0x8a, 0x88, 0x50, 0xb4, 0x52, 0xa2, 0x90, 0x5f, 0x28, 0x51, 0xfe, 0x20, 0x25, + 0x0a, 0xa0, 0x10, 0x45, 0x89, 0x48, 0x94, 0x04, 0x88, 0x44, 0x27, 0x6b, 0xf2, 0x27, 0x51, 0xa2, + 0x28, 0x12, 0x51, 0xc4, 0xfc, 0x8a, 0xee, 0xb3, 0x6e, 0x3d, 0xda, 0xd3, 0xed, 0x2e, 0x0f, 0xab, + 0x84, 0x7f, 0xdd, 0xf7, 0x9c, 0x7b, 0xce, 0x7d, 0x9f, 0xc7, 0x3d, 0xf7, 0x14, 0xac, 0x35, 0xed, + 0x60, 0xb7, 0xbb, 0xbd, 0x54, 0x77, 0xdb, 0xe7, 0x2c, 0xaf, 0xe9, 0x76, 0x3c, 0xf7, 0x06, 0xfb, + 0xf1, 0x6e, 0xcf, 0x6d, 0xb5, 0xdc, 0x6e, 0xe0, 0x9f, 0xeb, 0xdc, 0x6c, 0x9e, 0xb3, 0x3a, 0xb6, + 0x7f, 0x4e, 0x95, 0xec, 0xbd, 0xd7, 0x6a, 0x75, 0x76, 0xad, 0xf7, 0x9e, 0x6b, 0x12, 0x87, 0x78, + 0x56, 0x40, 0x1a, 0x4b, 0x1d, 0xcf, 0x0d, 0x5c, 0xf4, 0x81, 0x90, 0xda, 0x92, 0xa4, 0xc6, 0x7e, + 0xfc, 0xbc, 0xac, 0xbb, 0xd4, 0xb9, 0xd9, 0x5c, 0xa2, 0xd4, 0x96, 0x54, 0x89, 0xa4, 0xb6, 0xf8, + 0x6e, 0xad, 0x2d, 0x4d, 0xb7, 0xe9, 0x9e, 0x63, 0x44, 0xb7, 0xbb, 0x3b, 0xec, 0x1f, 0xfb, 0xc3, + 0x7e, 0x71, 0x66, 0x8b, 0x0f, 0xdf, 0x7c, 0xca, 0x5f, 0xb2, 0x5d, 0xda, 0xb6, 0x73, 0xdb, 0x56, + 0x50, 0xdf, 0x3d, 0xb7, 0x97, 0x68, 0xd1, 0xa2, 0xa9, 0x21, 0xd5, 0x5d, 0x8f, 0xa4, 0xe1, 0x3c, + 0x11, 0xe2, 0xb4, 0xad, 0xfa, 0xae, 0xed, 0x10, 0x6f, 0x3f, 0xec, 0x75, 0x9b, 0x04, 0x56, 0x5a, + 0xad, 0x73, 0xfd, 0x6a, 0x79, 0x5d, 0x27, 0xb0, 0xdb, 0x24, 0x51, 0xe1, 0xff, 0xde, 0xad, 0x82, + 0x5f, 0xdf, 0x25, 0x6d, 0x2b, 0x51, 0xef, 0xf1, 0x7e, 0xf5, 0xba, 0x81, 0xdd, 0x3a, 0x67, 0x3b, + 0x81, 0x1f, 0x78, 0xf1, 0x4a, 0xe6, 0xb7, 0xf2, 0x50, 0xaa, 0xac, 0x55, 0x6b, 0x81, 0x15, 0x74, + 0x7d, 0xf4, 0x9a, 0x01, 0x53, 0x2d, 0xd7, 0x6a, 0x54, 0xad, 0x96, 0xe5, 0xd4, 0x89, 0xb7, 0x60, + 0x3c, 0x64, 0x3c, 0x3a, 0xf9, 0xd8, 0xda, 0xd2, 0x28, 0xf3, 0xb5, 0x54, 0xb9, 0xe5, 0x63, 0xe2, + 0xbb, 0x5d, 0xaf, 0x4e, 0x30, 0xd9, 0xa9, 0xce, 0x7f, 0xa7, 0x57, 0xbe, 0xef, 0xa0, 0x57, 0x9e, + 0x5a, 0xd3, 0x38, 0xe1, 0x08, 0x5f, 0xf4, 0x65, 0x03, 0xe6, 0xea, 0x96, 0x63, 0x79, 0xfb, 0x5b, + 0x96, 0xd7, 0x24, 0xc1, 0xb3, 0x9e, 0xdb, 0xed, 0x2c, 0xe4, 0x8e, 0xa1, 0x35, 0xf7, 0x8b, 0xd6, + 0xcc, 0x2d, 0xc7, 0xd9, 0xe1, 0x64, 0x0b, 0x58, 0xbb, 0xfc, 0xc0, 0xda, 0x6e, 0x11, 0xbd, 0x5d, + 0xf9, 0xe3, 0x6c, 0x57, 0x2d, 0xce, 0x0e, 0x27, 0x5b, 0x60, 0xbe, 0x9a, 0x87, 0xb9, 0xca, 0x5a, + 0x75, 0xcb, 0xb3, 0x76, 0x76, 0xec, 0x3a, 0x76, 0xbb, 0x81, 0xed, 0x34, 0xd1, 0x3b, 0x61, 0xc2, + 0x76, 0x9a, 0x1e, 0xf1, 0x7d, 0x36, 0x91, 0xa5, 0xea, 0x8c, 0x20, 0x3a, 0xb1, 0xca, 0x8b, 0xb1, + 0x84, 0xa3, 0x27, 0x61, 0xd2, 0x27, 0xde, 0x9e, 0x5d, 0x27, 0x9b, 0xae, 0x17, 0xb0, 0x91, 0x2e, + 0x54, 0x4f, 0x0a, 0xf4, 0xc9, 0x5a, 0x08, 0xc2, 0x3a, 0x1e, 0xad, 0xe6, 0xb9, 0x6e, 0x20, 0xe0, + 0x6c, 0x20, 0x4a, 0x61, 0x35, 0x1c, 0x82, 0xb0, 0x8e, 0x87, 0x5e, 0x37, 0x60, 0xd6, 0x0f, 0xec, + 0xfa, 0x4d, 0xdb, 0x21, 0xbe, 0xbf, 0xec, 0x3a, 0x3b, 0x76, 0x73, 0xa1, 0xc0, 0x46, 0x71, 0x63, + 0xb4, 0x51, 0xac, 0xc5, 0xa8, 0x56, 0xe7, 0x0f, 0x7a, 0xe5, 0xd9, 0x78, 0x29, 0x4e, 0x70, 0x47, + 0x2b, 0x30, 0x6b, 0x39, 0x8e, 0x1b, 0x58, 0x81, 0xed, 0x3a, 0x9b, 0x1e, 0xd9, 0xb1, 0x6f, 0x2f, + 0x8c, 0xb1, 0xee, 0x2c, 0x88, 0xee, 0xcc, 0x56, 0x62, 0x70, 0x9c, 0xa8, 0x61, 0xae, 0xc0, 0x42, + 0xa5, 0xbd, 0x6d, 0xf9, 0xbe, 0xd5, 0x70, 0xbd, 0xd8, 0x6c, 0x3c, 0x0a, 0xc5, 0xb6, 0xd5, 0xe9, + 0xd8, 0x4e, 0x93, 0x4e, 0x47, 0xfe, 0xd1, 0x52, 0x75, 0xea, 0xa0, 0x57, 0x2e, 0xae, 0x8b, 0x32, + 0xac, 0xa0, 0xe6, 0x0f, 0x72, 0x30, 0x59, 0x71, 0xac, 0xd6, 0xbe, 0x6f, 0xfb, 0xb8, 0xeb, 0xa0, + 0x8f, 0x41, 0x91, 0x9e, 0x2e, 0x0d, 0x2b, 0xb0, 0xc4, 0x8e, 0x7c, 0xcf, 0x12, 0xdf, 0xec, 0x4b, + 0xfa, 0x66, 0x0f, 0xc7, 0x85, 0x62, 0x2f, 0xed, 0xbd, 0x77, 0xe9, 0xf2, 0xf6, 0x0d, 0x52, 0x0f, + 0xd6, 0x49, 0x60, 0x55, 0x91, 0xe8, 0x05, 0x84, 0x65, 0x58, 0x51, 0x45, 0x2e, 0x8c, 0xf9, 0x1d, + 0x52, 0x17, 0x3b, 0x6c, 0x7d, 0xc4, 0x95, 0x1c, 0x36, 0xbd, 0xd6, 0x21, 0xf5, 0xea, 0x94, 0x60, + 0x3d, 0x46, 0xff, 0x61, 0xc6, 0x08, 0xdd, 0x82, 0x71, 0x9f, 0x9d, 0x39, 0x62, 0xf3, 0x5c, 0xce, + 0x8e, 0x25, 0x23, 0x5b, 0x9d, 0x16, 0x4c, 0xc7, 0xf9, 0x7f, 0x2c, 0xd8, 0x99, 0x7f, 0x67, 0xc0, + 0x49, 0x0d, 0xbb, 0xe2, 0x35, 0xbb, 0x6d, 0xe2, 0x04, 0xe8, 0x21, 0x18, 0x73, 0xac, 0x36, 0x11, + 0x1b, 0x45, 0x35, 0x79, 0xc3, 0x6a, 0x13, 0xcc, 0x20, 0xe8, 0x61, 0x28, 0xec, 0x59, 0xad, 0x2e, + 0x61, 0x83, 0x54, 0xaa, 0x9e, 0x10, 0x28, 0x85, 0x6b, 0xb4, 0x10, 0x73, 0x18, 0x7a, 0x09, 0x4a, + 0xec, 0xc7, 0x05, 0xcf, 0x6d, 0x67, 0xd4, 0x35, 0xd1, 0xc2, 0x6b, 0x92, 0x6c, 0xf5, 0xc4, 0x41, + 0xaf, 0x5c, 0x52, 0x7f, 0x71, 0xc8, 0xd0, 0xfc, 0x7b, 0x03, 0x66, 0xb4, 0xce, 0xad, 0xd9, 0x7e, + 0x80, 0x3e, 0x92, 0x58, 0x3c, 0x4b, 0x83, 0x2d, 0x1e, 0x5a, 0x9b, 0x2d, 0x9d, 0x59, 0xd1, 0xd3, + 0xa2, 0x2c, 0xd1, 0x16, 0x8e, 0x03, 0x05, 0x3b, 0x20, 0x6d, 0x7f, 0x21, 0xf7, 0x50, 0xfe, 0xd1, + 0xc9, 0xc7, 0x56, 0x33, 0x9b, 0xc6, 0x70, 0x7c, 0x57, 0x29, 0x7d, 0xcc, 0xd9, 0x98, 0x5f, 0x1f, + 0x8b, 0xf4, 0x90, 0xae, 0x28, 0xe4, 0xc2, 0x44, 0x9b, 0x04, 0x9e, 0x5d, 0xe7, 0xfb, 0x6a, 0xf2, + 0xb1, 0x95, 0xd1, 0x5a, 0xb1, 0xce, 0x88, 0x85, 0x87, 0x25, 0xff, 0xef, 0x63, 0xc9, 0x05, 0xed, + 0xc2, 0x98, 0xe5, 0x35, 0x65, 0x9f, 0x2f, 0x64, 0x33, 0xbf, 0xe1, 0x9a, 0xab, 0x78, 0x4d, 0x1f, + 0x33, 0x0e, 0xe8, 0x1c, 0x94, 0x02, 0xe2, 0xb5, 0x6d, 0xc7, 0x0a, 0xf8, 0xe9, 0x5a, 0xac, 0xce, + 0x09, 0xb4, 0xd2, 0x96, 0x04, 0xe0, 0x10, 0x07, 0xb5, 0x60, 0xbc, 0xe1, 0xed, 0xe3, 0xae, 0xb3, + 0x30, 0x96, 0xc5, 0x50, 0xac, 0x30, 0x5a, 0xe1, 0x66, 0xe2, 0xff, 0xb1, 0xe0, 0x81, 0xde, 0x30, + 0x60, 0xbe, 0x4d, 0x2c, 0xbf, 0xeb, 0x11, 0xda, 0x05, 0x4c, 0x02, 0xe2, 0xd0, 0xd3, 0x70, 0xa1, + 0xc0, 0x98, 0xe3, 0x51, 0xe7, 0x21, 0x49, 0xb9, 0xfa, 0xa0, 0x68, 0xca, 0x7c, 0x1a, 0x14, 0xa7, + 0xb6, 0xc6, 0xfc, 0xc1, 0x18, 0xcc, 0x25, 0x4e, 0x08, 0xf4, 0x04, 0x14, 0x3a, 0xbb, 0x96, 0x2f, + 0xb7, 0xfc, 0x59, 0xb9, 0xde, 0x36, 0x69, 0xe1, 0x9d, 0x5e, 0xf9, 0x84, 0xac, 0xc2, 0x0a, 0x30, + 0x47, 0xa6, 0x32, 0xb5, 0x4d, 0x7c, 0xdf, 0x6a, 0xca, 0x73, 0x40, 0x5b, 0x26, 0xac, 0x18, 0x4b, + 0x38, 0xfa, 0x45, 0x03, 0x4e, 0xf0, 0x25, 0x83, 0x89, 0xdf, 0x6d, 0x05, 0xf4, 0xac, 0xa3, 0xc3, + 0x72, 0x29, 0x8b, 0xe5, 0xc9, 0x49, 0x56, 0x4f, 0x09, 0xee, 0x27, 0xf4, 0x52, 0x1f, 0x47, 0xf9, + 0xa2, 0xeb, 0x50, 0xf2, 0x03, 0xcb, 0x0b, 0x48, 0xa3, 0x12, 0x30, 0xa9, 0x36, 0xf9, 0xd8, 0xff, + 0x1e, 0xec, 0x10, 0xd8, 0xb2, 0xdb, 0x84, 0x1f, 0x38, 0x35, 0x49, 0x00, 0x87, 0xb4, 0xd0, 0x4b, + 0x00, 0x5e, 0xd7, 0xa9, 0x75, 0xdb, 0x6d, 0xcb, 0xdb, 0x17, 0x12, 0xfc, 0xe2, 0x68, 0xdd, 0xc3, + 0x8a, 0x5e, 0x28, 0xb3, 0xc2, 0x32, 0xac, 0xf1, 0x43, 0xaf, 0x18, 0x70, 0x82, 0xaf, 0x44, 0xd9, + 0x82, 0xf1, 0x8c, 0x5b, 0x30, 0x47, 0x87, 0x76, 0x45, 0x67, 0x81, 0xa3, 0x1c, 0xcd, 0xbf, 0x89, + 0xca, 0x93, 0x5a, 0x40, 0xb5, 0xeb, 0xe6, 0x3e, 0xfa, 0x30, 0xdc, 0xef, 0x77, 0xeb, 0x75, 0xe2, + 0xfb, 0x3b, 0xdd, 0x16, 0xee, 0x3a, 0x17, 0x6d, 0x3f, 0x70, 0xbd, 0xfd, 0x35, 0xbb, 0x6d, 0x07, + 0x6c, 0xc5, 0x15, 0xaa, 0x67, 0x0e, 0x7a, 0xe5, 0xfb, 0x6b, 0xfd, 0x90, 0x70, 0xff, 0xfa, 0xc8, + 0x82, 0x07, 0xba, 0x4e, 0x7f, 0xf2, 0x5c, 0x7b, 0x2b, 0x1f, 0xf4, 0xca, 0x0f, 0x5c, 0xed, 0x8f, + 0x86, 0x0f, 0xa3, 0x61, 0xfe, 0xb3, 0x01, 0xb3, 0xb2, 0x5f, 0x5b, 0xa4, 0xdd, 0x69, 0xd1, 0xd3, + 0xe5, 0xf8, 0x15, 0x91, 0x20, 0xa2, 0x88, 0xe0, 0x6c, 0xc4, 0x89, 0x6c, 0x7f, 0x3f, 0x6d, 0xc4, + 0xfc, 0x27, 0x03, 0xe6, 0xe3, 0xc8, 0xf7, 0x40, 0x78, 0xfa, 0x51, 0xe1, 0xb9, 0x91, 0x6d, 0x6f, + 0xfb, 0x48, 0xd0, 0xd7, 0xc6, 0x92, 0x7d, 0xfd, 0xef, 0x2e, 0x46, 0x43, 0xa9, 0x98, 0xff, 0x69, + 0x4a, 0xc5, 0xb1, 0xb7, 0x94, 0x54, 0xfc, 0xed, 0x31, 0x98, 0xaa, 0x38, 0x81, 0x5d, 0xd9, 0xd9, + 0xb1, 0x1d, 0x3b, 0xd8, 0x47, 0x9f, 0xcb, 0xc1, 0xb9, 0x8e, 0x47, 0x76, 0x88, 0xe7, 0x91, 0xc6, + 0x4a, 0xd7, 0xb3, 0x9d, 0x66, 0xad, 0xbe, 0x4b, 0x1a, 0xdd, 0x96, 0xed, 0x34, 0x57, 0x9b, 0x8e, + 0xab, 0x8a, 0xcf, 0xdf, 0x26, 0xf5, 0x2e, 0xeb, 0x12, 0xdf, 0x14, 0xed, 0xd1, 0xba, 0xb4, 0x39, + 0x1c, 0xd3, 0xea, 0xe3, 0x07, 0xbd, 0xf2, 0xb9, 0x21, 0x2b, 0xe1, 0x61, 0xbb, 0x86, 0x3e, 0x93, + 0x83, 0x25, 0x8f, 0x7c, 0xbc, 0x6b, 0x0f, 0x3e, 0x1a, 0xfc, 0xd4, 0x6a, 0x8d, 0x28, 0x7e, 0x86, + 0xe2, 0x59, 0x7d, 0xec, 0xa0, 0x57, 0x1e, 0xb2, 0x0e, 0x1e, 0xb2, 0x5f, 0xe6, 0x37, 0x73, 0x70, + 0xaa, 0xd2, 0xe9, 0xac, 0x13, 0x7f, 0x37, 0x66, 0xd4, 0x7e, 0xc1, 0x80, 0xe9, 0x3d, 0xdb, 0x0b, + 0xba, 0x56, 0x4b, 0x3a, 0x01, 0xf8, 0x92, 0xa8, 0x8d, 0xb8, 0x9d, 0x39, 0xb7, 0x6b, 0x11, 0xd2, + 0x55, 0x74, 0xd0, 0x2b, 0x4f, 0x47, 0xcb, 0x70, 0x8c, 0x3d, 0xfa, 0x55, 0x03, 0x66, 0x45, 0xd1, + 0x86, 0xdb, 0x20, 0xba, 0xe7, 0xe8, 0x6a, 0x96, 0x6d, 0x52, 0xc4, 0xb9, 0x8b, 0x21, 0x5e, 0x8a, + 0x13, 0x8d, 0x30, 0xff, 0x35, 0x07, 0xa7, 0xfb, 0xd0, 0x40, 0xbf, 0x65, 0xc0, 0x3c, 0x77, 0x37, + 0x69, 0x20, 0x4c, 0x76, 0xc4, 0x68, 0x7e, 0x28, 0xeb, 0x96, 0x63, 0xba, 0x17, 0x88, 0x53, 0x27, + 0xd5, 0x05, 0x7a, 0x6c, 0x2c, 0xa7, 0xb0, 0xc6, 0xa9, 0x0d, 0x62, 0x2d, 0xe5, 0x0e, 0xa8, 0x58, + 0x4b, 0x73, 0xf7, 0xa4, 0xa5, 0xb5, 0x14, 0xd6, 0x38, 0xb5, 0x41, 0xe6, 0xff, 0x87, 0x07, 0x0e, + 0x21, 0x77, 0x77, 0x8b, 0xdf, 0x7c, 0x41, 0xad, 0xfa, 0xe8, 0x9a, 0x1b, 0xc0, 0x59, 0x60, 0xc2, + 0xb8, 0xe7, 0x76, 0x03, 0xc2, 0xa5, 0x5b, 0xa9, 0x0a, 0x54, 0x4e, 0x60, 0x56, 0x82, 0x05, 0xc4, + 0xfc, 0xa6, 0x01, 0xc5, 0x21, 0xfc, 0x0f, 0xe5, 0xa8, 0xff, 0xa1, 0x94, 0xf0, 0x3d, 0x04, 0x49, + 0xdf, 0xc3, 0xb3, 0xa3, 0xcd, 0xc6, 0x20, 0x3e, 0x87, 0x7f, 0x33, 0x60, 0x2e, 0xe1, 0xa3, 0x40, + 0xbb, 0x30, 0xdf, 0x71, 0x1b, 0x52, 0xbf, 0xb8, 0x68, 0xf9, 0xbb, 0x0c, 0x26, 0xba, 0xf7, 0x04, + 0x9d, 0xc9, 0xcd, 0x14, 0xf8, 0x9d, 0x5e, 0x79, 0x41, 0x11, 0x89, 0x21, 0xe0, 0x54, 0x8a, 0xa8, + 0x03, 0xc5, 0x1d, 0x9b, 0xb4, 0x1a, 0xe1, 0x12, 0x1c, 0x51, 0x93, 0xb8, 0x20, 0xa8, 0x71, 0xf7, + 0x9c, 0xfc, 0x87, 0x15, 0x17, 0xf3, 0x0a, 0x4c, 0x47, 0x9d, 0xb5, 0x03, 0x4c, 0xde, 0x19, 0xc8, + 0x5b, 0x9e, 0x23, 0xa6, 0x6e, 0x52, 0x20, 0xe4, 0x2b, 0x78, 0x03, 0xd3, 0x72, 0xf3, 0x27, 0x63, + 0x30, 0x53, 0x6d, 0x75, 0xc9, 0xb3, 0x1e, 0x21, 0xd2, 0x3e, 0xad, 0xc0, 0x4c, 0xc7, 0x23, 0x7b, + 0x36, 0xb9, 0x55, 0x23, 0x2d, 0x52, 0x0f, 0x5c, 0x4f, 0xd0, 0x3f, 0x2d, 0xaa, 0xcf, 0x6c, 0x46, + 0xc1, 0x38, 0x8e, 0x8f, 0x9e, 0x81, 0x69, 0xab, 0x1e, 0xd8, 0x7b, 0x44, 0x51, 0xe0, 0x0d, 0x78, + 0x9b, 0xa0, 0x30, 0x5d, 0x89, 0x40, 0x71, 0x0c, 0x1b, 0x7d, 0x04, 0x16, 0xfc, 0xba, 0xd5, 0x22, + 0x57, 0x3b, 0x82, 0xd5, 0xf2, 0x2e, 0xa9, 0xdf, 0xdc, 0x74, 0x6d, 0x27, 0x10, 0xde, 0x88, 0x87, + 0x04, 0xa5, 0x85, 0x5a, 0x1f, 0x3c, 0xdc, 0x97, 0x02, 0xfa, 0x43, 0x03, 0xce, 0x74, 0x3c, 0xb2, + 0xe9, 0xb9, 0x6d, 0x97, 0x8a, 0x99, 0x84, 0x89, 0x2e, 0x4c, 0xd5, 0x6b, 0x23, 0xca, 0x53, 0x5e, + 0x92, 0x74, 0x11, 0xbe, 0xfd, 0xa0, 0x57, 0x3e, 0xb3, 0x79, 0x58, 0x03, 0xf0, 0xe1, 0xed, 0x43, + 0x7f, 0x6c, 0xc0, 0xd9, 0x8e, 0xeb, 0x07, 0x87, 0x74, 0xa1, 0x70, 0xac, 0x5d, 0x30, 0x0f, 0x7a, + 0xe5, 0xb3, 0x9b, 0x87, 0xb6, 0x00, 0xdf, 0xa5, 0x85, 0xe6, 0xc1, 0x24, 0xcc, 0x69, 0x6b, 0x4f, + 0xd8, 0xaf, 0x4f, 0xc3, 0x09, 0xb9, 0x18, 0x42, 0xb1, 0x5e, 0x0a, 0xfd, 0x0d, 0x15, 0x1d, 0x88, + 0xa3, 0xb8, 0x74, 0xdd, 0xa9, 0xa5, 0xc8, 0x6b, 0xc7, 0xd6, 0xdd, 0x66, 0x04, 0x8a, 0x63, 0xd8, + 0x68, 0x15, 0x4e, 0x8a, 0x12, 0x4c, 0x3a, 0x2d, 0xbb, 0x6e, 0x2d, 0xbb, 0x5d, 0xb1, 0xe4, 0x0a, + 0xd5, 0xd3, 0x07, 0xbd, 0xf2, 0xc9, 0xcd, 0x24, 0x18, 0xa7, 0xd5, 0x41, 0x6b, 0x30, 0x6f, 0x75, + 0x03, 0x57, 0xf5, 0xff, 0xbc, 0x43, 0x25, 0x45, 0x83, 0x2d, 0xad, 0x22, 0x17, 0x29, 0x95, 0x14, + 0x38, 0x4e, 0xad, 0x85, 0x36, 0x63, 0xd4, 0x6a, 0xa4, 0xee, 0x3a, 0x0d, 0x3e, 0xcb, 0x85, 0x50, + 0x0b, 0xaf, 0xa4, 0xe0, 0xe0, 0xd4, 0x9a, 0xa8, 0x05, 0xd3, 0x6d, 0xeb, 0xf6, 0x55, 0xc7, 0xda, + 0xb3, 0xec, 0x16, 0x65, 0x22, 0x7c, 0x18, 0xfd, 0x0d, 0xeb, 0x6e, 0x60, 0xb7, 0x96, 0xf8, 0x75, + 0xde, 0xd2, 0xaa, 0x13, 0x5c, 0xf6, 0x6a, 0x01, 0xd5, 0xd6, 0xb8, 0x72, 0xb4, 0x1e, 0xa1, 0x85, + 0x63, 0xb4, 0xd1, 0x65, 0x38, 0xc5, 0xb6, 0xe3, 0x8a, 0x7b, 0xcb, 0x59, 0x21, 0x2d, 0x6b, 0x5f, + 0x76, 0x60, 0x82, 0x75, 0xe0, 0xfe, 0x83, 0x5e, 0xf9, 0x54, 0x2d, 0x0d, 0x01, 0xa7, 0xd7, 0x43, + 0x16, 0x3c, 0x10, 0x05, 0x60, 0xb2, 0x67, 0xfb, 0xb6, 0xeb, 0x70, 0x4f, 0x44, 0x31, 0xf4, 0x44, + 0xd4, 0xfa, 0xa3, 0xe1, 0xc3, 0x68, 0xa0, 0x5f, 0x37, 0x60, 0x3e, 0x6d, 0x1b, 0x2e, 0x94, 0xb2, + 0xb8, 0xac, 0x88, 0x6d, 0x2d, 0xbe, 0x22, 0x52, 0x0f, 0x85, 0xd4, 0x46, 0xa0, 0x97, 0x0d, 0x98, + 0xb2, 0x34, 0x2b, 0x6a, 0x01, 0x58, 0xab, 0x2e, 0x8d, 0x6a, 0xcb, 0x87, 0x14, 0xab, 0xb3, 0x07, + 0xbd, 0x72, 0xc4, 0x52, 0xc3, 0x11, 0x8e, 0xe8, 0x37, 0x0c, 0x38, 0x95, 0xba, 0xc7, 0x17, 0x26, + 0x8f, 0x63, 0x84, 0xd8, 0x22, 0x49, 0x3f, 0x73, 0xd2, 0x9b, 0x81, 0x5e, 0x37, 0x94, 0x28, 0x5b, + 0x97, 0xde, 0x94, 0x29, 0xd6, 0xb4, 0x2b, 0x23, 0x1a, 0x8e, 0xa1, 0x42, 0x20, 0x09, 0x57, 0x4f, + 0x6a, 0x92, 0x51, 0x16, 0xe2, 0x38, 0x7b, 0xf4, 0x79, 0x43, 0x8a, 0x46, 0xd5, 0xa2, 0x13, 0xc7, + 0xd5, 0x22, 0x14, 0x4a, 0x5a, 0xd5, 0xa0, 0x18, 0x73, 0xf4, 0x51, 0x58, 0xb4, 0xb6, 0x5d, 0x2f, + 0x48, 0xdd, 0x7c, 0x0b, 0xd3, 0x6c, 0x1b, 0x9d, 0x3d, 0xe8, 0x95, 0x17, 0x2b, 0x7d, 0xb1, 0xf0, + 0x21, 0x14, 0xcc, 0xdf, 0x2d, 0xc0, 0x14, 0x57, 0xf2, 0x85, 0xe8, 0xfa, 0x86, 0x01, 0x0f, 0xd6, + 0xbb, 0x9e, 0x47, 0x9c, 0xa0, 0x16, 0x90, 0x4e, 0x52, 0x70, 0x19, 0xc7, 0x2a, 0xb8, 0x1e, 0x3a, + 0xe8, 0x95, 0x1f, 0x5c, 0x3e, 0x84, 0x3f, 0x3e, 0xb4, 0x75, 0xe8, 0x2f, 0x0c, 0x30, 0x05, 0x42, + 0xd5, 0xaa, 0xdf, 0x6c, 0x7a, 0x6e, 0xd7, 0x69, 0x24, 0x3b, 0x91, 0x3b, 0xd6, 0x4e, 0x3c, 0x72, + 0xd0, 0x2b, 0x9b, 0xcb, 0x77, 0x6d, 0x05, 0x1e, 0xa0, 0xa5, 0xe8, 0x59, 0x98, 0x13, 0x58, 0xe7, + 0x6f, 0x77, 0x88, 0x67, 0x53, 0x75, 0x5a, 0xdc, 0xa7, 0x87, 0x21, 0x0a, 0x71, 0x04, 0x9c, 0xac, + 0x83, 0x7c, 0x98, 0xb8, 0x45, 0xec, 0xe6, 0x6e, 0x20, 0xd5, 0xa7, 0x11, 0xe3, 0x12, 0x84, 0xc1, + 0x7f, 0x9d, 0xd3, 0xac, 0x4e, 0x1e, 0xf4, 0xca, 0x13, 0xe2, 0x0f, 0x96, 0x9c, 0xd0, 0x06, 0x4c, + 0x73, 0x13, 0x6c, 0xd3, 0x76, 0x9a, 0x9b, 0xae, 0xc3, 0x6f, 0xf3, 0x4b, 0xd5, 0x47, 0xa4, 0xc0, + 0xaf, 0x45, 0xa0, 0x77, 0x7a, 0xe5, 0x29, 0xf9, 0x7b, 0x6b, 0xbf, 0x43, 0x70, 0xac, 0xb6, 0xf9, + 0xcd, 0x02, 0x80, 0x5c, 0xae, 0xa4, 0x83, 0xfe, 0x0f, 0x94, 0x7c, 0x12, 0x70, 0xae, 0xc2, 0x79, + 0xce, 0xef, 0x24, 0x64, 0x21, 0x0e, 0xe1, 0xe8, 0x26, 0x14, 0x3a, 0x56, 0xd7, 0x27, 0x62, 0xf2, + 0x2f, 0x65, 0x32, 0xf9, 0x9b, 0x94, 0x22, 0xb7, 0xb9, 0xd8, 0x4f, 0xcc, 0x79, 0xa0, 0x4f, 0x1b, + 0x00, 0x24, 0x3a, 0x61, 0x23, 0xfb, 0x3e, 0x04, 0xcb, 0x70, 0x4e, 0xe9, 0x18, 0x54, 0xa7, 0x0f, + 0x7a, 0x65, 0xd0, 0xa6, 0x5e, 0x63, 0x8b, 0x6e, 0x41, 0xd1, 0x92, 0x67, 0xfe, 0xd8, 0x71, 0x9c, + 0xf9, 0xcc, 0x14, 0x52, 0x8b, 0x56, 0x31, 0x43, 0x9f, 0x31, 0x60, 0xda, 0x27, 0x81, 0x98, 0x2a, + 0x7a, 0xf2, 0x08, 0x85, 0x77, 0xc4, 0x45, 0x57, 0x8b, 0xd0, 0xe4, 0x27, 0x68, 0xb4, 0x0c, 0xc7, + 0xf8, 0xf2, 0x98, 0x12, 0x12, 0x5c, 0x24, 0x56, 0x83, 0x78, 0xc2, 0x3d, 0x25, 0x74, 0xa9, 0x8d, + 0x91, 0x1b, 0x13, 0xa1, 0x2a, 0x62, 0x4a, 0x62, 0xa5, 0x38, 0xc1, 0xdd, 0xfc, 0xab, 0x29, 0x98, + 0x96, 0xab, 0x38, 0x54, 0xab, 0xb9, 0x57, 0xa5, 0x8f, 0x5a, 0xbd, 0xac, 0x03, 0x71, 0x14, 0x97, + 0x56, 0xe6, 0xfb, 0x24, 0xaa, 0x55, 0xab, 0xca, 0x35, 0x1d, 0x88, 0xa3, 0xb8, 0xa8, 0x0d, 0x05, + 0x3f, 0x20, 0x1d, 0x79, 0x09, 0x39, 0xe2, 0x1d, 0x59, 0xb8, 0x39, 0xc3, 0x6b, 0x06, 0xfa, 0xcf, + 0xc7, 0x9c, 0x0b, 0x73, 0x0c, 0x06, 0x11, 0x5f, 0xa1, 0x58, 0x99, 0xd9, 0x6c, 0x8e, 0xa8, 0x1b, + 0x92, 0x2f, 0x90, 0x68, 0x19, 0x8e, 0xb1, 0x4f, 0xd1, 0xb4, 0x0b, 0xc7, 0xa8, 0x69, 0x3f, 0x0f, + 0xc5, 0xb6, 0x75, 0xbb, 0xd6, 0xf5, 0x9a, 0x47, 0xd7, 0xe8, 0x45, 0x7c, 0x10, 0xa7, 0x82, 0x15, + 0x3d, 0xf4, 0x8a, 0xa1, 0xed, 0xf7, 0x09, 0x46, 0xfc, 0x7a, 0xb6, 0xfb, 0x5d, 0x09, 0xaa, 0xbe, + 0x3b, 0x3f, 0xa1, 0xf7, 0x16, 0xef, 0xb9, 0xde, 0x4b, 0x75, 0x38, 0xbe, 0x41, 0x94, 0x0e, 0x57, + 0x3a, 0x56, 0x1d, 0x6e, 0x39, 0xc2, 0x0c, 0xc7, 0x98, 0xb3, 0xf6, 0xf0, 0x3d, 0xa7, 0xda, 0x03, + 0xc7, 0xda, 0x9e, 0x5a, 0x84, 0x19, 0x8e, 0x31, 0xef, 0x6f, 0xec, 0x4d, 0x1e, 0x8f, 0xb1, 0x37, + 0x95, 0x81, 0xb1, 0x77, 0xb8, 0x1e, 0x7c, 0x62, 0x54, 0x3d, 0x18, 0x5d, 0x02, 0xd4, 0xd8, 0x77, + 0xac, 0xb6, 0x5d, 0x17, 0x87, 0x25, 0x93, 0x59, 0xd3, 0xcc, 0x19, 0xb0, 0x28, 0x0e, 0x32, 0xb4, + 0x92, 0xc0, 0xc0, 0x29, 0xb5, 0x50, 0x00, 0xc5, 0x8e, 0x54, 0x77, 0x66, 0xb2, 0x58, 0xfd, 0x52, + 0xfd, 0xe1, 0xf7, 0xd4, 0x74, 0xe3, 0xc9, 0x12, 0xac, 0x38, 0x99, 0xff, 0x61, 0xc0, 0xec, 0x72, + 0xcb, 0xed, 0x36, 0xae, 0x5b, 0x41, 0x7d, 0x97, 0x5f, 0xaa, 0xa2, 0x67, 0xa0, 0x68, 0x3b, 0x01, + 0xf1, 0xf6, 0xac, 0x96, 0x90, 0x28, 0xa6, 0xbc, 0x77, 0x5e, 0x15, 0xe5, 0x77, 0x7a, 0xe5, 0xe9, + 0x95, 0xae, 0xc7, 0xa2, 0x15, 0xf9, 0xf9, 0x82, 0x55, 0x1d, 0xf4, 0x55, 0x03, 0xe6, 0xf8, 0xb5, + 0xec, 0x8a, 0x15, 0x58, 0x57, 0xba, 0xc4, 0xb3, 0x89, 0xbc, 0x98, 0x1d, 0xf1, 0x68, 0x89, 0xb7, + 0x55, 0x32, 0xd8, 0x0f, 0xf5, 0xda, 0xf5, 0x38, 0x67, 0x9c, 0x6c, 0x8c, 0xf9, 0xc5, 0x3c, 0xdc, + 0xdf, 0x97, 0x16, 0x5a, 0x84, 0x9c, 0xdd, 0x10, 0x5d, 0x07, 0x41, 0x37, 0xb7, 0xda, 0xc0, 0x39, + 0xbb, 0x81, 0x96, 0x98, 0x8a, 0xe6, 0x11, 0xdf, 0x97, 0x77, 0x74, 0x25, 0xa5, 0x4d, 0x89, 0x52, + 0xac, 0x61, 0xa0, 0x32, 0x14, 0x5a, 0xd6, 0x36, 0x69, 0x09, 0xf5, 0x9b, 0x29, 0x7d, 0x6b, 0xb4, + 0x00, 0xf3, 0x72, 0xf4, 0x0b, 0x06, 0x00, 0x6f, 0x20, 0x55, 0xde, 0x85, 0x5c, 0xc3, 0xd9, 0x0e, + 0x13, 0xa5, 0xcc, 0x5b, 0x19, 0xfe, 0xc7, 0x1a, 0x57, 0xb4, 0x05, 0xe3, 0x54, 0xff, 0x73, 0x1b, + 0x47, 0x16, 0x63, 0xec, 0x4e, 0x62, 0x93, 0xd1, 0xc0, 0x82, 0x16, 0x1d, 0x2b, 0x8f, 0x04, 0x5d, + 0xcf, 0xa1, 0x43, 0xcb, 0x04, 0x57, 0x91, 0xb7, 0x02, 0xab, 0x52, 0xac, 0x61, 0x98, 0x7f, 0x90, + 0x83, 0xf9, 0xb4, 0xa6, 0x53, 0xf9, 0x30, 0xce, 0x5b, 0x2b, 0x2c, 0xc9, 0x0f, 0x66, 0x3f, 0x3e, + 0x22, 0xc2, 0x40, 0xdd, 0xc3, 0x8b, 0x18, 0x28, 0xc1, 0x17, 0x7d, 0x50, 0x8d, 0x50, 0xee, 0x88, + 0x23, 0xa4, 0x28, 0xc7, 0x46, 0xe9, 0x21, 0x18, 0xf3, 0xe9, 0xcc, 0xe7, 0xa3, 0xfe, 0x7e, 0x36, + 0x47, 0x0c, 0x42, 0x31, 0xba, 0x8e, 0x1d, 0x88, 0x10, 0x62, 0x85, 0x71, 0xd5, 0xb1, 0x03, 0xcc, + 0x20, 0xe6, 0x97, 0x73, 0xb0, 0xd8, 0xbf, 0x53, 0xe8, 0xcb, 0x06, 0x40, 0x83, 0x6a, 0xf7, 0x74, + 0x49, 0xca, 0x88, 0x0c, 0xeb, 0xb8, 0xc6, 0x70, 0x45, 0x72, 0x0a, 0xc3, 0x73, 0x54, 0x91, 0x8f, + 0xb5, 0x86, 0xa0, 0xc7, 0xe4, 0xd2, 0xdf, 0xb0, 0xda, 0x52, 0x01, 0x55, 0x75, 0xd6, 0x15, 0x04, + 0x6b, 0x58, 0xd4, 0x7c, 0x73, 0xac, 0x36, 0xf1, 0x3b, 0x96, 0x8a, 0x11, 0x67, 0xe6, 0xdb, 0x86, + 0x2c, 0xc4, 0x21, 0xdc, 0x6c, 0xc1, 0xc3, 0x03, 0xb4, 0x33, 0xa3, 0x78, 0x5d, 0xf3, 0xdf, 0x0d, + 0x38, 0xbd, 0xdc, 0xea, 0xfa, 0x01, 0xf1, 0xfe, 0xc7, 0x44, 0x3b, 0xfd, 0xa7, 0x01, 0x0f, 0xf4, + 0xe9, 0xf3, 0x3d, 0x08, 0x7a, 0x7a, 0x31, 0x1a, 0xf4, 0x74, 0x75, 0xd4, 0x25, 0x9d, 0xda, 0x8f, + 0x3e, 0xb1, 0x4f, 0x01, 0x9c, 0xa0, 0xa7, 0x56, 0xc3, 0x6d, 0x66, 0x24, 0x37, 0x1f, 0x86, 0xc2, + 0xc7, 0xa9, 0xfc, 0x89, 0xaf, 0x31, 0x26, 0x94, 0x30, 0x87, 0x99, 0x1f, 0x00, 0x11, 0x21, 0x14, + 0xdb, 0x3c, 0xc6, 0x20, 0x9b, 0xc7, 0xfc, 0xdb, 0x1c, 0x68, 0x66, 0xff, 0x3d, 0x58, 0x94, 0x4e, + 0x64, 0x51, 0x8e, 0x68, 0xc8, 0x6b, 0x4e, 0x8c, 0x7e, 0x4f, 0x01, 0xf6, 0x62, 0x4f, 0x01, 0x36, + 0x32, 0xe3, 0x78, 0xf8, 0x4b, 0x80, 0xef, 0x19, 0xf0, 0x40, 0x88, 0x9c, 0xf4, 0xc8, 0xdd, 0xfd, + 0x84, 0x79, 0x12, 0x26, 0xad, 0xb0, 0x9a, 0x58, 0x03, 0xea, 0xf5, 0x8b, 0x46, 0x11, 0xeb, 0x78, + 0x61, 0xe0, 0x71, 0xfe, 0x88, 0x81, 0xc7, 0x63, 0x87, 0x07, 0x1e, 0x9b, 0x3f, 0xce, 0xc1, 0x99, + 0x64, 0xcf, 0xe4, 0xde, 0x18, 0xec, 0xc2, 0xfa, 0x29, 0x98, 0x0a, 0x44, 0x05, 0xed, 0xa4, 0x57, + 0x6f, 0xb7, 0xb6, 0x34, 0x18, 0x8e, 0x60, 0xd2, 0x9a, 0x75, 0xbe, 0x2b, 0x6b, 0x75, 0xb7, 0x23, + 0xc3, 0xd6, 0x55, 0xcd, 0x65, 0x0d, 0x86, 0x23, 0x98, 0x2a, 0x20, 0x70, 0xec, 0xd8, 0x03, 0x02, + 0x6b, 0x70, 0x4a, 0x86, 0x40, 0x5d, 0x70, 0xbd, 0x65, 0xb7, 0xdd, 0x69, 0x11, 0x11, 0xb8, 0x4e, + 0x1b, 0x7b, 0x46, 0x54, 0x39, 0x85, 0xd3, 0x90, 0x70, 0x7a, 0x5d, 0xf3, 0x7b, 0x79, 0x38, 0x19, + 0x0e, 0xfb, 0xb2, 0xeb, 0x34, 0x6c, 0x16, 0x48, 0xf6, 0x34, 0x8c, 0x05, 0xfb, 0x1d, 0x39, 0xd8, + 0xff, 0x4b, 0x36, 0x67, 0x6b, 0xbf, 0x43, 0x67, 0xfb, 0x74, 0x4a, 0x15, 0xe6, 0x13, 0x65, 0x95, + 0xd0, 0x9a, 0xda, 0x1d, 0x7c, 0x06, 0x9e, 0x88, 0xae, 0xe6, 0x3b, 0xbd, 0x72, 0xca, 0xd3, 0xc5, + 0x25, 0x45, 0x29, 0xba, 0xe6, 0xd1, 0x0d, 0x98, 0x6e, 0x59, 0x7e, 0x70, 0xb5, 0xd3, 0xb0, 0x02, + 0xb2, 0x65, 0xb7, 0x89, 0xd8, 0x73, 0xc3, 0x44, 0x83, 0xab, 0x4b, 0xdc, 0xb5, 0x08, 0x25, 0x1c, + 0xa3, 0x8c, 0xf6, 0x00, 0xd1, 0x92, 0x2d, 0xcf, 0x72, 0x7c, 0xde, 0x2b, 0xca, 0x6f, 0xf8, 0xe8, + 0x73, 0x65, 0x96, 0xad, 0x25, 0xa8, 0xe1, 0x14, 0x0e, 0xe8, 0x11, 0x18, 0xf7, 0x88, 0xe5, 0x8b, + 0xc9, 0x2c, 0x85, 0xfb, 0x1f, 0xb3, 0x52, 0x2c, 0xa0, 0xfa, 0x86, 0x1a, 0xbf, 0xcb, 0x86, 0xfa, + 0xa1, 0x01, 0xd3, 0xe1, 0x34, 0xdd, 0x03, 0x21, 0xd9, 0x8e, 0x0a, 0xc9, 0x8b, 0x59, 0x1d, 0x89, + 0x7d, 0xe4, 0xe2, 0x9f, 0x8c, 0xeb, 0xfd, 0x63, 0xd1, 0xc0, 0x9f, 0x80, 0x92, 0xdc, 0xd5, 0x52, + 0xfb, 0x1c, 0xd1, 0xba, 0x8d, 0xe8, 0x25, 0xda, 0x2b, 0x16, 0xc1, 0x04, 0x87, 0xfc, 0xa8, 0x58, + 0x6e, 0x08, 0x91, 0x2b, 0x96, 0xbd, 0x12, 0xcb, 0x52, 0x14, 0xa7, 0x89, 0x65, 0x59, 0x07, 0x5d, + 0x85, 0xd3, 0x1d, 0xcf, 0x65, 0x2f, 0x1b, 0x57, 0x88, 0xd5, 0x68, 0xd9, 0x0e, 0x91, 0x2e, 0x04, + 0x1e, 0x43, 0xf0, 0xc0, 0x41, 0xaf, 0x7c, 0x7a, 0x33, 0x1d, 0x05, 0xf7, 0xab, 0x1b, 0x7d, 0x8d, + 0x33, 0x36, 0xc0, 0x6b, 0x9c, 0xcf, 0x2a, 0x47, 0x1d, 0xf1, 0xc5, 0x9b, 0x98, 0x0f, 0x67, 0x35, + 0x95, 0x29, 0xc7, 0x7a, 0xb8, 0xa4, 0x2a, 0x82, 0x29, 0x56, 0xec, 0xfb, 0x7b, 0x83, 0xc6, 0x8f, + 0xe8, 0x0d, 0x0a, 0x83, 0xaa, 0x27, 0x7e, 0x9a, 0x41, 0xd5, 0xc5, 0xb7, 0x54, 0x50, 0xf5, 0xab, + 0x05, 0x98, 0x8d, 0x6b, 0x20, 0xc7, 0xff, 0xd2, 0xe8, 0x57, 0x0c, 0x98, 0x95, 0xbb, 0x87, 0xf3, + 0x24, 0xd2, 0xcf, 0xbf, 0x96, 0xd1, 0xa6, 0xe5, 0xba, 0x94, 0x7a, 0x0b, 0xbb, 0x15, 0xe3, 0x86, + 0x13, 0xfc, 0xd1, 0x0b, 0x30, 0xa9, 0xdc, 0xe1, 0x47, 0x7a, 0x76, 0x34, 0xc3, 0xb4, 0xa8, 0x90, + 0x04, 0xd6, 0xe9, 0xa1, 0x57, 0x0d, 0x80, 0xba, 0x14, 0x73, 0x72, 0x77, 0x5d, 0xc9, 0x6a, 0x77, + 0x29, 0x01, 0x1a, 0x2a, 0xcb, 0xaa, 0xc8, 0xc7, 0x1a, 0x63, 0xf4, 0x45, 0xe6, 0x08, 0x57, 0xda, + 0x1d, 0xdd, 0x4f, 0xf9, 0xd1, 0xe3, 0x60, 0x0f, 0x51, 0x4c, 0x43, 0x55, 0x4a, 0x03, 0xf9, 0x38, + 0xd2, 0x08, 0xf3, 0x69, 0x50, 0x91, 0x8b, 0xf4, 0xd8, 0x62, 0xb1, 0x8b, 0x9b, 0x56, 0xb0, 0x2b, + 0x96, 0xa0, 0x3a, 0xb6, 0x2e, 0x48, 0x00, 0x0e, 0x71, 0xcc, 0x8f, 0xc1, 0xf4, 0xb3, 0x9e, 0xd5, + 0xd9, 0xb5, 0x99, 0xc3, 0x99, 0xda, 0x49, 0xef, 0x84, 0x09, 0xab, 0xd1, 0x48, 0x7b, 0x49, 0x5e, + 0xe1, 0xc5, 0x58, 0xc2, 0x07, 0x33, 0x89, 0xfe, 0xcc, 0x00, 0x14, 0xb9, 0x2b, 0x5b, 0xa7, 0xd6, + 0x3e, 0xb5, 0x8f, 0x76, 0x59, 0x69, 0x9a, 0x7d, 0x74, 0x51, 0x41, 0xb0, 0x86, 0x85, 0x5e, 0x36, + 0x60, 0x92, 0xff, 0xbd, 0xa6, 0xac, 0xfd, 0x91, 0x1f, 0xa2, 0x72, 0x89, 0xc2, 0x1a, 0x15, 0x2a, + 0xf4, 0x17, 0x43, 0x2e, 0x58, 0x67, 0x49, 0xc7, 0x6b, 0xd5, 0xd9, 0x69, 0x75, 0x6f, 0x37, 0xb6, + 0xc3, 0xf1, 0xea, 0x78, 0xee, 0x8e, 0xdd, 0x22, 0xf1, 0xf1, 0xda, 0xe4, 0xc5, 0x58, 0xc2, 0x07, + 0x1b, 0xaf, 0x6f, 0x19, 0x30, 0xbf, 0xea, 0x07, 0xb6, 0xbb, 0x42, 0xfc, 0x80, 0xca, 0x16, 0x7a, + 0x02, 0x75, 0x5b, 0x83, 0x44, 0x22, 0xaf, 0xc0, 0xac, 0xb8, 0x45, 0xec, 0x6e, 0xfb, 0x24, 0xd0, + 0x94, 0x79, 0xb5, 0x99, 0x97, 0x63, 0x70, 0x9c, 0xa8, 0x41, 0xa9, 0x88, 0xeb, 0xc4, 0x90, 0x4a, + 0x3e, 0x4a, 0xa5, 0x16, 0x83, 0xe3, 0x44, 0x0d, 0xf3, 0xbb, 0x79, 0x38, 0xc9, 0xba, 0x11, 0x7b, + 0x45, 0xf0, 0xf9, 0x7e, 0xaf, 0x08, 0x46, 0xdc, 0xcf, 0x8c, 0xd7, 0x11, 0xde, 0x10, 0xfc, 0xb2, + 0x01, 0x33, 0x8d, 0xe8, 0x48, 0x67, 0xe3, 0xa3, 0x49, 0x9b, 0x43, 0x1e, 0xb1, 0x14, 0x2b, 0xc4, + 0x71, 0xfe, 0xe8, 0x4b, 0x06, 0xcc, 0x44, 0x9b, 0x29, 0x8f, 0xf8, 0x63, 0x18, 0x24, 0x15, 0x62, + 0x1c, 0x2d, 0xf7, 0x71, 0xbc, 0x09, 0xe6, 0x5f, 0x1b, 0x62, 0x4a, 0x8f, 0x23, 0x44, 0x1e, 0xdd, + 0x82, 0x52, 0xd0, 0xf2, 0x79, 0xa1, 0xe8, 0xed, 0x88, 0x66, 0xe1, 0xd6, 0x5a, 0x8d, 0x91, 0xd3, + 0x34, 0x37, 0x51, 0x42, 0x35, 0x50, 0xc9, 0xcb, 0xfc, 0x9a, 0x01, 0xa5, 0x4b, 0xae, 0xdc, 0xce, + 0x1f, 0xcd, 0xc0, 0xe9, 0xa2, 0x74, 0x33, 0x75, 0x5f, 0x17, 0xaa, 0xfb, 0xcf, 0x44, 0x5c, 0x2e, + 0x0f, 0x6a, 0xb4, 0x97, 0x58, 0xc6, 0x1a, 0x4a, 0xea, 0x92, 0xbb, 0xdd, 0xd7, 0xa3, 0xf7, 0x9b, + 0x05, 0x38, 0xf1, 0x9c, 0xb5, 0x4f, 0x9c, 0xc0, 0x1a, 0xfe, 0xc0, 0x7e, 0x12, 0x26, 0xad, 0x0e, + 0x8b, 0x98, 0xd5, 0xf4, 0xed, 0xd0, 0x8b, 0x11, 0x82, 0xb0, 0x8e, 0x17, 0x9e, 0x2b, 0x3c, 0x81, + 0x46, 0xda, 0x89, 0xb0, 0x1c, 0x83, 0xe3, 0x44, 0x0d, 0x74, 0x09, 0x90, 0x78, 0x0e, 0x58, 0xa9, + 0xd7, 0xdd, 0xae, 0xc3, 0x4f, 0x16, 0xee, 0xe0, 0x50, 0x86, 0xdf, 0x7a, 0x02, 0x03, 0xa7, 0xd4, + 0x42, 0x1f, 0x81, 0x85, 0x3a, 0xa3, 0x2c, 0xcc, 0x00, 0x9d, 0x22, 0x37, 0x05, 0x55, 0xb4, 0xfa, + 0x72, 0x1f, 0x3c, 0xdc, 0x97, 0x02, 0x6d, 0xa9, 0x1f, 0xb8, 0x9e, 0xd5, 0x24, 0x3a, 0xdd, 0xf1, + 0x68, 0x4b, 0x6b, 0x09, 0x0c, 0x9c, 0x52, 0x0b, 0x7d, 0x0a, 0x4a, 0xc1, 0xae, 0x47, 0xfc, 0x5d, + 0xb7, 0xd5, 0x10, 0x17, 0xf8, 0x23, 0x7a, 0xbd, 0xc4, 0xec, 0x6f, 0x49, 0xaa, 0xda, 0xf2, 0x96, + 0x45, 0x38, 0xe4, 0x89, 0x3c, 0x18, 0xf7, 0xeb, 0x6e, 0x87, 0xf8, 0x42, 0x7d, 0xbe, 0x94, 0x09, + 0x77, 0xe6, 0xc5, 0xd1, 0xfc, 0x6d, 0x8c, 0x03, 0x16, 0x9c, 0xcc, 0x6f, 0xe7, 0x60, 0x4a, 0x47, + 0x1c, 0xe0, 0x88, 0xf8, 0xb4, 0x01, 0x53, 0x75, 0xd7, 0x09, 0x3c, 0xb7, 0xc5, 0x7d, 0x49, 0xd9, + 0x08, 0x77, 0x4a, 0x6a, 0x85, 0x04, 0x96, 0xdd, 0xd2, 0xdc, 0x52, 0x1a, 0x1b, 0x1c, 0x61, 0x8a, + 0x3e, 0x67, 0xc0, 0x4c, 0x18, 0x6c, 0x15, 0x3a, 0xb5, 0x32, 0x6d, 0x88, 0x3a, 0x71, 0xcf, 0x47, + 0x39, 0xe1, 0x38, 0x6b, 0x73, 0x1b, 0x66, 0xe3, 0xb3, 0x4d, 0x87, 0xb2, 0x63, 0x89, 0xbd, 0x9e, + 0x0f, 0x87, 0x72, 0xd3, 0xf2, 0x7d, 0xcc, 0x20, 0xe8, 0x5d, 0x50, 0x6c, 0x5b, 0x5e, 0xd3, 0x76, + 0xac, 0x16, 0x1b, 0xc5, 0xbc, 0x76, 0x20, 0x89, 0x72, 0xac, 0x30, 0xcc, 0x1f, 0x8d, 0xc1, 0xa4, + 0x66, 0xf5, 0x1c, 0xbf, 0x05, 0x13, 0xc9, 0x50, 0x90, 0xcf, 0x30, 0x43, 0xc1, 0xf3, 0x00, 0x3b, + 0xb6, 0x63, 0xfb, 0xbb, 0x47, 0xcc, 0x7d, 0xc0, 0x2e, 0x3f, 0x2f, 0x28, 0x0a, 0x58, 0xa3, 0x16, + 0xde, 0x30, 0x15, 0x0e, 0xc9, 0x08, 0xf3, 0xaa, 0xa1, 0x09, 0x8f, 0xf1, 0x2c, 0x6e, 0xd4, 0xb5, + 0x89, 0x59, 0x92, 0xc2, 0xe4, 0xbc, 0x13, 0x78, 0xfb, 0x87, 0xca, 0x98, 0x2d, 0x28, 0x7a, 0xc4, + 0xef, 0xb6, 0xa9, 0x2d, 0x36, 0x31, 0xf4, 0x30, 0xb0, 0x68, 0x04, 0x2c, 0xea, 0x63, 0x45, 0x69, + 0xf1, 0x69, 0x38, 0x11, 0x69, 0x02, 0x9a, 0x85, 0xfc, 0x4d, 0xb2, 0xcf, 0xd7, 0x09, 0xa6, 0x3f, + 0xd1, 0x7c, 0xe4, 0x1e, 0x4e, 0x0c, 0xcb, 0xfb, 0x73, 0x4f, 0x19, 0xa6, 0x0b, 0xa9, 0xa6, 0xf5, + 0x51, 0xae, 0x49, 0xe8, 0x5c, 0xb4, 0xb4, 0xe4, 0x07, 0x6a, 0x2e, 0x78, 0xcc, 0x09, 0x87, 0x99, + 0x3f, 0x1e, 0x07, 0x71, 0x49, 0x3c, 0xc0, 0xe1, 0xa3, 0xdf, 0x0d, 0xe5, 0x8e, 0x70, 0x37, 0x74, + 0x09, 0xa6, 0x6c, 0xc7, 0x0e, 0x6c, 0xab, 0xc5, 0xdc, 0x26, 0x42, 0x38, 0xca, 0x88, 0xd8, 0xa9, + 0x55, 0x0d, 0x96, 0x42, 0x27, 0x52, 0x17, 0x5d, 0x81, 0x02, 0x93, 0x1e, 0x62, 0x01, 0x0f, 0x7f, + 0x93, 0xcd, 0x82, 0x18, 0xf8, 0x33, 0x19, 0x4e, 0x89, 0x69, 0xf4, 0x3c, 0xfb, 0x83, 0x32, 0x6c, + 0xc5, 0x3a, 0x0e, 0x35, 0xfa, 0x18, 0x1c, 0x27, 0x6a, 0x50, 0x2a, 0x3b, 0x96, 0xdd, 0xea, 0x7a, + 0x24, 0xa4, 0x32, 0x1e, 0xa5, 0x72, 0x21, 0x06, 0xc7, 0x89, 0x1a, 0x68, 0x07, 0xa6, 0x44, 0x19, + 0x8f, 0x24, 0x9a, 0x38, 0x62, 0x2f, 0x59, 0xc4, 0xd8, 0x05, 0x8d, 0x12, 0x8e, 0xd0, 0x45, 0x5d, + 0x98, 0xb3, 0x9d, 0xba, 0xeb, 0xd4, 0x5b, 0x5d, 0xdf, 0xde, 0x23, 0xe1, 0x1b, 0x95, 0xa3, 0x30, + 0x3b, 0x75, 0xd0, 0x2b, 0xcf, 0xad, 0xc6, 0xc9, 0xe1, 0x24, 0x07, 0xf4, 0x8a, 0x01, 0xa7, 0xea, + 0xae, 0xe3, 0xb3, 0xe7, 0xd4, 0x7b, 0xe4, 0xbc, 0xe7, 0xb9, 0x1e, 0xe7, 0x5d, 0x3a, 0x22, 0x6f, + 0xe6, 0xad, 0x5b, 0x4e, 0x23, 0x89, 0xd3, 0x39, 0xa1, 0x17, 0xa1, 0xd8, 0xf1, 0xdc, 0x3d, 0xbb, + 0x41, 0x3c, 0x11, 0x95, 0xb6, 0x96, 0x45, 0x7a, 0x87, 0x4d, 0x41, 0x33, 0x3c, 0x7a, 0x64, 0x09, + 0x56, 0xfc, 0xcc, 0x37, 0x4a, 0x30, 0x1d, 0x45, 0x47, 0x9f, 0x04, 0xe8, 0x78, 0x6e, 0x9b, 0x04, + 0xbb, 0x44, 0xbd, 0x35, 0xd8, 0x18, 0x35, 0x8b, 0x80, 0xa4, 0x27, 0xe3, 0x42, 0xe8, 0x71, 0x11, + 0x96, 0x62, 0x8d, 0x23, 0xf2, 0x60, 0xe2, 0x26, 0x17, 0xa2, 0x42, 0xa7, 0x78, 0x2e, 0x13, 0x0d, + 0x48, 0x70, 0x66, 0x41, 0xf2, 0xa2, 0x08, 0x4b, 0x46, 0x68, 0x1b, 0xf2, 0xb7, 0xc8, 0x76, 0x36, + 0x2f, 0x73, 0xaf, 0x13, 0x61, 0x9b, 0x54, 0x27, 0x0e, 0x7a, 0xe5, 0xfc, 0x75, 0xb2, 0x8d, 0x29, + 0x71, 0xda, 0xaf, 0x06, 0xbf, 0xe1, 0x16, 0x47, 0xc5, 0x88, 0xfd, 0x8a, 0x5c, 0x97, 0xf3, 0x7e, + 0x89, 0x22, 0x2c, 0x19, 0xa1, 0x17, 0xa1, 0x74, 0xcb, 0xda, 0x23, 0x3b, 0x9e, 0xeb, 0x04, 0x22, + 0x18, 0x69, 0xc4, 0xf0, 0xf3, 0xeb, 0x92, 0x9c, 0xe0, 0xcb, 0xc4, 0xbb, 0x2a, 0xc4, 0x21, 0x3b, + 0xb4, 0x07, 0x45, 0x87, 0xdc, 0xc2, 0xa4, 0x65, 0xd7, 0x45, 0x98, 0xed, 0x88, 0xcb, 0x7a, 0x43, + 0x50, 0x13, 0x9c, 0x99, 0xdc, 0x93, 0x65, 0x58, 0xf1, 0xa2, 0x73, 0x79, 0xc3, 0xdd, 0x16, 0x07, + 0xd5, 0x88, 0x73, 0xa9, 0xec, 0x4c, 0x3e, 0x97, 0x97, 0xdc, 0x6d, 0x4c, 0x89, 0xd3, 0x3d, 0x52, + 0x57, 0x91, 0x30, 0xe2, 0x98, 0xda, 0xc8, 0x36, 0x02, 0x88, 0xef, 0x91, 0xb0, 0x14, 0x6b, 0x1c, + 0xe9, 0xd8, 0x36, 0x85, 0x1b, 0x50, 0x1c, 0x54, 0x23, 0x8e, 0x6d, 0xd4, 0xa9, 0xc8, 0xc7, 0x56, + 0x96, 0x61, 0xc5, 0x8b, 0xf2, 0xb5, 0x85, 0x3b, 0x2d, 0x9b, 0xa3, 0x2a, 0xea, 0x9c, 0xe3, 0x7c, + 0x65, 0x19, 0x56, 0xbc, 0xcc, 0xaf, 0x8d, 0xc3, 0x94, 0x9e, 0x46, 0x6b, 0x00, 0x1d, 0x41, 0xe9, + 0xc5, 0xb9, 0x61, 0xf4, 0x62, 0x6a, 0xd6, 0x68, 0xb7, 0x07, 0xd2, 0xb3, 0xb1, 0x9a, 0x99, 0x5a, + 0x18, 0x9a, 0x35, 0x5a, 0xa1, 0x8f, 0x23, 0x4c, 0x87, 0x08, 0x28, 0xa0, 0xca, 0x15, 0x57, 0x3f, + 0x0a, 0x51, 0xe5, 0x2a, 0xa2, 0x50, 0x3c, 0x06, 0x10, 0xa6, 0x93, 0x12, 0xb7, 0x4a, 0x4a, 0x6b, + 0xd3, 0xd2, 0x5c, 0x69, 0x58, 0xe8, 0x11, 0x18, 0xa7, 0x02, 0x9a, 0x34, 0xc4, 0x03, 0x54, 0x65, + 0x3b, 0x5e, 0x60, 0xa5, 0x58, 0x40, 0xd1, 0x53, 0x54, 0x97, 0x0a, 0xc5, 0xaa, 0x78, 0x57, 0x3a, + 0x1f, 0xea, 0x52, 0x21, 0x0c, 0x47, 0x30, 0x69, 0xd3, 0x09, 0x95, 0x82, 0x6c, 0x05, 0x6b, 0x4d, + 0x67, 0xa2, 0x11, 0x73, 0x18, 0xf3, 0x65, 0xc4, 0xa4, 0x26, 0x5b, 0x79, 0x05, 0xcd, 0x97, 0x11, + 0x83, 0xe3, 0x44, 0x0d, 0xda, 0x19, 0x71, 0x21, 0x36, 0xc9, 0xe3, 0x26, 0xfb, 0x5c, 0x65, 0xbd, + 0xa6, 0x5b, 0x04, 0x53, 0x6c, 0xea, 0x3f, 0x98, 0x5d, 0x4a, 0xb8, 0xc1, 0x4d, 0x82, 0xd1, 0x94, + 0xf7, 0x8f, 0xc1, 0x74, 0xf4, 0xac, 0xcc, 0xdc, 0xe9, 0xfd, 0xa7, 0x79, 0x38, 0xb9, 0xd1, 0xb4, + 0x9d, 0xdb, 0x31, 0x6f, 0x71, 0x5a, 0xaa, 0x56, 0x63, 0xd8, 0x54, 0xad, 0xe1, 0x63, 0x1a, 0x91, + 0x0b, 0x37, 0xfd, 0x31, 0x8d, 0x4c, 0x94, 0x1b, 0xc5, 0x45, 0x3f, 0x34, 0xe0, 0x41, 0xab, 0xc1, + 0xb5, 0x57, 0xab, 0x25, 0x4a, 0x43, 0xa6, 0x72, 0x47, 0xfb, 0x23, 0xca, 0xa2, 0x64, 0xe7, 0x97, + 0x2a, 0x87, 0x70, 0xe5, 0x33, 0xfe, 0x0e, 0xd1, 0x83, 0x07, 0x0f, 0x43, 0xc5, 0x87, 0x36, 0x7f, + 0xf1, 0x32, 0xbc, 0xfd, 0xae, 0x8c, 0x86, 0x5a, 0x2d, 0x9f, 0x36, 0xa0, 0xc4, 0x9d, 0xa1, 0x98, + 0xec, 0xd0, 0xa3, 0xc2, 0xea, 0xd8, 0xd7, 0x88, 0xe7, 0xcb, 0x1c, 0x52, 0x9a, 0x81, 0x57, 0xd9, + 0x5c, 0x15, 0x10, 0xac, 0x61, 0xd1, 0xc3, 0xf8, 0xa6, 0xed, 0x34, 0xc4, 0x34, 0xa9, 0xc3, 0xf8, + 0x39, 0xdb, 0x69, 0x60, 0x06, 0x51, 0xc7, 0x75, 0xbe, 0x6f, 0x42, 0x97, 0x37, 0x0c, 0x98, 0x66, + 0xcf, 0xf7, 0x42, 0xd3, 0xe3, 0x49, 0x15, 0x2d, 0xc2, 0x9b, 0x71, 0x26, 0x1a, 0x2d, 0x72, 0xa7, + 0x57, 0x9e, 0xe4, 0x0f, 0xfe, 0xa2, 0xc1, 0x23, 0x1f, 0x16, 0xfe, 0x0a, 0x16, 0xd3, 0x92, 0x1b, + 0xda, 0x9c, 0x56, 0xde, 0xb9, 0x9a, 0x24, 0x82, 0x43, 0x7a, 0xe6, 0x4b, 0x30, 0xa5, 0x3f, 0x05, + 0x40, 0x4f, 0xc2, 0x64, 0xc7, 0x76, 0x9a, 0xd1, 0x27, 0x63, 0xca, 0x43, 0xbb, 0x19, 0x82, 0xb0, + 0x8e, 0xc7, 0xaa, 0xb9, 0x61, 0xb5, 0x98, 0x63, 0x77, 0xd3, 0xd5, 0xab, 0x85, 0x7f, 0xcc, 0xdf, + 0xcb, 0xc3, 0xc9, 0x94, 0x27, 0x27, 0xe8, 0x55, 0x03, 0xc6, 0x59, 0xfc, 0xbb, 0x8c, 0x07, 0x79, + 0x21, 0xf3, 0x67, 0x2d, 0x4b, 0x2c, 0xcc, 0x5e, 0xac, 0x63, 0x75, 0x7c, 0xf2, 0x42, 0x2c, 0x98, + 0xa3, 0x5f, 0x33, 0x60, 0xd2, 0xd2, 0xb6, 0x1a, 0x0f, 0x91, 0xd9, 0xce, 0xbe, 0x31, 0x89, 0x9d, + 0xa5, 0x85, 0xf6, 0x85, 0x1b, 0x49, 0x6f, 0xcb, 0xe2, 0xfb, 0x60, 0x52, 0xeb, 0xc2, 0x30, 0x3b, + 0x64, 0xf1, 0x19, 0x98, 0x1d, 0x69, 0x87, 0x7d, 0x08, 0x86, 0x4d, 0x89, 0x46, 0x05, 0xd6, 0x2d, + 0xfd, 0x4d, 0xad, 0x1a, 0x71, 0xf1, 0xa8, 0x56, 0x40, 0xcd, 0x6d, 0x98, 0x8d, 0x1b, 0x57, 0x99, + 0xdf, 0x08, 0xbf, 0x07, 0x86, 0x4c, 0x62, 0x66, 0xfe, 0x79, 0x0e, 0x26, 0xc4, 0xbb, 0xb5, 0x7b, + 0x10, 0x15, 0x7b, 0x33, 0x72, 0x45, 0xb3, 0x9a, 0xc9, 0x73, 0xbb, 0xbe, 0x21, 0xb1, 0x7e, 0x2c, + 0x24, 0xf6, 0xb9, 0x6c, 0xd8, 0x1d, 0x1e, 0x0f, 0xfb, 0xc6, 0x18, 0xcc, 0xc4, 0xde, 0x01, 0x52, + 0x55, 0x25, 0x11, 0x06, 0x76, 0x35, 0xd3, 0xa7, 0x86, 0x2a, 0x62, 0xfb, 0xf0, 0x88, 0x30, 0x3f, + 0x92, 0x2b, 0xf2, 0x4a, 0x66, 0x69, 0xa6, 0x7f, 0x96, 0x36, 0x72, 0xd8, 0x08, 0xa7, 0x7f, 0x34, + 0xe0, 0xfe, 0xbe, 0xcf, 0x45, 0x59, 0xaa, 0x0f, 0x2f, 0x0a, 0x15, 0x1b, 0x32, 0xe3, 0x17, 0xe9, + 0xea, 0xbe, 0x24, 0x9e, 0x9d, 0x21, 0xce, 0x1e, 0x3d, 0x01, 0x53, 0x4c, 0xb4, 0xd2, 0x33, 0x25, + 0x20, 0x1d, 0xe1, 0x20, 0x66, 0xae, 0xc2, 0x9a, 0x56, 0x8e, 0x23, 0x58, 0xe6, 0x57, 0x0d, 0x58, + 0xe8, 0x97, 0xf8, 0x61, 0x00, 0xc3, 0xf0, 0xff, 0xc5, 0xc2, 0x76, 0xcb, 0x89, 0xb0, 0xdd, 0x98, + 0x69, 0x28, 0x23, 0x74, 0x35, 0xab, 0x2c, 0x7f, 0x97, 0xa8, 0xd4, 0xcf, 0x1b, 0x70, 0xba, 0xcf, + 0x6e, 0x4a, 0x84, 0x6f, 0x1b, 0x47, 0x0e, 0xdf, 0xce, 0x0d, 0x1a, 0xbe, 0x6d, 0xfe, 0x65, 0x1e, + 0x66, 0x45, 0x7b, 0x42, 0xfd, 0xea, 0xa9, 0x48, 0xf0, 0xf3, 0x3b, 0x62, 0xc1, 0xcf, 0xf3, 0x71, + 0xfc, 0x9f, 0x45, 0x3e, 0xbf, 0xb5, 0x22, 0x9f, 0x7f, 0x92, 0x83, 0x53, 0xa9, 0xf9, 0x28, 0xd0, + 0x67, 0x52, 0x44, 0xc3, 0xf5, 0x8c, 0x13, 0x5f, 0x0c, 0x28, 0x1c, 0x46, 0x0d, 0x17, 0xfe, 0x92, + 0x1e, 0xa6, 0xcb, 0x8f, 0xfa, 0x9d, 0x63, 0x48, 0xe1, 0x31, 0x64, 0xc4, 0xae, 0xf9, 0x4b, 0x79, + 0x78, 0x74, 0x50, 0x42, 0x6f, 0xd1, 0x17, 0x1d, 0x7e, 0xe4, 0x45, 0xc7, 0x3d, 0x12, 0xdb, 0xc7, + 0xf2, 0xb8, 0xe3, 0x6b, 0x79, 0x25, 0xf6, 0x92, 0xeb, 0x73, 0xa0, 0xdb, 0xc4, 0x09, 0xaa, 0xda, + 0xc9, 0x2c, 0x95, 0xe1, 0x51, 0x38, 0x51, 0xe3, 0xc5, 0x77, 0x7a, 0xe5, 0x39, 0x91, 0xb9, 0xae, + 0x46, 0x02, 0x51, 0x88, 0x65, 0x25, 0xf4, 0x28, 0x14, 0x3d, 0x0e, 0x95, 0x31, 0xec, 0xe2, 0x4a, + 0x96, 0x97, 0x61, 0x05, 0x45, 0x9f, 0xd2, 0x74, 0xe1, 0xb1, 0xe3, 0xca, 0x3f, 0x70, 0xd8, 0x4d, + 0xf3, 0x0b, 0x50, 0xf4, 0x65, 0xbe, 0x49, 0x7e, 0x1d, 0xf0, 0xf8, 0x80, 0x4f, 0x23, 0xa8, 0xe9, + 0x24, 0x93, 0x4f, 0xf2, 0xfe, 0xa9, 0xd4, 0x94, 0x8a, 0x24, 0x32, 0x95, 0xd5, 0xc2, 0x7d, 0x8c, + 0x90, 0x62, 0xb1, 0x7c, 0xcf, 0x80, 0x49, 0x31, 0x5b, 0xf7, 0xe0, 0xb5, 0xc6, 0x8d, 0xe8, 0x6b, + 0x8d, 0xf3, 0x99, 0x9c, 0x1d, 0x7d, 0x9e, 0x6a, 0xdc, 0x80, 0x29, 0x3d, 0x25, 0x11, 0x7a, 0x5e, + 0x3b, 0xfb, 0x8c, 0x51, 0xf2, 0x8c, 0xc8, 0xd3, 0x31, 0x3c, 0x17, 0xcd, 0xaf, 0x14, 0xd5, 0x28, + 0x32, 0x3f, 0x84, 0xbe, 0x06, 0x8d, 0x43, 0xd7, 0xa0, 0xbe, 0x04, 0x72, 0xd9, 0x2f, 0x81, 0x2b, + 0x50, 0x94, 0x07, 0x94, 0x10, 0xe3, 0x0f, 0xeb, 0x31, 0x73, 0x54, 0x17, 0xa0, 0xc4, 0xb4, 0x85, + 0xcb, 0x4c, 0x2d, 0x35, 0x87, 0xea, 0xe0, 0x54, 0x64, 0xd0, 0x8b, 0x30, 0x79, 0xcb, 0xf5, 0x6e, + 0xb6, 0x5c, 0x8b, 0x65, 0x92, 0x85, 0x2c, 0x2e, 0x76, 0x94, 0xc3, 0x8b, 0x87, 0xb2, 0x5f, 0x0f, + 0xe9, 0x63, 0x9d, 0x19, 0xaa, 0xc0, 0x4c, 0xdb, 0x76, 0x30, 0xb1, 0x1a, 0xea, 0x51, 0xc6, 0x18, + 0x4f, 0x75, 0x29, 0x95, 0xdc, 0xf5, 0x28, 0x18, 0xc7, 0xf1, 0xd1, 0x27, 0xa0, 0xe8, 0x8b, 0x1c, + 0x43, 0xd9, 0x5c, 0xc1, 0x29, 0x9b, 0x91, 0x13, 0x0d, 0xc7, 0x4e, 0x96, 0x60, 0xc5, 0x10, 0xad, + 0xc1, 0xbc, 0x27, 0xb2, 0x78, 0x44, 0xbe, 0x43, 0xc1, 0xf7, 0x27, 0xcb, 0xa8, 0x88, 0x53, 0xe0, + 0x38, 0xb5, 0x16, 0xd5, 0x62, 0x58, 0x6e, 0x2d, 0x7e, 0x27, 0xa0, 0xb9, 0xd1, 0xd9, 0x82, 0x6f, + 0x60, 0x01, 0x3d, 0xec, 0x91, 0x4f, 0x71, 0x84, 0x47, 0x3e, 0x35, 0x38, 0x15, 0x07, 0xb1, 0x5c, + 0x23, 0x2c, 0xbd, 0x89, 0x26, 0x3d, 0x36, 0xd3, 0x90, 0x70, 0x7a, 0x5d, 0x74, 0x1d, 0x4a, 0x1e, + 0x61, 0xf6, 0x45, 0x45, 0x5e, 0xfa, 0x0f, 0x1d, 0xde, 0x84, 0x25, 0x01, 0x1c, 0xd2, 0xa2, 0xf3, + 0x6e, 0x45, 0xb3, 0x3d, 0x5e, 0xc9, 0xf0, 0x4b, 0x5a, 0x62, 0xee, 0xfb, 0xe4, 0x00, 0x32, 0xdf, + 0x9c, 0x86, 0x13, 0x11, 0xdf, 0x02, 0x7a, 0x18, 0x0a, 0x2c, 0xf9, 0x0a, 0x3b, 0x1e, 0x8a, 0xe1, + 0x11, 0xc6, 0x07, 0x87, 0xc3, 0xd0, 0x17, 0x0c, 0x98, 0xe9, 0x44, 0xbc, 0xb0, 0xf2, 0xe4, 0x1c, + 0xf1, 0x9e, 0x2f, 0xea, 0xda, 0xd5, 0xf2, 0x24, 0x47, 0x99, 0xe1, 0x38, 0x77, 0xba, 0x01, 0x45, + 0xc4, 0x5f, 0x8b, 0x78, 0x0c, 0x5b, 0xe8, 0x38, 0x8a, 0xc4, 0x72, 0x14, 0x8c, 0xe3, 0xf8, 0x74, + 0x86, 0x59, 0xef, 0x46, 0xf9, 0xc4, 0x4e, 0x45, 0x12, 0xc0, 0x21, 0x2d, 0xf4, 0x0c, 0x4c, 0x8b, + 0x24, 0x7f, 0x9b, 0x6e, 0xe3, 0xa2, 0xe5, 0xef, 0x0a, 0xe5, 0x5e, 0x19, 0x23, 0xcb, 0x11, 0x28, + 0x8e, 0x61, 0xb3, 0xbe, 0x85, 0x99, 0x14, 0x19, 0x81, 0xf1, 0x68, 0x1a, 0xe9, 0xe5, 0x28, 0x18, + 0xc7, 0xf1, 0xd1, 0xbb, 0xb4, 0x73, 0x9f, 0xdf, 0xd3, 0xa9, 0xd3, 0x20, 0xe5, 0xec, 0xaf, 0xc0, + 0x4c, 0x97, 0xd9, 0x42, 0x0d, 0x09, 0x14, 0xfb, 0x51, 0x31, 0xbc, 0x1a, 0x05, 0xe3, 0x38, 0x3e, + 0x7a, 0x1a, 0x4e, 0x78, 0xf4, 0x74, 0x53, 0x04, 0xf8, 0xe5, 0x9d, 0xba, 0x9b, 0xc1, 0x3a, 0x10, + 0x47, 0x71, 0xd1, 0xb3, 0x30, 0x17, 0xa6, 0xe5, 0x92, 0x04, 0xf8, 0x6d, 0x9e, 0xca, 0x38, 0x53, + 0x89, 0x23, 0xe0, 0x64, 0x1d, 0xf4, 0x73, 0x30, 0xab, 0x8d, 0xc4, 0xaa, 0xd3, 0x20, 0xb7, 0x45, + 0xea, 0x24, 0x96, 0x00, 0x6e, 0x39, 0x06, 0xc3, 0x09, 0x6c, 0xf4, 0x7e, 0x98, 0xae, 0xbb, 0xad, + 0x16, 0x3b, 0xe3, 0x78, 0x0a, 0x63, 0x9e, 0x23, 0x89, 0x67, 0x93, 0x8a, 0x40, 0x70, 0x0c, 0x13, + 0x5d, 0x02, 0xe4, 0x6e, 0xfb, 0xc4, 0xdb, 0x23, 0x8d, 0x67, 0xf9, 0x47, 0x3b, 0xa9, 0x88, 0x3f, + 0x11, 0x8d, 0x37, 0xbe, 0x9c, 0xc0, 0xc0, 0x29, 0xb5, 0x58, 0xc2, 0x1a, 0xed, 0xad, 0xd4, 0x74, + 0x16, 0x9f, 0x9b, 0x89, 0x5b, 0xee, 0x77, 0x7d, 0x28, 0xe5, 0xc1, 0x38, 0x0f, 0xff, 0xce, 0x26, + 0x59, 0x92, 0x9e, 0xcd, 0x34, 0x94, 0x11, 0xbc, 0x14, 0x0b, 0x4e, 0xe8, 0x93, 0x50, 0xda, 0x96, + 0xa9, 0xad, 0x17, 0x66, 0xb3, 0x90, 0x8b, 0xb1, 0x2c, 0xed, 0xa1, 0x65, 0xaa, 0x00, 0x38, 0x64, + 0x89, 0x1e, 0x81, 0xc9, 0x8b, 0x9b, 0x15, 0xb5, 0x0a, 0xe7, 0xd8, 0xec, 0x8f, 0xd1, 0x2a, 0x58, + 0x07, 0xd0, 0x1d, 0xa6, 0xf4, 0x25, 0xc4, 0xa6, 0x38, 0x94, 0xb7, 0x49, 0xf5, 0x87, 0x62, 0xb3, + 0xeb, 0x48, 0x5c, 0x5b, 0x38, 0x19, 0xc3, 0x16, 0xe5, 0x58, 0x61, 0xa0, 0x17, 0x60, 0x52, 0xc8, + 0x0b, 0x76, 0x36, 0xcd, 0x1f, 0xed, 0x1d, 0x1e, 0x0e, 0x49, 0x60, 0x9d, 0x1e, 0xbb, 0x65, 0x62, + 0x19, 0x7f, 0xc9, 0x85, 0x6e, 0xab, 0xb5, 0x70, 0x8a, 0x9d, 0x9b, 0xe1, 0x2d, 0x53, 0x08, 0xc2, + 0x3a, 0x1e, 0x7a, 0x5c, 0x46, 0x4e, 0xbc, 0x2d, 0x72, 0xed, 0xa6, 0x22, 0x27, 0x94, 0x96, 0xdb, + 0x27, 0xa0, 0xf8, 0xf4, 0x5d, 0x42, 0x16, 0xb6, 0x61, 0x51, 0xaa, 0x58, 0xc9, 0x4d, 0xb2, 0xb0, + 0x10, 0xf1, 0x12, 0x2c, 0x5e, 0xef, 0x8b, 0x89, 0x0f, 0xa1, 0x82, 0xb6, 0x21, 0x6f, 0xb5, 0xb6, + 0x17, 0xee, 0xcf, 0x42, 0x57, 0x54, 0x1f, 0xe1, 0xe5, 0x41, 0x40, 0x95, 0xb5, 0x2a, 0xa6, 0xc4, + 0xcd, 0x57, 0x72, 0xca, 0x2b, 0xaf, 0x92, 0x48, 0xbe, 0xa4, 0xaf, 0x6a, 0x23, 0x8b, 0x8f, 0x4c, + 0x26, 0xf2, 0xbf, 0x73, 0x81, 0x94, 0xba, 0xa6, 0x3b, 0x6a, 0x1f, 0x67, 0x92, 0x21, 0x24, 0x9a, + 0x20, 0x93, 0x5b, 0x73, 0xd1, 0x5d, 0x6c, 0x7e, 0x7f, 0x5c, 0x39, 0xa1, 0x62, 0xa1, 0x00, 0x1e, + 0x14, 0x6c, 0x3f, 0xb0, 0xdd, 0x0c, 0x9f, 0x8b, 0xc5, 0x32, 0x4b, 0xb2, 0xc0, 0x59, 0x06, 0xc0, + 0x9c, 0x15, 0xe5, 0xe9, 0x34, 0x6d, 0xe7, 0xb6, 0xe8, 0xfe, 0x95, 0xcc, 0xef, 0xf8, 0x39, 0x4f, + 0x06, 0xc0, 0x9c, 0x15, 0xba, 0xc1, 0x57, 0x5a, 0x36, 0x1f, 0x14, 0x8d, 0x7f, 0x27, 0x38, 0xba, + 0xe2, 0x28, 0x2f, 0xbf, 0x6d, 0x0b, 0x1d, 0x66, 0x44, 0x5e, 0xb5, 0xf5, 0xd5, 0x34, 0x5e, 0xb5, + 0xf5, 0x55, 0x4c, 0x99, 0xa0, 0xd7, 0x0c, 0x00, 0x4b, 0x7d, 0x30, 0x37, 0x9b, 0x8f, 0x25, 0xf4, + 0xfb, 0x00, 0x2f, 0x8f, 0x75, 0x0b, 0xa1, 0x58, 0xe3, 0x8c, 0x5e, 0x84, 0x09, 0x8b, 0x7f, 0xea, + 0x45, 0x84, 0x11, 0x66, 0xf3, 0xfd, 0xa2, 0x58, 0x0b, 0x58, 0xfc, 0xa4, 0x00, 0x61, 0xc9, 0x90, + 0xf2, 0x0e, 0x3c, 0x8b, 0xec, 0xd8, 0x37, 0x45, 0x3c, 0x61, 0x6d, 0xe4, 0x8c, 0xcd, 0x94, 0x58, + 0x1a, 0x6f, 0x01, 0xc2, 0x92, 0xa1, 0xf9, 0x2f, 0x06, 0x68, 0x5f, 0x57, 0x0c, 0x03, 0xbd, 0x8c, + 0x81, 0x03, 0xbd, 0x72, 0x43, 0x06, 0x7a, 0xe5, 0x87, 0x0a, 0xf4, 0x1a, 0x1b, 0x3e, 0xd0, 0xab, + 0xd0, 0x3f, 0xd0, 0xcb, 0x7c, 0xdd, 0x80, 0xb9, 0xc4, 0x9a, 0x8c, 0x7f, 0xc5, 0xda, 0x18, 0xf0, + 0x2b, 0xd6, 0x2b, 0x30, 0x2b, 0x52, 0xcc, 0xd6, 0x3a, 0x2d, 0x3b, 0xf5, 0x65, 0xed, 0x56, 0x0c, + 0x8e, 0x13, 0x35, 0xcc, 0x3f, 0x32, 0x60, 0x52, 0x7b, 0x08, 0x44, 0xfb, 0xc1, 0x1e, 0x4c, 0x89, + 0x66, 0x84, 0xd9, 0x75, 0x99, 0x7b, 0x95, 0xc3, 0xb8, 0xa7, 0xbf, 0xa9, 0xa5, 0x33, 0x0c, 0x3d, + 0xfd, 0xb4, 0x14, 0x0b, 0x28, 0x4f, 0x54, 0x47, 0xf8, 0x17, 0xca, 0xf3, 0x7a, 0xa2, 0x3a, 0xd2, + 0xc1, 0x0c, 0xc2, 0xd8, 0x51, 0x59, 0x2e, 0x62, 0x00, 0xb5, 0x64, 0xbe, 0x16, 0xb5, 0xd8, 0x18, + 0x0c, 0x9d, 0x81, 0x3c, 0x71, 0x1a, 0xc2, 0xf0, 0x50, 0x5f, 0xaf, 0x39, 0xef, 0x34, 0x30, 0x2d, + 0x37, 0x2f, 0xc3, 0x54, 0x8d, 0xd4, 0x3d, 0x12, 0x3c, 0x47, 0xf6, 0x07, 0xfe, 0x1c, 0xce, 0x4d, + 0xb2, 0x1f, 0xff, 0x1c, 0x0e, 0xad, 0x4e, 0xcb, 0xcd, 0xdf, 0x31, 0x20, 0x96, 0xee, 0x59, 0xf3, + 0xfa, 0x19, 0xfd, 0xbc, 0x7e, 0x11, 0xff, 0x54, 0xee, 0x50, 0xff, 0xd4, 0x25, 0x40, 0x6d, 0x2b, + 0xa8, 0xef, 0x46, 0x92, 0x9b, 0x0b, 0x9b, 0x2f, 0x7c, 0x76, 0x98, 0xc0, 0xc0, 0x29, 0xb5, 0xcc, + 0xcf, 0x1a, 0x90, 0x48, 0x06, 0x8d, 0xba, 0x50, 0x60, 0xa8, 0xe2, 0x62, 0x64, 0x73, 0xb4, 0x1d, + 0x9d, 0x7c, 0x2a, 0x1f, 0x4e, 0x14, 0xfb, 0x8b, 0x39, 0x37, 0xf3, 0x65, 0xda, 0x96, 0xf8, 0xa7, + 0xcd, 0xdf, 0x09, 0x13, 0x44, 0x7c, 0xf5, 0x84, 0x9b, 0xe5, 0x4a, 0x6b, 0x92, 0x1f, 0x3b, 0x91, + 0x70, 0x6a, 0xbb, 0x49, 0xef, 0x9f, 0xf4, 0xa5, 0xf0, 0xc7, 0x62, 0xca, 0x76, 0x5b, 0x89, 0x82, + 0x71, 0x1c, 0xdf, 0xfc, 0x14, 0x4c, 0x6a, 0xaf, 0xe7, 0xd9, 0xb6, 0xbc, 0x6d, 0xd5, 0x83, 0xf8, + 0x72, 0x3e, 0x4f, 0x0b, 0x31, 0x87, 0x31, 0x97, 0x0f, 0x8f, 0xe3, 0x8b, 0x2d, 0x67, 0x11, 0xbd, + 0x27, 0xa0, 0x94, 0x98, 0x47, 0x9a, 0xe4, 0xb6, 0x4c, 0x22, 0x28, 0x89, 0x61, 0x5a, 0x88, 0x39, + 0xcc, 0xbc, 0x06, 0x45, 0xf9, 0xa4, 0x97, 0xbd, 0x8b, 0x93, 0xee, 0x08, 0xfd, 0x5d, 0x9c, 0xeb, + 0x05, 0x98, 0x41, 0xe8, 0x9a, 0xf1, 0x1d, 0xfb, 0xa2, 0xeb, 0x07, 0xf2, 0x1d, 0x32, 0x77, 0x3a, + 0x6e, 0xac, 0xb2, 0x32, 0xac, 0xa0, 0xe6, 0x1c, 0xcc, 0x28, 0x6f, 0xa2, 0x08, 0x95, 0xfa, 0x76, + 0x1e, 0xa6, 0x22, 0xdf, 0xd0, 0xbc, 0xfb, 0xca, 0x1f, 0x7c, 0x8d, 0xa6, 0x78, 0x05, 0xf3, 0x43, + 0x7a, 0x05, 0x75, 0x37, 0xec, 0xd8, 0xf1, 0xba, 0x61, 0x0b, 0xd9, 0xb8, 0x61, 0x03, 0x98, 0xf0, + 0xc5, 0x31, 0x3c, 0x9e, 0x85, 0xb9, 0x16, 0x9b, 0x31, 0x2e, 0x05, 0xe5, 0x69, 0x2e, 0x59, 0x99, + 0xdf, 0x28, 0xc0, 0x74, 0x34, 0xa3, 0xc9, 0x00, 0x33, 0xf9, 0xae, 0xc4, 0x4c, 0x0e, 0xe9, 0x15, + 0xc9, 0x8f, 0xea, 0x15, 0x19, 0x1b, 0xd5, 0x2b, 0x52, 0x38, 0x82, 0x57, 0x24, 0xe9, 0xd3, 0x18, + 0x1f, 0xd8, 0xa7, 0xf1, 0x01, 0x75, 0xa5, 0x3f, 0x11, 0xb9, 0x03, 0x0b, 0xaf, 0xf4, 0x51, 0x74, + 0x1a, 0x96, 0xdd, 0x46, 0x6a, 0x68, 0x44, 0xf1, 0x2e, 0xd6, 0x9f, 0x97, 0x7a, 0x03, 0x3f, 0xbc, + 0xe3, 0xf5, 0x6d, 0x43, 0xdc, 0xbe, 0x3f, 0x09, 0x93, 0x62, 0x3d, 0x31, 0x4d, 0x00, 0xa2, 0x5a, + 0x44, 0x2d, 0x04, 0x61, 0x1d, 0x8f, 0x7d, 0xe6, 0x2d, 0xfa, 0x5d, 0x3b, 0xe6, 0x64, 0xd2, 0x3f, + 0xf3, 0x16, 0xfb, 0x0e, 0x5e, 0x1c, 0xdf, 0xfc, 0x04, 0x9c, 0x4a, 0xd5, 0xf9, 0x98, 0x11, 0xcc, + 0x84, 0x14, 0x69, 0x08, 0x04, 0xad, 0x19, 0xb1, 0x84, 0x97, 0x8b, 0xd7, 0xfb, 0x62, 0xe2, 0x43, + 0xa8, 0x98, 0x5f, 0xcf, 0xc3, 0x74, 0xf4, 0x1b, 0x21, 0xe8, 0x96, 0xb2, 0x10, 0x33, 0x31, 0x4e, + 0x39, 0x59, 0x2d, 0x41, 0x46, 0x5f, 0x77, 0xcf, 0x2d, 0xb6, 0xbe, 0xb6, 0x55, 0xb6, 0x8e, 0xe3, + 0x63, 0x2c, 0xfc, 0x2c, 0x82, 0x1d, 0xfb, 0x0c, 0x48, 0x18, 0x50, 0x2d, 0x62, 0x08, 0x32, 0xe7, + 0x1e, 0x86, 0x48, 0x2b, 0x56, 0x58, 0x63, 0x4b, 0x65, 0xcb, 0x1e, 0xf1, 0xec, 0x1d, 0x5b, 0x7d, + 0xdf, 0x8c, 0x9d, 0xdc, 0xd7, 0x44, 0x19, 0x56, 0x50, 0xf3, 0xe5, 0x1c, 0x84, 0x5f, 0x73, 0x64, + 0xb9, 0xfc, 0x7d, 0x4d, 0x81, 0x13, 0xd3, 0x76, 0x69, 0xd4, 0xcf, 0x66, 0x84, 0x14, 0x45, 0xb8, + 0x95, 0x56, 0x82, 0x23, 0x1c, 0x7f, 0x0a, 0x5f, 0x71, 0xb4, 0x60, 0x26, 0xf6, 0xcc, 0x2c, 0xf3, + 0x98, 0xd6, 0xaf, 0xe4, 0xa1, 0xa4, 0x1e, 0xea, 0xa1, 0xf7, 0xb1, 0x84, 0xd8, 0xbb, 0xae, 0x4c, + 0x53, 0xfe, 0x76, 0x2d, 0x6d, 0xf5, 0xae, 0xdb, 0xb8, 0xd3, 0x2b, 0xcf, 0x28, 0x64, 0x5e, 0x84, + 0x45, 0x05, 0xaa, 0x2e, 0x77, 0xbd, 0x56, 0x5c, 0x5d, 0xbe, 0x8a, 0xd7, 0x30, 0x2d, 0x47, 0xb7, + 0x61, 0x82, 0xa7, 0x23, 0x92, 0xd1, 0x2b, 0xeb, 0x19, 0x3d, 0x2e, 0xe4, 0x7a, 0x67, 0x38, 0x0c, + 0xfc, 0xbf, 0x8f, 0x25, 0x3b, 0x2a, 0x25, 0xb7, 0xdd, 0xc6, 0x7e, 0x3c, 0xcd, 0x75, 0xd5, 0x6d, + 0xec, 0x63, 0x06, 0x41, 0xcf, 0xc0, 0x74, 0x60, 0xb7, 0x89, 0xdb, 0x0d, 0xf4, 0x6f, 0xe5, 0xe5, + 0xc3, 0xeb, 0x8b, 0xad, 0x08, 0x14, 0xc7, 0xb0, 0xa9, 0x94, 0xbd, 0xe1, 0xbb, 0x0e, 0xcb, 0x5d, + 0x35, 0x1e, 0xf5, 0x75, 0x5e, 0xaa, 0x5d, 0xde, 0x60, 0xa9, 0xab, 0x14, 0x06, 0xc5, 0xb6, 0xd9, + 0xab, 0x1c, 0x8f, 0x88, 0xdb, 0xc3, 0xd9, 0xf0, 0xcd, 0x36, 0x2f, 0xc7, 0x0a, 0xc3, 0xbc, 0x0a, + 0x33, 0xb1, 0xae, 0x4a, 0xc3, 0xc4, 0x48, 0x37, 0x4c, 0x06, 0xcb, 0x29, 0xfd, 0xfb, 0x06, 0xcc, + 0x25, 0x36, 0xef, 0xa0, 0xc1, 0xd6, 0x71, 0x31, 0x92, 0x3b, 0xba, 0x18, 0xc9, 0x0f, 0x27, 0x46, + 0xaa, 0x4b, 0xdf, 0x79, 0xf3, 0xec, 0x7d, 0xdf, 0x7d, 0xf3, 0xec, 0x7d, 0xdf, 0x7f, 0xf3, 0xec, + 0x7d, 0x2f, 0x1f, 0x9c, 0x35, 0xbe, 0x73, 0x70, 0xd6, 0xf8, 0xee, 0xc1, 0x59, 0xe3, 0xfb, 0x07, + 0x67, 0x8d, 0x7f, 0x38, 0x38, 0x6b, 0xbc, 0xfe, 0xa3, 0xb3, 0xf7, 0x3d, 0x5f, 0x94, 0xcb, 0xe4, + 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0xc9, 0xa1, 0xbf, 0xd2, 0x14, 0x8e, 0x00, 0x00, } func (m *ALBStatus) Marshal() (dAtA []byte, err error) { @@ -5867,6 +5897,39 @@ func (m *HeaderRoutingMatch) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *InfluxdbMetric) 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 *InfluxdbMetric) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *InfluxdbMetric) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.Query) + copy(dAtA[i:], m.Query) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Query))) + i-- + dAtA[i] = 0x12 + i -= len(m.Profile) + copy(dAtA[i:], m.Profile) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Profile))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *IstioDestinationRule) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -6469,6 +6532,18 @@ func (m *MetricProvider) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.Influxdb != nil { + { + size, err := m.Influxdb.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + } if m.Graphite != nil { { size, err := m.Graphite.MarshalToSizedBuffer(dAtA[:i]) @@ -9848,6 +9923,19 @@ func (m *HeaderRoutingMatch) Size() (n int) { return n } +func (m *InfluxdbMetric) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Profile) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Query) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + func (m *IstioDestinationRule) Size() (n int) { if m == nil { return 0 @@ -10103,6 +10191,10 @@ func (m *MetricProvider) Size() (n int) { l = m.Graphite.Size() n += 1 + l + sovGenerated(uint64(l)) } + if m.Influxdb != nil { + l = m.Influxdb.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -11639,6 +11731,17 @@ func (this *HeaderRoutingMatch) String() string { }, "") return s } +func (this *InfluxdbMetric) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&InfluxdbMetric{`, + `Profile:` + fmt.Sprintf("%v", this.Profile) + `,`, + `Query:` + fmt.Sprintf("%v", this.Query) + `,`, + `}`, + }, "") + return s +} func (this *IstioDestinationRule) String() string { if this == nil { return "nil" @@ -11811,6 +11914,7 @@ func (this *MetricProvider) String() string { `Job:` + strings.Replace(this.Job.String(), "JobMetric", "JobMetric", 1) + `,`, `CloudWatch:` + strings.Replace(this.CloudWatch.String(), "CloudWatchMetric", "CloudWatchMetric", 1) + `,`, `Graphite:` + strings.Replace(this.Graphite.String(), "GraphiteMetric", "GraphiteMetric", 1) + `,`, + `Influxdb:` + strings.Replace(this.Influxdb.String(), "InfluxdbMetric", "InfluxdbMetric", 1) + `,`, `}`, }, "") return s @@ -19856,6 +19960,120 @@ func (m *HeaderRoutingMatch) Unmarshal(dAtA []byte) error { } return nil } +func (m *InfluxdbMetric) 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: InfluxdbMetric: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: InfluxdbMetric: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Profile", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Profile = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Query = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *IstioDestinationRule) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -22189,6 +22407,42 @@ func (m *MetricProvider) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Influxdb", 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.Influxdb == nil { + m.Influxdb = &InfluxdbMetric{} + } + if err := m.Influxdb.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) diff --git a/pkg/apis/rollouts/v1alpha1/generated.proto b/pkg/apis/rollouts/v1alpha1/generated.proto index d035b8aecc..fe49259724 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.proto +++ b/pkg/apis/rollouts/v1alpha1/generated.proto @@ -749,6 +749,15 @@ message HeaderRoutingMatch { optional StringMatch headerValue = 2; } +// InfluxdbMetric defines the InfluxDB Flux query to perform canary analysis +message InfluxdbMetric { + // Profile is the name of the secret holding InfluxDB account configuration + optional string profile = 1; + + // Query is a raw InfluxDB flux query to perform + optional string query = 2; +} + // IstioDestinationRule is a reference to an Istio DestinationRule to modify and shape traffic message IstioDestinationRule { // Name holds the name of the DestinationRule @@ -933,6 +942,9 @@ message MetricProvider { // Graphite specifies the Graphite metric to query optional GraphiteMetric graphite = 9; + + // Influxdb specifies the influxdb metric to query + optional InfluxdbMetric influxdb = 10; } // MetricResult contain a list of the most recent measurements for a single metric along with diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index 977aae1e8e..3572f2f360 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -74,6 +74,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.FieldRef": schema_pkg_apis_rollouts_v1alpha1_FieldRef(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.GraphiteMetric": schema_pkg_apis_rollouts_v1alpha1_GraphiteMetric(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.HeaderRoutingMatch": schema_pkg_apis_rollouts_v1alpha1_HeaderRoutingMatch(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.InfluxdbMetric": schema_pkg_apis_rollouts_v1alpha1_InfluxdbMetric(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.IstioDestinationRule": schema_pkg_apis_rollouts_v1alpha1_IstioDestinationRule(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.IstioTrafficRouting": schema_pkg_apis_rollouts_v1alpha1_IstioTrafficRouting(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.IstioVirtualService": schema_pkg_apis_rollouts_v1alpha1_IstioVirtualService(ref), @@ -2237,6 +2238,33 @@ func schema_pkg_apis_rollouts_v1alpha1_HeaderRoutingMatch(ref common.ReferenceCa } } +func schema_pkg_apis_rollouts_v1alpha1_InfluxdbMetric(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "InfluxdbMetric defines the InfluxDB Flux query to perform canary analysis", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "profile": { + SchemaProps: spec.SchemaProps{ + Description: "Profile is the name of the secret holding InfluxDB account configuration", + Type: []string{"string"}, + Format: "", + }, + }, + "query": { + SchemaProps: spec.SchemaProps{ + Description: "Query is a raw InfluxDB flux query to perform", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + func schema_pkg_apis_rollouts_v1alpha1_IstioDestinationRule(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -2780,11 +2808,17 @@ func schema_pkg_apis_rollouts_v1alpha1_MetricProvider(ref common.ReferenceCallba Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.GraphiteMetric"), }, }, + "influxdb": { + SchemaProps: spec.SchemaProps{ + Description: "Influxdb specifies the influxdb metric to query", + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.InfluxdbMetric"), + }, + }, }, }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.CloudWatchMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DatadogMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.GraphiteMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.JobMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.KayentaMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.NewRelicMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PrometheusMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.WavefrontMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.WebMetric"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.CloudWatchMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.DatadogMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.GraphiteMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.InfluxdbMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.JobMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.KayentaMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.NewRelicMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.PrometheusMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.WavefrontMetric", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.WebMetric"}, } } diff --git a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go index e45cf0dba6..e628726898 100644 --- a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go @@ -1276,6 +1276,22 @@ func (in *HeaderRoutingMatch) DeepCopy() *HeaderRoutingMatch { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InfluxdbMetric) DeepCopyInto(out *InfluxdbMetric) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfluxdbMetric. +func (in *InfluxdbMetric) DeepCopy() *InfluxdbMetric { + if in == nil { + return nil + } + out := new(InfluxdbMetric) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *IstioDestinationRule) DeepCopyInto(out *IstioDestinationRule) { *out = *in @@ -1563,6 +1579,11 @@ func (in *MetricProvider) DeepCopyInto(out *MetricProvider) { *out = new(GraphiteMetric) **out = **in } + if in.Influxdb != nil { + in, out := &in.Influxdb, &out.Influxdb + *out = new(InfluxdbMetric) + **out = **in + } return } diff --git a/utils/analysis/factory.go b/utils/analysis/factory.go index b500bfd30d..0fb57030f5 100644 --- a/utils/analysis/factory.go +++ b/utils/analysis/factory.go @@ -219,6 +219,12 @@ func ValidateMetric(metric v1alpha1.Metric) error { if metric.Provider.CloudWatch != nil { numProviders++ } + if metric.Provider.Graphite != nil { + numProviders++ + } + if metric.Provider.Influxdb != nil { + numProviders++ + } if numProviders == 0 { return fmt.Errorf("no provider specified") } diff --git a/utils/analysis/factory_test.go b/utils/analysis/factory_test.go index 21b55fb592..c485081999 100644 --- a/utils/analysis/factory_test.go +++ b/utils/analysis/factory_test.go @@ -398,6 +398,8 @@ func TestValidateMetrics(t *testing.T) { Datadog: &v1alpha1.DatadogMetric{}, NewRelic: &v1alpha1.NewRelicMetric{}, CloudWatch: &v1alpha1.CloudWatchMetric{}, + Graphite: &v1alpha1.GraphiteMetric{}, + Influxdb: &v1alpha1.InfluxdbMetric{}, }, }, }, From 40c356c64e5b6c78d1d3e08f092e339662c839b6 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Wed, 29 Jun 2022 16:28:59 -0500 Subject: [PATCH 148/175] feat: Adds support for Istio traffic mirroring (#2074) * feat: Add support for istio traffic mirroring steps Signed-off-by: zachaller * bump e2e timeout Signed-off-by: zachaller * Remove unintended change Signed-off-by: zachaller * Cleaner events Signed-off-by: zachaller * Add docs for mirror and fix up header routing Signed-off-by: zachaller * small doc changes Signed-off-by: zachaller * Add example Signed-off-by: zachaller * Fix types and change example Signed-off-by: zachaller * Remove unused type Signed-off-by: zachaller * Docs change Signed-off-by: zachaller * Fix PR comments Signed-off-by: zachaller * Check for >= Signed-off-by: zachaller * Remove unused function Signed-off-by: zachaller * codegen Signed-off-by: zachaller * Add better error logging Signed-off-by: zachaller * a few more error msgs Signed-off-by: zachaller * fix comments Signed-off-by: zachaller * typo Signed-off-by: zachaller * fix logic error Signed-off-by: zachaller * redo header logic Signed-off-by: zachaller * cleanup Signed-off-by: zachaller * Fix issue with keeping route weight updated when no routes are defined in spec.strategy.canary.trafficRouting.istio.virtualService.routes requiring only a single route Signed-off-by: zachaller * cleanup routes when promiting with last step being a pause Signed-off-by: zachaller * fix bug with promote and last step is a pause Signed-off-by: zachaller * Fix tests Signed-off-by: zachaller * fix typo Signed-off-by: zachaller --- Makefile | 2 +- docs/features/specification.md | 58 +- docs/features/traffic-management/index.md | 107 +- examples/traffic-routing/istio-mirror.yaml | 117 + go.mod | 2 +- manifests/crds/rollout-crd.yaml | 57 +- manifests/install.yaml | 57 +- manifests/namespace-install.yaml | 57 +- pkg/apiclient/rollout/rollout.swagger.json | 74 +- pkg/apis/api-rules/violation_exceptions.list | 4 +- pkg/apis/rollouts/v1alpha1/generated.pb.go | 2174 ++++++++++++----- pkg/apis/rollouts/v1alpha1/generated.proto | 56 +- .../rollouts/v1alpha1/openapi_generated.go | 152 +- pkg/apis/rollouts/v1alpha1/types.go | 62 +- .../v1alpha1/zz_generated.deepcopy.go | 111 +- pkg/apis/rollouts/validation/validation.go | 101 +- .../rollouts/validation/validation_test.go | 168 +- rollout/canary.go | 4 +- rollout/mocks/TrafficRoutingReconciler.go | 38 +- rollout/trafficrouting.go | 35 +- rollout/trafficrouting/alb/alb.go | 10 +- rollout/trafficrouting/alb/alb_test.go | 66 + .../trafficrouting/ambassador/ambassador.go | 10 +- .../ambassador/ambassador_test.go | 99 + rollout/trafficrouting/appmesh/appmesh.go | 10 +- .../trafficrouting/appmesh/appmesh_test.go | 57 + rollout/trafficrouting/istio/istio.go | 571 ++++- rollout/trafficrouting/istio/istio_test.go | 514 +++- rollout/trafficrouting/istio/istio_types.go | 24 +- rollout/trafficrouting/nginx/nginx.go | 10 +- rollout/trafficrouting/nginx/nginx_test.go | 39 + rollout/trafficrouting/smi/smi.go | 10 +- rollout/trafficrouting/smi/smi_test.go | 59 + rollout/trafficrouting/traefik/traefik.go | 10 +- .../trafficrouting/traefik/traefik_test.go | 55 + rollout/trafficrouting/trafficroutingutil.go | 8 +- rollout/trafficrouting_test.go | 33 +- test/e2e/header-routing/istio-hr-host.yaml | 11 +- ...r_routing_test.go => header_route_test.go} | 12 +- test/e2e/mirror-route/istio-mirror-host.yaml | 124 + test/e2e/mirror_route_test.go | 102 + test/fixtures/e2e_suite.go | 2 +- ui/package.json | 1 + ui/src/app/components/rollout/rollout.tsx | 128 +- ui/src/models/rollout/generated/api.ts | 91 +- utils/replicaset/canary.go | 13 - utils/replicaset/canary_test.go | 36 - 47 files changed, 4600 insertions(+), 941 deletions(-) create mode 100644 examples/traffic-routing/istio-mirror.yaml rename test/e2e/{header_routing_test.go => header_route_test.go} (85%) create mode 100644 test/e2e/mirror-route/istio-mirror-host.yaml create mode 100644 test/e2e/mirror_route_test.go diff --git a/Makefile b/Makefile index 3302b41c1d..61f91da345 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ DEV_IMAGE=false E2E_INSTANCE_ID ?= argo-rollouts-e2e E2E_TEST_OPTIONS ?= E2E_PARALLEL ?= 4 -E2E_WAIT_TIMEOUT ?= 90 +E2E_WAIT_TIMEOUT ?= 120 override LDFLAGS += \ -X ${PACKAGE}/utils/version.version=${VERSION} \ diff --git a/docs/features/specification.md b/docs/features/specification.md index dbea102893..100ddbb430 100644 --- a/docs/features/specification.md +++ b/docs/features/specification.md @@ -268,19 +268,52 @@ spec: # Setting header based route will send all 100 traffic to the canary for the requests # O with a specified header, in this case request header "version":"2" # (supported only with trafficRouting, for Istio only at the moment) - - setHeaderRouting: + - setHeaderRoute: + # Name of the route that will be created by argo rollouts this must also be configured + # in spec.strategy.canary.trafficRouting.managedRoutes + name: "header-route-1" + # The matching rules for the header route, if this is missing it acts as a removal of the route. match: + # headerName The name of the header to apply the match rules to. - headerName: "version" + # headerValue must contain exactly one field of exact, regex, or prefix. Not all traffic routers support + # all types headerValue: + # Exact will only match if the header value is exactly the same exact: "2" - - # Sets header based route with specified header values using regex as a value - # Could be used 'headerValue' or 'headerRegex' one of that values - - setHeaderRouting: - match: - - headerName: "version" - headerValue: + # Will match the rule if the regular expression matches regex: "2.0.(.*)" + # prefix will be a prefix match of the header value + prefix: "2.0" + + # Sets up a mirror/shadow based route with the specified match rules + # The traffic will be mirrored at the configured percentage to the canary service + # during the rollout + # (supported only with trafficRouting, for Istio only at the moment) + - setMirrorRoute: + # Name of the route that will be created by argo rollouts this must also be configured + # in spec.strategy.canary.trafficRouting.managedRoutes + name: "header-route-1" + # The percentage of the matched traffic to mirror to the canary + percentage: 100 + # The matching rules for the header route, if this is missing it acts as a removal of the route. + # All conditions inside a single match block have AND semantics, while the list of match blocks have OR semantics. + # Each type within a match (method, path, headers) must have one and only one match type (exact, regex, prefix) + # Not all match types (exact, regex, prefix) will be supported by all traffic routers. + match: + - method: # What HTTP method to match + exact: "GET" + regex: "P.*" + prefix: "POST" + path: # What HTTP url paths to match. + exact: "/test" + regex: ""/test/.*" + prefix: ""/" + headers: + agent-1b: # What HTTP header name to use in the match. + exact: "firefox" + regex: "firefox2(.*)" + prefix: "firefox" # an inline analysis step - analysis: @@ -311,7 +344,14 @@ spec: # will achieve traffic split via a weighted replica counts between # the canary and stable ReplicaSet. trafficRouting: - + # This is a list of routes that Argo Rollouts has the rights to manage it is currently only required for + # setMirrorRoute and setHeaderRoute. The order of managedRoutes array also sets the precedence of the route + # in the traffic router. Argo Rollouts will place these routes in the order specified above any routes already + # defined in the used traffic router if something exists. The names here must match the names from the + # setHeaderRoute and setMirrorRoute steps. + managedRoutes: + - name: set-header + - name: mirror-route # Istio traffic routing configuration istio: # Either virtualService or virtualServices can be configured. diff --git a/docs/features/traffic-management/index.md b/docs/features/traffic-management/index.md index 78561992ca..8c2e97d152 100644 --- a/docs/features/traffic-management/index.md +++ b/docs/features/traffic-management/index.md @@ -49,14 +49,53 @@ Since the traffic is controlled independently by the Service Mesh resources, the [^1]: The Rollout has to assume that the application can handle 100% of traffic if it is fully scaled up. It should outsource to the HPA to detect if the Rollout needs to more replicas if 100% isn't enough. +## Traffic routing with managed routes and route precedence +##### Traffic router support: (Istio) + +When traffic routing is enabled, you have the ability to also let argo rollouts add and manage other routes besides just +controlling the traffic weight to the canary. Two such routing rules are header and mirror based routes. When using these +routes we also have to set a route precedence with the upstream traffic router. We do this using the `spec.strategy.canary.trafficRouting.managedRoutes` +field which is an array the order of the items in the array determine the precedence. This set of routes will also be placed +in the order specified on top of any other routes defined manually. + +#### WARNING: All routes listed in managed routes will be removed at the end of a rollout or on an abort. Do not put any manually created routes in the list. + + +Here is an example: + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +spec: + ... + strategy: + canary: + ... + trafficRouting: + managedRoutes: + - name: priority-route-1 + - name: priority-route-2 + - name: priority-route-3 +``` + + ## Traffic routing based on a header values for Canary +##### Traffic router support: (Istio) + +Argo Rollouts has ability to send all traffic to the canary-service based on a http request header value. +The step for the header based traffic routing is `setHeaderRoute` and has a list of matchers for the header. -Argo Rollouts has ability to send all traffic to the canary-service based on a http request header value. Right now it's implemented for the Istio only. -The step for the header based traffic routing `setHeaderRouting` has a list of matchers for the header. -Should be specified the `headerName` - name of the header and a value. -The value could be one of 3 `exact` - specify the exact header value, `regex` - value in a regex format, `prefix` - the prefix of the value could be provided. +`name` - name of the header route. -To disable header based traffic routing just need to specify empty `setHeaderRouting`. +`match` - header matching rules is an array of `headerName, headerValue` pairs. + +`headerName` - name of the header to match. + +`headerValue`- contains exactly one of `exact` - specify the exact header value, +`regex` - value in a regex format, `prefix` - the prefix of the value could be provided. Not all traffic routers will support +all match types. + +To disable header based traffic routing just need to specify empty `setHeaderRoute` with only the name of the route. Example: @@ -70,12 +109,15 @@ spec: canaryService: canary-service stableService: stable-service trafficRouting: + managedRoutes: + - name: set-header-1 istio: virtualService: name: rollouts-demo-vsvc steps: - setWeight: 20 - - setHeaderRouting: # enable header based traffic routing where + - setHeaderRoute: # enable header based traffic routing where + name: "set-header-1" match: - headerName: Custom-Header1 # Custom-Header1=Mozilla headerValue: @@ -87,5 +129,56 @@ spec: headerValue: regex: Mozilla(.*) - pause: {} - - setHeaderRouting: {} # disable header based traffic routing + - setHeaderRoute: + name: "set-header-1" # disable header based traffic routing +``` + +## Traffic routing mirroring traffic to canary +##### Traffic router support: (Istio) + +Argo Rollouts has ability to mirror traffic to the canary-service based on a various matching rules. +The step for the mirror based traffic routing is `setMirrorRoute` and has a list of matchers for the header. + +`name` - name of the mirror route. + +`percentage` - what percentage of the matched traffic to mirror + +`match` - The matching rules for the header route, if this is missing it acts as a removal of the route. +All conditions inside a single match block have AND semantics, while the list of match blocks have OR semantics. +Each type within a match (method, path, headers) must have one and only one match type (exact, regex, prefix) +Not all match types (exact, regex, prefix) will be supported by all traffic routers. + +To disable mirror based traffic route you just need to specify a `setMirrorRoute` with only the name of the route. + +This example will mirror 35% of HTTP traffic that matches a `GET` requests and with the url prefix of `/` +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +spec: + ... + strategy: + canary: + canaryService: canary-service + stableService: stable-service + trafficRouting: + managedRoutes: + - name: mirror-route + istio: + virtualService: + name: rollouts-demo-vsvc + steps: + - setCanaryScale: + weight: 25 + - setMirrorRoute: + name: mirror-route + percentage: 35 + match: + - method: + exact: GET + path: + prefix: / + - pause: + duration: 10m + - setMirrorRoute: + name: "mirror-route" # removes mirror based traffic route ``` \ No newline at end of file diff --git a/examples/traffic-routing/istio-mirror.yaml b/examples/traffic-routing/istio-mirror.yaml new file mode 100644 index 0000000000..d56c36add4 --- /dev/null +++ b/examples/traffic-routing/istio-mirror.yaml @@ -0,0 +1,117 @@ +## This examples sets up istio mirroring if running locally using docker for destkop you can add +## istio-host-split.com to your /etc/hosts and point it to 127.0.0.1 to view demo. +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-canary +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-stable +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: istio-host-split-vsvc +spec: + hosts: + - istio-host-split.com + gateways: + - istio-host-split-gateway + http: + - name: primary + route: + - destination: + host: istio-host-split-stable + weight: 100 + - destination: + host: istio-host-split-canary + weight: 0 + +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: istio-host-split +spec: + replicas: 4 + strategy: + canary: + canaryService: istio-host-split-canary + stableService: istio-host-split-stable + trafficRouting: + managedRoutes: + - name: mirror-route + istio: + virtualService: + name: istio-host-split-vsvc + routes: + - primary + steps: + - setCanaryScale: + weight: 50 + - setMirrorRoute: + name: mirror-route + percentage: 50 + match: + - method: + exact: POST + path: + prefix: /color + - pause: {} + selector: + matchLabels: + app: istio-host-split + template: + metadata: + labels: + app: istio-host-split + spec: + containers: + - name: istio-host-split + image: argoproj/rollouts-demo:green + ports: + - name: http + containerPort: 8080 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m + +--- + +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: istio-host-split-gateway +spec: + selector: + istio: ingressgateway # use istio default controller + servers: + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - "istio-host-split.com" + diff --git a/go.mod b/go.mod index e78e3ee333..d3d30f19e4 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,6 @@ require ( github.com/aws/aws-sdk-go-v2/config v1.13.1 github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.15.0 github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.16.0 - github.com/aws/smithy-go v1.10.0 github.com/blang/semver v3.5.1+incompatible github.com/evanphx/json-patch/v5 v5.6.0 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 @@ -77,6 +76,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.9.0 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.14.0 // indirect + github.com/aws/smithy-go v1.10.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bradleyfalzon/ghinstallation/v2 v2.0.4 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect diff --git a/manifests/crds/rollout-crd.yaml b/manifests/crds/rollout-crd.yaml index bda1fdd4fc..5c1c374544 100644 --- a/manifests/crds/rollout-crd.yaml +++ b/manifests/crds/rollout-crd.yaml @@ -593,7 +593,7 @@ spec: format: int32 type: integer type: object - setHeaderRouting: + setHeaderRoute: properties: match: items: @@ -614,6 +614,52 @@ spec: - headerValue type: object type: array + name: + type: string + type: object + setMirrorRoute: + properties: + match: + items: + properties: + headers: + additionalProperties: + properties: + exact: + type: string + prefix: + type: string + regex: + type: string + type: object + type: object + method: + properties: + exact: + type: string + prefix: + type: string + regex: + type: string + type: object + path: + properties: + exact: + type: string + prefix: + type: string + regex: + type: string + type: object + type: object + type: array + name: + type: string + percentage: + format: int32 + type: integer + required: + - name type: object setWeight: format: int32 @@ -755,6 +801,15 @@ spec: type: object type: array type: object + managedRoutes: + items: + properties: + name: + type: string + required: + - name + type: object + type: array nginx: properties: additionalIngressAnnotations: diff --git a/manifests/install.yaml b/manifests/install.yaml index 4238f06eef..89c74a17a4 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -11582,7 +11582,7 @@ spec: format: int32 type: integer type: object - setHeaderRouting: + setHeaderRoute: properties: match: items: @@ -11603,6 +11603,52 @@ spec: - headerValue type: object type: array + name: + type: string + type: object + setMirrorRoute: + properties: + match: + items: + properties: + headers: + additionalProperties: + properties: + exact: + type: string + prefix: + type: string + regex: + type: string + type: object + type: object + method: + properties: + exact: + type: string + prefix: + type: string + regex: + type: string + type: object + path: + properties: + exact: + type: string + prefix: + type: string + regex: + type: string + type: object + type: object + type: array + name: + type: string + percentage: + format: int32 + type: integer + required: + - name type: object setWeight: format: int32 @@ -11744,6 +11790,15 @@ spec: type: object type: array type: object + managedRoutes: + items: + properties: + name: + type: string + required: + - name + type: object + type: array nginx: properties: additionalIngressAnnotations: diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index f10bf17255..ec026bfcfd 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -11582,7 +11582,7 @@ spec: format: int32 type: integer type: object - setHeaderRouting: + setHeaderRoute: properties: match: items: @@ -11603,6 +11603,52 @@ spec: - headerValue type: object type: array + name: + type: string + type: object + setMirrorRoute: + properties: + match: + items: + properties: + headers: + additionalProperties: + properties: + exact: + type: string + prefix: + type: string + regex: + type: string + type: object + type: object + method: + properties: + exact: + type: string + prefix: + type: string + regex: + type: string + type: object + path: + properties: + exact: + type: string + prefix: + type: string + regex: + type: string + type: object + type: object + type: array + name: + type: string + percentage: + format: int32 + type: integer + required: + - name type: object setWeight: format: int32 @@ -11744,6 +11790,15 @@ spec: type: object type: array type: object + managedRoutes: + items: + properties: + name: + type: string + required: + - name + type: object + type: array nginx: properties: additionalIngressAnnotations: diff --git a/pkg/apiclient/rollout/rollout.swagger.json b/pkg/apiclient/rollout/rollout.swagger.json index 384103913b..42b6c893bc 100644 --- a/pkg/apiclient/rollout/rollout.swagger.json +++ b/pkg/apiclient/rollout/rollout.swagger.json @@ -821,9 +821,13 @@ "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SetCanaryScale", "title": "SetCanaryScale defines how to scale the newRS without changing traffic weight\n+optional" }, - "setHeaderRouting": { - "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SetHeaderRouting", - "title": "SetHeaderRouting defines the route with specified header name to send 100% of traffic to the canary service" + "setHeaderRoute": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SetHeaderRoute", + "title": "SetHeaderRoute defines the route with specified header name to send 100% of traffic to the canary service\n+optional" + }, + "setMirrorRoute": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SetMirrorRoute", + "title": "SetMirrorRoutes Mirrors traffic that matches rules to a particular destination\n+optional" } }, "description": "CanaryStep defines a step of a canary deployment." @@ -995,6 +999,14 @@ }, "title": "IstioVirtualService holds information on the virtual service the rollout needs to modify" }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MangedRoutes": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MeasurementRetention": { "type": "object", "properties": { @@ -1545,10 +1557,37 @@ "traefik": { "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.TraefikTrafficRouting", "title": "Traefik holds specific configuration to use Traefik to route traffic" + }, + "managedRoutes": { + "type": "array", + "items": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MangedRoutes" + }, + "description": "A list of HTTP routes that Argo Rollouts manages, the order of this array also becomes the precedence in the upstream\ntraffic router." } }, "title": "RolloutTrafficRouting hosts all the different configuration for supported service meshes to enable more fine-grained traffic routing" }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.RouteMatch": { + "type": "object", + "properties": { + "method": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.StringMatch", + "title": "Method What http methods should be mirrored\n+optional" + }, + "path": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.StringMatch", + "title": "Path What url paths should be mirrored\n+optional" + }, + "headers": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.StringMatch" + }, + "title": "Headers What request with matching headers should be mirrored\n+optional" + } + } + }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SMITrafficRouting": { "type": "object", "properties": { @@ -1583,9 +1622,13 @@ }, "title": "SetCanaryScale defines how to scale the newRS without changing traffic weight" }, - "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SetHeaderRouting": { + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SetHeaderRoute": { "type": "object", "properties": { + "name": { + "type": "string", + "title": "Name this is the name of the route to use for the mirroring of traffic this also needs\nto be included in the `spec.strategy.canary.trafficRouting.managedRoutes` field" + }, "match": { "type": "array", "items": { @@ -1593,7 +1636,28 @@ } } }, - "title": "SetHeaderRouting defines the route with specified header name to send 100% of traffic to the canary service" + "title": "SetHeaderRoute defines the route with specified header name to send 100% of traffic to the canary service" + }, + "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SetMirrorRoute": { + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "Name this is the name of the route to use for the mirroring of traffic this also needs\nto be included in the `spec.strategy.canary.trafficRouting.managedRoutes` field" + }, + "match": { + "type": "array", + "items": { + "$ref": "#/definitions/github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.RouteMatch" + }, + "title": "Match Contains a list of rules that if mated will mirror the traffic to the services\n+optional" + }, + "percentage": { + "type": "integer", + "format": "int32", + "title": "Services The list of services to mirror the traffic to if the method, path, headers match\nService string `json:\"service\" protobuf:\"bytes,3,opt,name=service\"`\nPercentage What percent of the traffic that matched the rules should be mirrored" + } + } }, "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.StickinessConfig": { "type": "object", diff --git a/pkg/apis/api-rules/violation_exceptions.list b/pkg/apis/api-rules/violation_exceptions.list index d9cc556c27..479a0f52c1 100644 --- a/pkg/apis/api-rules/violation_exceptions.list +++ b/pkg/apis/api-rules/violation_exceptions.list @@ -34,7 +34,9 @@ API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutExperimentStepAnalysisTemplateRef,Args API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutStatus,Conditions API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutStatus,PauseConditions -API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,SetHeaderRouting,Match +API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,RolloutTrafficRouting,ManagedRoutes +API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,SetHeaderRoute,Match +API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,SetMirrorRoute,Match API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,TLSRoute,SNIHosts API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,TrafficWeights,Additional API rule violation: list_type_missing,github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1,WebMetric,Headers diff --git a/pkg/apis/rollouts/v1alpha1/generated.pb.go b/pkg/apis/rollouts/v1alpha1/generated.pb.go index 8f9b715371..0dc12eaa6b 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.pb.go +++ b/pkg/apis/rollouts/v1alpha1/generated.pb.go @@ -1504,10 +1504,38 @@ func (m *KayentaThreshold) XXX_DiscardUnknown() { var xxx_messageInfo_KayentaThreshold proto.InternalMessageInfo +func (m *MangedRoutes) Reset() { *m = MangedRoutes{} } +func (*MangedRoutes) ProtoMessage() {} +func (*MangedRoutes) Descriptor() ([]byte, []int) { + return fileDescriptor_e0e705f843545fab, []int{52} +} +func (m *MangedRoutes) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MangedRoutes) 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 *MangedRoutes) XXX_Merge(src proto.Message) { + xxx_messageInfo_MangedRoutes.Merge(m, src) +} +func (m *MangedRoutes) XXX_Size() int { + return m.Size() +} +func (m *MangedRoutes) XXX_DiscardUnknown() { + xxx_messageInfo_MangedRoutes.DiscardUnknown(m) +} + +var xxx_messageInfo_MangedRoutes proto.InternalMessageInfo + func (m *Measurement) Reset() { *m = Measurement{} } func (*Measurement) ProtoMessage() {} func (*Measurement) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{52} + return fileDescriptor_e0e705f843545fab, []int{53} } func (m *Measurement) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1535,7 +1563,7 @@ var xxx_messageInfo_Measurement proto.InternalMessageInfo func (m *MeasurementRetention) Reset() { *m = MeasurementRetention{} } func (*MeasurementRetention) ProtoMessage() {} func (*MeasurementRetention) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{53} + return fileDescriptor_e0e705f843545fab, []int{54} } func (m *MeasurementRetention) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1563,7 +1591,7 @@ var xxx_messageInfo_MeasurementRetention proto.InternalMessageInfo func (m *Metric) Reset() { *m = Metric{} } func (*Metric) ProtoMessage() {} func (*Metric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{54} + return fileDescriptor_e0e705f843545fab, []int{55} } func (m *Metric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1591,7 +1619,7 @@ var xxx_messageInfo_Metric proto.InternalMessageInfo func (m *MetricProvider) Reset() { *m = MetricProvider{} } func (*MetricProvider) ProtoMessage() {} func (*MetricProvider) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{55} + return fileDescriptor_e0e705f843545fab, []int{56} } func (m *MetricProvider) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1619,7 +1647,7 @@ var xxx_messageInfo_MetricProvider proto.InternalMessageInfo func (m *MetricResult) Reset() { *m = MetricResult{} } func (*MetricResult) ProtoMessage() {} func (*MetricResult) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{56} + return fileDescriptor_e0e705f843545fab, []int{57} } func (m *MetricResult) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1647,7 +1675,7 @@ var xxx_messageInfo_MetricResult proto.InternalMessageInfo func (m *NewRelicMetric) Reset() { *m = NewRelicMetric{} } func (*NewRelicMetric) ProtoMessage() {} func (*NewRelicMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{57} + return fileDescriptor_e0e705f843545fab, []int{58} } func (m *NewRelicMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1675,7 +1703,7 @@ var xxx_messageInfo_NewRelicMetric proto.InternalMessageInfo func (m *NginxTrafficRouting) Reset() { *m = NginxTrafficRouting{} } func (*NginxTrafficRouting) ProtoMessage() {} func (*NginxTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{58} + return fileDescriptor_e0e705f843545fab, []int{59} } func (m *NginxTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1703,7 +1731,7 @@ var xxx_messageInfo_NginxTrafficRouting proto.InternalMessageInfo func (m *ObjectRef) Reset() { *m = ObjectRef{} } func (*ObjectRef) ProtoMessage() {} func (*ObjectRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{59} + return fileDescriptor_e0e705f843545fab, []int{60} } func (m *ObjectRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1731,7 +1759,7 @@ var xxx_messageInfo_ObjectRef proto.InternalMessageInfo func (m *PauseCondition) Reset() { *m = PauseCondition{} } func (*PauseCondition) ProtoMessage() {} func (*PauseCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{60} + return fileDescriptor_e0e705f843545fab, []int{61} } func (m *PauseCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1759,7 +1787,7 @@ var xxx_messageInfo_PauseCondition proto.InternalMessageInfo func (m *PingPongSpec) Reset() { *m = PingPongSpec{} } func (*PingPongSpec) ProtoMessage() {} func (*PingPongSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{61} + return fileDescriptor_e0e705f843545fab, []int{62} } func (m *PingPongSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1787,7 +1815,7 @@ var xxx_messageInfo_PingPongSpec proto.InternalMessageInfo func (m *PodTemplateMetadata) Reset() { *m = PodTemplateMetadata{} } func (*PodTemplateMetadata) ProtoMessage() {} func (*PodTemplateMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{62} + return fileDescriptor_e0e705f843545fab, []int{63} } func (m *PodTemplateMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1817,7 +1845,7 @@ func (m *PreferredDuringSchedulingIgnoredDuringExecution) Reset() { } func (*PreferredDuringSchedulingIgnoredDuringExecution) ProtoMessage() {} func (*PreferredDuringSchedulingIgnoredDuringExecution) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{63} + return fileDescriptor_e0e705f843545fab, []int{64} } func (m *PreferredDuringSchedulingIgnoredDuringExecution) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1845,7 +1873,7 @@ var xxx_messageInfo_PreferredDuringSchedulingIgnoredDuringExecution proto.Intern func (m *PrometheusMetric) Reset() { *m = PrometheusMetric{} } func (*PrometheusMetric) ProtoMessage() {} func (*PrometheusMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{64} + return fileDescriptor_e0e705f843545fab, []int{65} } func (m *PrometheusMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1875,7 +1903,7 @@ func (m *RequiredDuringSchedulingIgnoredDuringExecution) Reset() { } func (*RequiredDuringSchedulingIgnoredDuringExecution) ProtoMessage() {} func (*RequiredDuringSchedulingIgnoredDuringExecution) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{65} + return fileDescriptor_e0e705f843545fab, []int{66} } func (m *RequiredDuringSchedulingIgnoredDuringExecution) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1903,7 +1931,7 @@ var xxx_messageInfo_RequiredDuringSchedulingIgnoredDuringExecution proto.Interna func (m *Rollout) Reset() { *m = Rollout{} } func (*Rollout) ProtoMessage() {} func (*Rollout) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{66} + return fileDescriptor_e0e705f843545fab, []int{67} } func (m *Rollout) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1931,7 +1959,7 @@ var xxx_messageInfo_Rollout proto.InternalMessageInfo func (m *RolloutAnalysis) Reset() { *m = RolloutAnalysis{} } func (*RolloutAnalysis) ProtoMessage() {} func (*RolloutAnalysis) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{67} + return fileDescriptor_e0e705f843545fab, []int{68} } func (m *RolloutAnalysis) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1959,7 +1987,7 @@ var xxx_messageInfo_RolloutAnalysis proto.InternalMessageInfo func (m *RolloutAnalysisBackground) Reset() { *m = RolloutAnalysisBackground{} } func (*RolloutAnalysisBackground) ProtoMessage() {} func (*RolloutAnalysisBackground) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{68} + return fileDescriptor_e0e705f843545fab, []int{69} } func (m *RolloutAnalysisBackground) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1987,7 +2015,7 @@ var xxx_messageInfo_RolloutAnalysisBackground proto.InternalMessageInfo func (m *RolloutAnalysisRunStatus) Reset() { *m = RolloutAnalysisRunStatus{} } func (*RolloutAnalysisRunStatus) ProtoMessage() {} func (*RolloutAnalysisRunStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{69} + return fileDescriptor_e0e705f843545fab, []int{70} } func (m *RolloutAnalysisRunStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2015,7 +2043,7 @@ var xxx_messageInfo_RolloutAnalysisRunStatus proto.InternalMessageInfo func (m *RolloutAnalysisTemplate) Reset() { *m = RolloutAnalysisTemplate{} } func (*RolloutAnalysisTemplate) ProtoMessage() {} func (*RolloutAnalysisTemplate) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{70} + return fileDescriptor_e0e705f843545fab, []int{71} } func (m *RolloutAnalysisTemplate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2043,7 +2071,7 @@ var xxx_messageInfo_RolloutAnalysisTemplate proto.InternalMessageInfo func (m *RolloutCondition) Reset() { *m = RolloutCondition{} } func (*RolloutCondition) ProtoMessage() {} func (*RolloutCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{71} + return fileDescriptor_e0e705f843545fab, []int{72} } func (m *RolloutCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2071,7 +2099,7 @@ var xxx_messageInfo_RolloutCondition proto.InternalMessageInfo func (m *RolloutExperimentStep) Reset() { *m = RolloutExperimentStep{} } func (*RolloutExperimentStep) ProtoMessage() {} func (*RolloutExperimentStep) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{72} + return fileDescriptor_e0e705f843545fab, []int{73} } func (m *RolloutExperimentStep) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2101,7 +2129,7 @@ func (m *RolloutExperimentStepAnalysisTemplateRef) Reset() { } func (*RolloutExperimentStepAnalysisTemplateRef) ProtoMessage() {} func (*RolloutExperimentStepAnalysisTemplateRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{73} + return fileDescriptor_e0e705f843545fab, []int{74} } func (m *RolloutExperimentStepAnalysisTemplateRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2129,7 +2157,7 @@ var xxx_messageInfo_RolloutExperimentStepAnalysisTemplateRef proto.InternalMessa func (m *RolloutExperimentTemplate) Reset() { *m = RolloutExperimentTemplate{} } func (*RolloutExperimentTemplate) ProtoMessage() {} func (*RolloutExperimentTemplate) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{74} + return fileDescriptor_e0e705f843545fab, []int{75} } func (m *RolloutExperimentTemplate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2157,7 +2185,7 @@ var xxx_messageInfo_RolloutExperimentTemplate proto.InternalMessageInfo func (m *RolloutList) Reset() { *m = RolloutList{} } func (*RolloutList) ProtoMessage() {} func (*RolloutList) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{75} + return fileDescriptor_e0e705f843545fab, []int{76} } func (m *RolloutList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2185,7 +2213,7 @@ var xxx_messageInfo_RolloutList proto.InternalMessageInfo func (m *RolloutPause) Reset() { *m = RolloutPause{} } func (*RolloutPause) ProtoMessage() {} func (*RolloutPause) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{76} + return fileDescriptor_e0e705f843545fab, []int{77} } func (m *RolloutPause) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2213,7 +2241,7 @@ var xxx_messageInfo_RolloutPause proto.InternalMessageInfo func (m *RolloutSpec) Reset() { *m = RolloutSpec{} } func (*RolloutSpec) ProtoMessage() {} func (*RolloutSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{77} + return fileDescriptor_e0e705f843545fab, []int{78} } func (m *RolloutSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2241,7 +2269,7 @@ var xxx_messageInfo_RolloutSpec proto.InternalMessageInfo func (m *RolloutStatus) Reset() { *m = RolloutStatus{} } func (*RolloutStatus) ProtoMessage() {} func (*RolloutStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{78} + return fileDescriptor_e0e705f843545fab, []int{79} } func (m *RolloutStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2269,7 +2297,7 @@ var xxx_messageInfo_RolloutStatus proto.InternalMessageInfo func (m *RolloutStrategy) Reset() { *m = RolloutStrategy{} } func (*RolloutStrategy) ProtoMessage() {} func (*RolloutStrategy) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{79} + return fileDescriptor_e0e705f843545fab, []int{80} } func (m *RolloutStrategy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2297,7 +2325,7 @@ var xxx_messageInfo_RolloutStrategy proto.InternalMessageInfo func (m *RolloutTrafficRouting) Reset() { *m = RolloutTrafficRouting{} } func (*RolloutTrafficRouting) ProtoMessage() {} func (*RolloutTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{80} + return fileDescriptor_e0e705f843545fab, []int{81} } func (m *RolloutTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2322,10 +2350,38 @@ func (m *RolloutTrafficRouting) XXX_DiscardUnknown() { var xxx_messageInfo_RolloutTrafficRouting proto.InternalMessageInfo +func (m *RouteMatch) Reset() { *m = RouteMatch{} } +func (*RouteMatch) ProtoMessage() {} +func (*RouteMatch) Descriptor() ([]byte, []int) { + return fileDescriptor_e0e705f843545fab, []int{82} +} +func (m *RouteMatch) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RouteMatch) 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 *RouteMatch) XXX_Merge(src proto.Message) { + xxx_messageInfo_RouteMatch.Merge(m, src) +} +func (m *RouteMatch) XXX_Size() int { + return m.Size() +} +func (m *RouteMatch) XXX_DiscardUnknown() { + xxx_messageInfo_RouteMatch.DiscardUnknown(m) +} + +var xxx_messageInfo_RouteMatch proto.InternalMessageInfo + func (m *RunSummary) Reset() { *m = RunSummary{} } func (*RunSummary) ProtoMessage() {} func (*RunSummary) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{81} + return fileDescriptor_e0e705f843545fab, []int{83} } func (m *RunSummary) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2353,7 +2409,7 @@ var xxx_messageInfo_RunSummary proto.InternalMessageInfo func (m *SMITrafficRouting) Reset() { *m = SMITrafficRouting{} } func (*SMITrafficRouting) ProtoMessage() {} func (*SMITrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{82} + return fileDescriptor_e0e705f843545fab, []int{84} } func (m *SMITrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2381,7 +2437,7 @@ var xxx_messageInfo_SMITrafficRouting proto.InternalMessageInfo func (m *ScopeDetail) Reset() { *m = ScopeDetail{} } func (*ScopeDetail) ProtoMessage() {} func (*ScopeDetail) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{83} + return fileDescriptor_e0e705f843545fab, []int{85} } func (m *ScopeDetail) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2409,7 +2465,7 @@ var xxx_messageInfo_ScopeDetail proto.InternalMessageInfo func (m *SecretKeyRef) Reset() { *m = SecretKeyRef{} } func (*SecretKeyRef) ProtoMessage() {} func (*SecretKeyRef) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{84} + return fileDescriptor_e0e705f843545fab, []int{86} } func (m *SecretKeyRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2437,7 +2493,7 @@ var xxx_messageInfo_SecretKeyRef proto.InternalMessageInfo func (m *SetCanaryScale) Reset() { *m = SetCanaryScale{} } func (*SetCanaryScale) ProtoMessage() {} func (*SetCanaryScale) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{85} + return fileDescriptor_e0e705f843545fab, []int{87} } func (m *SetCanaryScale) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2462,15 +2518,43 @@ func (m *SetCanaryScale) XXX_DiscardUnknown() { var xxx_messageInfo_SetCanaryScale proto.InternalMessageInfo -func (m *SetHeaderRouting) Reset() { *m = SetHeaderRouting{} } -func (*SetHeaderRouting) ProtoMessage() {} -func (*SetHeaderRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{86} +func (m *SetHeaderRoute) Reset() { *m = SetHeaderRoute{} } +func (*SetHeaderRoute) ProtoMessage() {} +func (*SetHeaderRoute) Descriptor() ([]byte, []int) { + return fileDescriptor_e0e705f843545fab, []int{88} +} +func (m *SetHeaderRoute) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SetHeaderRoute) 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 *SetHeaderRoute) XXX_Merge(src proto.Message) { + xxx_messageInfo_SetHeaderRoute.Merge(m, src) +} +func (m *SetHeaderRoute) XXX_Size() int { + return m.Size() +} +func (m *SetHeaderRoute) XXX_DiscardUnknown() { + xxx_messageInfo_SetHeaderRoute.DiscardUnknown(m) +} + +var xxx_messageInfo_SetHeaderRoute proto.InternalMessageInfo + +func (m *SetMirrorRoute) Reset() { *m = SetMirrorRoute{} } +func (*SetMirrorRoute) ProtoMessage() {} +func (*SetMirrorRoute) Descriptor() ([]byte, []int) { + return fileDescriptor_e0e705f843545fab, []int{89} } -func (m *SetHeaderRouting) XXX_Unmarshal(b []byte) error { +func (m *SetMirrorRoute) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *SetHeaderRouting) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *SetMirrorRoute) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) if err != nil { @@ -2478,22 +2562,22 @@ func (m *SetHeaderRouting) XXX_Marshal(b []byte, deterministic bool) ([]byte, er } return b[:n], nil } -func (m *SetHeaderRouting) XXX_Merge(src proto.Message) { - xxx_messageInfo_SetHeaderRouting.Merge(m, src) +func (m *SetMirrorRoute) XXX_Merge(src proto.Message) { + xxx_messageInfo_SetMirrorRoute.Merge(m, src) } -func (m *SetHeaderRouting) XXX_Size() int { +func (m *SetMirrorRoute) XXX_Size() int { return m.Size() } -func (m *SetHeaderRouting) XXX_DiscardUnknown() { - xxx_messageInfo_SetHeaderRouting.DiscardUnknown(m) +func (m *SetMirrorRoute) XXX_DiscardUnknown() { + xxx_messageInfo_SetMirrorRoute.DiscardUnknown(m) } -var xxx_messageInfo_SetHeaderRouting proto.InternalMessageInfo +var xxx_messageInfo_SetMirrorRoute proto.InternalMessageInfo func (m *StickinessConfig) Reset() { *m = StickinessConfig{} } func (*StickinessConfig) ProtoMessage() {} func (*StickinessConfig) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{87} + return fileDescriptor_e0e705f843545fab, []int{90} } func (m *StickinessConfig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2521,7 +2605,7 @@ var xxx_messageInfo_StickinessConfig proto.InternalMessageInfo func (m *StringMatch) Reset() { *m = StringMatch{} } func (*StringMatch) ProtoMessage() {} func (*StringMatch) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{88} + return fileDescriptor_e0e705f843545fab, []int{91} } func (m *StringMatch) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2549,7 +2633,7 @@ var xxx_messageInfo_StringMatch proto.InternalMessageInfo func (m *TLSRoute) Reset() { *m = TLSRoute{} } func (*TLSRoute) ProtoMessage() {} func (*TLSRoute) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{89} + return fileDescriptor_e0e705f843545fab, []int{92} } func (m *TLSRoute) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2577,7 +2661,7 @@ var xxx_messageInfo_TLSRoute proto.InternalMessageInfo func (m *TemplateService) Reset() { *m = TemplateService{} } func (*TemplateService) ProtoMessage() {} func (*TemplateService) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{90} + return fileDescriptor_e0e705f843545fab, []int{93} } func (m *TemplateService) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2605,7 +2689,7 @@ var xxx_messageInfo_TemplateService proto.InternalMessageInfo func (m *TemplateSpec) Reset() { *m = TemplateSpec{} } func (*TemplateSpec) ProtoMessage() {} func (*TemplateSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{91} + return fileDescriptor_e0e705f843545fab, []int{94} } func (m *TemplateSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2633,7 +2717,7 @@ var xxx_messageInfo_TemplateSpec proto.InternalMessageInfo func (m *TemplateStatus) Reset() { *m = TemplateStatus{} } func (*TemplateStatus) ProtoMessage() {} func (*TemplateStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{92} + return fileDescriptor_e0e705f843545fab, []int{95} } func (m *TemplateStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2661,7 +2745,7 @@ var xxx_messageInfo_TemplateStatus proto.InternalMessageInfo func (m *TraefikTrafficRouting) Reset() { *m = TraefikTrafficRouting{} } func (*TraefikTrafficRouting) ProtoMessage() {} func (*TraefikTrafficRouting) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{93} + return fileDescriptor_e0e705f843545fab, []int{96} } func (m *TraefikTrafficRouting) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2689,7 +2773,7 @@ var xxx_messageInfo_TraefikTrafficRouting proto.InternalMessageInfo func (m *TrafficWeights) Reset() { *m = TrafficWeights{} } func (*TrafficWeights) ProtoMessage() {} func (*TrafficWeights) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{94} + return fileDescriptor_e0e705f843545fab, []int{97} } func (m *TrafficWeights) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2717,7 +2801,7 @@ var xxx_messageInfo_TrafficWeights proto.InternalMessageInfo func (m *ValueFrom) Reset() { *m = ValueFrom{} } func (*ValueFrom) ProtoMessage() {} func (*ValueFrom) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{95} + return fileDescriptor_e0e705f843545fab, []int{98} } func (m *ValueFrom) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2745,7 +2829,7 @@ var xxx_messageInfo_ValueFrom proto.InternalMessageInfo func (m *WavefrontMetric) Reset() { *m = WavefrontMetric{} } func (*WavefrontMetric) ProtoMessage() {} func (*WavefrontMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{96} + return fileDescriptor_e0e705f843545fab, []int{99} } func (m *WavefrontMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2773,7 +2857,7 @@ var xxx_messageInfo_WavefrontMetric proto.InternalMessageInfo func (m *WebMetric) Reset() { *m = WebMetric{} } func (*WebMetric) ProtoMessage() {} func (*WebMetric) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{97} + return fileDescriptor_e0e705f843545fab, []int{100} } func (m *WebMetric) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2801,7 +2885,7 @@ var xxx_messageInfo_WebMetric proto.InternalMessageInfo func (m *WebMetricHeader) Reset() { *m = WebMetricHeader{} } func (*WebMetricHeader) ProtoMessage() {} func (*WebMetricHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{98} + return fileDescriptor_e0e705f843545fab, []int{101} } func (m *WebMetricHeader) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2829,7 +2913,7 @@ var xxx_messageInfo_WebMetricHeader proto.InternalMessageInfo func (m *WeightDestination) Reset() { *m = WeightDestination{} } func (*WeightDestination) ProtoMessage() {} func (*WeightDestination) Descriptor() ([]byte, []int) { - return fileDescriptor_e0e705f843545fab, []int{99} + return fileDescriptor_e0e705f843545fab, []int{102} } func (m *WeightDestination) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2907,6 +2991,7 @@ func init() { proto.RegisterType((*KayentaMetric)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.KayentaMetric") proto.RegisterType((*KayentaScope)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.KayentaScope") proto.RegisterType((*KayentaThreshold)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.KayentaThreshold") + proto.RegisterType((*MangedRoutes)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MangedRoutes") proto.RegisterType((*Measurement)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.Measurement") proto.RegisterMapType((map[string]string)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.Measurement.MetadataEntry") proto.RegisterType((*MeasurementRetention)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.MeasurementRetention") @@ -2941,12 +3026,15 @@ func init() { proto.RegisterType((*RolloutStatus)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.RolloutStatus") proto.RegisterType((*RolloutStrategy)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.RolloutStrategy") proto.RegisterType((*RolloutTrafficRouting)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.RolloutTrafficRouting") + proto.RegisterType((*RouteMatch)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.RouteMatch") + proto.RegisterMapType((map[string]StringMatch)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.RouteMatch.HeadersEntry") proto.RegisterType((*RunSummary)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.RunSummary") proto.RegisterType((*SMITrafficRouting)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SMITrafficRouting") proto.RegisterType((*ScopeDetail)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.ScopeDetail") proto.RegisterType((*SecretKeyRef)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SecretKeyRef") proto.RegisterType((*SetCanaryScale)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SetCanaryScale") - proto.RegisterType((*SetHeaderRouting)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SetHeaderRouting") + proto.RegisterType((*SetHeaderRoute)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SetHeaderRoute") + proto.RegisterType((*SetMirrorRoute)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.SetMirrorRoute") proto.RegisterType((*StickinessConfig)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.StickinessConfig") proto.RegisterType((*StringMatch)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.StringMatch") proto.RegisterType((*TLSRoute)(nil), "github.com.argoproj.argo_rollouts.pkg.apis.rollouts.v1alpha1.TLSRoute") @@ -2967,466 +3055,478 @@ func init() { } var fileDescriptor_e0e705f843545fab = []byte{ - // 7342 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x6b, 0x6c, 0x24, 0x59, - 0x75, 0xf0, 0x56, 0xb7, 0xdb, 0xee, 0x3e, 0xf6, 0xf8, 0x71, 0xc7, 0xc3, 0x78, 0xbd, 0x3b, 0xd3, - 0x4b, 0x2d, 0xda, 0x6f, 0xf9, 0x3e, 0xf0, 0xc0, 0x3e, 0xbe, 0x6f, 0x61, 0xd1, 0x7e, 0xe9, 0xb6, - 0x67, 0x76, 0x3c, 0x6b, 0x7b, 0x3c, 0xb7, 0x3d, 0x33, 0xb0, 0xb0, 0x84, 0x72, 0xf7, 0x75, 0xbb, - 0x66, 0xba, 0xab, 0x9a, 0xaa, 0x6a, 0xcf, 0x78, 0x59, 0xc1, 0x6e, 0xd0, 0x6e, 0x20, 0x02, 0xb1, - 0x09, 0xa0, 0x28, 0x8a, 0x88, 0x50, 0xb4, 0x52, 0xa2, 0x90, 0x5f, 0x28, 0x51, 0xfe, 0x20, 0x25, - 0x0a, 0xa0, 0x10, 0x45, 0x89, 0x48, 0x94, 0x04, 0x88, 0x44, 0x27, 0x6b, 0xf2, 0x27, 0x51, 0xa2, - 0x28, 0x12, 0x51, 0xc4, 0xfc, 0x8a, 0xee, 0xb3, 0x6e, 0x3d, 0xda, 0xd3, 0xed, 0x2e, 0x0f, 0xab, - 0x84, 0x7f, 0xdd, 0xf7, 0x9c, 0x7b, 0xce, 0x7d, 0x9f, 0xc7, 0x3d, 0xf7, 0x14, 0xac, 0x35, 0xed, - 0x60, 0xb7, 0xbb, 0xbd, 0x54, 0x77, 0xdb, 0xe7, 0x2c, 0xaf, 0xe9, 0x76, 0x3c, 0xf7, 0x06, 0xfb, - 0xf1, 0x6e, 0xcf, 0x6d, 0xb5, 0xdc, 0x6e, 0xe0, 0x9f, 0xeb, 0xdc, 0x6c, 0x9e, 0xb3, 0x3a, 0xb6, - 0x7f, 0x4e, 0x95, 0xec, 0xbd, 0xd7, 0x6a, 0x75, 0x76, 0xad, 0xf7, 0x9e, 0x6b, 0x12, 0x87, 0x78, - 0x56, 0x40, 0x1a, 0x4b, 0x1d, 0xcf, 0x0d, 0x5c, 0xf4, 0x81, 0x90, 0xda, 0x92, 0xa4, 0xc6, 0x7e, - 0xfc, 0xbc, 0xac, 0xbb, 0xd4, 0xb9, 0xd9, 0x5c, 0xa2, 0xd4, 0x96, 0x54, 0x89, 0xa4, 0xb6, 0xf8, - 0x6e, 0xad, 0x2d, 0x4d, 0xb7, 0xe9, 0x9e, 0x63, 0x44, 0xb7, 0xbb, 0x3b, 0xec, 0x1f, 0xfb, 0xc3, - 0x7e, 0x71, 0x66, 0x8b, 0x0f, 0xdf, 0x7c, 0xca, 0x5f, 0xb2, 0x5d, 0xda, 0xb6, 0x73, 0xdb, 0x56, - 0x50, 0xdf, 0x3d, 0xb7, 0x97, 0x68, 0xd1, 0xa2, 0xa9, 0x21, 0xd5, 0x5d, 0x8f, 0xa4, 0xe1, 0x3c, - 0x11, 0xe2, 0xb4, 0xad, 0xfa, 0xae, 0xed, 0x10, 0x6f, 0x3f, 0xec, 0x75, 0x9b, 0x04, 0x56, 0x5a, - 0xad, 0x73, 0xfd, 0x6a, 0x79, 0x5d, 0x27, 0xb0, 0xdb, 0x24, 0x51, 0xe1, 0xff, 0xde, 0xad, 0x82, - 0x5f, 0xdf, 0x25, 0x6d, 0x2b, 0x51, 0xef, 0xf1, 0x7e, 0xf5, 0xba, 0x81, 0xdd, 0x3a, 0x67, 0x3b, - 0x81, 0x1f, 0x78, 0xf1, 0x4a, 0xe6, 0xb7, 0xf2, 0x50, 0xaa, 0xac, 0x55, 0x6b, 0x81, 0x15, 0x74, - 0x7d, 0xf4, 0x9a, 0x01, 0x53, 0x2d, 0xd7, 0x6a, 0x54, 0xad, 0x96, 0xe5, 0xd4, 0x89, 0xb7, 0x60, - 0x3c, 0x64, 0x3c, 0x3a, 0xf9, 0xd8, 0xda, 0xd2, 0x28, 0xf3, 0xb5, 0x54, 0xb9, 0xe5, 0x63, 0xe2, - 0xbb, 0x5d, 0xaf, 0x4e, 0x30, 0xd9, 0xa9, 0xce, 0x7f, 0xa7, 0x57, 0xbe, 0xef, 0xa0, 0x57, 0x9e, - 0x5a, 0xd3, 0x38, 0xe1, 0x08, 0x5f, 0xf4, 0x65, 0x03, 0xe6, 0xea, 0x96, 0x63, 0x79, 0xfb, 0x5b, - 0x96, 0xd7, 0x24, 0xc1, 0xb3, 0x9e, 0xdb, 0xed, 0x2c, 0xe4, 0x8e, 0xa1, 0x35, 0xf7, 0x8b, 0xd6, - 0xcc, 0x2d, 0xc7, 0xd9, 0xe1, 0x64, 0x0b, 0x58, 0xbb, 0xfc, 0xc0, 0xda, 0x6e, 0x11, 0xbd, 0x5d, - 0xf9, 0xe3, 0x6c, 0x57, 0x2d, 0xce, 0x0e, 0x27, 0x5b, 0x60, 0xbe, 0x9a, 0x87, 0xb9, 0xca, 0x5a, - 0x75, 0xcb, 0xb3, 0x76, 0x76, 0xec, 0x3a, 0x76, 0xbb, 0x81, 0xed, 0x34, 0xd1, 0x3b, 0x61, 0xc2, - 0x76, 0x9a, 0x1e, 0xf1, 0x7d, 0x36, 0x91, 0xa5, 0xea, 0x8c, 0x20, 0x3a, 0xb1, 0xca, 0x8b, 0xb1, - 0x84, 0xa3, 0x27, 0x61, 0xd2, 0x27, 0xde, 0x9e, 0x5d, 0x27, 0x9b, 0xae, 0x17, 0xb0, 0x91, 0x2e, - 0x54, 0x4f, 0x0a, 0xf4, 0xc9, 0x5a, 0x08, 0xc2, 0x3a, 0x1e, 0xad, 0xe6, 0xb9, 0x6e, 0x20, 0xe0, - 0x6c, 0x20, 0x4a, 0x61, 0x35, 0x1c, 0x82, 0xb0, 0x8e, 0x87, 0x5e, 0x37, 0x60, 0xd6, 0x0f, 0xec, - 0xfa, 0x4d, 0xdb, 0x21, 0xbe, 0xbf, 0xec, 0x3a, 0x3b, 0x76, 0x73, 0xa1, 0xc0, 0x46, 0x71, 0x63, - 0xb4, 0x51, 0xac, 0xc5, 0xa8, 0x56, 0xe7, 0x0f, 0x7a, 0xe5, 0xd9, 0x78, 0x29, 0x4e, 0x70, 0x47, - 0x2b, 0x30, 0x6b, 0x39, 0x8e, 0x1b, 0x58, 0x81, 0xed, 0x3a, 0x9b, 0x1e, 0xd9, 0xb1, 0x6f, 0x2f, - 0x8c, 0xb1, 0xee, 0x2c, 0x88, 0xee, 0xcc, 0x56, 0x62, 0x70, 0x9c, 0xa8, 0x61, 0xae, 0xc0, 0x42, - 0xa5, 0xbd, 0x6d, 0xf9, 0xbe, 0xd5, 0x70, 0xbd, 0xd8, 0x6c, 0x3c, 0x0a, 0xc5, 0xb6, 0xd5, 0xe9, - 0xd8, 0x4e, 0x93, 0x4e, 0x47, 0xfe, 0xd1, 0x52, 0x75, 0xea, 0xa0, 0x57, 0x2e, 0xae, 0x8b, 0x32, - 0xac, 0xa0, 0xe6, 0x0f, 0x72, 0x30, 0x59, 0x71, 0xac, 0xd6, 0xbe, 0x6f, 0xfb, 0xb8, 0xeb, 0xa0, - 0x8f, 0x41, 0x91, 0x9e, 0x2e, 0x0d, 0x2b, 0xb0, 0xc4, 0x8e, 0x7c, 0xcf, 0x12, 0xdf, 0xec, 0x4b, - 0xfa, 0x66, 0x0f, 0xc7, 0x85, 0x62, 0x2f, 0xed, 0xbd, 0x77, 0xe9, 0xf2, 0xf6, 0x0d, 0x52, 0x0f, - 0xd6, 0x49, 0x60, 0x55, 0x91, 0xe8, 0x05, 0x84, 0x65, 0x58, 0x51, 0x45, 0x2e, 0x8c, 0xf9, 0x1d, - 0x52, 0x17, 0x3b, 0x6c, 0x7d, 0xc4, 0x95, 0x1c, 0x36, 0xbd, 0xd6, 0x21, 0xf5, 0xea, 0x94, 0x60, - 0x3d, 0x46, 0xff, 0x61, 0xc6, 0x08, 0xdd, 0x82, 0x71, 0x9f, 0x9d, 0x39, 0x62, 0xf3, 0x5c, 0xce, - 0x8e, 0x25, 0x23, 0x5b, 0x9d, 0x16, 0x4c, 0xc7, 0xf9, 0x7f, 0x2c, 0xd8, 0x99, 0x7f, 0x67, 0xc0, - 0x49, 0x0d, 0xbb, 0xe2, 0x35, 0xbb, 0x6d, 0xe2, 0x04, 0xe8, 0x21, 0x18, 0x73, 0xac, 0x36, 0x11, - 0x1b, 0x45, 0x35, 0x79, 0xc3, 0x6a, 0x13, 0xcc, 0x20, 0xe8, 0x61, 0x28, 0xec, 0x59, 0xad, 0x2e, - 0x61, 0x83, 0x54, 0xaa, 0x9e, 0x10, 0x28, 0x85, 0x6b, 0xb4, 0x10, 0x73, 0x18, 0x7a, 0x09, 0x4a, - 0xec, 0xc7, 0x05, 0xcf, 0x6d, 0x67, 0xd4, 0x35, 0xd1, 0xc2, 0x6b, 0x92, 0x6c, 0xf5, 0xc4, 0x41, - 0xaf, 0x5c, 0x52, 0x7f, 0x71, 0xc8, 0xd0, 0xfc, 0x7b, 0x03, 0x66, 0xb4, 0xce, 0xad, 0xd9, 0x7e, - 0x80, 0x3e, 0x92, 0x58, 0x3c, 0x4b, 0x83, 0x2d, 0x1e, 0x5a, 0x9b, 0x2d, 0x9d, 0x59, 0xd1, 0xd3, - 0xa2, 0x2c, 0xd1, 0x16, 0x8e, 0x03, 0x05, 0x3b, 0x20, 0x6d, 0x7f, 0x21, 0xf7, 0x50, 0xfe, 0xd1, - 0xc9, 0xc7, 0x56, 0x33, 0x9b, 0xc6, 0x70, 0x7c, 0x57, 0x29, 0x7d, 0xcc, 0xd9, 0x98, 0x5f, 0x1f, - 0x8b, 0xf4, 0x90, 0xae, 0x28, 0xe4, 0xc2, 0x44, 0x9b, 0x04, 0x9e, 0x5d, 0xe7, 0xfb, 0x6a, 0xf2, - 0xb1, 0x95, 0xd1, 0x5a, 0xb1, 0xce, 0x88, 0x85, 0x87, 0x25, 0xff, 0xef, 0x63, 0xc9, 0x05, 0xed, - 0xc2, 0x98, 0xe5, 0x35, 0x65, 0x9f, 0x2f, 0x64, 0x33, 0xbf, 0xe1, 0x9a, 0xab, 0x78, 0x4d, 0x1f, - 0x33, 0x0e, 0xe8, 0x1c, 0x94, 0x02, 0xe2, 0xb5, 0x6d, 0xc7, 0x0a, 0xf8, 0xe9, 0x5a, 0xac, 0xce, - 0x09, 0xb4, 0xd2, 0x96, 0x04, 0xe0, 0x10, 0x07, 0xb5, 0x60, 0xbc, 0xe1, 0xed, 0xe3, 0xae, 0xb3, - 0x30, 0x96, 0xc5, 0x50, 0xac, 0x30, 0x5a, 0xe1, 0x66, 0xe2, 0xff, 0xb1, 0xe0, 0x81, 0xde, 0x30, - 0x60, 0xbe, 0x4d, 0x2c, 0xbf, 0xeb, 0x11, 0xda, 0x05, 0x4c, 0x02, 0xe2, 0xd0, 0xd3, 0x70, 0xa1, - 0xc0, 0x98, 0xe3, 0x51, 0xe7, 0x21, 0x49, 0xb9, 0xfa, 0xa0, 0x68, 0xca, 0x7c, 0x1a, 0x14, 0xa7, - 0xb6, 0xc6, 0xfc, 0xc1, 0x18, 0xcc, 0x25, 0x4e, 0x08, 0xf4, 0x04, 0x14, 0x3a, 0xbb, 0x96, 0x2f, - 0xb7, 0xfc, 0x59, 0xb9, 0xde, 0x36, 0x69, 0xe1, 0x9d, 0x5e, 0xf9, 0x84, 0xac, 0xc2, 0x0a, 0x30, - 0x47, 0xa6, 0x32, 0xb5, 0x4d, 0x7c, 0xdf, 0x6a, 0xca, 0x73, 0x40, 0x5b, 0x26, 0xac, 0x18, 0x4b, - 0x38, 0xfa, 0x45, 0x03, 0x4e, 0xf0, 0x25, 0x83, 0x89, 0xdf, 0x6d, 0x05, 0xf4, 0xac, 0xa3, 0xc3, - 0x72, 0x29, 0x8b, 0xe5, 0xc9, 0x49, 0x56, 0x4f, 0x09, 0xee, 0x27, 0xf4, 0x52, 0x1f, 0x47, 0xf9, - 0xa2, 0xeb, 0x50, 0xf2, 0x03, 0xcb, 0x0b, 0x48, 0xa3, 0x12, 0x30, 0xa9, 0x36, 0xf9, 0xd8, 0xff, - 0x1e, 0xec, 0x10, 0xd8, 0xb2, 0xdb, 0x84, 0x1f, 0x38, 0x35, 0x49, 0x00, 0x87, 0xb4, 0xd0, 0x4b, - 0x00, 0x5e, 0xd7, 0xa9, 0x75, 0xdb, 0x6d, 0xcb, 0xdb, 0x17, 0x12, 0xfc, 0xe2, 0x68, 0xdd, 0xc3, - 0x8a, 0x5e, 0x28, 0xb3, 0xc2, 0x32, 0xac, 0xf1, 0x43, 0xaf, 0x18, 0x70, 0x82, 0xaf, 0x44, 0xd9, - 0x82, 0xf1, 0x8c, 0x5b, 0x30, 0x47, 0x87, 0x76, 0x45, 0x67, 0x81, 0xa3, 0x1c, 0xcd, 0xbf, 0x89, - 0xca, 0x93, 0x5a, 0x40, 0xb5, 0xeb, 0xe6, 0x3e, 0xfa, 0x30, 0xdc, 0xef, 0x77, 0xeb, 0x75, 0xe2, - 0xfb, 0x3b, 0xdd, 0x16, 0xee, 0x3a, 0x17, 0x6d, 0x3f, 0x70, 0xbd, 0xfd, 0x35, 0xbb, 0x6d, 0x07, - 0x6c, 0xc5, 0x15, 0xaa, 0x67, 0x0e, 0x7a, 0xe5, 0xfb, 0x6b, 0xfd, 0x90, 0x70, 0xff, 0xfa, 0xc8, - 0x82, 0x07, 0xba, 0x4e, 0x7f, 0xf2, 0x5c, 0x7b, 0x2b, 0x1f, 0xf4, 0xca, 0x0f, 0x5c, 0xed, 0x8f, - 0x86, 0x0f, 0xa3, 0x61, 0xfe, 0xb3, 0x01, 0xb3, 0xb2, 0x5f, 0x5b, 0xa4, 0xdd, 0x69, 0xd1, 0xd3, - 0xe5, 0xf8, 0x15, 0x91, 0x20, 0xa2, 0x88, 0xe0, 0x6c, 0xc4, 0x89, 0x6c, 0x7f, 0x3f, 0x6d, 0xc4, - 0xfc, 0x27, 0x03, 0xe6, 0xe3, 0xc8, 0xf7, 0x40, 0x78, 0xfa, 0x51, 0xe1, 0xb9, 0x91, 0x6d, 0x6f, - 0xfb, 0x48, 0xd0, 0xd7, 0xc6, 0x92, 0x7d, 0xfd, 0xef, 0x2e, 0x46, 0x43, 0xa9, 0x98, 0xff, 0x69, - 0x4a, 0xc5, 0xb1, 0xb7, 0x94, 0x54, 0xfc, 0xed, 0x31, 0x98, 0xaa, 0x38, 0x81, 0x5d, 0xd9, 0xd9, - 0xb1, 0x1d, 0x3b, 0xd8, 0x47, 0x9f, 0xcb, 0xc1, 0xb9, 0x8e, 0x47, 0x76, 0x88, 0xe7, 0x91, 0xc6, - 0x4a, 0xd7, 0xb3, 0x9d, 0x66, 0xad, 0xbe, 0x4b, 0x1a, 0xdd, 0x96, 0xed, 0x34, 0x57, 0x9b, 0x8e, - 0xab, 0x8a, 0xcf, 0xdf, 0x26, 0xf5, 0x2e, 0xeb, 0x12, 0xdf, 0x14, 0xed, 0xd1, 0xba, 0xb4, 0x39, - 0x1c, 0xd3, 0xea, 0xe3, 0x07, 0xbd, 0xf2, 0xb9, 0x21, 0x2b, 0xe1, 0x61, 0xbb, 0x86, 0x3e, 0x93, - 0x83, 0x25, 0x8f, 0x7c, 0xbc, 0x6b, 0x0f, 0x3e, 0x1a, 0xfc, 0xd4, 0x6a, 0x8d, 0x28, 0x7e, 0x86, - 0xe2, 0x59, 0x7d, 0xec, 0xa0, 0x57, 0x1e, 0xb2, 0x0e, 0x1e, 0xb2, 0x5f, 0xe6, 0x37, 0x73, 0x70, - 0xaa, 0xd2, 0xe9, 0xac, 0x13, 0x7f, 0x37, 0x66, 0xd4, 0x7e, 0xc1, 0x80, 0xe9, 0x3d, 0xdb, 0x0b, - 0xba, 0x56, 0x4b, 0x3a, 0x01, 0xf8, 0x92, 0xa8, 0x8d, 0xb8, 0x9d, 0x39, 0xb7, 0x6b, 0x11, 0xd2, - 0x55, 0x74, 0xd0, 0x2b, 0x4f, 0x47, 0xcb, 0x70, 0x8c, 0x3d, 0xfa, 0x55, 0x03, 0x66, 0x45, 0xd1, - 0x86, 0xdb, 0x20, 0xba, 0xe7, 0xe8, 0x6a, 0x96, 0x6d, 0x52, 0xc4, 0xb9, 0x8b, 0x21, 0x5e, 0x8a, - 0x13, 0x8d, 0x30, 0xff, 0x35, 0x07, 0xa7, 0xfb, 0xd0, 0x40, 0xbf, 0x65, 0xc0, 0x3c, 0x77, 0x37, - 0x69, 0x20, 0x4c, 0x76, 0xc4, 0x68, 0x7e, 0x28, 0xeb, 0x96, 0x63, 0xba, 0x17, 0x88, 0x53, 0x27, - 0xd5, 0x05, 0x7a, 0x6c, 0x2c, 0xa7, 0xb0, 0xc6, 0xa9, 0x0d, 0x62, 0x2d, 0xe5, 0x0e, 0xa8, 0x58, - 0x4b, 0x73, 0xf7, 0xa4, 0xa5, 0xb5, 0x14, 0xd6, 0x38, 0xb5, 0x41, 0xe6, 0xff, 0x87, 0x07, 0x0e, - 0x21, 0x77, 0x77, 0x8b, 0xdf, 0x7c, 0x41, 0xad, 0xfa, 0xe8, 0x9a, 0x1b, 0xc0, 0x59, 0x60, 0xc2, - 0xb8, 0xe7, 0x76, 0x03, 0xc2, 0xa5, 0x5b, 0xa9, 0x0a, 0x54, 0x4e, 0x60, 0x56, 0x82, 0x05, 0xc4, - 0xfc, 0xa6, 0x01, 0xc5, 0x21, 0xfc, 0x0f, 0xe5, 0xa8, 0xff, 0xa1, 0x94, 0xf0, 0x3d, 0x04, 0x49, - 0xdf, 0xc3, 0xb3, 0xa3, 0xcd, 0xc6, 0x20, 0x3e, 0x87, 0x7f, 0x33, 0x60, 0x2e, 0xe1, 0xa3, 0x40, - 0xbb, 0x30, 0xdf, 0x71, 0x1b, 0x52, 0xbf, 0xb8, 0x68, 0xf9, 0xbb, 0x0c, 0x26, 0xba, 0xf7, 0x04, - 0x9d, 0xc9, 0xcd, 0x14, 0xf8, 0x9d, 0x5e, 0x79, 0x41, 0x11, 0x89, 0x21, 0xe0, 0x54, 0x8a, 0xa8, - 0x03, 0xc5, 0x1d, 0x9b, 0xb4, 0x1a, 0xe1, 0x12, 0x1c, 0x51, 0x93, 0xb8, 0x20, 0xa8, 0x71, 0xf7, - 0x9c, 0xfc, 0x87, 0x15, 0x17, 0xf3, 0x0a, 0x4c, 0x47, 0x9d, 0xb5, 0x03, 0x4c, 0xde, 0x19, 0xc8, - 0x5b, 0x9e, 0x23, 0xa6, 0x6e, 0x52, 0x20, 0xe4, 0x2b, 0x78, 0x03, 0xd3, 0x72, 0xf3, 0x27, 0x63, - 0x30, 0x53, 0x6d, 0x75, 0xc9, 0xb3, 0x1e, 0x21, 0xd2, 0x3e, 0xad, 0xc0, 0x4c, 0xc7, 0x23, 0x7b, - 0x36, 0xb9, 0x55, 0x23, 0x2d, 0x52, 0x0f, 0x5c, 0x4f, 0xd0, 0x3f, 0x2d, 0xaa, 0xcf, 0x6c, 0x46, - 0xc1, 0x38, 0x8e, 0x8f, 0x9e, 0x81, 0x69, 0xab, 0x1e, 0xd8, 0x7b, 0x44, 0x51, 0xe0, 0x0d, 0x78, - 0x9b, 0xa0, 0x30, 0x5d, 0x89, 0x40, 0x71, 0x0c, 0x1b, 0x7d, 0x04, 0x16, 0xfc, 0xba, 0xd5, 0x22, - 0x57, 0x3b, 0x82, 0xd5, 0xf2, 0x2e, 0xa9, 0xdf, 0xdc, 0x74, 0x6d, 0x27, 0x10, 0xde, 0x88, 0x87, - 0x04, 0xa5, 0x85, 0x5a, 0x1f, 0x3c, 0xdc, 0x97, 0x02, 0xfa, 0x43, 0x03, 0xce, 0x74, 0x3c, 0xb2, - 0xe9, 0xb9, 0x6d, 0x97, 0x8a, 0x99, 0x84, 0x89, 0x2e, 0x4c, 0xd5, 0x6b, 0x23, 0xca, 0x53, 0x5e, - 0x92, 0x74, 0x11, 0xbe, 0xfd, 0xa0, 0x57, 0x3e, 0xb3, 0x79, 0x58, 0x03, 0xf0, 0xe1, 0xed, 0x43, - 0x7f, 0x6c, 0xc0, 0xd9, 0x8e, 0xeb, 0x07, 0x87, 0x74, 0xa1, 0x70, 0xac, 0x5d, 0x30, 0x0f, 0x7a, - 0xe5, 0xb3, 0x9b, 0x87, 0xb6, 0x00, 0xdf, 0xa5, 0x85, 0xe6, 0xc1, 0x24, 0xcc, 0x69, 0x6b, 0x4f, - 0xd8, 0xaf, 0x4f, 0xc3, 0x09, 0xb9, 0x18, 0x42, 0xb1, 0x5e, 0x0a, 0xfd, 0x0d, 0x15, 0x1d, 0x88, - 0xa3, 0xb8, 0x74, 0xdd, 0xa9, 0xa5, 0xc8, 0x6b, 0xc7, 0xd6, 0xdd, 0x66, 0x04, 0x8a, 0x63, 0xd8, - 0x68, 0x15, 0x4e, 0x8a, 0x12, 0x4c, 0x3a, 0x2d, 0xbb, 0x6e, 0x2d, 0xbb, 0x5d, 0xb1, 0xe4, 0x0a, - 0xd5, 0xd3, 0x07, 0xbd, 0xf2, 0xc9, 0xcd, 0x24, 0x18, 0xa7, 0xd5, 0x41, 0x6b, 0x30, 0x6f, 0x75, - 0x03, 0x57, 0xf5, 0xff, 0xbc, 0x43, 0x25, 0x45, 0x83, 0x2d, 0xad, 0x22, 0x17, 0x29, 0x95, 0x14, - 0x38, 0x4e, 0xad, 0x85, 0x36, 0x63, 0xd4, 0x6a, 0xa4, 0xee, 0x3a, 0x0d, 0x3e, 0xcb, 0x85, 0x50, - 0x0b, 0xaf, 0xa4, 0xe0, 0xe0, 0xd4, 0x9a, 0xa8, 0x05, 0xd3, 0x6d, 0xeb, 0xf6, 0x55, 0xc7, 0xda, - 0xb3, 0xec, 0x16, 0x65, 0x22, 0x7c, 0x18, 0xfd, 0x0d, 0xeb, 0x6e, 0x60, 0xb7, 0x96, 0xf8, 0x75, - 0xde, 0xd2, 0xaa, 0x13, 0x5c, 0xf6, 0x6a, 0x01, 0xd5, 0xd6, 0xb8, 0x72, 0xb4, 0x1e, 0xa1, 0x85, - 0x63, 0xb4, 0xd1, 0x65, 0x38, 0xc5, 0xb6, 0xe3, 0x8a, 0x7b, 0xcb, 0x59, 0x21, 0x2d, 0x6b, 0x5f, - 0x76, 0x60, 0x82, 0x75, 0xe0, 0xfe, 0x83, 0x5e, 0xf9, 0x54, 0x2d, 0x0d, 0x01, 0xa7, 0xd7, 0x43, - 0x16, 0x3c, 0x10, 0x05, 0x60, 0xb2, 0x67, 0xfb, 0xb6, 0xeb, 0x70, 0x4f, 0x44, 0x31, 0xf4, 0x44, - 0xd4, 0xfa, 0xa3, 0xe1, 0xc3, 0x68, 0xa0, 0x5f, 0x37, 0x60, 0x3e, 0x6d, 0x1b, 0x2e, 0x94, 0xb2, - 0xb8, 0xac, 0x88, 0x6d, 0x2d, 0xbe, 0x22, 0x52, 0x0f, 0x85, 0xd4, 0x46, 0xa0, 0x97, 0x0d, 0x98, - 0xb2, 0x34, 0x2b, 0x6a, 0x01, 0x58, 0xab, 0x2e, 0x8d, 0x6a, 0xcb, 0x87, 0x14, 0xab, 0xb3, 0x07, - 0xbd, 0x72, 0xc4, 0x52, 0xc3, 0x11, 0x8e, 0xe8, 0x37, 0x0c, 0x38, 0x95, 0xba, 0xc7, 0x17, 0x26, - 0x8f, 0x63, 0x84, 0xd8, 0x22, 0x49, 0x3f, 0x73, 0xd2, 0x9b, 0x81, 0x5e, 0x37, 0x94, 0x28, 0x5b, - 0x97, 0xde, 0x94, 0x29, 0xd6, 0xb4, 0x2b, 0x23, 0x1a, 0x8e, 0xa1, 0x42, 0x20, 0x09, 0x57, 0x4f, - 0x6a, 0x92, 0x51, 0x16, 0xe2, 0x38, 0x7b, 0xf4, 0x79, 0x43, 0x8a, 0x46, 0xd5, 0xa2, 0x13, 0xc7, - 0xd5, 0x22, 0x14, 0x4a, 0x5a, 0xd5, 0xa0, 0x18, 0x73, 0xf4, 0x51, 0x58, 0xb4, 0xb6, 0x5d, 0x2f, - 0x48, 0xdd, 0x7c, 0x0b, 0xd3, 0x6c, 0x1b, 0x9d, 0x3d, 0xe8, 0x95, 0x17, 0x2b, 0x7d, 0xb1, 0xf0, - 0x21, 0x14, 0xcc, 0xdf, 0x2d, 0xc0, 0x14, 0x57, 0xf2, 0x85, 0xe8, 0xfa, 0x86, 0x01, 0x0f, 0xd6, - 0xbb, 0x9e, 0x47, 0x9c, 0xa0, 0x16, 0x90, 0x4e, 0x52, 0x70, 0x19, 0xc7, 0x2a, 0xb8, 0x1e, 0x3a, - 0xe8, 0x95, 0x1f, 0x5c, 0x3e, 0x84, 0x3f, 0x3e, 0xb4, 0x75, 0xe8, 0x2f, 0x0c, 0x30, 0x05, 0x42, - 0xd5, 0xaa, 0xdf, 0x6c, 0x7a, 0x6e, 0xd7, 0x69, 0x24, 0x3b, 0x91, 0x3b, 0xd6, 0x4e, 0x3c, 0x72, - 0xd0, 0x2b, 0x9b, 0xcb, 0x77, 0x6d, 0x05, 0x1e, 0xa0, 0xa5, 0xe8, 0x59, 0x98, 0x13, 0x58, 0xe7, - 0x6f, 0x77, 0x88, 0x67, 0x53, 0x75, 0x5a, 0xdc, 0xa7, 0x87, 0x21, 0x0a, 0x71, 0x04, 0x9c, 0xac, - 0x83, 0x7c, 0x98, 0xb8, 0x45, 0xec, 0xe6, 0x6e, 0x20, 0xd5, 0xa7, 0x11, 0xe3, 0x12, 0x84, 0xc1, - 0x7f, 0x9d, 0xd3, 0xac, 0x4e, 0x1e, 0xf4, 0xca, 0x13, 0xe2, 0x0f, 0x96, 0x9c, 0xd0, 0x06, 0x4c, - 0x73, 0x13, 0x6c, 0xd3, 0x76, 0x9a, 0x9b, 0xae, 0xc3, 0x6f, 0xf3, 0x4b, 0xd5, 0x47, 0xa4, 0xc0, - 0xaf, 0x45, 0xa0, 0x77, 0x7a, 0xe5, 0x29, 0xf9, 0x7b, 0x6b, 0xbf, 0x43, 0x70, 0xac, 0xb6, 0xf9, - 0xcd, 0x02, 0x80, 0x5c, 0xae, 0xa4, 0x83, 0xfe, 0x0f, 0x94, 0x7c, 0x12, 0x70, 0xae, 0xc2, 0x79, - 0xce, 0xef, 0x24, 0x64, 0x21, 0x0e, 0xe1, 0xe8, 0x26, 0x14, 0x3a, 0x56, 0xd7, 0x27, 0x62, 0xf2, - 0x2f, 0x65, 0x32, 0xf9, 0x9b, 0x94, 0x22, 0xb7, 0xb9, 0xd8, 0x4f, 0xcc, 0x79, 0xa0, 0x4f, 0x1b, - 0x00, 0x24, 0x3a, 0x61, 0x23, 0xfb, 0x3e, 0x04, 0xcb, 0x70, 0x4e, 0xe9, 0x18, 0x54, 0xa7, 0x0f, - 0x7a, 0x65, 0xd0, 0xa6, 0x5e, 0x63, 0x8b, 0x6e, 0x41, 0xd1, 0x92, 0x67, 0xfe, 0xd8, 0x71, 0x9c, - 0xf9, 0xcc, 0x14, 0x52, 0x8b, 0x56, 0x31, 0x43, 0x9f, 0x31, 0x60, 0xda, 0x27, 0x81, 0x98, 0x2a, - 0x7a, 0xf2, 0x08, 0x85, 0x77, 0xc4, 0x45, 0x57, 0x8b, 0xd0, 0xe4, 0x27, 0x68, 0xb4, 0x0c, 0xc7, - 0xf8, 0xf2, 0x98, 0x12, 0x12, 0x5c, 0x24, 0x56, 0x83, 0x78, 0xc2, 0x3d, 0x25, 0x74, 0xa9, 0x8d, - 0x91, 0x1b, 0x13, 0xa1, 0x2a, 0x62, 0x4a, 0x62, 0xa5, 0x38, 0xc1, 0xdd, 0xfc, 0xab, 0x29, 0x98, - 0x96, 0xab, 0x38, 0x54, 0xab, 0xb9, 0x57, 0xa5, 0x8f, 0x5a, 0xbd, 0xac, 0x03, 0x71, 0x14, 0x97, - 0x56, 0xe6, 0xfb, 0x24, 0xaa, 0x55, 0xab, 0xca, 0x35, 0x1d, 0x88, 0xa3, 0xb8, 0xa8, 0x0d, 0x05, - 0x3f, 0x20, 0x1d, 0x79, 0x09, 0x39, 0xe2, 0x1d, 0x59, 0xb8, 0x39, 0xc3, 0x6b, 0x06, 0xfa, 0xcf, - 0xc7, 0x9c, 0x0b, 0x73, 0x0c, 0x06, 0x11, 0x5f, 0xa1, 0x58, 0x99, 0xd9, 0x6c, 0x8e, 0xa8, 0x1b, - 0x92, 0x2f, 0x90, 0x68, 0x19, 0x8e, 0xb1, 0x4f, 0xd1, 0xb4, 0x0b, 0xc7, 0xa8, 0x69, 0x3f, 0x0f, - 0xc5, 0xb6, 0x75, 0xbb, 0xd6, 0xf5, 0x9a, 0x47, 0xd7, 0xe8, 0x45, 0x7c, 0x10, 0xa7, 0x82, 0x15, - 0x3d, 0xf4, 0x8a, 0xa1, 0xed, 0xf7, 0x09, 0x46, 0xfc, 0x7a, 0xb6, 0xfb, 0x5d, 0x09, 0xaa, 0xbe, - 0x3b, 0x3f, 0xa1, 0xf7, 0x16, 0xef, 0xb9, 0xde, 0x4b, 0x75, 0x38, 0xbe, 0x41, 0x94, 0x0e, 0x57, - 0x3a, 0x56, 0x1d, 0x6e, 0x39, 0xc2, 0x0c, 0xc7, 0x98, 0xb3, 0xf6, 0xf0, 0x3d, 0xa7, 0xda, 0x03, - 0xc7, 0xda, 0x9e, 0x5a, 0x84, 0x19, 0x8e, 0x31, 0xef, 0x6f, 0xec, 0x4d, 0x1e, 0x8f, 0xb1, 0x37, - 0x95, 0x81, 0xb1, 0x77, 0xb8, 0x1e, 0x7c, 0x62, 0x54, 0x3d, 0x18, 0x5d, 0x02, 0xd4, 0xd8, 0x77, - 0xac, 0xb6, 0x5d, 0x17, 0x87, 0x25, 0x93, 0x59, 0xd3, 0xcc, 0x19, 0xb0, 0x28, 0x0e, 0x32, 0xb4, - 0x92, 0xc0, 0xc0, 0x29, 0xb5, 0x50, 0x00, 0xc5, 0x8e, 0x54, 0x77, 0x66, 0xb2, 0x58, 0xfd, 0x52, - 0xfd, 0xe1, 0xf7, 0xd4, 0x74, 0xe3, 0xc9, 0x12, 0xac, 0x38, 0x99, 0xff, 0x61, 0xc0, 0xec, 0x72, - 0xcb, 0xed, 0x36, 0xae, 0x5b, 0x41, 0x7d, 0x97, 0x5f, 0xaa, 0xa2, 0x67, 0xa0, 0x68, 0x3b, 0x01, - 0xf1, 0xf6, 0xac, 0x96, 0x90, 0x28, 0xa6, 0xbc, 0x77, 0x5e, 0x15, 0xe5, 0x77, 0x7a, 0xe5, 0xe9, - 0x95, 0xae, 0xc7, 0xa2, 0x15, 0xf9, 0xf9, 0x82, 0x55, 0x1d, 0xf4, 0x55, 0x03, 0xe6, 0xf8, 0xb5, - 0xec, 0x8a, 0x15, 0x58, 0x57, 0xba, 0xc4, 0xb3, 0x89, 0xbc, 0x98, 0x1d, 0xf1, 0x68, 0x89, 0xb7, - 0x55, 0x32, 0xd8, 0x0f, 0xf5, 0xda, 0xf5, 0x38, 0x67, 0x9c, 0x6c, 0x8c, 0xf9, 0xc5, 0x3c, 0xdc, - 0xdf, 0x97, 0x16, 0x5a, 0x84, 0x9c, 0xdd, 0x10, 0x5d, 0x07, 0x41, 0x37, 0xb7, 0xda, 0xc0, 0x39, - 0xbb, 0x81, 0x96, 0x98, 0x8a, 0xe6, 0x11, 0xdf, 0x97, 0x77, 0x74, 0x25, 0xa5, 0x4d, 0x89, 0x52, - 0xac, 0x61, 0xa0, 0x32, 0x14, 0x5a, 0xd6, 0x36, 0x69, 0x09, 0xf5, 0x9b, 0x29, 0x7d, 0x6b, 0xb4, - 0x00, 0xf3, 0x72, 0xf4, 0x0b, 0x06, 0x00, 0x6f, 0x20, 0x55, 0xde, 0x85, 0x5c, 0xc3, 0xd9, 0x0e, - 0x13, 0xa5, 0xcc, 0x5b, 0x19, 0xfe, 0xc7, 0x1a, 0x57, 0xb4, 0x05, 0xe3, 0x54, 0xff, 0x73, 0x1b, - 0x47, 0x16, 0x63, 0xec, 0x4e, 0x62, 0x93, 0xd1, 0xc0, 0x82, 0x16, 0x1d, 0x2b, 0x8f, 0x04, 0x5d, - 0xcf, 0xa1, 0x43, 0xcb, 0x04, 0x57, 0x91, 0xb7, 0x02, 0xab, 0x52, 0xac, 0x61, 0x98, 0x7f, 0x90, - 0x83, 0xf9, 0xb4, 0xa6, 0x53, 0xf9, 0x30, 0xce, 0x5b, 0x2b, 0x2c, 0xc9, 0x0f, 0x66, 0x3f, 0x3e, - 0x22, 0xc2, 0x40, 0xdd, 0xc3, 0x8b, 0x18, 0x28, 0xc1, 0x17, 0x7d, 0x50, 0x8d, 0x50, 0xee, 0x88, - 0x23, 0xa4, 0x28, 0xc7, 0x46, 0xe9, 0x21, 0x18, 0xf3, 0xe9, 0xcc, 0xe7, 0xa3, 0xfe, 0x7e, 0x36, - 0x47, 0x0c, 0x42, 0x31, 0xba, 0x8e, 0x1d, 0x88, 0x10, 0x62, 0x85, 0x71, 0xd5, 0xb1, 0x03, 0xcc, - 0x20, 0xe6, 0x97, 0x73, 0xb0, 0xd8, 0xbf, 0x53, 0xe8, 0xcb, 0x06, 0x40, 0x83, 0x6a, 0xf7, 0x74, - 0x49, 0xca, 0x88, 0x0c, 0xeb, 0xb8, 0xc6, 0x70, 0x45, 0x72, 0x0a, 0xc3, 0x73, 0x54, 0x91, 0x8f, - 0xb5, 0x86, 0xa0, 0xc7, 0xe4, 0xd2, 0xdf, 0xb0, 0xda, 0x52, 0x01, 0x55, 0x75, 0xd6, 0x15, 0x04, - 0x6b, 0x58, 0xd4, 0x7c, 0x73, 0xac, 0x36, 0xf1, 0x3b, 0x96, 0x8a, 0x11, 0x67, 0xe6, 0xdb, 0x86, - 0x2c, 0xc4, 0x21, 0xdc, 0x6c, 0xc1, 0xc3, 0x03, 0xb4, 0x33, 0xa3, 0x78, 0x5d, 0xf3, 0xdf, 0x0d, - 0x38, 0xbd, 0xdc, 0xea, 0xfa, 0x01, 0xf1, 0xfe, 0xc7, 0x44, 0x3b, 0xfd, 0xa7, 0x01, 0x0f, 0xf4, - 0xe9, 0xf3, 0x3d, 0x08, 0x7a, 0x7a, 0x31, 0x1a, 0xf4, 0x74, 0x75, 0xd4, 0x25, 0x9d, 0xda, 0x8f, - 0x3e, 0xb1, 0x4f, 0x01, 0x9c, 0xa0, 0xa7, 0x56, 0xc3, 0x6d, 0x66, 0x24, 0x37, 0x1f, 0x86, 0xc2, - 0xc7, 0xa9, 0xfc, 0x89, 0xaf, 0x31, 0x26, 0x94, 0x30, 0x87, 0x99, 0x1f, 0x00, 0x11, 0x21, 0x14, - 0xdb, 0x3c, 0xc6, 0x20, 0x9b, 0xc7, 0xfc, 0xdb, 0x1c, 0x68, 0x66, 0xff, 0x3d, 0x58, 0x94, 0x4e, - 0x64, 0x51, 0x8e, 0x68, 0xc8, 0x6b, 0x4e, 0x8c, 0x7e, 0x4f, 0x01, 0xf6, 0x62, 0x4f, 0x01, 0x36, - 0x32, 0xe3, 0x78, 0xf8, 0x4b, 0x80, 0xef, 0x19, 0xf0, 0x40, 0x88, 0x9c, 0xf4, 0xc8, 0xdd, 0xfd, - 0x84, 0x79, 0x12, 0x26, 0xad, 0xb0, 0x9a, 0x58, 0x03, 0xea, 0xf5, 0x8b, 0x46, 0x11, 0xeb, 0x78, - 0x61, 0xe0, 0x71, 0xfe, 0x88, 0x81, 0xc7, 0x63, 0x87, 0x07, 0x1e, 0x9b, 0x3f, 0xce, 0xc1, 0x99, - 0x64, 0xcf, 0xe4, 0xde, 0x18, 0xec, 0xc2, 0xfa, 0x29, 0x98, 0x0a, 0x44, 0x05, 0xed, 0xa4, 0x57, - 0x6f, 0xb7, 0xb6, 0x34, 0x18, 0x8e, 0x60, 0xd2, 0x9a, 0x75, 0xbe, 0x2b, 0x6b, 0x75, 0xb7, 0x23, - 0xc3, 0xd6, 0x55, 0xcd, 0x65, 0x0d, 0x86, 0x23, 0x98, 0x2a, 0x20, 0x70, 0xec, 0xd8, 0x03, 0x02, - 0x6b, 0x70, 0x4a, 0x86, 0x40, 0x5d, 0x70, 0xbd, 0x65, 0xb7, 0xdd, 0x69, 0x11, 0x11, 0xb8, 0x4e, - 0x1b, 0x7b, 0x46, 0x54, 0x39, 0x85, 0xd3, 0x90, 0x70, 0x7a, 0x5d, 0xf3, 0x7b, 0x79, 0x38, 0x19, - 0x0e, 0xfb, 0xb2, 0xeb, 0x34, 0x6c, 0x16, 0x48, 0xf6, 0x34, 0x8c, 0x05, 0xfb, 0x1d, 0x39, 0xd8, - 0xff, 0x4b, 0x36, 0x67, 0x6b, 0xbf, 0x43, 0x67, 0xfb, 0x74, 0x4a, 0x15, 0xe6, 0x13, 0x65, 0x95, - 0xd0, 0x9a, 0xda, 0x1d, 0x7c, 0x06, 0x9e, 0x88, 0xae, 0xe6, 0x3b, 0xbd, 0x72, 0xca, 0xd3, 0xc5, - 0x25, 0x45, 0x29, 0xba, 0xe6, 0xd1, 0x0d, 0x98, 0x6e, 0x59, 0x7e, 0x70, 0xb5, 0xd3, 0xb0, 0x02, - 0xb2, 0x65, 0xb7, 0x89, 0xd8, 0x73, 0xc3, 0x44, 0x83, 0xab, 0x4b, 0xdc, 0xb5, 0x08, 0x25, 0x1c, - 0xa3, 0x8c, 0xf6, 0x00, 0xd1, 0x92, 0x2d, 0xcf, 0x72, 0x7c, 0xde, 0x2b, 0xca, 0x6f, 0xf8, 0xe8, - 0x73, 0x65, 0x96, 0xad, 0x25, 0xa8, 0xe1, 0x14, 0x0e, 0xe8, 0x11, 0x18, 0xf7, 0x88, 0xe5, 0x8b, - 0xc9, 0x2c, 0x85, 0xfb, 0x1f, 0xb3, 0x52, 0x2c, 0xa0, 0xfa, 0x86, 0x1a, 0xbf, 0xcb, 0x86, 0xfa, - 0xa1, 0x01, 0xd3, 0xe1, 0x34, 0xdd, 0x03, 0x21, 0xd9, 0x8e, 0x0a, 0xc9, 0x8b, 0x59, 0x1d, 0x89, - 0x7d, 0xe4, 0xe2, 0x9f, 0x8c, 0xeb, 0xfd, 0x63, 0xd1, 0xc0, 0x9f, 0x80, 0x92, 0xdc, 0xd5, 0x52, - 0xfb, 0x1c, 0xd1, 0xba, 0x8d, 0xe8, 0x25, 0xda, 0x2b, 0x16, 0xc1, 0x04, 0x87, 0xfc, 0xa8, 0x58, - 0x6e, 0x08, 0x91, 0x2b, 0x96, 0xbd, 0x12, 0xcb, 0x52, 0x14, 0xa7, 0x89, 0x65, 0x59, 0x07, 0x5d, - 0x85, 0xd3, 0x1d, 0xcf, 0x65, 0x2f, 0x1b, 0x57, 0x88, 0xd5, 0x68, 0xd9, 0x0e, 0x91, 0x2e, 0x04, - 0x1e, 0x43, 0xf0, 0xc0, 0x41, 0xaf, 0x7c, 0x7a, 0x33, 0x1d, 0x05, 0xf7, 0xab, 0x1b, 0x7d, 0x8d, - 0x33, 0x36, 0xc0, 0x6b, 0x9c, 0xcf, 0x2a, 0x47, 0x1d, 0xf1, 0xc5, 0x9b, 0x98, 0x0f, 0x67, 0x35, - 0x95, 0x29, 0xc7, 0x7a, 0xb8, 0xa4, 0x2a, 0x82, 0x29, 0x56, 0xec, 0xfb, 0x7b, 0x83, 0xc6, 0x8f, - 0xe8, 0x0d, 0x0a, 0x83, 0xaa, 0x27, 0x7e, 0x9a, 0x41, 0xd5, 0xc5, 0xb7, 0x54, 0x50, 0xf5, 0xab, - 0x05, 0x98, 0x8d, 0x6b, 0x20, 0xc7, 0xff, 0xd2, 0xe8, 0x57, 0x0c, 0x98, 0x95, 0xbb, 0x87, 0xf3, - 0x24, 0xd2, 0xcf, 0xbf, 0x96, 0xd1, 0xa6, 0xe5, 0xba, 0x94, 0x7a, 0x0b, 0xbb, 0x15, 0xe3, 0x86, - 0x13, 0xfc, 0xd1, 0x0b, 0x30, 0xa9, 0xdc, 0xe1, 0x47, 0x7a, 0x76, 0x34, 0xc3, 0xb4, 0xa8, 0x90, - 0x04, 0xd6, 0xe9, 0xa1, 0x57, 0x0d, 0x80, 0xba, 0x14, 0x73, 0x72, 0x77, 0x5d, 0xc9, 0x6a, 0x77, - 0x29, 0x01, 0x1a, 0x2a, 0xcb, 0xaa, 0xc8, 0xc7, 0x1a, 0x63, 0xf4, 0x45, 0xe6, 0x08, 0x57, 0xda, - 0x1d, 0xdd, 0x4f, 0xf9, 0xd1, 0xe3, 0x60, 0x0f, 0x51, 0x4c, 0x43, 0x55, 0x4a, 0x03, 0xf9, 0x38, - 0xd2, 0x08, 0xf3, 0x69, 0x50, 0x91, 0x8b, 0xf4, 0xd8, 0x62, 0xb1, 0x8b, 0x9b, 0x56, 0xb0, 0x2b, - 0x96, 0xa0, 0x3a, 0xb6, 0x2e, 0x48, 0x00, 0x0e, 0x71, 0xcc, 0x8f, 0xc1, 0xf4, 0xb3, 0x9e, 0xd5, - 0xd9, 0xb5, 0x99, 0xc3, 0x99, 0xda, 0x49, 0xef, 0x84, 0x09, 0xab, 0xd1, 0x48, 0x7b, 0x49, 0x5e, - 0xe1, 0xc5, 0x58, 0xc2, 0x07, 0x33, 0x89, 0xfe, 0xcc, 0x00, 0x14, 0xb9, 0x2b, 0x5b, 0xa7, 0xd6, - 0x3e, 0xb5, 0x8f, 0x76, 0x59, 0x69, 0x9a, 0x7d, 0x74, 0x51, 0x41, 0xb0, 0x86, 0x85, 0x5e, 0x36, - 0x60, 0x92, 0xff, 0xbd, 0xa6, 0xac, 0xfd, 0x91, 0x1f, 0xa2, 0x72, 0x89, 0xc2, 0x1a, 0x15, 0x2a, - 0xf4, 0x17, 0x43, 0x2e, 0x58, 0x67, 0x49, 0xc7, 0x6b, 0xd5, 0xd9, 0x69, 0x75, 0x6f, 0x37, 0xb6, - 0xc3, 0xf1, 0xea, 0x78, 0xee, 0x8e, 0xdd, 0x22, 0xf1, 0xf1, 0xda, 0xe4, 0xc5, 0x58, 0xc2, 0x07, - 0x1b, 0xaf, 0x6f, 0x19, 0x30, 0xbf, 0xea, 0x07, 0xb6, 0xbb, 0x42, 0xfc, 0x80, 0xca, 0x16, 0x7a, - 0x02, 0x75, 0x5b, 0x83, 0x44, 0x22, 0xaf, 0xc0, 0xac, 0xb8, 0x45, 0xec, 0x6e, 0xfb, 0x24, 0xd0, - 0x94, 0x79, 0xb5, 0x99, 0x97, 0x63, 0x70, 0x9c, 0xa8, 0x41, 0xa9, 0x88, 0xeb, 0xc4, 0x90, 0x4a, - 0x3e, 0x4a, 0xa5, 0x16, 0x83, 0xe3, 0x44, 0x0d, 0xf3, 0xbb, 0x79, 0x38, 0xc9, 0xba, 0x11, 0x7b, - 0x45, 0xf0, 0xf9, 0x7e, 0xaf, 0x08, 0x46, 0xdc, 0xcf, 0x8c, 0xd7, 0x11, 0xde, 0x10, 0xfc, 0xb2, - 0x01, 0x33, 0x8d, 0xe8, 0x48, 0x67, 0xe3, 0xa3, 0x49, 0x9b, 0x43, 0x1e, 0xb1, 0x14, 0x2b, 0xc4, - 0x71, 0xfe, 0xe8, 0x4b, 0x06, 0xcc, 0x44, 0x9b, 0x29, 0x8f, 0xf8, 0x63, 0x18, 0x24, 0x15, 0x62, - 0x1c, 0x2d, 0xf7, 0x71, 0xbc, 0x09, 0xe6, 0x5f, 0x1b, 0x62, 0x4a, 0x8f, 0x23, 0x44, 0x1e, 0xdd, - 0x82, 0x52, 0xd0, 0xf2, 0x79, 0xa1, 0xe8, 0xed, 0x88, 0x66, 0xe1, 0xd6, 0x5a, 0x8d, 0x91, 0xd3, - 0x34, 0x37, 0x51, 0x42, 0x35, 0x50, 0xc9, 0xcb, 0xfc, 0x9a, 0x01, 0xa5, 0x4b, 0xae, 0xdc, 0xce, - 0x1f, 0xcd, 0xc0, 0xe9, 0xa2, 0x74, 0x33, 0x75, 0x5f, 0x17, 0xaa, 0xfb, 0xcf, 0x44, 0x5c, 0x2e, - 0x0f, 0x6a, 0xb4, 0x97, 0x58, 0xc6, 0x1a, 0x4a, 0xea, 0x92, 0xbb, 0xdd, 0xd7, 0xa3, 0xf7, 0x9b, - 0x05, 0x38, 0xf1, 0x9c, 0xb5, 0x4f, 0x9c, 0xc0, 0x1a, 0xfe, 0xc0, 0x7e, 0x12, 0x26, 0xad, 0x0e, - 0x8b, 0x98, 0xd5, 0xf4, 0xed, 0xd0, 0x8b, 0x11, 0x82, 0xb0, 0x8e, 0x17, 0x9e, 0x2b, 0x3c, 0x81, - 0x46, 0xda, 0x89, 0xb0, 0x1c, 0x83, 0xe3, 0x44, 0x0d, 0x74, 0x09, 0x90, 0x78, 0x0e, 0x58, 0xa9, - 0xd7, 0xdd, 0xae, 0xc3, 0x4f, 0x16, 0xee, 0xe0, 0x50, 0x86, 0xdf, 0x7a, 0x02, 0x03, 0xa7, 0xd4, - 0x42, 0x1f, 0x81, 0x85, 0x3a, 0xa3, 0x2c, 0xcc, 0x00, 0x9d, 0x22, 0x37, 0x05, 0x55, 0xb4, 0xfa, - 0x72, 0x1f, 0x3c, 0xdc, 0x97, 0x02, 0x6d, 0xa9, 0x1f, 0xb8, 0x9e, 0xd5, 0x24, 0x3a, 0xdd, 0xf1, - 0x68, 0x4b, 0x6b, 0x09, 0x0c, 0x9c, 0x52, 0x0b, 0x7d, 0x0a, 0x4a, 0xc1, 0xae, 0x47, 0xfc, 0x5d, - 0xb7, 0xd5, 0x10, 0x17, 0xf8, 0x23, 0x7a, 0xbd, 0xc4, 0xec, 0x6f, 0x49, 0xaa, 0xda, 0xf2, 0x96, - 0x45, 0x38, 0xe4, 0x89, 0x3c, 0x18, 0xf7, 0xeb, 0x6e, 0x87, 0xf8, 0x42, 0x7d, 0xbe, 0x94, 0x09, - 0x77, 0xe6, 0xc5, 0xd1, 0xfc, 0x6d, 0x8c, 0x03, 0x16, 0x9c, 0xcc, 0x6f, 0xe7, 0x60, 0x4a, 0x47, - 0x1c, 0xe0, 0x88, 0xf8, 0xb4, 0x01, 0x53, 0x75, 0xd7, 0x09, 0x3c, 0xb7, 0xc5, 0x7d, 0x49, 0xd9, - 0x08, 0x77, 0x4a, 0x6a, 0x85, 0x04, 0x96, 0xdd, 0xd2, 0xdc, 0x52, 0x1a, 0x1b, 0x1c, 0x61, 0x8a, - 0x3e, 0x67, 0xc0, 0x4c, 0x18, 0x6c, 0x15, 0x3a, 0xb5, 0x32, 0x6d, 0x88, 0x3a, 0x71, 0xcf, 0x47, - 0x39, 0xe1, 0x38, 0x6b, 0x73, 0x1b, 0x66, 0xe3, 0xb3, 0x4d, 0x87, 0xb2, 0x63, 0x89, 0xbd, 0x9e, - 0x0f, 0x87, 0x72, 0xd3, 0xf2, 0x7d, 0xcc, 0x20, 0xe8, 0x5d, 0x50, 0x6c, 0x5b, 0x5e, 0xd3, 0x76, - 0xac, 0x16, 0x1b, 0xc5, 0xbc, 0x76, 0x20, 0x89, 0x72, 0xac, 0x30, 0xcc, 0x1f, 0x8d, 0xc1, 0xa4, - 0x66, 0xf5, 0x1c, 0xbf, 0x05, 0x13, 0xc9, 0x50, 0x90, 0xcf, 0x30, 0x43, 0xc1, 0xf3, 0x00, 0x3b, - 0xb6, 0x63, 0xfb, 0xbb, 0x47, 0xcc, 0x7d, 0xc0, 0x2e, 0x3f, 0x2f, 0x28, 0x0a, 0x58, 0xa3, 0x16, - 0xde, 0x30, 0x15, 0x0e, 0xc9, 0x08, 0xf3, 0xaa, 0xa1, 0x09, 0x8f, 0xf1, 0x2c, 0x6e, 0xd4, 0xb5, - 0x89, 0x59, 0x92, 0xc2, 0xe4, 0xbc, 0x13, 0x78, 0xfb, 0x87, 0xca, 0x98, 0x2d, 0x28, 0x7a, 0xc4, - 0xef, 0xb6, 0xa9, 0x2d, 0x36, 0x31, 0xf4, 0x30, 0xb0, 0x68, 0x04, 0x2c, 0xea, 0x63, 0x45, 0x69, - 0xf1, 0x69, 0x38, 0x11, 0x69, 0x02, 0x9a, 0x85, 0xfc, 0x4d, 0xb2, 0xcf, 0xd7, 0x09, 0xa6, 0x3f, - 0xd1, 0x7c, 0xe4, 0x1e, 0x4e, 0x0c, 0xcb, 0xfb, 0x73, 0x4f, 0x19, 0xa6, 0x0b, 0xa9, 0xa6, 0xf5, - 0x51, 0xae, 0x49, 0xe8, 0x5c, 0xb4, 0xb4, 0xe4, 0x07, 0x6a, 0x2e, 0x78, 0xcc, 0x09, 0x87, 0x99, - 0x3f, 0x1e, 0x07, 0x71, 0x49, 0x3c, 0xc0, 0xe1, 0xa3, 0xdf, 0x0d, 0xe5, 0x8e, 0x70, 0x37, 0x74, - 0x09, 0xa6, 0x6c, 0xc7, 0x0e, 0x6c, 0xab, 0xc5, 0xdc, 0x26, 0x42, 0x38, 0xca, 0x88, 0xd8, 0xa9, - 0x55, 0x0d, 0x96, 0x42, 0x27, 0x52, 0x17, 0x5d, 0x81, 0x02, 0x93, 0x1e, 0x62, 0x01, 0x0f, 0x7f, - 0x93, 0xcd, 0x82, 0x18, 0xf8, 0x33, 0x19, 0x4e, 0x89, 0x69, 0xf4, 0x3c, 0xfb, 0x83, 0x32, 0x6c, - 0xc5, 0x3a, 0x0e, 0x35, 0xfa, 0x18, 0x1c, 0x27, 0x6a, 0x50, 0x2a, 0x3b, 0x96, 0xdd, 0xea, 0x7a, - 0x24, 0xa4, 0x32, 0x1e, 0xa5, 0x72, 0x21, 0x06, 0xc7, 0x89, 0x1a, 0x68, 0x07, 0xa6, 0x44, 0x19, - 0x8f, 0x24, 0x9a, 0x38, 0x62, 0x2f, 0x59, 0xc4, 0xd8, 0x05, 0x8d, 0x12, 0x8e, 0xd0, 0x45, 0x5d, - 0x98, 0xb3, 0x9d, 0xba, 0xeb, 0xd4, 0x5b, 0x5d, 0xdf, 0xde, 0x23, 0xe1, 0x1b, 0x95, 0xa3, 0x30, - 0x3b, 0x75, 0xd0, 0x2b, 0xcf, 0xad, 0xc6, 0xc9, 0xe1, 0x24, 0x07, 0xf4, 0x8a, 0x01, 0xa7, 0xea, - 0xae, 0xe3, 0xb3, 0xe7, 0xd4, 0x7b, 0xe4, 0xbc, 0xe7, 0xb9, 0x1e, 0xe7, 0x5d, 0x3a, 0x22, 0x6f, - 0xe6, 0xad, 0x5b, 0x4e, 0x23, 0x89, 0xd3, 0x39, 0xa1, 0x17, 0xa1, 0xd8, 0xf1, 0xdc, 0x3d, 0xbb, - 0x41, 0x3c, 0x11, 0x95, 0xb6, 0x96, 0x45, 0x7a, 0x87, 0x4d, 0x41, 0x33, 0x3c, 0x7a, 0x64, 0x09, - 0x56, 0xfc, 0xcc, 0x37, 0x4a, 0x30, 0x1d, 0x45, 0x47, 0x9f, 0x04, 0xe8, 0x78, 0x6e, 0x9b, 0x04, - 0xbb, 0x44, 0xbd, 0x35, 0xd8, 0x18, 0x35, 0x8b, 0x80, 0xa4, 0x27, 0xe3, 0x42, 0xe8, 0x71, 0x11, - 0x96, 0x62, 0x8d, 0x23, 0xf2, 0x60, 0xe2, 0x26, 0x17, 0xa2, 0x42, 0xa7, 0x78, 0x2e, 0x13, 0x0d, - 0x48, 0x70, 0x66, 0x41, 0xf2, 0xa2, 0x08, 0x4b, 0x46, 0x68, 0x1b, 0xf2, 0xb7, 0xc8, 0x76, 0x36, - 0x2f, 0x73, 0xaf, 0x13, 0x61, 0x9b, 0x54, 0x27, 0x0e, 0x7a, 0xe5, 0xfc, 0x75, 0xb2, 0x8d, 0x29, - 0x71, 0xda, 0xaf, 0x06, 0xbf, 0xe1, 0x16, 0x47, 0xc5, 0x88, 0xfd, 0x8a, 0x5c, 0x97, 0xf3, 0x7e, - 0x89, 0x22, 0x2c, 0x19, 0xa1, 0x17, 0xa1, 0x74, 0xcb, 0xda, 0x23, 0x3b, 0x9e, 0xeb, 0x04, 0x22, - 0x18, 0x69, 0xc4, 0xf0, 0xf3, 0xeb, 0x92, 0x9c, 0xe0, 0xcb, 0xc4, 0xbb, 0x2a, 0xc4, 0x21, 0x3b, - 0xb4, 0x07, 0x45, 0x87, 0xdc, 0xc2, 0xa4, 0x65, 0xd7, 0x45, 0x98, 0xed, 0x88, 0xcb, 0x7a, 0x43, - 0x50, 0x13, 0x9c, 0x99, 0xdc, 0x93, 0x65, 0x58, 0xf1, 0xa2, 0x73, 0x79, 0xc3, 0xdd, 0x16, 0x07, - 0xd5, 0x88, 0x73, 0xa9, 0xec, 0x4c, 0x3e, 0x97, 0x97, 0xdc, 0x6d, 0x4c, 0x89, 0xd3, 0x3d, 0x52, - 0x57, 0x91, 0x30, 0xe2, 0x98, 0xda, 0xc8, 0x36, 0x02, 0x88, 0xef, 0x91, 0xb0, 0x14, 0x6b, 0x1c, - 0xe9, 0xd8, 0x36, 0x85, 0x1b, 0x50, 0x1c, 0x54, 0x23, 0x8e, 0x6d, 0xd4, 0xa9, 0xc8, 0xc7, 0x56, - 0x96, 0x61, 0xc5, 0x8b, 0xf2, 0xb5, 0x85, 0x3b, 0x2d, 0x9b, 0xa3, 0x2a, 0xea, 0x9c, 0xe3, 0x7c, - 0x65, 0x19, 0x56, 0xbc, 0xcc, 0xaf, 0x8d, 0xc3, 0x94, 0x9e, 0x46, 0x6b, 0x00, 0x1d, 0x41, 0xe9, - 0xc5, 0xb9, 0x61, 0xf4, 0x62, 0x6a, 0xd6, 0x68, 0xb7, 0x07, 0xd2, 0xb3, 0xb1, 0x9a, 0x99, 0x5a, - 0x18, 0x9a, 0x35, 0x5a, 0xa1, 0x8f, 0x23, 0x4c, 0x87, 0x08, 0x28, 0xa0, 0xca, 0x15, 0x57, 0x3f, - 0x0a, 0x51, 0xe5, 0x2a, 0xa2, 0x50, 0x3c, 0x06, 0x10, 0xa6, 0x93, 0x12, 0xb7, 0x4a, 0x4a, 0x6b, - 0xd3, 0xd2, 0x5c, 0x69, 0x58, 0xe8, 0x11, 0x18, 0xa7, 0x02, 0x9a, 0x34, 0xc4, 0x03, 0x54, 0x65, - 0x3b, 0x5e, 0x60, 0xa5, 0x58, 0x40, 0xd1, 0x53, 0x54, 0x97, 0x0a, 0xc5, 0xaa, 0x78, 0x57, 0x3a, - 0x1f, 0xea, 0x52, 0x21, 0x0c, 0x47, 0x30, 0x69, 0xd3, 0x09, 0x95, 0x82, 0x6c, 0x05, 0x6b, 0x4d, - 0x67, 0xa2, 0x11, 0x73, 0x18, 0xf3, 0x65, 0xc4, 0xa4, 0x26, 0x5b, 0x79, 0x05, 0xcd, 0x97, 0x11, - 0x83, 0xe3, 0x44, 0x0d, 0xda, 0x19, 0x71, 0x21, 0x36, 0xc9, 0xe3, 0x26, 0xfb, 0x5c, 0x65, 0xbd, - 0xa6, 0x5b, 0x04, 0x53, 0x6c, 0xea, 0x3f, 0x98, 0x5d, 0x4a, 0xb8, 0xc1, 0x4d, 0x82, 0xd1, 0x94, - 0xf7, 0x8f, 0xc1, 0x74, 0xf4, 0xac, 0xcc, 0xdc, 0xe9, 0xfd, 0xa7, 0x79, 0x38, 0xb9, 0xd1, 0xb4, - 0x9d, 0xdb, 0x31, 0x6f, 0x71, 0x5a, 0xaa, 0x56, 0x63, 0xd8, 0x54, 0xad, 0xe1, 0x63, 0x1a, 0x91, - 0x0b, 0x37, 0xfd, 0x31, 0x8d, 0x4c, 0x94, 0x1b, 0xc5, 0x45, 0x3f, 0x34, 0xe0, 0x41, 0xab, 0xc1, - 0xb5, 0x57, 0xab, 0x25, 0x4a, 0x43, 0xa6, 0x72, 0x47, 0xfb, 0x23, 0xca, 0xa2, 0x64, 0xe7, 0x97, - 0x2a, 0x87, 0x70, 0xe5, 0x33, 0xfe, 0x0e, 0xd1, 0x83, 0x07, 0x0f, 0x43, 0xc5, 0x87, 0x36, 0x7f, - 0xf1, 0x32, 0xbc, 0xfd, 0xae, 0x8c, 0x86, 0x5a, 0x2d, 0x9f, 0x36, 0xa0, 0xc4, 0x9d, 0xa1, 0x98, - 0xec, 0xd0, 0xa3, 0xc2, 0xea, 0xd8, 0xd7, 0x88, 0xe7, 0xcb, 0x1c, 0x52, 0x9a, 0x81, 0x57, 0xd9, - 0x5c, 0x15, 0x10, 0xac, 0x61, 0xd1, 0xc3, 0xf8, 0xa6, 0xed, 0x34, 0xc4, 0x34, 0xa9, 0xc3, 0xf8, - 0x39, 0xdb, 0x69, 0x60, 0x06, 0x51, 0xc7, 0x75, 0xbe, 0x6f, 0x42, 0x97, 0x37, 0x0c, 0x98, 0x66, - 0xcf, 0xf7, 0x42, 0xd3, 0xe3, 0x49, 0x15, 0x2d, 0xc2, 0x9b, 0x71, 0x26, 0x1a, 0x2d, 0x72, 0xa7, - 0x57, 0x9e, 0xe4, 0x0f, 0xfe, 0xa2, 0xc1, 0x23, 0x1f, 0x16, 0xfe, 0x0a, 0x16, 0xd3, 0x92, 0x1b, - 0xda, 0x9c, 0x56, 0xde, 0xb9, 0x9a, 0x24, 0x82, 0x43, 0x7a, 0xe6, 0x4b, 0x30, 0xa5, 0x3f, 0x05, - 0x40, 0x4f, 0xc2, 0x64, 0xc7, 0x76, 0x9a, 0xd1, 0x27, 0x63, 0xca, 0x43, 0xbb, 0x19, 0x82, 0xb0, - 0x8e, 0xc7, 0xaa, 0xb9, 0x61, 0xb5, 0x98, 0x63, 0x77, 0xd3, 0xd5, 0xab, 0x85, 0x7f, 0xcc, 0xdf, - 0xcb, 0xc3, 0xc9, 0x94, 0x27, 0x27, 0xe8, 0x55, 0x03, 0xc6, 0x59, 0xfc, 0xbb, 0x8c, 0x07, 0x79, - 0x21, 0xf3, 0x67, 0x2d, 0x4b, 0x2c, 0xcc, 0x5e, 0xac, 0x63, 0x75, 0x7c, 0xf2, 0x42, 0x2c, 0x98, - 0xa3, 0x5f, 0x33, 0x60, 0xd2, 0xd2, 0xb6, 0x1a, 0x0f, 0x91, 0xd9, 0xce, 0xbe, 0x31, 0x89, 0x9d, - 0xa5, 0x85, 0xf6, 0x85, 0x1b, 0x49, 0x6f, 0xcb, 0xe2, 0xfb, 0x60, 0x52, 0xeb, 0xc2, 0x30, 0x3b, - 0x64, 0xf1, 0x19, 0x98, 0x1d, 0x69, 0x87, 0x7d, 0x08, 0x86, 0x4d, 0x89, 0x46, 0x05, 0xd6, 0x2d, - 0xfd, 0x4d, 0xad, 0x1a, 0x71, 0xf1, 0xa8, 0x56, 0x40, 0xcd, 0x6d, 0x98, 0x8d, 0x1b, 0x57, 0x99, - 0xdf, 0x08, 0xbf, 0x07, 0x86, 0x4c, 0x62, 0x66, 0xfe, 0x79, 0x0e, 0x26, 0xc4, 0xbb, 0xb5, 0x7b, - 0x10, 0x15, 0x7b, 0x33, 0x72, 0x45, 0xb3, 0x9a, 0xc9, 0x73, 0xbb, 0xbe, 0x21, 0xb1, 0x7e, 0x2c, - 0x24, 0xf6, 0xb9, 0x6c, 0xd8, 0x1d, 0x1e, 0x0f, 0xfb, 0xc6, 0x18, 0xcc, 0xc4, 0xde, 0x01, 0x52, - 0x55, 0x25, 0x11, 0x06, 0x76, 0x35, 0xd3, 0xa7, 0x86, 0x2a, 0x62, 0xfb, 0xf0, 0x88, 0x30, 0x3f, - 0x92, 0x2b, 0xf2, 0x4a, 0x66, 0x69, 0xa6, 0x7f, 0x96, 0x36, 0x72, 0xd8, 0x08, 0xa7, 0x7f, 0x34, - 0xe0, 0xfe, 0xbe, 0xcf, 0x45, 0x59, 0xaa, 0x0f, 0x2f, 0x0a, 0x15, 0x1b, 0x32, 0xe3, 0x17, 0xe9, - 0xea, 0xbe, 0x24, 0x9e, 0x9d, 0x21, 0xce, 0x1e, 0x3d, 0x01, 0x53, 0x4c, 0xb4, 0xd2, 0x33, 0x25, - 0x20, 0x1d, 0xe1, 0x20, 0x66, 0xae, 0xc2, 0x9a, 0x56, 0x8e, 0x23, 0x58, 0xe6, 0x57, 0x0d, 0x58, - 0xe8, 0x97, 0xf8, 0x61, 0x00, 0xc3, 0xf0, 0xff, 0xc5, 0xc2, 0x76, 0xcb, 0x89, 0xb0, 0xdd, 0x98, - 0x69, 0x28, 0x23, 0x74, 0x35, 0xab, 0x2c, 0x7f, 0x97, 0xa8, 0xd4, 0xcf, 0x1b, 0x70, 0xba, 0xcf, - 0x6e, 0x4a, 0x84, 0x6f, 0x1b, 0x47, 0x0e, 0xdf, 0xce, 0x0d, 0x1a, 0xbe, 0x6d, 0xfe, 0x65, 0x1e, - 0x66, 0x45, 0x7b, 0x42, 0xfd, 0xea, 0xa9, 0x48, 0xf0, 0xf3, 0x3b, 0x62, 0xc1, 0xcf, 0xf3, 0x71, - 0xfc, 0x9f, 0x45, 0x3e, 0xbf, 0xb5, 0x22, 0x9f, 0x7f, 0x92, 0x83, 0x53, 0xa9, 0xf9, 0x28, 0xd0, - 0x67, 0x52, 0x44, 0xc3, 0xf5, 0x8c, 0x13, 0x5f, 0x0c, 0x28, 0x1c, 0x46, 0x0d, 0x17, 0xfe, 0x92, - 0x1e, 0xa6, 0xcb, 0x8f, 0xfa, 0x9d, 0x63, 0x48, 0xe1, 0x31, 0x64, 0xc4, 0xae, 0xf9, 0x4b, 0x79, - 0x78, 0x74, 0x50, 0x42, 0x6f, 0xd1, 0x17, 0x1d, 0x7e, 0xe4, 0x45, 0xc7, 0x3d, 0x12, 0xdb, 0xc7, - 0xf2, 0xb8, 0xe3, 0x6b, 0x79, 0x25, 0xf6, 0x92, 0xeb, 0x73, 0xa0, 0xdb, 0xc4, 0x09, 0xaa, 0xda, - 0xc9, 0x2c, 0x95, 0xe1, 0x51, 0x38, 0x51, 0xe3, 0xc5, 0x77, 0x7a, 0xe5, 0x39, 0x91, 0xb9, 0xae, - 0x46, 0x02, 0x51, 0x88, 0x65, 0x25, 0xf4, 0x28, 0x14, 0x3d, 0x0e, 0x95, 0x31, 0xec, 0xe2, 0x4a, - 0x96, 0x97, 0x61, 0x05, 0x45, 0x9f, 0xd2, 0x74, 0xe1, 0xb1, 0xe3, 0xca, 0x3f, 0x70, 0xd8, 0x4d, - 0xf3, 0x0b, 0x50, 0xf4, 0x65, 0xbe, 0x49, 0x7e, 0x1d, 0xf0, 0xf8, 0x80, 0x4f, 0x23, 0xa8, 0xe9, - 0x24, 0x93, 0x4f, 0xf2, 0xfe, 0xa9, 0xd4, 0x94, 0x8a, 0x24, 0x32, 0x95, 0xd5, 0xc2, 0x7d, 0x8c, - 0x90, 0x62, 0xb1, 0x7c, 0xcf, 0x80, 0x49, 0x31, 0x5b, 0xf7, 0xe0, 0xb5, 0xc6, 0x8d, 0xe8, 0x6b, - 0x8d, 0xf3, 0x99, 0x9c, 0x1d, 0x7d, 0x9e, 0x6a, 0xdc, 0x80, 0x29, 0x3d, 0x25, 0x11, 0x7a, 0x5e, - 0x3b, 0xfb, 0x8c, 0x51, 0xf2, 0x8c, 0xc8, 0xd3, 0x31, 0x3c, 0x17, 0xcd, 0xaf, 0x14, 0xd5, 0x28, - 0x32, 0x3f, 0x84, 0xbe, 0x06, 0x8d, 0x43, 0xd7, 0xa0, 0xbe, 0x04, 0x72, 0xd9, 0x2f, 0x81, 0x2b, - 0x50, 0x94, 0x07, 0x94, 0x10, 0xe3, 0x0f, 0xeb, 0x31, 0x73, 0x54, 0x17, 0xa0, 0xc4, 0xb4, 0x85, - 0xcb, 0x4c, 0x2d, 0x35, 0x87, 0xea, 0xe0, 0x54, 0x64, 0xd0, 0x8b, 0x30, 0x79, 0xcb, 0xf5, 0x6e, - 0xb6, 0x5c, 0x8b, 0x65, 0x92, 0x85, 0x2c, 0x2e, 0x76, 0x94, 0xc3, 0x8b, 0x87, 0xb2, 0x5f, 0x0f, - 0xe9, 0x63, 0x9d, 0x19, 0xaa, 0xc0, 0x4c, 0xdb, 0x76, 0x30, 0xb1, 0x1a, 0xea, 0x51, 0xc6, 0x18, - 0x4f, 0x75, 0x29, 0x95, 0xdc, 0xf5, 0x28, 0x18, 0xc7, 0xf1, 0xd1, 0x27, 0xa0, 0xe8, 0x8b, 0x1c, - 0x43, 0xd9, 0x5c, 0xc1, 0x29, 0x9b, 0x91, 0x13, 0x0d, 0xc7, 0x4e, 0x96, 0x60, 0xc5, 0x10, 0xad, - 0xc1, 0xbc, 0x27, 0xb2, 0x78, 0x44, 0xbe, 0x43, 0xc1, 0xf7, 0x27, 0xcb, 0xa8, 0x88, 0x53, 0xe0, - 0x38, 0xb5, 0x16, 0xd5, 0x62, 0x58, 0x6e, 0x2d, 0x7e, 0x27, 0xa0, 0xb9, 0xd1, 0xd9, 0x82, 0x6f, - 0x60, 0x01, 0x3d, 0xec, 0x91, 0x4f, 0x71, 0x84, 0x47, 0x3e, 0x35, 0x38, 0x15, 0x07, 0xb1, 0x5c, - 0x23, 0x2c, 0xbd, 0x89, 0x26, 0x3d, 0x36, 0xd3, 0x90, 0x70, 0x7a, 0x5d, 0x74, 0x1d, 0x4a, 0x1e, - 0x61, 0xf6, 0x45, 0x45, 0x5e, 0xfa, 0x0f, 0x1d, 0xde, 0x84, 0x25, 0x01, 0x1c, 0xd2, 0xa2, 0xf3, - 0x6e, 0x45, 0xb3, 0x3d, 0x5e, 0xc9, 0xf0, 0x4b, 0x5a, 0x62, 0xee, 0xfb, 0xe4, 0x00, 0x32, 0xdf, - 0x9c, 0x86, 0x13, 0x11, 0xdf, 0x02, 0x7a, 0x18, 0x0a, 0x2c, 0xf9, 0x0a, 0x3b, 0x1e, 0x8a, 0xe1, - 0x11, 0xc6, 0x07, 0x87, 0xc3, 0xd0, 0x17, 0x0c, 0x98, 0xe9, 0x44, 0xbc, 0xb0, 0xf2, 0xe4, 0x1c, - 0xf1, 0x9e, 0x2f, 0xea, 0xda, 0xd5, 0xf2, 0x24, 0x47, 0x99, 0xe1, 0x38, 0x77, 0xba, 0x01, 0x45, - 0xc4, 0x5f, 0x8b, 0x78, 0x0c, 0x5b, 0xe8, 0x38, 0x8a, 0xc4, 0x72, 0x14, 0x8c, 0xe3, 0xf8, 0x74, - 0x86, 0x59, 0xef, 0x46, 0xf9, 0xc4, 0x4e, 0x45, 0x12, 0xc0, 0x21, 0x2d, 0xf4, 0x0c, 0x4c, 0x8b, - 0x24, 0x7f, 0x9b, 0x6e, 0xe3, 0xa2, 0xe5, 0xef, 0x0a, 0xe5, 0x5e, 0x19, 0x23, 0xcb, 0x11, 0x28, - 0x8e, 0x61, 0xb3, 0xbe, 0x85, 0x99, 0x14, 0x19, 0x81, 0xf1, 0x68, 0x1a, 0xe9, 0xe5, 0x28, 0x18, - 0xc7, 0xf1, 0xd1, 0xbb, 0xb4, 0x73, 0x9f, 0xdf, 0xd3, 0xa9, 0xd3, 0x20, 0xe5, 0xec, 0xaf, 0xc0, - 0x4c, 0x97, 0xd9, 0x42, 0x0d, 0x09, 0x14, 0xfb, 0x51, 0x31, 0xbc, 0x1a, 0x05, 0xe3, 0x38, 0x3e, - 0x7a, 0x1a, 0x4e, 0x78, 0xf4, 0x74, 0x53, 0x04, 0xf8, 0xe5, 0x9d, 0xba, 0x9b, 0xc1, 0x3a, 0x10, - 0x47, 0x71, 0xd1, 0xb3, 0x30, 0x17, 0xa6, 0xe5, 0x92, 0x04, 0xf8, 0x6d, 0x9e, 0xca, 0x38, 0x53, - 0x89, 0x23, 0xe0, 0x64, 0x1d, 0xf4, 0x73, 0x30, 0xab, 0x8d, 0xc4, 0xaa, 0xd3, 0x20, 0xb7, 0x45, - 0xea, 0x24, 0x96, 0x00, 0x6e, 0x39, 0x06, 0xc3, 0x09, 0x6c, 0xf4, 0x7e, 0x98, 0xae, 0xbb, 0xad, - 0x16, 0x3b, 0xe3, 0x78, 0x0a, 0x63, 0x9e, 0x23, 0x89, 0x67, 0x93, 0x8a, 0x40, 0x70, 0x0c, 0x13, - 0x5d, 0x02, 0xe4, 0x6e, 0xfb, 0xc4, 0xdb, 0x23, 0x8d, 0x67, 0xf9, 0x47, 0x3b, 0xa9, 0x88, 0x3f, - 0x11, 0x8d, 0x37, 0xbe, 0x9c, 0xc0, 0xc0, 0x29, 0xb5, 0x58, 0xc2, 0x1a, 0xed, 0xad, 0xd4, 0x74, - 0x16, 0x9f, 0x9b, 0x89, 0x5b, 0xee, 0x77, 0x7d, 0x28, 0xe5, 0xc1, 0x38, 0x0f, 0xff, 0xce, 0x26, - 0x59, 0x92, 0x9e, 0xcd, 0x34, 0x94, 0x11, 0xbc, 0x14, 0x0b, 0x4e, 0xe8, 0x93, 0x50, 0xda, 0x96, - 0xa9, 0xad, 0x17, 0x66, 0xb3, 0x90, 0x8b, 0xb1, 0x2c, 0xed, 0xa1, 0x65, 0xaa, 0x00, 0x38, 0x64, - 0x89, 0x1e, 0x81, 0xc9, 0x8b, 0x9b, 0x15, 0xb5, 0x0a, 0xe7, 0xd8, 0xec, 0x8f, 0xd1, 0x2a, 0x58, - 0x07, 0xd0, 0x1d, 0xa6, 0xf4, 0x25, 0xc4, 0xa6, 0x38, 0x94, 0xb7, 0x49, 0xf5, 0x87, 0x62, 0xb3, - 0xeb, 0x48, 0x5c, 0x5b, 0x38, 0x19, 0xc3, 0x16, 0xe5, 0x58, 0x61, 0xa0, 0x17, 0x60, 0x52, 0xc8, - 0x0b, 0x76, 0x36, 0xcd, 0x1f, 0xed, 0x1d, 0x1e, 0x0e, 0x49, 0x60, 0x9d, 0x1e, 0xbb, 0x65, 0x62, - 0x19, 0x7f, 0xc9, 0x85, 0x6e, 0xab, 0xb5, 0x70, 0x8a, 0x9d, 0x9b, 0xe1, 0x2d, 0x53, 0x08, 0xc2, - 0x3a, 0x1e, 0x7a, 0x5c, 0x46, 0x4e, 0xbc, 0x2d, 0x72, 0xed, 0xa6, 0x22, 0x27, 0x94, 0x96, 0xdb, - 0x27, 0xa0, 0xf8, 0xf4, 0x5d, 0x42, 0x16, 0xb6, 0x61, 0x51, 0xaa, 0x58, 0xc9, 0x4d, 0xb2, 0xb0, - 0x10, 0xf1, 0x12, 0x2c, 0x5e, 0xef, 0x8b, 0x89, 0x0f, 0xa1, 0x82, 0xb6, 0x21, 0x6f, 0xb5, 0xb6, - 0x17, 0xee, 0xcf, 0x42, 0x57, 0x54, 0x1f, 0xe1, 0xe5, 0x41, 0x40, 0x95, 0xb5, 0x2a, 0xa6, 0xc4, - 0xcd, 0x57, 0x72, 0xca, 0x2b, 0xaf, 0x92, 0x48, 0xbe, 0xa4, 0xaf, 0x6a, 0x23, 0x8b, 0x8f, 0x4c, - 0x26, 0xf2, 0xbf, 0x73, 0x81, 0x94, 0xba, 0xa6, 0x3b, 0x6a, 0x1f, 0x67, 0x92, 0x21, 0x24, 0x9a, - 0x20, 0x93, 0x5b, 0x73, 0xd1, 0x5d, 0x6c, 0x7e, 0x7f, 0x5c, 0x39, 0xa1, 0x62, 0xa1, 0x00, 0x1e, - 0x14, 0x6c, 0x3f, 0xb0, 0xdd, 0x0c, 0x9f, 0x8b, 0xc5, 0x32, 0x4b, 0xb2, 0xc0, 0x59, 0x06, 0xc0, - 0x9c, 0x15, 0xe5, 0xe9, 0x34, 0x6d, 0xe7, 0xb6, 0xe8, 0xfe, 0x95, 0xcc, 0xef, 0xf8, 0x39, 0x4f, - 0x06, 0xc0, 0x9c, 0x15, 0xba, 0xc1, 0x57, 0x5a, 0x36, 0x1f, 0x14, 0x8d, 0x7f, 0x27, 0x38, 0xba, - 0xe2, 0x28, 0x2f, 0xbf, 0x6d, 0x0b, 0x1d, 0x66, 0x44, 0x5e, 0xb5, 0xf5, 0xd5, 0x34, 0x5e, 0xb5, - 0xf5, 0x55, 0x4c, 0x99, 0xa0, 0xd7, 0x0c, 0x00, 0x4b, 0x7d, 0x30, 0x37, 0x9b, 0x8f, 0x25, 0xf4, - 0xfb, 0x00, 0x2f, 0x8f, 0x75, 0x0b, 0xa1, 0x58, 0xe3, 0x8c, 0x5e, 0x84, 0x09, 0x8b, 0x7f, 0xea, - 0x45, 0x84, 0x11, 0x66, 0xf3, 0xfd, 0xa2, 0x58, 0x0b, 0x58, 0xfc, 0xa4, 0x00, 0x61, 0xc9, 0x90, - 0xf2, 0x0e, 0x3c, 0x8b, 0xec, 0xd8, 0x37, 0x45, 0x3c, 0x61, 0x6d, 0xe4, 0x8c, 0xcd, 0x94, 0x58, - 0x1a, 0x6f, 0x01, 0xc2, 0x92, 0xa1, 0xf9, 0x2f, 0x06, 0x68, 0x5f, 0x57, 0x0c, 0x03, 0xbd, 0x8c, - 0x81, 0x03, 0xbd, 0x72, 0x43, 0x06, 0x7a, 0xe5, 0x87, 0x0a, 0xf4, 0x1a, 0x1b, 0x3e, 0xd0, 0xab, - 0xd0, 0x3f, 0xd0, 0xcb, 0x7c, 0xdd, 0x80, 0xb9, 0xc4, 0x9a, 0x8c, 0x7f, 0xc5, 0xda, 0x18, 0xf0, - 0x2b, 0xd6, 0x2b, 0x30, 0x2b, 0x52, 0xcc, 0xd6, 0x3a, 0x2d, 0x3b, 0xf5, 0x65, 0xed, 0x56, 0x0c, - 0x8e, 0x13, 0x35, 0xcc, 0x3f, 0x32, 0x60, 0x52, 0x7b, 0x08, 0x44, 0xfb, 0xc1, 0x1e, 0x4c, 0x89, - 0x66, 0x84, 0xd9, 0x75, 0x99, 0x7b, 0x95, 0xc3, 0xb8, 0xa7, 0xbf, 0xa9, 0xa5, 0x33, 0x0c, 0x3d, - 0xfd, 0xb4, 0x14, 0x0b, 0x28, 0x4f, 0x54, 0x47, 0xf8, 0x17, 0xca, 0xf3, 0x7a, 0xa2, 0x3a, 0xd2, - 0xc1, 0x0c, 0xc2, 0xd8, 0x51, 0x59, 0x2e, 0x62, 0x00, 0xb5, 0x64, 0xbe, 0x16, 0xb5, 0xd8, 0x18, - 0x0c, 0x9d, 0x81, 0x3c, 0x71, 0x1a, 0xc2, 0xf0, 0x50, 0x5f, 0xaf, 0x39, 0xef, 0x34, 0x30, 0x2d, - 0x37, 0x2f, 0xc3, 0x54, 0x8d, 0xd4, 0x3d, 0x12, 0x3c, 0x47, 0xf6, 0x07, 0xfe, 0x1c, 0xce, 0x4d, - 0xb2, 0x1f, 0xff, 0x1c, 0x0e, 0xad, 0x4e, 0xcb, 0xcd, 0xdf, 0x31, 0x20, 0x96, 0xee, 0x59, 0xf3, - 0xfa, 0x19, 0xfd, 0xbc, 0x7e, 0x11, 0xff, 0x54, 0xee, 0x50, 0xff, 0xd4, 0x25, 0x40, 0x6d, 0x2b, - 0xa8, 0xef, 0x46, 0x92, 0x9b, 0x0b, 0x9b, 0x2f, 0x7c, 0x76, 0x98, 0xc0, 0xc0, 0x29, 0xb5, 0xcc, - 0xcf, 0x1a, 0x90, 0x48, 0x06, 0x8d, 0xba, 0x50, 0x60, 0xa8, 0xe2, 0x62, 0x64, 0x73, 0xb4, 0x1d, - 0x9d, 0x7c, 0x2a, 0x1f, 0x4e, 0x14, 0xfb, 0x8b, 0x39, 0x37, 0xf3, 0x65, 0xda, 0x96, 0xf8, 0xa7, - 0xcd, 0xdf, 0x09, 0x13, 0x44, 0x7c, 0xf5, 0x84, 0x9b, 0xe5, 0x4a, 0x6b, 0x92, 0x1f, 0x3b, 0x91, - 0x70, 0x6a, 0xbb, 0x49, 0xef, 0x9f, 0xf4, 0xa5, 0xf0, 0xc7, 0x62, 0xca, 0x76, 0x5b, 0x89, 0x82, - 0x71, 0x1c, 0xdf, 0xfc, 0x14, 0x4c, 0x6a, 0xaf, 0xe7, 0xd9, 0xb6, 0xbc, 0x6d, 0xd5, 0x83, 0xf8, - 0x72, 0x3e, 0x4f, 0x0b, 0x31, 0x87, 0x31, 0x97, 0x0f, 0x8f, 0xe3, 0x8b, 0x2d, 0x67, 0x11, 0xbd, - 0x27, 0xa0, 0x94, 0x98, 0x47, 0x9a, 0xe4, 0xb6, 0x4c, 0x22, 0x28, 0x89, 0x61, 0x5a, 0x88, 0x39, - 0xcc, 0xbc, 0x06, 0x45, 0xf9, 0xa4, 0x97, 0xbd, 0x8b, 0x93, 0xee, 0x08, 0xfd, 0x5d, 0x9c, 0xeb, - 0x05, 0x98, 0x41, 0xe8, 0x9a, 0xf1, 0x1d, 0xfb, 0xa2, 0xeb, 0x07, 0xf2, 0x1d, 0x32, 0x77, 0x3a, - 0x6e, 0xac, 0xb2, 0x32, 0xac, 0xa0, 0xe6, 0x1c, 0xcc, 0x28, 0x6f, 0xa2, 0x08, 0x95, 0xfa, 0x76, - 0x1e, 0xa6, 0x22, 0xdf, 0xd0, 0xbc, 0xfb, 0xca, 0x1f, 0x7c, 0x8d, 0xa6, 0x78, 0x05, 0xf3, 0x43, - 0x7a, 0x05, 0x75, 0x37, 0xec, 0xd8, 0xf1, 0xba, 0x61, 0x0b, 0xd9, 0xb8, 0x61, 0x03, 0x98, 0xf0, - 0xc5, 0x31, 0x3c, 0x9e, 0x85, 0xb9, 0x16, 0x9b, 0x31, 0x2e, 0x05, 0xe5, 0x69, 0x2e, 0x59, 0x99, - 0xdf, 0x28, 0xc0, 0x74, 0x34, 0xa3, 0xc9, 0x00, 0x33, 0xf9, 0xae, 0xc4, 0x4c, 0x0e, 0xe9, 0x15, - 0xc9, 0x8f, 0xea, 0x15, 0x19, 0x1b, 0xd5, 0x2b, 0x52, 0x38, 0x82, 0x57, 0x24, 0xe9, 0xd3, 0x18, - 0x1f, 0xd8, 0xa7, 0xf1, 0x01, 0x75, 0xa5, 0x3f, 0x11, 0xb9, 0x03, 0x0b, 0xaf, 0xf4, 0x51, 0x74, - 0x1a, 0x96, 0xdd, 0x46, 0x6a, 0x68, 0x44, 0xf1, 0x2e, 0xd6, 0x9f, 0x97, 0x7a, 0x03, 0x3f, 0xbc, - 0xe3, 0xf5, 0x6d, 0x43, 0xdc, 0xbe, 0x3f, 0x09, 0x93, 0x62, 0x3d, 0x31, 0x4d, 0x00, 0xa2, 0x5a, - 0x44, 0x2d, 0x04, 0x61, 0x1d, 0x8f, 0x7d, 0xe6, 0x2d, 0xfa, 0x5d, 0x3b, 0xe6, 0x64, 0xd2, 0x3f, - 0xf3, 0x16, 0xfb, 0x0e, 0x5e, 0x1c, 0xdf, 0xfc, 0x04, 0x9c, 0x4a, 0xd5, 0xf9, 0x98, 0x11, 0xcc, - 0x84, 0x14, 0x69, 0x08, 0x04, 0xad, 0x19, 0xb1, 0x84, 0x97, 0x8b, 0xd7, 0xfb, 0x62, 0xe2, 0x43, - 0xa8, 0x98, 0x5f, 0xcf, 0xc3, 0x74, 0xf4, 0x1b, 0x21, 0xe8, 0x96, 0xb2, 0x10, 0x33, 0x31, 0x4e, - 0x39, 0x59, 0x2d, 0x41, 0x46, 0x5f, 0x77, 0xcf, 0x2d, 0xb6, 0xbe, 0xb6, 0x55, 0xb6, 0x8e, 0xe3, - 0x63, 0x2c, 0xfc, 0x2c, 0x82, 0x1d, 0xfb, 0x0c, 0x48, 0x18, 0x50, 0x2d, 0x62, 0x08, 0x32, 0xe7, - 0x1e, 0x86, 0x48, 0x2b, 0x56, 0x58, 0x63, 0x4b, 0x65, 0xcb, 0x1e, 0xf1, 0xec, 0x1d, 0x5b, 0x7d, - 0xdf, 0x8c, 0x9d, 0xdc, 0xd7, 0x44, 0x19, 0x56, 0x50, 0xf3, 0xe5, 0x1c, 0x84, 0x5f, 0x73, 0x64, - 0xb9, 0xfc, 0x7d, 0x4d, 0x81, 0x13, 0xd3, 0x76, 0x69, 0xd4, 0xcf, 0x66, 0x84, 0x14, 0x45, 0xb8, - 0x95, 0x56, 0x82, 0x23, 0x1c, 0x7f, 0x0a, 0x5f, 0x71, 0xb4, 0x60, 0x26, 0xf6, 0xcc, 0x2c, 0xf3, - 0x98, 0xd6, 0xaf, 0xe4, 0xa1, 0xa4, 0x1e, 0xea, 0xa1, 0xf7, 0xb1, 0x84, 0xd8, 0xbb, 0xae, 0x4c, - 0x53, 0xfe, 0x76, 0x2d, 0x6d, 0xf5, 0xae, 0xdb, 0xb8, 0xd3, 0x2b, 0xcf, 0x28, 0x64, 0x5e, 0x84, - 0x45, 0x05, 0xaa, 0x2e, 0x77, 0xbd, 0x56, 0x5c, 0x5d, 0xbe, 0x8a, 0xd7, 0x30, 0x2d, 0x47, 0xb7, - 0x61, 0x82, 0xa7, 0x23, 0x92, 0xd1, 0x2b, 0xeb, 0x19, 0x3d, 0x2e, 0xe4, 0x7a, 0x67, 0x38, 0x0c, - 0xfc, 0xbf, 0x8f, 0x25, 0x3b, 0x2a, 0x25, 0xb7, 0xdd, 0xc6, 0x7e, 0x3c, 0xcd, 0x75, 0xd5, 0x6d, - 0xec, 0x63, 0x06, 0x41, 0xcf, 0xc0, 0x74, 0x60, 0xb7, 0x89, 0xdb, 0x0d, 0xf4, 0x6f, 0xe5, 0xe5, - 0xc3, 0xeb, 0x8b, 0xad, 0x08, 0x14, 0xc7, 0xb0, 0xa9, 0x94, 0xbd, 0xe1, 0xbb, 0x0e, 0xcb, 0x5d, - 0x35, 0x1e, 0xf5, 0x75, 0x5e, 0xaa, 0x5d, 0xde, 0x60, 0xa9, 0xab, 0x14, 0x06, 0xc5, 0xb6, 0xd9, - 0xab, 0x1c, 0x8f, 0x88, 0xdb, 0xc3, 0xd9, 0xf0, 0xcd, 0x36, 0x2f, 0xc7, 0x0a, 0xc3, 0xbc, 0x0a, - 0x33, 0xb1, 0xae, 0x4a, 0xc3, 0xc4, 0x48, 0x37, 0x4c, 0x06, 0xcb, 0x29, 0xfd, 0xfb, 0x06, 0xcc, - 0x25, 0x36, 0xef, 0xa0, 0xc1, 0xd6, 0x71, 0x31, 0x92, 0x3b, 0xba, 0x18, 0xc9, 0x0f, 0x27, 0x46, - 0xaa, 0x4b, 0xdf, 0x79, 0xf3, 0xec, 0x7d, 0xdf, 0x7d, 0xf3, 0xec, 0x7d, 0xdf, 0x7f, 0xf3, 0xec, - 0x7d, 0x2f, 0x1f, 0x9c, 0x35, 0xbe, 0x73, 0x70, 0xd6, 0xf8, 0xee, 0xc1, 0x59, 0xe3, 0xfb, 0x07, - 0x67, 0x8d, 0x7f, 0x38, 0x38, 0x6b, 0xbc, 0xfe, 0xa3, 0xb3, 0xf7, 0x3d, 0x5f, 0x94, 0xcb, 0xe4, - 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0xc9, 0xa1, 0xbf, 0xd2, 0x14, 0x8e, 0x00, 0x00, + // 7521 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x6b, 0x8c, 0x24, 0x57, + 0x75, 0xb0, 0xab, 0x7b, 0x7a, 0xa6, 0xfb, 0xcc, 0xfb, 0xee, 0x2c, 0x3b, 0x1e, 0x7b, 0xb7, 0x4d, + 0x19, 0xf9, 0x33, 0xdf, 0x07, 0xb3, 0xe0, 0xc7, 0xf7, 0x19, 0x8c, 0xfc, 0xa5, 0x7b, 0x66, 0x1f, + 0xb3, 0x9e, 0x99, 0x9d, 0xbd, 0x3d, 0xbb, 0x0b, 0x06, 0x03, 0x35, 0xdd, 0x77, 0x7a, 0x6a, 0xb7, + 0xbb, 0xaa, 0xa9, 0xaa, 0x9e, 0xdd, 0x31, 0x16, 0xd8, 0x41, 0x76, 0x48, 0x04, 0xc2, 0x09, 0xa0, + 0x28, 0x8a, 0x88, 0x50, 0x64, 0x29, 0x0f, 0xf2, 0x0b, 0x25, 0xca, 0x1f, 0xa4, 0x44, 0xe1, 0x11, + 0xf2, 0x23, 0x11, 0x44, 0x49, 0x80, 0x48, 0x74, 0xe2, 0x26, 0x7f, 0x12, 0x25, 0x42, 0x91, 0x88, + 0x22, 0xf6, 0x57, 0x74, 0x9f, 0x75, 0xab, 0xba, 0x7a, 0xb6, 0x7b, 0xba, 0x66, 0xb1, 0x12, 0xfe, + 0x75, 0xdf, 0x73, 0xee, 0x39, 0xe7, 0x3e, 0xcf, 0xb9, 0xe7, 0x9e, 0x7b, 0x0a, 0xd6, 0xeb, 0x76, + 0xb0, 0xd7, 0xde, 0x59, 0xae, 0xba, 0xcd, 0xb3, 0x96, 0x57, 0x77, 0x5b, 0x9e, 0x7b, 0x83, 0xfd, + 0x78, 0xa7, 0xe7, 0x36, 0x1a, 0x6e, 0x3b, 0xf0, 0xcf, 0xb6, 0x6e, 0xd6, 0xcf, 0x5a, 0x2d, 0xdb, + 0x3f, 0xab, 0x4a, 0xf6, 0xdf, 0x6d, 0x35, 0x5a, 0x7b, 0xd6, 0xbb, 0xcf, 0xd6, 0x89, 0x43, 0x3c, + 0x2b, 0x20, 0xb5, 0xe5, 0x96, 0xe7, 0x06, 0x2e, 0x7a, 0x5f, 0x48, 0x6d, 0x59, 0x52, 0x63, 0x3f, + 0x3e, 0x22, 0xeb, 0x2e, 0xb7, 0x6e, 0xd6, 0x97, 0x29, 0xb5, 0x65, 0x55, 0x22, 0xa9, 0x2d, 0xbd, + 0x53, 0x93, 0xa5, 0xee, 0xd6, 0xdd, 0xb3, 0x8c, 0xe8, 0x4e, 0x7b, 0x97, 0xfd, 0x63, 0x7f, 0xd8, + 0x2f, 0xce, 0x6c, 0xe9, 0xe1, 0x9b, 0x4f, 0xf9, 0xcb, 0xb6, 0x4b, 0x65, 0x3b, 0xbb, 0x63, 0x05, + 0xd5, 0xbd, 0xb3, 0xfb, 0x3d, 0x12, 0x2d, 0x99, 0x1a, 0x52, 0xd5, 0xf5, 0x48, 0x12, 0xce, 0x13, + 0x21, 0x4e, 0xd3, 0xaa, 0xee, 0xd9, 0x0e, 0xf1, 0x0e, 0xc2, 0x56, 0x37, 0x49, 0x60, 0x25, 0xd5, + 0x3a, 0xdb, 0xaf, 0x96, 0xd7, 0x76, 0x02, 0xbb, 0x49, 0x7a, 0x2a, 0xfc, 0xdf, 0xbb, 0x55, 0xf0, + 0xab, 0x7b, 0xa4, 0x69, 0xf5, 0xd4, 0x7b, 0xbc, 0x5f, 0xbd, 0x76, 0x60, 0x37, 0xce, 0xda, 0x4e, + 0xe0, 0x07, 0x5e, 0xbc, 0x92, 0xf9, 0x8d, 0x2c, 0x14, 0x4a, 0xeb, 0xe5, 0x4a, 0x60, 0x05, 0x6d, + 0x1f, 0xbd, 0x6a, 0xc0, 0x54, 0xc3, 0xb5, 0x6a, 0x65, 0xab, 0x61, 0x39, 0x55, 0xe2, 0x2d, 0x1a, + 0x0f, 0x19, 0x8f, 0x4e, 0x3e, 0xb6, 0xbe, 0x3c, 0xca, 0x78, 0x2d, 0x97, 0x6e, 0xf9, 0x98, 0xf8, + 0x6e, 0xdb, 0xab, 0x12, 0x4c, 0x76, 0xcb, 0x0b, 0xdf, 0xee, 0x14, 0xef, 0xeb, 0x76, 0x8a, 0x53, + 0xeb, 0x1a, 0x27, 0x1c, 0xe1, 0x8b, 0xbe, 0x68, 0xc0, 0x7c, 0xd5, 0x72, 0x2c, 0xef, 0x60, 0xdb, + 0xf2, 0xea, 0x24, 0xb8, 0xe0, 0xb9, 0xed, 0xd6, 0x62, 0xe6, 0x18, 0xa4, 0xb9, 0x5f, 0x48, 0x33, + 0xbf, 0x12, 0x67, 0x87, 0x7b, 0x25, 0x60, 0x72, 0xf9, 0x81, 0xb5, 0xd3, 0x20, 0xba, 0x5c, 0xd9, + 0xe3, 0x94, 0xab, 0x12, 0x67, 0x87, 0x7b, 0x25, 0x30, 0x5f, 0xc9, 0xc2, 0x7c, 0x69, 0xbd, 0xbc, + 0xed, 0x59, 0xbb, 0xbb, 0x76, 0x15, 0xbb, 0xed, 0xc0, 0x76, 0xea, 0xe8, 0xed, 0x30, 0x61, 0x3b, + 0x75, 0x8f, 0xf8, 0x3e, 0x1b, 0xc8, 0x42, 0x79, 0x56, 0x10, 0x9d, 0x58, 0xe3, 0xc5, 0x58, 0xc2, + 0xd1, 0x93, 0x30, 0xe9, 0x13, 0x6f, 0xdf, 0xae, 0x92, 0x2d, 0xd7, 0x0b, 0x58, 0x4f, 0xe7, 0xca, + 0x27, 0x04, 0xfa, 0x64, 0x25, 0x04, 0x61, 0x1d, 0x8f, 0x56, 0xf3, 0x5c, 0x37, 0x10, 0x70, 0xd6, + 0x11, 0x85, 0xb0, 0x1a, 0x0e, 0x41, 0x58, 0xc7, 0x43, 0xaf, 0x19, 0x30, 0xe7, 0x07, 0x76, 0xf5, + 0xa6, 0xed, 0x10, 0xdf, 0x5f, 0x71, 0x9d, 0x5d, 0xbb, 0xbe, 0x98, 0x63, 0xbd, 0xb8, 0x39, 0x5a, + 0x2f, 0x56, 0x62, 0x54, 0xcb, 0x0b, 0xdd, 0x4e, 0x71, 0x2e, 0x5e, 0x8a, 0x7b, 0xb8, 0xa3, 0x55, + 0x98, 0xb3, 0x1c, 0xc7, 0x0d, 0xac, 0xc0, 0x76, 0x9d, 0x2d, 0x8f, 0xec, 0xda, 0xb7, 0x17, 0xc7, + 0x58, 0x73, 0x16, 0x45, 0x73, 0xe6, 0x4a, 0x31, 0x38, 0xee, 0xa9, 0x61, 0xae, 0xc2, 0x62, 0xa9, + 0xb9, 0x63, 0xf9, 0xbe, 0x55, 0x73, 0xbd, 0xd8, 0x68, 0x3c, 0x0a, 0xf9, 0xa6, 0xd5, 0x6a, 0xd9, + 0x4e, 0x9d, 0x0e, 0x47, 0xf6, 0xd1, 0x42, 0x79, 0xaa, 0xdb, 0x29, 0xe6, 0x37, 0x44, 0x19, 0x56, + 0x50, 0xf3, 0x07, 0x19, 0x98, 0x2c, 0x39, 0x56, 0xe3, 0xc0, 0xb7, 0x7d, 0xdc, 0x76, 0xd0, 0x47, + 0x21, 0x4f, 0x77, 0x97, 0x9a, 0x15, 0x58, 0x62, 0x45, 0xbe, 0x6b, 0x99, 0x2f, 0xf6, 0x65, 0x7d, + 0xb1, 0x87, 0xfd, 0x42, 0xb1, 0x97, 0xf7, 0xdf, 0xbd, 0x7c, 0x79, 0xe7, 0x06, 0xa9, 0x06, 0x1b, + 0x24, 0xb0, 0xca, 0x48, 0xb4, 0x02, 0xc2, 0x32, 0xac, 0xa8, 0x22, 0x17, 0xc6, 0xfc, 0x16, 0xa9, + 0x8a, 0x15, 0xb6, 0x31, 0xe2, 0x4c, 0x0e, 0x45, 0xaf, 0xb4, 0x48, 0xb5, 0x3c, 0x25, 0x58, 0x8f, + 0xd1, 0x7f, 0x98, 0x31, 0x42, 0xb7, 0x60, 0xdc, 0x67, 0x7b, 0x8e, 0x58, 0x3c, 0x97, 0xd3, 0x63, + 0xc9, 0xc8, 0x96, 0x67, 0x04, 0xd3, 0x71, 0xfe, 0x1f, 0x0b, 0x76, 0xe6, 0xdf, 0x1b, 0x70, 0x42, + 0xc3, 0x2e, 0x79, 0xf5, 0x76, 0x93, 0x38, 0x01, 0x7a, 0x08, 0xc6, 0x1c, 0xab, 0x49, 0xc4, 0x42, + 0x51, 0x22, 0x6f, 0x5a, 0x4d, 0x82, 0x19, 0x04, 0x3d, 0x0c, 0xb9, 0x7d, 0xab, 0xd1, 0x26, 0xac, + 0x93, 0x0a, 0xe5, 0x69, 0x81, 0x92, 0xbb, 0x46, 0x0b, 0x31, 0x87, 0xa1, 0x17, 0xa1, 0xc0, 0x7e, + 0x9c, 0xf7, 0xdc, 0x66, 0x4a, 0x4d, 0x13, 0x12, 0x5e, 0x93, 0x64, 0xcb, 0xd3, 0xdd, 0x4e, 0xb1, + 0xa0, 0xfe, 0xe2, 0x90, 0xa1, 0xf9, 0x0f, 0x06, 0xcc, 0x6a, 0x8d, 0x5b, 0xb7, 0xfd, 0x00, 0x7d, + 0xa8, 0x67, 0xf2, 0x2c, 0x0f, 0x36, 0x79, 0x68, 0x6d, 0x36, 0x75, 0xe6, 0x44, 0x4b, 0xf3, 0xb2, + 0x44, 0x9b, 0x38, 0x0e, 0xe4, 0xec, 0x80, 0x34, 0xfd, 0xc5, 0xcc, 0x43, 0xd9, 0x47, 0x27, 0x1f, + 0x5b, 0x4b, 0x6d, 0x18, 0xc3, 0xfe, 0x5d, 0xa3, 0xf4, 0x31, 0x67, 0x63, 0x7e, 0x75, 0x2c, 0xd2, + 0x42, 0x3a, 0xa3, 0x90, 0x0b, 0x13, 0x4d, 0x12, 0x78, 0x76, 0x95, 0xaf, 0xab, 0xc9, 0xc7, 0x56, + 0x47, 0x93, 0x62, 0x83, 0x11, 0x0b, 0x37, 0x4b, 0xfe, 0xdf, 0xc7, 0x92, 0x0b, 0xda, 0x83, 0x31, + 0xcb, 0xab, 0xcb, 0x36, 0x9f, 0x4f, 0x67, 0x7c, 0xc3, 0x39, 0x57, 0xf2, 0xea, 0x3e, 0x66, 0x1c, + 0xd0, 0x59, 0x28, 0x04, 0xc4, 0x6b, 0xda, 0x8e, 0x15, 0xf0, 0xdd, 0x35, 0x5f, 0x9e, 0x17, 0x68, + 0x85, 0x6d, 0x09, 0xc0, 0x21, 0x0e, 0x6a, 0xc0, 0x78, 0xcd, 0x3b, 0xc0, 0x6d, 0x67, 0x71, 0x2c, + 0x8d, 0xae, 0x58, 0x65, 0xb4, 0xc2, 0xc5, 0xc4, 0xff, 0x63, 0xc1, 0x03, 0xbd, 0x6e, 0xc0, 0x42, + 0x93, 0x58, 0x7e, 0xdb, 0x23, 0xb4, 0x09, 0x98, 0x04, 0xc4, 0xa1, 0xbb, 0xe1, 0x62, 0x8e, 0x31, + 0xc7, 0xa3, 0x8e, 0x43, 0x2f, 0xe5, 0xf2, 0x83, 0x42, 0x94, 0x85, 0x24, 0x28, 0x4e, 0x94, 0xc6, + 0xfc, 0xc1, 0x18, 0xcc, 0xf7, 0xec, 0x10, 0xe8, 0x09, 0xc8, 0xb5, 0xf6, 0x2c, 0x5f, 0x2e, 0xf9, + 0x33, 0x72, 0xbe, 0x6d, 0xd1, 0xc2, 0x3b, 0x9d, 0xe2, 0xb4, 0xac, 0xc2, 0x0a, 0x30, 0x47, 0xa6, + 0x3a, 0xb5, 0x49, 0x7c, 0xdf, 0xaa, 0xcb, 0x7d, 0x40, 0x9b, 0x26, 0xac, 0x18, 0x4b, 0x38, 0xfa, + 0x25, 0x03, 0xa6, 0xf9, 0x94, 0xc1, 0xc4, 0x6f, 0x37, 0x02, 0xba, 0xd7, 0xd1, 0x6e, 0xb9, 0x94, + 0xc6, 0xf4, 0xe4, 0x24, 0xcb, 0x27, 0x05, 0xf7, 0x69, 0xbd, 0xd4, 0xc7, 0x51, 0xbe, 0xe8, 0x3a, + 0x14, 0xfc, 0xc0, 0xf2, 0x02, 0x52, 0x2b, 0x05, 0x4c, 0xab, 0x4d, 0x3e, 0xf6, 0xbf, 0x07, 0xdb, + 0x04, 0xb6, 0xed, 0x26, 0xe1, 0x1b, 0x4e, 0x45, 0x12, 0xc0, 0x21, 0x2d, 0xf4, 0x22, 0x80, 0xd7, + 0x76, 0x2a, 0xed, 0x66, 0xd3, 0xf2, 0x0e, 0x84, 0x06, 0xbf, 0x38, 0x5a, 0xf3, 0xb0, 0xa2, 0x17, + 0xea, 0xac, 0xb0, 0x0c, 0x6b, 0xfc, 0xd0, 0xcb, 0x06, 0x4c, 0xf3, 0x99, 0x28, 0x25, 0x18, 0x4f, + 0x59, 0x82, 0x79, 0xda, 0xb5, 0xab, 0x3a, 0x0b, 0x1c, 0xe5, 0x68, 0xfe, 0x6d, 0x54, 0x9f, 0x54, + 0x02, 0x6a, 0x5d, 0xd7, 0x0f, 0xd0, 0x07, 0xe1, 0x7e, 0xbf, 0x5d, 0xad, 0x12, 0xdf, 0xdf, 0x6d, + 0x37, 0x70, 0xdb, 0xb9, 0x68, 0xfb, 0x81, 0xeb, 0x1d, 0xac, 0xdb, 0x4d, 0x3b, 0x60, 0x33, 0x2e, + 0x57, 0x3e, 0xdd, 0xed, 0x14, 0xef, 0xaf, 0xf4, 0x43, 0xc2, 0xfd, 0xeb, 0x23, 0x0b, 0x1e, 0x68, + 0x3b, 0xfd, 0xc9, 0x73, 0xeb, 0xad, 0xd8, 0xed, 0x14, 0x1f, 0xb8, 0xda, 0x1f, 0x0d, 0x1f, 0x46, + 0xc3, 0xfc, 0x17, 0x03, 0xe6, 0x64, 0xbb, 0xb6, 0x49, 0xb3, 0xd5, 0xa0, 0xbb, 0xcb, 0xf1, 0x1b, + 0x22, 0x41, 0xc4, 0x10, 0xc1, 0xe9, 0xa8, 0x13, 0x29, 0x7f, 0x3f, 0x6b, 0xc4, 0xfc, 0x67, 0x03, + 0x16, 0xe2, 0xc8, 0xf7, 0x40, 0x79, 0xfa, 0x51, 0xe5, 0xb9, 0x99, 0x6e, 0x6b, 0xfb, 0x68, 0xd0, + 0x57, 0xc7, 0x7a, 0xdb, 0xfa, 0xdf, 0x5d, 0x8d, 0x86, 0x5a, 0x31, 0xfb, 0xb3, 0xd4, 0x8a, 0x63, + 0x6f, 0x2a, 0xad, 0xf8, 0xbb, 0x63, 0x30, 0x55, 0x72, 0x02, 0xbb, 0xb4, 0xbb, 0x6b, 0x3b, 0x76, + 0x70, 0x80, 0x3e, 0x93, 0x81, 0xb3, 0x2d, 0x8f, 0xec, 0x12, 0xcf, 0x23, 0xb5, 0xd5, 0xb6, 0x67, + 0x3b, 0xf5, 0x4a, 0x75, 0x8f, 0xd4, 0xda, 0x0d, 0xdb, 0xa9, 0xaf, 0xd5, 0x1d, 0x57, 0x15, 0x9f, + 0xbb, 0x4d, 0xaa, 0x6d, 0xd6, 0x24, 0xbe, 0x28, 0x9a, 0xa3, 0x35, 0x69, 0x6b, 0x38, 0xa6, 0xe5, + 0xc7, 0xbb, 0x9d, 0xe2, 0xd9, 0x21, 0x2b, 0xe1, 0x61, 0x9b, 0x86, 0x3e, 0x9d, 0x81, 0x65, 0x8f, + 0x7c, 0xac, 0x6d, 0x0f, 0xde, 0x1b, 0x7c, 0xd7, 0x6a, 0x8c, 0xa8, 0x7e, 0x86, 0xe2, 0x59, 0x7e, + 0xac, 0xdb, 0x29, 0x0e, 0x59, 0x07, 0x0f, 0xd9, 0x2e, 0xf3, 0xeb, 0x19, 0x38, 0x59, 0x6a, 0xb5, + 0x36, 0x88, 0xbf, 0x17, 0x3b, 0xd4, 0x7e, 0xce, 0x80, 0x99, 0x7d, 0xdb, 0x0b, 0xda, 0x56, 0x43, + 0x3a, 0x01, 0xf8, 0x94, 0xa8, 0x8c, 0xb8, 0x9c, 0x39, 0xb7, 0x6b, 0x11, 0xd2, 0x65, 0xd4, 0xed, + 0x14, 0x67, 0xa2, 0x65, 0x38, 0xc6, 0x1e, 0xfd, 0xba, 0x01, 0x73, 0xa2, 0x68, 0xd3, 0xad, 0x11, + 0xdd, 0x73, 0x74, 0x35, 0x4d, 0x99, 0x14, 0x71, 0xee, 0x62, 0x88, 0x97, 0xe2, 0x1e, 0x21, 0xcc, + 0x7f, 0xcb, 0xc0, 0xa9, 0x3e, 0x34, 0xd0, 0xef, 0x18, 0xb0, 0xc0, 0xdd, 0x4d, 0x1a, 0x08, 0x93, + 0x5d, 0xd1, 0x9b, 0x1f, 0x48, 0x5b, 0x72, 0x4c, 0xd7, 0x02, 0x71, 0xaa, 0xa4, 0xbc, 0x48, 0xb7, + 0x8d, 0x95, 0x04, 0xd6, 0x38, 0x51, 0x20, 0x26, 0x29, 0x77, 0x40, 0xc5, 0x24, 0xcd, 0xdc, 0x13, + 0x49, 0x2b, 0x09, 0xac, 0x71, 0xa2, 0x40, 0xe6, 0xff, 0x87, 0x07, 0x0e, 0x21, 0x77, 0xf7, 0x13, + 0xbf, 0xf9, 0xbc, 0x9a, 0xf5, 0xd1, 0x39, 0x37, 0x80, 0xb3, 0xc0, 0x84, 0x71, 0xcf, 0x6d, 0x07, + 0x84, 0x6b, 0xb7, 0x42, 0x19, 0xa8, 0x9e, 0xc0, 0xac, 0x04, 0x0b, 0x88, 0xf9, 0x75, 0x03, 0xf2, + 0x43, 0xf8, 0x1f, 0x8a, 0x51, 0xff, 0x43, 0xa1, 0xc7, 0xf7, 0x10, 0xf4, 0xfa, 0x1e, 0x2e, 0x8c, + 0x36, 0x1a, 0x83, 0xf8, 0x1c, 0x7e, 0x6c, 0xc0, 0x7c, 0x8f, 0x8f, 0x02, 0xed, 0xc1, 0x42, 0xcb, + 0xad, 0x49, 0xfb, 0xe2, 0xa2, 0xe5, 0xef, 0x31, 0x98, 0x68, 0xde, 0x13, 0x74, 0x24, 0xb7, 0x12, + 0xe0, 0x77, 0x3a, 0xc5, 0x45, 0x45, 0x24, 0x86, 0x80, 0x13, 0x29, 0xa2, 0x16, 0xe4, 0x77, 0x6d, + 0xd2, 0xa8, 0x85, 0x53, 0x70, 0x44, 0x4b, 0xe2, 0xbc, 0xa0, 0xc6, 0xdd, 0x73, 0xf2, 0x1f, 0x56, + 0x5c, 0xcc, 0x2b, 0x30, 0x13, 0x75, 0xd6, 0x0e, 0x30, 0x78, 0xa7, 0x21, 0x6b, 0x79, 0x8e, 0x18, + 0xba, 0x49, 0x81, 0x90, 0x2d, 0xe1, 0x4d, 0x4c, 0xcb, 0xcd, 0x9f, 0x8e, 0xc1, 0x6c, 0xb9, 0xd1, + 0x26, 0x17, 0x3c, 0x42, 0xe4, 0xf9, 0xb4, 0x04, 0xb3, 0x2d, 0x8f, 0xec, 0xdb, 0xe4, 0x56, 0x85, + 0x34, 0x48, 0x35, 0x70, 0x3d, 0x41, 0xff, 0x94, 0xa8, 0x3e, 0xbb, 0x15, 0x05, 0xe3, 0x38, 0x3e, + 0x7a, 0x06, 0x66, 0xac, 0x6a, 0x60, 0xef, 0x13, 0x45, 0x81, 0x0b, 0xf0, 0x16, 0x41, 0x61, 0xa6, + 0x14, 0x81, 0xe2, 0x18, 0x36, 0xfa, 0x10, 0x2c, 0xfa, 0x55, 0xab, 0x41, 0xae, 0xb6, 0x04, 0xab, + 0x95, 0x3d, 0x52, 0xbd, 0xb9, 0xe5, 0xda, 0x4e, 0x20, 0xbc, 0x11, 0x0f, 0x09, 0x4a, 0x8b, 0x95, + 0x3e, 0x78, 0xb8, 0x2f, 0x05, 0xf4, 0x27, 0x06, 0x9c, 0x6e, 0x79, 0x64, 0xcb, 0x73, 0x9b, 0x2e, + 0x55, 0x33, 0x3d, 0x47, 0x74, 0x71, 0x54, 0xbd, 0x36, 0xa2, 0x3e, 0xe5, 0x25, 0xbd, 0x2e, 0xc2, + 0xb7, 0x76, 0x3b, 0xc5, 0xd3, 0x5b, 0x87, 0x09, 0x80, 0x0f, 0x97, 0x0f, 0xfd, 0x99, 0x01, 0x67, + 0x5a, 0xae, 0x1f, 0x1c, 0xd2, 0x84, 0xdc, 0xb1, 0x36, 0xc1, 0xec, 0x76, 0x8a, 0x67, 0xb6, 0x0e, + 0x95, 0x00, 0xdf, 0x45, 0x42, 0xb3, 0x3b, 0x09, 0xf3, 0xda, 0xdc, 0x13, 0xe7, 0xd7, 0xa7, 0x61, + 0x5a, 0x4e, 0x86, 0x50, 0xad, 0x17, 0x42, 0x7f, 0x43, 0x49, 0x07, 0xe2, 0x28, 0x2e, 0x9d, 0x77, + 0x6a, 0x2a, 0xf2, 0xda, 0xb1, 0x79, 0xb7, 0x15, 0x81, 0xe2, 0x18, 0x36, 0x5a, 0x83, 0x13, 0xa2, + 0x04, 0x93, 0x56, 0xc3, 0xae, 0x5a, 0x2b, 0x6e, 0x5b, 0x4c, 0xb9, 0x5c, 0xf9, 0x54, 0xb7, 0x53, + 0x3c, 0xb1, 0xd5, 0x0b, 0xc6, 0x49, 0x75, 0xd0, 0x3a, 0x2c, 0x58, 0xed, 0xc0, 0x55, 0xed, 0x3f, + 0xe7, 0x50, 0x4d, 0x51, 0x63, 0x53, 0x2b, 0xcf, 0x55, 0x4a, 0x29, 0x01, 0x8e, 0x13, 0x6b, 0xa1, + 0xad, 0x18, 0xb5, 0x0a, 0xa9, 0xba, 0x4e, 0x8d, 0x8f, 0x72, 0x2e, 0xb4, 0xc2, 0x4b, 0x09, 0x38, + 0x38, 0xb1, 0x26, 0x6a, 0xc0, 0x4c, 0xd3, 0xba, 0x7d, 0xd5, 0xb1, 0xf6, 0x2d, 0xbb, 0x41, 0x99, + 0x08, 0x1f, 0x46, 0xff, 0x83, 0x75, 0x3b, 0xb0, 0x1b, 0xcb, 0xfc, 0x3a, 0x6f, 0x79, 0xcd, 0x09, + 0x2e, 0x7b, 0x95, 0x80, 0x5a, 0x6b, 0xdc, 0x38, 0xda, 0x88, 0xd0, 0xc2, 0x31, 0xda, 0xe8, 0x32, + 0x9c, 0x64, 0xcb, 0x71, 0xd5, 0xbd, 0xe5, 0xac, 0x92, 0x86, 0x75, 0x20, 0x1b, 0x30, 0xc1, 0x1a, + 0x70, 0x7f, 0xb7, 0x53, 0x3c, 0x59, 0x49, 0x42, 0xc0, 0xc9, 0xf5, 0x90, 0x05, 0x0f, 0x44, 0x01, + 0x98, 0xec, 0xdb, 0xbe, 0xed, 0x3a, 0xdc, 0x13, 0x91, 0x0f, 0x3d, 0x11, 0x95, 0xfe, 0x68, 0xf8, + 0x30, 0x1a, 0xe8, 0x37, 0x0d, 0x58, 0x48, 0x5a, 0x86, 0x8b, 0x85, 0x34, 0x2e, 0x2b, 0x62, 0x4b, + 0x8b, 0xcf, 0x88, 0xc4, 0x4d, 0x21, 0x51, 0x08, 0xf4, 0x92, 0x01, 0x53, 0x96, 0x76, 0x8a, 0x5a, + 0x04, 0x26, 0xd5, 0xa5, 0x51, 0xcf, 0xf2, 0x21, 0xc5, 0xf2, 0x5c, 0xb7, 0x53, 0x8c, 0x9c, 0xd4, + 0x70, 0x84, 0x23, 0xfa, 0x2d, 0x03, 0x4e, 0x26, 0xae, 0xf1, 0xc5, 0xc9, 0xe3, 0xe8, 0x21, 0x36, + 0x49, 0x92, 0xf7, 0x9c, 0x64, 0x31, 0xd0, 0x6b, 0x86, 0x52, 0x65, 0x1b, 0xd2, 0x9b, 0x32, 0xc5, + 0x44, 0xbb, 0x32, 0xe2, 0xc1, 0x31, 0x34, 0x08, 0x24, 0xe1, 0xf2, 0x09, 0x4d, 0x33, 0xca, 0x42, + 0x1c, 0x67, 0x8f, 0x3e, 0x6b, 0x48, 0xd5, 0xa8, 0x24, 0x9a, 0x3e, 0x2e, 0x89, 0x50, 0xa8, 0x69, + 0x95, 0x40, 0x31, 0xe6, 0xe8, 0xc3, 0xb0, 0x64, 0xed, 0xb8, 0x5e, 0x90, 0xb8, 0xf8, 0x16, 0x67, + 0xd8, 0x32, 0x3a, 0xd3, 0xed, 0x14, 0x97, 0x4a, 0x7d, 0xb1, 0xf0, 0x21, 0x14, 0xcc, 0x3f, 0xc8, + 0xc1, 0x14, 0x37, 0xf2, 0x85, 0xea, 0xfa, 0x9a, 0x01, 0x0f, 0x56, 0xdb, 0x9e, 0x47, 0x9c, 0xa0, + 0x12, 0x90, 0x56, 0xaf, 0xe2, 0x32, 0x8e, 0x55, 0x71, 0x3d, 0xd4, 0xed, 0x14, 0x1f, 0x5c, 0x39, + 0x84, 0x3f, 0x3e, 0x54, 0x3a, 0xf4, 0x57, 0x06, 0x98, 0x02, 0xa1, 0x6c, 0x55, 0x6f, 0xd6, 0x3d, + 0xb7, 0xed, 0xd4, 0x7a, 0x1b, 0x91, 0x39, 0xd6, 0x46, 0x3c, 0xd2, 0xed, 0x14, 0xcd, 0x95, 0xbb, + 0x4a, 0x81, 0x07, 0x90, 0x14, 0x5d, 0x80, 0x79, 0x81, 0x75, 0xee, 0x76, 0x8b, 0x78, 0x36, 0x35, + 0xa7, 0xc5, 0x7d, 0x7a, 0x18, 0xa2, 0x10, 0x47, 0xc0, 0xbd, 0x75, 0x90, 0x0f, 0x13, 0xb7, 0x88, + 0x5d, 0xdf, 0x0b, 0xa4, 0xf9, 0x34, 0x62, 0x5c, 0x82, 0x38, 0xf0, 0x5f, 0xe7, 0x34, 0xcb, 0x93, + 0xdd, 0x4e, 0x71, 0x42, 0xfc, 0xc1, 0x92, 0x13, 0xda, 0x84, 0x19, 0x7e, 0x04, 0xdb, 0xb2, 0x9d, + 0xfa, 0x96, 0xeb, 0xf0, 0xdb, 0xfc, 0x42, 0xf9, 0x11, 0xa9, 0xf0, 0x2b, 0x11, 0xe8, 0x9d, 0x4e, + 0x71, 0x4a, 0xfe, 0xde, 0x3e, 0x68, 0x11, 0x1c, 0xab, 0x6d, 0x7e, 0x6b, 0x1c, 0x40, 0x4e, 0x57, + 0xd2, 0x42, 0xff, 0x07, 0x0a, 0x3e, 0x09, 0x38, 0x57, 0xe1, 0x3c, 0xe7, 0x77, 0x12, 0xb2, 0x10, + 0x87, 0x70, 0x74, 0x13, 0x72, 0x2d, 0xab, 0xed, 0x13, 0x31, 0xf8, 0x97, 0x52, 0x19, 0xfc, 0x2d, + 0x4a, 0x91, 0x9f, 0xb9, 0xd8, 0x4f, 0xcc, 0x79, 0xa0, 0x4f, 0x19, 0x00, 0x24, 0x3a, 0x60, 0x23, + 0xfb, 0x3e, 0x04, 0xcb, 0x70, 0x4c, 0x69, 0x1f, 0x94, 0x67, 0xba, 0x9d, 0x22, 0x68, 0x43, 0xaf, + 0xb1, 0x45, 0xb7, 0x20, 0x6f, 0xc9, 0x3d, 0x7f, 0xec, 0x38, 0xf6, 0x7c, 0x76, 0x14, 0x52, 0x93, + 0x56, 0x31, 0x43, 0x9f, 0x36, 0x60, 0xc6, 0x27, 0x81, 0x18, 0x2a, 0xba, 0xf3, 0x08, 0x83, 0x77, + 0xc4, 0x49, 0x57, 0x89, 0xd0, 0xe4, 0x3b, 0x68, 0xb4, 0x0c, 0xc7, 0xf8, 0x4a, 0x51, 0x2e, 0x12, + 0xab, 0x46, 0x3c, 0x76, 0xd2, 0x16, 0x96, 0xd4, 0xe8, 0xa2, 0x68, 0x34, 0x95, 0x28, 0x5a, 0x19, + 0x8e, 0xf1, 0x95, 0xa2, 0x6c, 0xd8, 0x9e, 0xe7, 0x0a, 0x51, 0xf2, 0x29, 0x89, 0xa2, 0xd1, 0x54, + 0xa2, 0x68, 0x65, 0x38, 0xc6, 0xd7, 0xfc, 0xeb, 0x29, 0x98, 0x91, 0x0b, 0x29, 0xb4, 0xec, 0xb9, + 0x63, 0xa7, 0x8f, 0x65, 0xbf, 0xa2, 0x03, 0x71, 0x14, 0x97, 0x56, 0xe6, 0x4b, 0x35, 0x6a, 0xd8, + 0xab, 0xca, 0x15, 0x1d, 0x88, 0xa3, 0xb8, 0xa8, 0x09, 0x39, 0x3f, 0x20, 0x2d, 0x79, 0x0f, 0x3a, + 0xe2, 0x35, 0x5d, 0xb8, 0x3f, 0x84, 0x37, 0x1d, 0xf4, 0x9f, 0x8f, 0x39, 0x17, 0xe6, 0x9b, 0x0c, + 0x22, 0xee, 0x4a, 0xb1, 0x38, 0xd2, 0x59, 0x9f, 0x51, 0x4f, 0x28, 0x1f, 0x8d, 0x68, 0x19, 0x8e, + 0xb1, 0x4f, 0x30, 0xf6, 0x73, 0xc7, 0x68, 0xec, 0x3f, 0x07, 0xf9, 0xa6, 0x75, 0xbb, 0xd2, 0xf6, + 0xea, 0x47, 0x3f, 0x54, 0x88, 0x10, 0x25, 0x4e, 0x05, 0x2b, 0x7a, 0xe8, 0x65, 0x43, 0xdb, 0x72, + 0x26, 0x18, 0xf1, 0xeb, 0xe9, 0x6e, 0x39, 0x4a, 0x57, 0xf6, 0xdd, 0x7c, 0x7a, 0x4c, 0xef, 0xfc, + 0x3d, 0x37, 0xbd, 0xa9, 0x19, 0xc9, 0x17, 0x88, 0x32, 0x23, 0x0b, 0xc7, 0x6a, 0x46, 0xae, 0x44, + 0x98, 0xe1, 0x18, 0x73, 0x26, 0x0f, 0x5f, 0x73, 0x4a, 0x1e, 0x38, 0x56, 0x79, 0x2a, 0x11, 0x66, + 0x38, 0xc6, 0xbc, 0xff, 0x79, 0x73, 0xf2, 0x78, 0xce, 0x9b, 0x53, 0x29, 0x9c, 0x37, 0x0f, 0x37, + 0xc5, 0xa7, 0x47, 0x35, 0xc5, 0xd1, 0x25, 0x40, 0xb5, 0x03, 0xc7, 0x6a, 0xda, 0x55, 0xb1, 0x59, + 0x32, 0xb5, 0x39, 0xc3, 0xfc, 0x11, 0x4b, 0x62, 0x23, 0x43, 0xab, 0x3d, 0x18, 0x38, 0xa1, 0x16, + 0x0a, 0x20, 0xdf, 0x92, 0x16, 0xd7, 0x6c, 0x1a, 0xb3, 0x5f, 0x5a, 0x60, 0xfc, 0xaa, 0x9c, 0x2e, + 0x3c, 0x59, 0x82, 0x15, 0x27, 0xf3, 0x3f, 0x0c, 0x98, 0x5b, 0x69, 0xb8, 0xed, 0xda, 0x75, 0x2b, + 0xa8, 0xee, 0xf1, 0x7b, 0x5d, 0xf4, 0x0c, 0xe4, 0x6d, 0x27, 0x20, 0xde, 0xbe, 0xd5, 0x10, 0x1a, + 0xc5, 0x94, 0x57, 0xdf, 0x6b, 0xa2, 0xfc, 0x4e, 0xa7, 0x38, 0xb3, 0xda, 0xf6, 0x58, 0xc0, 0x24, + 0xdf, 0x5f, 0xb0, 0xaa, 0x83, 0xbe, 0x6c, 0xc0, 0x3c, 0xbf, 0x19, 0x5e, 0xb5, 0x02, 0xeb, 0x4a, + 0x9b, 0x78, 0x36, 0x91, 0x77, 0xc3, 0x23, 0x6e, 0x2d, 0x71, 0x59, 0x25, 0x83, 0x83, 0xd0, 0xb4, + 0xde, 0x88, 0x73, 0xc6, 0xbd, 0xc2, 0x98, 0x9f, 0xcf, 0xc2, 0xfd, 0x7d, 0x69, 0xa1, 0x25, 0xc8, + 0xd8, 0x35, 0xd1, 0x74, 0x10, 0x74, 0x33, 0x6b, 0x35, 0x9c, 0xb1, 0x6b, 0x68, 0x99, 0x59, 0x89, + 0x1e, 0xf1, 0x7d, 0x79, 0x4d, 0x58, 0x50, 0x06, 0x9d, 0x28, 0xc5, 0x1a, 0x06, 0x2a, 0x42, 0xae, + 0x61, 0xed, 0x90, 0x86, 0x38, 0x01, 0x30, 0xbb, 0x73, 0x9d, 0x16, 0x60, 0x5e, 0x8e, 0x7e, 0xd1, + 0x00, 0xe0, 0x02, 0xd2, 0xf3, 0x83, 0xd0, 0x6b, 0x38, 0xdd, 0x6e, 0xa2, 0x94, 0xb9, 0x94, 0xe1, + 0x7f, 0xac, 0x71, 0x45, 0xdb, 0x30, 0x4e, 0x4d, 0x50, 0xb7, 0x76, 0x64, 0x35, 0xc6, 0xae, 0x45, + 0xb6, 0x18, 0x0d, 0x2c, 0x68, 0xd1, 0xbe, 0xf2, 0x48, 0xd0, 0xf6, 0x1c, 0xda, 0xb5, 0x4c, 0x71, + 0xe5, 0xb9, 0x14, 0x58, 0x95, 0x62, 0x0d, 0xc3, 0xfc, 0xe3, 0x0c, 0x2c, 0x24, 0x89, 0x4e, 0xf5, + 0xc3, 0x38, 0x97, 0x56, 0x1c, 0x66, 0xdf, 0x9f, 0x7e, 0xff, 0x88, 0x20, 0x07, 0x15, 0x0a, 0x20, + 0xc2, 0xb0, 0x04, 0x5f, 0xf4, 0x7e, 0xd5, 0x43, 0x99, 0x23, 0xf6, 0x90, 0xa2, 0x1c, 0xeb, 0xa5, + 0x87, 0x60, 0xcc, 0xa7, 0x23, 0x9f, 0x8d, 0x5e, 0x39, 0xb0, 0x31, 0x62, 0x10, 0x8a, 0xd1, 0x76, + 0xec, 0x40, 0x44, 0x31, 0x2b, 0x8c, 0xab, 0x8e, 0x1d, 0x60, 0x06, 0x31, 0xbf, 0x98, 0x81, 0xa5, + 0xfe, 0x8d, 0x42, 0x5f, 0x34, 0x00, 0x6a, 0xf4, 0x80, 0x41, 0xa7, 0xa4, 0x0c, 0x0a, 0xb1, 0x8e, + 0xab, 0x0f, 0x57, 0x25, 0xa7, 0x30, 0x42, 0x48, 0x15, 0xf9, 0x58, 0x13, 0x04, 0x3d, 0x26, 0xa7, + 0xfe, 0xa6, 0xd5, 0x94, 0x06, 0xa8, 0xaa, 0xb3, 0xa1, 0x20, 0x58, 0xc3, 0xa2, 0x27, 0x48, 0xc7, + 0x6a, 0x12, 0xbf, 0x65, 0xa9, 0x30, 0x75, 0x76, 0x82, 0xdc, 0x94, 0x85, 0x38, 0x84, 0x9b, 0x0d, + 0x78, 0x78, 0x00, 0x39, 0x53, 0x0a, 0x19, 0x36, 0xff, 0xdd, 0x80, 0x53, 0x2b, 0x8d, 0xb6, 0x1f, + 0x10, 0xef, 0x7f, 0x4c, 0xc0, 0xd5, 0x7f, 0x1a, 0xf0, 0x40, 0x9f, 0x36, 0xdf, 0x83, 0xb8, 0xab, + 0x17, 0xa2, 0x71, 0x57, 0x57, 0x47, 0x9d, 0xd2, 0x89, 0xed, 0xe8, 0x13, 0x7e, 0x15, 0xc0, 0x34, + 0xdd, 0xb5, 0x6a, 0x6e, 0x3d, 0x25, 0xbd, 0xf9, 0x30, 0xe4, 0x3e, 0x46, 0xf5, 0x4f, 0x7c, 0x8e, + 0x31, 0xa5, 0x84, 0x39, 0xcc, 0x7c, 0x1f, 0x88, 0x20, 0xa5, 0xd8, 0xe2, 0x31, 0x06, 0x59, 0x3c, + 0xe6, 0xdf, 0x65, 0x40, 0xf3, 0x3c, 0xdc, 0x83, 0x49, 0xe9, 0x44, 0x26, 0xe5, 0x88, 0xa7, 0x66, + 0xcd, 0x8f, 0xd2, 0xef, 0x35, 0xc2, 0x7e, 0xec, 0x35, 0xc2, 0x66, 0x6a, 0x1c, 0x0f, 0x7f, 0x8c, + 0xf0, 0x3d, 0x03, 0x1e, 0x08, 0x91, 0x7b, 0x9d, 0x82, 0x77, 0xdf, 0x61, 0x9e, 0x84, 0x49, 0x2b, + 0xac, 0x26, 0xe6, 0x80, 0x7a, 0x80, 0xa3, 0x51, 0xc4, 0x3a, 0x5e, 0x18, 0xfb, 0x9c, 0x3d, 0x62, + 0xec, 0xf3, 0xd8, 0xe1, 0xb1, 0xcf, 0xe6, 0x4f, 0x32, 0x70, 0xba, 0xb7, 0x65, 0x72, 0x6d, 0x0c, + 0x76, 0x67, 0xfe, 0x14, 0x4c, 0x05, 0xa2, 0x82, 0xb6, 0xd3, 0xab, 0xe7, 0x63, 0xdb, 0x1a, 0x0c, + 0x47, 0x30, 0x69, 0xcd, 0x2a, 0x5f, 0x95, 0x95, 0xaa, 0xdb, 0x92, 0x91, 0xf3, 0xaa, 0xe6, 0x8a, + 0x06, 0xc3, 0x11, 0x4c, 0x15, 0x93, 0x38, 0x76, 0xec, 0x31, 0x89, 0x15, 0x38, 0x29, 0xa3, 0xb0, + 0xce, 0xbb, 0xde, 0x8a, 0xdb, 0x6c, 0x35, 0x88, 0x88, 0x9d, 0xa7, 0xc2, 0x9e, 0x16, 0x55, 0x4e, + 0xe2, 0x24, 0x24, 0x9c, 0x5c, 0xd7, 0xfc, 0x5e, 0x16, 0x4e, 0x84, 0xdd, 0xbe, 0xe2, 0x3a, 0x35, + 0x9b, 0xc5, 0xb2, 0x3d, 0x0d, 0x63, 0xc1, 0x41, 0x4b, 0x76, 0xf6, 0xff, 0x92, 0xe2, 0x6c, 0x1f, + 0xb4, 0xe8, 0x68, 0x9f, 0x4a, 0xa8, 0xc2, 0xdc, 0xb2, 0xac, 0x12, 0x5a, 0x57, 0xab, 0x83, 0x8f, + 0xc0, 0x13, 0xd1, 0xd9, 0x7c, 0xa7, 0x53, 0x4c, 0x78, 0x3d, 0xb9, 0xac, 0x28, 0x45, 0xe7, 0x3c, + 0xba, 0x01, 0x33, 0x0d, 0xcb, 0x0f, 0xae, 0xb6, 0x6a, 0x56, 0x40, 0xb6, 0xed, 0x26, 0x11, 0x6b, + 0x6e, 0x98, 0x80, 0x74, 0x75, 0x8f, 0xbc, 0x1e, 0xa1, 0x84, 0x63, 0x94, 0xd1, 0x3e, 0x20, 0x5a, + 0xb2, 0xed, 0x59, 0x8e, 0xcf, 0x5b, 0x45, 0xf9, 0x0d, 0x1f, 0x00, 0xaf, 0x8e, 0x65, 0xeb, 0x3d, + 0xd4, 0x70, 0x02, 0x07, 0xf4, 0x08, 0x8c, 0x7b, 0xc4, 0xf2, 0xc5, 0x60, 0x16, 0xc2, 0xf5, 0x8f, + 0x59, 0x29, 0x16, 0x50, 0x7d, 0x41, 0x8d, 0xdf, 0x65, 0x41, 0xfd, 0xd0, 0x80, 0x99, 0x70, 0x98, + 0xee, 0x81, 0x92, 0x6c, 0x46, 0x95, 0xe4, 0xc5, 0xb4, 0xb6, 0xc4, 0x3e, 0x7a, 0xf1, 0xcf, 0xc7, + 0xf5, 0xf6, 0xb1, 0x80, 0xe4, 0x8f, 0x43, 0x41, 0xae, 0x6a, 0x69, 0x7d, 0x8e, 0x78, 0xba, 0x8d, + 0xd8, 0x25, 0xda, 0x43, 0x1a, 0xc1, 0x04, 0x87, 0xfc, 0xa8, 0x5a, 0xae, 0x09, 0x95, 0x2b, 0xa6, + 0xbd, 0x52, 0xcb, 0x52, 0x15, 0x27, 0xa9, 0x65, 0x59, 0x07, 0x5d, 0x85, 0x53, 0x2d, 0xcf, 0x65, + 0x8f, 0x2b, 0x57, 0x89, 0x55, 0x6b, 0xd8, 0x0e, 0x91, 0x2e, 0x04, 0x1e, 0xc6, 0xf0, 0x40, 0xb7, + 0x53, 0x3c, 0xb5, 0x95, 0x8c, 0x82, 0xfb, 0xd5, 0x8d, 0x3e, 0x08, 0x1a, 0x1b, 0xe0, 0x41, 0xd0, + 0x2f, 0x2b, 0x47, 0x1d, 0xf1, 0xc5, 0xb3, 0x9c, 0x0f, 0xa6, 0x35, 0x94, 0x09, 0xdb, 0x7a, 0x38, + 0xa5, 0x4a, 0x82, 0x29, 0x56, 0xec, 0xfb, 0x7b, 0x83, 0xc6, 0x8f, 0xe8, 0x0d, 0x0a, 0xe3, 0xba, + 0x27, 0x7e, 0x96, 0x71, 0xdd, 0xf9, 0x37, 0x55, 0x5c, 0xf7, 0x2b, 0x39, 0x98, 0x8b, 0x5b, 0x20, + 0xc7, 0xff, 0xd8, 0xe9, 0xd7, 0x0c, 0x98, 0x93, 0xab, 0x87, 0xf3, 0x24, 0xd2, 0xcf, 0xbf, 0x9e, + 0xd2, 0xa2, 0xe5, 0xb6, 0x94, 0x7a, 0x8e, 0xbb, 0x1d, 0xe3, 0x86, 0x7b, 0xf8, 0xa3, 0xe7, 0x61, + 0x52, 0xb9, 0xc3, 0x8f, 0xf4, 0xf2, 0x69, 0x96, 0x59, 0x51, 0x21, 0x09, 0xac, 0xd3, 0x43, 0xaf, + 0x18, 0x00, 0x55, 0xa9, 0xe6, 0xe4, 0xea, 0xba, 0x92, 0xd6, 0xea, 0x52, 0x0a, 0x34, 0x34, 0x96, + 0x55, 0x91, 0x8f, 0x35, 0xc6, 0xe8, 0xf3, 0xcc, 0x11, 0xae, 0xac, 0x3b, 0xba, 0x9e, 0xb2, 0xa3, + 0x87, 0xe2, 0x1e, 0x62, 0x98, 0x86, 0xa6, 0x94, 0x06, 0xf2, 0x71, 0x44, 0x08, 0xf3, 0x69, 0x50, + 0xc1, 0x93, 0x74, 0xdb, 0x62, 0xe1, 0x93, 0x5b, 0x56, 0xb0, 0x27, 0xa6, 0xa0, 0xda, 0xb6, 0xce, + 0x4b, 0x00, 0x0e, 0x71, 0xcc, 0x8f, 0xc2, 0xcc, 0x05, 0xcf, 0x6a, 0xed, 0xd9, 0xcc, 0xe1, 0x4c, + 0xcf, 0x49, 0x6f, 0x87, 0x09, 0xab, 0x56, 0x4b, 0x7a, 0xcc, 0x5e, 0xe2, 0xc5, 0x58, 0xc2, 0x07, + 0x3b, 0x12, 0x7d, 0xcb, 0x00, 0x14, 0x5e, 0xda, 0xd9, 0x4e, 0x7d, 0x83, 0x9e, 0xf6, 0xe9, 0xf9, + 0x68, 0x8f, 0x95, 0x26, 0x9d, 0x8f, 0x2e, 0x2a, 0x08, 0xd6, 0xb0, 0xd0, 0x8b, 0x30, 0xc9, 0xff, + 0x5d, 0x53, 0x87, 0xfd, 0x91, 0x9f, 0xc2, 0x72, 0x85, 0xc2, 0x64, 0xe2, 0xb3, 0xf0, 0x62, 0xc8, + 0x01, 0xeb, 0xec, 0x68, 0x57, 0xad, 0x39, 0xbb, 0x8d, 0xf6, 0xed, 0xda, 0x4e, 0xd8, 0x55, 0x2d, + 0xcf, 0xdd, 0xb5, 0x1b, 0x24, 0xde, 0x55, 0x5b, 0xbc, 0x18, 0x4b, 0xf8, 0x60, 0x5d, 0xf5, 0x0d, + 0x03, 0x16, 0xd6, 0xfc, 0xc0, 0x76, 0x57, 0x89, 0x1f, 0x50, 0xb5, 0x42, 0x37, 0x9f, 0x76, 0x63, + 0x90, 0x38, 0xe8, 0x55, 0x98, 0x13, 0x17, 0x88, 0xed, 0x1d, 0x9f, 0x04, 0x9a, 0x1d, 0xaf, 0xd6, + 0xf1, 0x4a, 0x0c, 0x8e, 0x7b, 0x6a, 0x50, 0x2a, 0xe2, 0x26, 0x31, 0xa4, 0x92, 0x8d, 0x52, 0xa9, + 0xc4, 0xe0, 0xb8, 0xa7, 0x86, 0xf9, 0x9d, 0x2c, 0x9c, 0x60, 0xcd, 0x88, 0xbd, 0x61, 0xf8, 0x6c, + 0xbf, 0x37, 0x0c, 0x23, 0x2e, 0x65, 0xc6, 0xeb, 0x08, 0x2f, 0x18, 0x7e, 0xd5, 0x80, 0xd9, 0x5a, + 0xb4, 0xa7, 0xd3, 0x71, 0xcf, 0x24, 0x8d, 0x21, 0x8f, 0x97, 0x8a, 0x15, 0xe2, 0x38, 0x7f, 0xf4, + 0x05, 0x03, 0x66, 0xa3, 0x62, 0xca, 0xdd, 0xfd, 0x18, 0x3a, 0x49, 0x05, 0x38, 0x47, 0xcb, 0x7d, + 0x1c, 0x17, 0xc1, 0xfc, 0x1b, 0x43, 0x0c, 0xe9, 0x71, 0x04, 0xe8, 0xa3, 0x5b, 0x50, 0x08, 0x1a, + 0x3e, 0x2f, 0x14, 0xad, 0x1d, 0xf1, 0x44, 0xb8, 0xbd, 0x5e, 0xe1, 0x77, 0xf7, 0xa1, 0xd1, 0x26, + 0x4a, 0xa8, 0xf1, 0x29, 0x79, 0x99, 0x5f, 0x31, 0xa0, 0x70, 0xc9, 0x95, 0xcb, 0xf9, 0xc3, 0x29, + 0xf8, 0x5b, 0x94, 0x59, 0xa6, 0xae, 0xea, 0x42, 0x4b, 0xff, 0x99, 0x88, 0xb7, 0xe5, 0x41, 0x8d, + 0xf6, 0x32, 0xcb, 0x97, 0x43, 0x49, 0x5d, 0x72, 0x77, 0xfa, 0x3a, 0xf3, 0x7e, 0x3b, 0x07, 0xd3, + 0xcf, 0x5a, 0x07, 0xc4, 0x09, 0xac, 0xe1, 0xf7, 0xea, 0x27, 0x61, 0xd2, 0x6a, 0xb1, 0x78, 0x5d, + 0xcd, 0xd4, 0x0e, 0x1d, 0x18, 0x21, 0x08, 0xeb, 0x78, 0xe1, 0xbe, 0xc2, 0xd3, 0x77, 0x24, 0xed, + 0x08, 0x2b, 0x31, 0x38, 0xee, 0xa9, 0x81, 0x2e, 0x01, 0x12, 0x8f, 0x11, 0x4b, 0xd5, 0xaa, 0xdb, + 0x76, 0xf8, 0xce, 0xc2, 0x7d, 0x1b, 0xea, 0xcc, 0xb7, 0xd1, 0x83, 0x81, 0x13, 0x6a, 0xa1, 0x0f, + 0xc1, 0x62, 0x95, 0x51, 0x16, 0x27, 0x00, 0x9d, 0x22, 0x3f, 0x05, 0xaa, 0x58, 0xf9, 0x95, 0x3e, + 0x78, 0xb8, 0x2f, 0x05, 0x2a, 0xa9, 0x1f, 0xb8, 0x9e, 0x55, 0x27, 0x3a, 0xdd, 0xf1, 0xa8, 0xa4, + 0x95, 0x1e, 0x0c, 0x9c, 0x50, 0x0b, 0x7d, 0x12, 0x0a, 0xc1, 0x9e, 0x47, 0xfc, 0x3d, 0xb7, 0x51, + 0x13, 0x77, 0xf7, 0x23, 0x3a, 0xbc, 0xc4, 0xe8, 0x6f, 0x4b, 0xaa, 0xda, 0xf4, 0x96, 0x45, 0x38, + 0xe4, 0x89, 0x3c, 0x18, 0xf7, 0xab, 0x6e, 0x8b, 0xf8, 0xc2, 0x72, 0xbe, 0x94, 0x0a, 0x77, 0xe6, + 0xc0, 0xd1, 0x5c, 0x6d, 0x8c, 0x03, 0x16, 0x9c, 0xcc, 0x6f, 0x66, 0x60, 0x4a, 0x47, 0x1c, 0x60, + 0x8b, 0xf8, 0x94, 0x01, 0x53, 0x55, 0xd7, 0x09, 0x3c, 0xb7, 0xc1, 0xdd, 0x48, 0xe9, 0x28, 0x76, + 0x4a, 0x6a, 0x95, 0x04, 0x96, 0xdd, 0xd0, 0x3c, 0x52, 0x1a, 0x1b, 0x1c, 0x61, 0x8a, 0x3e, 0x63, + 0xc0, 0x6c, 0x18, 0xea, 0x15, 0xfa, 0xb3, 0x52, 0x15, 0x44, 0xed, 0xb8, 0xe7, 0xa2, 0x9c, 0x70, + 0x9c, 0xb5, 0xb9, 0x03, 0x73, 0xf1, 0xd1, 0xa6, 0x5d, 0xd9, 0xb2, 0xc4, 0x5a, 0xcf, 0x86, 0x5d, + 0xb9, 0x65, 0xf9, 0x3e, 0x66, 0x10, 0xf4, 0x0e, 0xc8, 0x37, 0x2d, 0xaf, 0x6e, 0x3b, 0x56, 0x83, + 0xf5, 0x62, 0x56, 0xdb, 0x90, 0x44, 0x39, 0x56, 0x18, 0xe6, 0xbb, 0x60, 0x6a, 0xc3, 0x72, 0xea, + 0xa4, 0xc6, 0xb7, 0xc3, 0x01, 0x5e, 0x6a, 0xfd, 0x68, 0x0c, 0x26, 0xb5, 0x23, 0xd2, 0xf1, 0x1f, + 0x77, 0x22, 0x19, 0x15, 0xb2, 0x29, 0x66, 0x54, 0x78, 0x0e, 0x60, 0xd7, 0x76, 0x6c, 0x7f, 0xef, + 0x88, 0xb9, 0x1a, 0xd8, 0x4d, 0xe9, 0x79, 0x45, 0x01, 0x6b, 0xd4, 0xc2, 0xeb, 0xa8, 0xdc, 0x21, + 0x19, 0x6c, 0x5e, 0x31, 0x34, 0x75, 0x33, 0x9e, 0xc6, 0xf5, 0xbb, 0x36, 0x30, 0xcb, 0x52, 0xfd, + 0x9c, 0x73, 0x02, 0xef, 0xe0, 0x50, 0xad, 0xb4, 0x0d, 0x79, 0x8f, 0xf8, 0xed, 0x26, 0x3d, 0xb8, + 0x4d, 0x0c, 0xdd, 0x0d, 0x2c, 0x74, 0x01, 0x8b, 0xfa, 0x58, 0x51, 0x5a, 0x7a, 0x1a, 0xa6, 0x23, + 0x22, 0xa0, 0x39, 0xc8, 0xde, 0x24, 0x07, 0x7c, 0x9e, 0x60, 0xfa, 0x13, 0x2d, 0x44, 0x2e, 0xed, + 0x44, 0xb7, 0xbc, 0x37, 0xf3, 0x94, 0x61, 0xba, 0x90, 0x78, 0x0e, 0x3f, 0xca, 0x9d, 0x0a, 0x1d, + 0x8b, 0x86, 0x96, 0xac, 0x41, 0x8d, 0x05, 0x0f, 0x50, 0xe1, 0x30, 0xf3, 0x27, 0xe3, 0x20, 0x6e, + 0x94, 0x07, 0xd8, 0xae, 0xf4, 0x8b, 0xa4, 0xcc, 0x11, 0x2e, 0x92, 0x2e, 0xc1, 0x94, 0xed, 0xd8, + 0x81, 0x6d, 0x35, 0x98, 0x8f, 0x45, 0xa8, 0x53, 0x19, 0xc1, 0x3b, 0xb5, 0xa6, 0xc1, 0x12, 0xe8, + 0x44, 0xea, 0xa2, 0x2b, 0x90, 0x63, 0xfa, 0x46, 0x4c, 0xe0, 0xe1, 0xaf, 0xbd, 0x59, 0xc4, 0x03, + 0x7f, 0xd6, 0xc3, 0x29, 0xb1, 0x33, 0x00, 0xcf, 0x56, 0xa1, 0x4e, 0xc1, 0x62, 0x1e, 0x87, 0x67, + 0x80, 0x18, 0x1c, 0xf7, 0xd4, 0xa0, 0x54, 0x76, 0x2d, 0xbb, 0xd1, 0xf6, 0x48, 0x48, 0x65, 0x3c, + 0x4a, 0xe5, 0x7c, 0x0c, 0x8e, 0x7b, 0x6a, 0xa0, 0x5d, 0x98, 0x12, 0x65, 0x3c, 0xec, 0x68, 0xe2, + 0x88, 0xad, 0x64, 0xe1, 0x65, 0xe7, 0x35, 0x4a, 0x38, 0x42, 0x17, 0xb5, 0x61, 0xde, 0x76, 0xaa, + 0xae, 0x53, 0x6d, 0xb4, 0x7d, 0x7b, 0x9f, 0x84, 0x6f, 0x6a, 0x8e, 0xc2, 0xec, 0x64, 0xb7, 0x53, + 0x9c, 0x5f, 0x8b, 0x93, 0xc3, 0xbd, 0x1c, 0xd0, 0xcb, 0x06, 0x9c, 0xac, 0xba, 0x8e, 0xcf, 0x9e, + 0x7f, 0xef, 0x93, 0x73, 0x9e, 0xe7, 0x7a, 0x9c, 0x77, 0xe1, 0x88, 0xbc, 0x99, 0x6b, 0x6f, 0x25, + 0x89, 0x24, 0x4e, 0xe6, 0x84, 0x5e, 0x80, 0x7c, 0xcb, 0x73, 0xf7, 0xed, 0x1a, 0xf1, 0x44, 0x08, + 0xdb, 0x7a, 0x1a, 0xe9, 0x28, 0xb6, 0x04, 0xcd, 0x70, 0xeb, 0x91, 0x25, 0x58, 0xf1, 0x33, 0x5f, + 0x2f, 0xc0, 0x4c, 0x14, 0x1d, 0x7d, 0x02, 0xa0, 0xe5, 0xb9, 0x4d, 0x12, 0xec, 0x11, 0xf5, 0x36, + 0x62, 0x73, 0xd4, 0xac, 0x07, 0x92, 0x9e, 0x0c, 0x22, 0xa1, 0xdb, 0x45, 0x58, 0x8a, 0x35, 0x8e, + 0xc8, 0x83, 0x89, 0x9b, 0x5c, 0xed, 0x0a, 0x2b, 0xe4, 0xd9, 0x54, 0x6c, 0x26, 0xc1, 0x99, 0x05, + 0xf5, 0x8b, 0x22, 0x2c, 0x19, 0xa1, 0x1d, 0xc8, 0xde, 0x22, 0x3b, 0xe9, 0xbc, 0x24, 0xbe, 0x4e, + 0xc4, 0x69, 0xa6, 0x3c, 0xd1, 0xed, 0x14, 0xb3, 0xd7, 0xc9, 0x0e, 0xa6, 0xc4, 0x69, 0xbb, 0x6a, + 0xfc, 0x3a, 0x5c, 0x6c, 0x15, 0x23, 0xb6, 0x2b, 0x72, 0xb7, 0xce, 0xdb, 0x25, 0x8a, 0xb0, 0x64, + 0x84, 0x5e, 0x80, 0xc2, 0x2d, 0x6b, 0x9f, 0xec, 0x7a, 0xae, 0x13, 0x88, 0xc8, 0xa5, 0x11, 0xc3, + 0xe5, 0xaf, 0x4b, 0x72, 0x82, 0x2f, 0x53, 0xef, 0xaa, 0x10, 0x87, 0xec, 0xd0, 0x3e, 0xe4, 0x1d, + 0x72, 0x0b, 0x93, 0x86, 0x5d, 0x4d, 0x27, 0x3c, 0x7d, 0x53, 0x50, 0x13, 0x9c, 0x99, 0xde, 0x93, + 0x65, 0x58, 0xf1, 0xa2, 0x63, 0x79, 0xc3, 0xdd, 0x11, 0x1b, 0xd5, 0x88, 0x63, 0xa9, 0x4e, 0xa6, + 0x7c, 0x2c, 0x2f, 0xb9, 0x3b, 0x98, 0x12, 0xa7, 0x6b, 0xa4, 0xaa, 0xc2, 0x66, 0xc4, 0x36, 0xb5, + 0x99, 0x6e, 0xb8, 0x10, 0x5f, 0x23, 0x61, 0x29, 0xd6, 0x38, 0xd2, 0xbe, 0xad, 0x0b, 0x9f, 0xa1, + 0xd8, 0xa8, 0x46, 0xec, 0xdb, 0xa8, 0x07, 0x92, 0xf7, 0xad, 0x2c, 0xc3, 0x8a, 0x17, 0xe5, 0x6b, + 0x0b, 0x07, 0x5c, 0x3a, 0x5b, 0x55, 0xd4, 0x9d, 0xc7, 0xf9, 0xca, 0x32, 0xac, 0x78, 0x99, 0x5f, + 0x19, 0x87, 0x29, 0x3d, 0xed, 0xd7, 0x00, 0x36, 0x82, 0xb2, 0x8b, 0x33, 0xc3, 0xd8, 0xc5, 0xf4, + 0x20, 0xa4, 0x5d, 0x35, 0x48, 0x5f, 0xc8, 0x5a, 0x6a, 0x66, 0x61, 0x78, 0x10, 0xd2, 0x0a, 0x7d, + 0x1c, 0x61, 0x3a, 0x44, 0xf4, 0x01, 0x35, 0xae, 0xb8, 0xf9, 0x91, 0x8b, 0x1a, 0x57, 0x11, 0x83, + 0xe2, 0x31, 0x80, 0x30, 0xfd, 0x95, 0xb8, 0x82, 0x52, 0x56, 0x9b, 0x96, 0x96, 0x4b, 0xc3, 0x42, + 0x8f, 0xc0, 0x38, 0x55, 0xd0, 0xa4, 0x26, 0x1e, 0xcc, 0xaa, 0xd3, 0xe6, 0x79, 0x56, 0x8a, 0x05, + 0x14, 0x3d, 0x45, 0x6d, 0xa9, 0x50, 0xad, 0x8a, 0x77, 0xb0, 0x0b, 0xa1, 0x2d, 0x15, 0xc2, 0x70, + 0x04, 0x93, 0x8a, 0x4e, 0xa8, 0x16, 0x64, 0x33, 0x58, 0x13, 0x9d, 0xa9, 0x46, 0xcc, 0x61, 0xcc, + 0xfb, 0x11, 0xd3, 0x9a, 0x6c, 0xe6, 0xe5, 0x34, 0xef, 0x47, 0x0c, 0x8e, 0x7b, 0x6a, 0xd0, 0xc6, + 0x88, 0xdb, 0xb3, 0x49, 0x1e, 0x64, 0xd9, 0xe7, 0xde, 0xeb, 0x55, 0xfd, 0x44, 0x30, 0xc5, 0x86, + 0xfe, 0xfd, 0xe9, 0xa5, 0xb0, 0x1b, 0xfc, 0x48, 0x30, 0x9a, 0xf1, 0xfe, 0x51, 0x98, 0x89, 0xee, + 0x95, 0xa9, 0xbb, 0xc9, 0xff, 0x22, 0x0b, 0x27, 0x36, 0xeb, 0xb6, 0x73, 0x3b, 0xe6, 0x5f, 0x4e, + 0x4a, 0x2d, 0x6b, 0x0c, 0x9b, 0x5a, 0x36, 0x7c, 0x79, 0x23, 0x72, 0xf7, 0x26, 0xbf, 0xbc, 0x91, + 0x89, 0x7d, 0xa3, 0xb8, 0xe8, 0x87, 0x06, 0x3c, 0x68, 0xd5, 0xb8, 0xf5, 0x6a, 0x35, 0x44, 0x69, + 0xc8, 0x54, 0xae, 0x68, 0x7f, 0x44, 0x5d, 0xd4, 0xdb, 0xf8, 0xe5, 0xd2, 0x21, 0x5c, 0xf9, 0x88, + 0xbf, 0x4d, 0xb4, 0xe0, 0xc1, 0xc3, 0x50, 0xf1, 0xa1, 0xe2, 0x2f, 0x5d, 0x86, 0xb7, 0xde, 0x95, + 0xd1, 0x50, 0xb3, 0xe5, 0x53, 0x06, 0x14, 0xb8, 0xfb, 0x14, 0x93, 0x5d, 0xba, 0x55, 0x58, 0x2d, + 0xfb, 0x1a, 0xf1, 0x7c, 0x99, 0xf3, 0x4a, 0x3b, 0xe0, 0x95, 0xb6, 0xd6, 0x04, 0x04, 0x6b, 0x58, + 0x74, 0x33, 0xbe, 0x69, 0x3b, 0x35, 0x31, 0x4c, 0x6a, 0x33, 0x7e, 0xd6, 0x76, 0x6a, 0x98, 0x41, + 0xd4, 0x76, 0x9d, 0xed, 0xeb, 0xd6, 0x78, 0xdd, 0x80, 0x19, 0xf6, 0xdc, 0x30, 0x3c, 0x7a, 0x3c, + 0xa9, 0x42, 0x4b, 0xb8, 0x18, 0xa7, 0xa3, 0xa1, 0x25, 0x77, 0x3a, 0xc5, 0x49, 0xfe, 0x40, 0x31, + 0x1a, 0x69, 0xf2, 0x41, 0xe1, 0xaf, 0x60, 0x01, 0x30, 0x99, 0xa1, 0x8f, 0xd3, 0xca, 0x9f, 0x57, + 0x91, 0x44, 0x70, 0x48, 0xcf, 0x7c, 0x11, 0xa6, 0xf4, 0x77, 0x03, 0xe8, 0x49, 0x98, 0x6c, 0xd9, + 0x4e, 0x3d, 0xfa, 0xbe, 0x4c, 0xf9, 0x74, 0xb7, 0x42, 0x10, 0xd6, 0xf1, 0x58, 0x35, 0x37, 0xac, + 0x16, 0x73, 0x05, 0x6f, 0xb9, 0x7a, 0xb5, 0xf0, 0x8f, 0xf9, 0x87, 0x59, 0x38, 0x91, 0xf0, 0x3e, + 0x05, 0xbd, 0x62, 0xc0, 0x38, 0x0b, 0x96, 0x97, 0xc1, 0x23, 0xcf, 0xa7, 0xfe, 0x06, 0x66, 0x99, + 0xc5, 0xe4, 0x8b, 0x79, 0xac, 0xb6, 0x4f, 0x5e, 0x88, 0x05, 0x73, 0xf4, 0x1b, 0x06, 0x4c, 0x5a, + 0xda, 0x52, 0xe3, 0xf1, 0x34, 0x3b, 0xe9, 0x0b, 0xd3, 0xb3, 0xb2, 0xb4, 0x38, 0xc0, 0x70, 0x21, + 0xe9, 0xb2, 0x2c, 0xbd, 0x07, 0x26, 0xb5, 0x26, 0x0c, 0xb3, 0x42, 0x96, 0x9e, 0x81, 0xb9, 0x91, + 0x56, 0xd8, 0x07, 0x60, 0xd8, 0x14, 0x6e, 0x54, 0x61, 0xdd, 0xd2, 0xdf, 0x00, 0xab, 0x1e, 0x17, + 0x8f, 0x80, 0x05, 0xd4, 0xdc, 0x81, 0xb9, 0xf8, 0xe1, 0x2a, 0xf5, 0xeb, 0xe3, 0x77, 0xc1, 0x90, + 0x49, 0xd7, 0xcc, 0xbf, 0xcc, 0xc0, 0x84, 0x78, 0xe4, 0x76, 0x0f, 0x42, 0x68, 0x6f, 0x46, 0x2e, + 0x75, 0xd6, 0x52, 0x79, 0x9b, 0xd7, 0x37, 0x7e, 0xd6, 0x8f, 0xc5, 0xcf, 0x3e, 0x9b, 0x0e, 0xbb, + 0xc3, 0x83, 0x67, 0x5f, 0x1f, 0x83, 0xd9, 0xd8, 0xa3, 0x41, 0x6a, 0xaa, 0xf4, 0xc4, 0x8c, 0x5d, + 0x4d, 0xf5, 0x5d, 0xa2, 0x0a, 0xef, 0x3e, 0x3c, 0x7c, 0xcc, 0x8f, 0xe4, 0xb6, 0xbc, 0x92, 0x5a, + 0x5a, 0xec, 0x9f, 0xa7, 0xb9, 0x1c, 0x36, 0x1c, 0xea, 0x9f, 0x0c, 0xb8, 0xbf, 0xef, 0xdb, 0x52, + 0x96, 0x9a, 0xc4, 0x8b, 0x42, 0xc5, 0x82, 0x4c, 0xf9, 0x05, 0xbd, 0xba, 0x61, 0x89, 0x67, 0x93, + 0x88, 0xb3, 0x47, 0x4f, 0xc0, 0x14, 0x53, 0xad, 0x74, 0x4f, 0x09, 0x48, 0x4b, 0x38, 0x88, 0x99, + 0xab, 0xb0, 0xa2, 0x95, 0xe3, 0x08, 0x96, 0xf9, 0x65, 0x03, 0x16, 0xfb, 0x25, 0xaa, 0x18, 0xe0, + 0x60, 0xf8, 0xff, 0x62, 0x31, 0xbe, 0xc5, 0x9e, 0x18, 0xdf, 0xd8, 0xd1, 0x50, 0x86, 0xf3, 0x6a, + 0xa7, 0xb2, 0xec, 0x5d, 0x42, 0x58, 0x3f, 0x6b, 0xc0, 0xa9, 0x3e, 0xab, 0xa9, 0x27, 0xd6, 0xdb, + 0x38, 0x72, 0xac, 0x77, 0x66, 0xd0, 0x58, 0x6f, 0xf3, 0xbb, 0x59, 0x98, 0x13, 0xf2, 0x84, 0xf6, + 0xd5, 0x53, 0x91, 0x48, 0xe9, 0xb7, 0xc5, 0x22, 0xa5, 0x17, 0xe2, 0xf8, 0x3f, 0x0f, 0x93, 0x7e, + 0x73, 0x85, 0x49, 0xff, 0x34, 0x03, 0x27, 0x13, 0xf3, 0x67, 0xa0, 0x4f, 0x27, 0xa8, 0x86, 0xeb, + 0x29, 0x27, 0xea, 0x18, 0x50, 0x39, 0x8c, 0x1a, 0x5b, 0xfc, 0x05, 0x3d, 0xa6, 0x97, 0x6f, 0xf5, + 0xbb, 0xc7, 0x90, 0x72, 0x64, 0xc8, 0xf0, 0x5e, 0xf3, 0x57, 0xb2, 0xf0, 0xe8, 0xa0, 0x84, 0xde, + 0xa4, 0xcf, 0x3f, 0xfc, 0xc8, 0xf3, 0x8f, 0x7b, 0xa4, 0xb6, 0x8f, 0xe5, 0x25, 0xc8, 0x57, 0xb2, + 0x4a, 0xed, 0xf5, 0xce, 0xcf, 0x81, 0x6e, 0x13, 0x27, 0xa8, 0x69, 0x27, 0xb3, 0x6a, 0x86, 0x5b, + 0xe1, 0x44, 0x85, 0x17, 0xdf, 0xe9, 0x14, 0xe7, 0x45, 0xa6, 0xbd, 0x0a, 0x09, 0x44, 0x21, 0x96, + 0x95, 0xd0, 0xa3, 0x90, 0xf7, 0x38, 0x54, 0x06, 0xbc, 0x8b, 0x2b, 0x59, 0x5e, 0x86, 0x15, 0x14, + 0x7d, 0x52, 0xb3, 0x85, 0xc7, 0x8e, 0x2b, 0x59, 0xc1, 0x61, 0x37, 0xcd, 0xcf, 0x43, 0xde, 0x97, + 0xf9, 0x31, 0xf9, 0x75, 0xc0, 0xe3, 0x03, 0xbe, 0xa3, 0xa0, 0x47, 0x27, 0x99, 0x2c, 0x93, 0xb7, + 0x4f, 0xa5, 0xd2, 0x54, 0x24, 0x91, 0xa9, 0x4e, 0x2d, 0xdc, 0xc7, 0x08, 0x09, 0x27, 0x96, 0xef, + 0x19, 0x30, 0x29, 0x46, 0xeb, 0x1e, 0x3c, 0xed, 0xb8, 0x11, 0x7d, 0xda, 0x71, 0x2e, 0x95, 0xbd, + 0xa3, 0xcf, 0xbb, 0x8e, 0x1b, 0x30, 0xa5, 0xa7, 0x50, 0x42, 0xcf, 0x69, 0x7b, 0x9f, 0x31, 0x4a, + 0x52, 0x12, 0xb9, 0x3b, 0x86, 0xfb, 0xa2, 0xf9, 0xa5, 0xbc, 0xea, 0x45, 0xe6, 0x87, 0xd0, 0xe7, + 0xa0, 0x71, 0xe8, 0x1c, 0xd4, 0xa7, 0x40, 0x26, 0xfd, 0x29, 0x70, 0x05, 0xf2, 0x72, 0x83, 0x12, + 0x6a, 0xfc, 0x61, 0x3d, 0xca, 0x8e, 0xda, 0x02, 0x94, 0x98, 0x36, 0x71, 0xd9, 0x51, 0x4b, 0x8d, + 0xa1, 0xda, 0x38, 0x15, 0x19, 0xf4, 0x02, 0x4c, 0xde, 0x72, 0xbd, 0x9b, 0x0d, 0xd7, 0x62, 0x99, + 0x6f, 0x21, 0x8d, 0x8b, 0x1d, 0xe5, 0xf0, 0xe2, 0x11, 0xc7, 0xd7, 0x43, 0xfa, 0x58, 0x67, 0x86, + 0x4a, 0x30, 0xdb, 0xb4, 0x1d, 0x4c, 0xac, 0x9a, 0x7a, 0xc1, 0x31, 0xc6, 0x53, 0x73, 0x4a, 0x23, + 0x77, 0x23, 0x0a, 0xc6, 0x71, 0x7c, 0xf4, 0x71, 0xc8, 0xfb, 0x22, 0x21, 0x51, 0x3a, 0x57, 0x70, + 0xea, 0xcc, 0xc8, 0x89, 0x86, 0x7d, 0x27, 0x4b, 0xb0, 0x62, 0x88, 0xd6, 0x61, 0xc1, 0x13, 0x29, + 0x3f, 0x22, 0xdf, 0xcd, 0xe0, 0xeb, 0x93, 0x65, 0x80, 0xc4, 0x09, 0x70, 0x9c, 0x58, 0x8b, 0x5a, + 0x31, 0x2c, 0x17, 0x18, 0xbf, 0x13, 0xd0, 0xdc, 0xe8, 0x6c, 0xc2, 0xd7, 0xb0, 0x80, 0x1e, 0xf6, + 0x22, 0x28, 0x3f, 0xc2, 0x8b, 0xa0, 0x0a, 0x9c, 0x8c, 0x83, 0x58, 0x62, 0x12, 0x96, 0x0b, 0x45, + 0xd3, 0x1e, 0x5b, 0x49, 0x48, 0x38, 0xb9, 0x2e, 0xba, 0x0e, 0x05, 0x8f, 0xb0, 0xf3, 0x45, 0x49, + 0x5e, 0xfa, 0x0f, 0x1d, 0xde, 0x84, 0x25, 0x01, 0x1c, 0xd2, 0xa2, 0xe3, 0x6e, 0x45, 0xb3, 0x53, + 0x5e, 0x49, 0xf1, 0xcb, 0x5f, 0x62, 0xec, 0xfb, 0x24, 0x0c, 0x32, 0xdf, 0x98, 0x81, 0xe9, 0x88, + 0x6f, 0x01, 0x3d, 0x0c, 0x39, 0x96, 0xa9, 0x85, 0x6d, 0x0f, 0xf9, 0x70, 0x0b, 0xe3, 0x9d, 0xc3, + 0x61, 0xe8, 0x73, 0x06, 0xcc, 0xb6, 0x22, 0x5e, 0x58, 0xb9, 0x73, 0x8e, 0x78, 0xcf, 0x17, 0x75, + 0xed, 0x6a, 0x79, 0x9d, 0xa3, 0xcc, 0x70, 0x9c, 0x3b, 0x5d, 0x80, 0x22, 0x46, 0xb0, 0x41, 0x3c, + 0x86, 0x2d, 0x6c, 0x1c, 0x45, 0x62, 0x25, 0x0a, 0xc6, 0x71, 0x7c, 0x3a, 0xc2, 0xac, 0x75, 0xa3, + 0x7c, 0x12, 0xa8, 0x24, 0x09, 0xe0, 0x90, 0x16, 0x7a, 0x06, 0x66, 0x44, 0x52, 0xc2, 0x2d, 0xb7, + 0x76, 0xd1, 0xf2, 0xf7, 0x84, 0x71, 0xaf, 0x0e, 0x23, 0x2b, 0x11, 0x28, 0x8e, 0x61, 0xb3, 0xb6, + 0x85, 0x99, 0x1f, 0x19, 0x81, 0xf1, 0x68, 0xda, 0xeb, 0x95, 0x28, 0x18, 0xc7, 0xf1, 0xd1, 0x3b, + 0xb4, 0x7d, 0x9f, 0xdf, 0xd3, 0xa9, 0xdd, 0x20, 0x61, 0xef, 0x2f, 0xc1, 0x6c, 0x9b, 0x9d, 0x85, + 0x6a, 0x12, 0x28, 0xd6, 0xa3, 0x62, 0x78, 0x35, 0x0a, 0xc6, 0x71, 0x7c, 0xf4, 0x34, 0x4c, 0x7b, + 0x74, 0x77, 0x53, 0x04, 0xf8, 0xe5, 0x9d, 0xba, 0x9b, 0xc1, 0x3a, 0x10, 0x47, 0x71, 0xd1, 0x05, + 0x98, 0x0f, 0x73, 0x78, 0x49, 0x02, 0xfc, 0x36, 0x4f, 0xa5, 0xa7, 0x29, 0xc5, 0x11, 0x70, 0x6f, + 0x1d, 0xf4, 0x0b, 0x30, 0xa7, 0xf5, 0xc4, 0x9a, 0x53, 0x23, 0xb7, 0x45, 0x9e, 0x25, 0xf6, 0x85, + 0x82, 0x95, 0x18, 0x0c, 0xf7, 0x60, 0xa3, 0xf7, 0xc2, 0x4c, 0xd5, 0x6d, 0x34, 0xd8, 0x1e, 0xc7, + 0x53, 0x2e, 0xf3, 0x84, 0x4a, 0x3c, 0xf5, 0x54, 0x04, 0x82, 0x63, 0x98, 0xe8, 0x12, 0x20, 0x77, + 0xc7, 0x27, 0xde, 0x3e, 0xa9, 0x5d, 0xe0, 0x1f, 0x19, 0xa5, 0x2a, 0x7e, 0x3a, 0x1a, 0xa1, 0x7c, + 0xb9, 0x07, 0x03, 0x27, 0xd4, 0x62, 0xd9, 0x6d, 0xb4, 0x87, 0x55, 0x33, 0x69, 0x7c, 0x1e, 0x27, + 0x7e, 0x72, 0xbf, 0xeb, 0xab, 0x2a, 0x0f, 0xc6, 0x79, 0xc0, 0x78, 0x3a, 0x99, 0x95, 0xf4, 0xec, + 0xab, 0xa1, 0x8e, 0xe0, 0xa5, 0x58, 0x70, 0x42, 0x9f, 0x80, 0xc2, 0x8e, 0x4c, 0xc5, 0xbd, 0x38, + 0x97, 0x86, 0x5e, 0x8c, 0x65, 0x95, 0x0f, 0x4f, 0xa6, 0x0a, 0x80, 0x43, 0x96, 0xe8, 0x11, 0x98, + 0xbc, 0xb8, 0x55, 0x52, 0xb3, 0x70, 0x9e, 0x8d, 0xfe, 0x18, 0xad, 0x82, 0x75, 0x00, 0x5d, 0x61, + 0xca, 0x5e, 0x42, 0x6c, 0x88, 0x43, 0x7d, 0xdb, 0x6b, 0xfe, 0x50, 0x6c, 0x76, 0x1d, 0x89, 0x2b, + 0x8b, 0x27, 0x62, 0xd8, 0xa2, 0x1c, 0x2b, 0x0c, 0xf4, 0x3c, 0x4c, 0x0a, 0x7d, 0xc1, 0xf6, 0xa6, + 0x85, 0xa3, 0x3d, 0xda, 0xc3, 0x21, 0x09, 0xac, 0xd3, 0x63, 0xb7, 0x4c, 0x2c, 0x43, 0x31, 0x39, + 0xdf, 0x6e, 0x34, 0x16, 0x4f, 0xb2, 0x7d, 0x33, 0xbc, 0x65, 0x0a, 0x41, 0x58, 0xc7, 0x43, 0x8f, + 0xcb, 0xc8, 0x89, 0xb7, 0x44, 0xae, 0xdd, 0x54, 0xe4, 0x84, 0xb2, 0x72, 0xfb, 0x04, 0x14, 0x9f, + 0xba, 0x4b, 0xc8, 0xc2, 0x0e, 0x2c, 0x49, 0x13, 0xab, 0x77, 0x91, 0x2c, 0x2e, 0x46, 0xbc, 0x04, + 0x4b, 0xd7, 0xfb, 0x62, 0xe2, 0x43, 0xa8, 0xa0, 0x1d, 0xc8, 0x5a, 0x8d, 0x9d, 0xc5, 0xfb, 0xd3, + 0xb0, 0x15, 0xd5, 0x47, 0x83, 0x79, 0x10, 0x50, 0x69, 0xbd, 0x8c, 0x29, 0x71, 0xf3, 0xe5, 0x8c, + 0xf2, 0xca, 0xab, 0x8c, 0x93, 0x2f, 0xea, 0xb3, 0xda, 0x48, 0xe3, 0xa3, 0x98, 0x3d, 0xf9, 0xea, + 0xb9, 0x42, 0x4a, 0x9c, 0xd3, 0x2d, 0xb5, 0x8e, 0x53, 0x49, 0x27, 0x12, 0xcd, 0xa6, 0xc9, 0x4f, + 0x73, 0xd1, 0x55, 0x6c, 0x76, 0x27, 0x94, 0x13, 0x2a, 0x16, 0x0a, 0xe0, 0x41, 0xce, 0xf6, 0x03, + 0xdb, 0x4d, 0xf1, 0x81, 0x59, 0x2c, 0x0d, 0x25, 0x0b, 0x9c, 0x65, 0x00, 0xcc, 0x59, 0x51, 0x9e, + 0x4e, 0xdd, 0x76, 0x6e, 0x8b, 0xe6, 0x5f, 0x49, 0xfd, 0x8e, 0x9f, 0xf3, 0x64, 0x00, 0xcc, 0x59, + 0xa1, 0x1b, 0x7c, 0xa6, 0xa5, 0xf3, 0x01, 0xd4, 0xf8, 0x77, 0x8d, 0xa3, 0x33, 0x8e, 0xf2, 0xf2, + 0x9b, 0xb6, 0xb0, 0x61, 0x46, 0xe4, 0x55, 0xd9, 0x58, 0x4b, 0xe2, 0x55, 0xd9, 0x58, 0xc3, 0x94, + 0x09, 0x7a, 0xd5, 0x00, 0xb0, 0xd4, 0x07, 0x7e, 0xd3, 0xf9, 0xb8, 0x43, 0xbf, 0x0f, 0x06, 0xf3, + 0x58, 0xb7, 0x10, 0x8a, 0x35, 0xce, 0xe8, 0x05, 0x98, 0xb0, 0xf8, 0xa7, 0x69, 0x44, 0x18, 0x61, + 0x3a, 0xdf, 0x5b, 0x8a, 0x49, 0xc0, 0xe2, 0x27, 0x05, 0x08, 0x4b, 0x86, 0x94, 0x77, 0xe0, 0x59, + 0x64, 0xd7, 0xbe, 0x29, 0xe2, 0x09, 0x2b, 0x23, 0x67, 0x98, 0xa6, 0xc4, 0x92, 0x78, 0x0b, 0x10, + 0x96, 0x0c, 0xf9, 0x37, 0x35, 0x2d, 0xc7, 0x52, 0x8f, 0x43, 0xd2, 0x79, 0x42, 0xa4, 0x3f, 0x37, + 0xd1, 0xbe, 0xa9, 0xa9, 0x33, 0xc2, 0x51, 0xbe, 0xe6, 0x8f, 0xb3, 0x00, 0xec, 0x27, 0x7f, 0x37, + 0xdc, 0x64, 0xb9, 0xe6, 0xf6, 0xdc, 0x9a, 0x58, 0xda, 0x29, 0x3e, 0xff, 0x05, 0x91, 0x58, 0x6e, + 0xcf, 0xad, 0x61, 0xc1, 0x04, 0xd5, 0x61, 0xac, 0x65, 0x05, 0x7b, 0xe9, 0xbf, 0x35, 0xce, 0xf3, + 0x97, 0x3b, 0xc1, 0x1e, 0x66, 0x0c, 0xd0, 0x4b, 0x06, 0x4c, 0xf0, 0xd7, 0xc6, 0xd2, 0xd5, 0x3c, + 0xf2, 0x7d, 0xaa, 0xec, 0xb3, 0x65, 0xfe, 0xa4, 0x59, 0x04, 0x2b, 0x28, 0xd5, 0x28, 0x4a, 0xb1, + 0x64, 0xbb, 0xf4, 0x8a, 0x01, 0x53, 0x3a, 0x6a, 0x42, 0x98, 0xc1, 0x47, 0xf4, 0x30, 0x83, 0x34, + 0xfb, 0x43, 0x8f, 0x58, 0xf8, 0x57, 0x03, 0xb4, 0x2f, 0x91, 0x86, 0x41, 0x86, 0xc6, 0xc0, 0x41, + 0x86, 0x99, 0x21, 0x83, 0x0c, 0xb3, 0x43, 0x05, 0x19, 0x8e, 0x0d, 0x1f, 0x64, 0x98, 0xeb, 0x1f, + 0x64, 0x68, 0xbe, 0x66, 0xc0, 0x7c, 0xcf, 0x7e, 0x18, 0xff, 0xe2, 0xbb, 0x31, 0xe0, 0x17, 0xdf, + 0x57, 0x61, 0x4e, 0xe4, 0x42, 0xae, 0xb4, 0x1a, 0x76, 0xe2, 0x3b, 0xf0, 0xed, 0x18, 0x1c, 0xf7, + 0xd4, 0x30, 0xff, 0xd4, 0x80, 0x49, 0xed, 0xd9, 0x1a, 0x6d, 0x07, 0x7b, 0xde, 0x27, 0xc4, 0x08, + 0xd3, 0x40, 0x33, 0xd7, 0x3e, 0x87, 0xf1, 0x5b, 0xa6, 0xba, 0x96, 0x77, 0x33, 0xbc, 0x65, 0xa2, + 0xa5, 0x58, 0x40, 0x79, 0x46, 0x45, 0xc2, 0xbf, 0xe6, 0x9f, 0xd5, 0x33, 0x2a, 0x92, 0x16, 0x66, + 0x10, 0xc6, 0x8e, 0xda, 0x91, 0x22, 0xfe, 0x54, 0xcb, 0x3a, 0x6d, 0x79, 0x01, 0xe6, 0x30, 0x74, + 0x1a, 0xb2, 0xc4, 0xa9, 0x89, 0x43, 0xaf, 0xfa, 0xd2, 0xd3, 0x39, 0xa7, 0x86, 0x69, 0xb9, 0x79, + 0x19, 0xa6, 0x2a, 0xa4, 0xea, 0x91, 0xe0, 0x59, 0x72, 0x30, 0xf0, 0xa7, 0xa3, 0xe8, 0x6c, 0x8f, + 0x7d, 0x3a, 0x8a, 0x56, 0xa7, 0xe5, 0xe6, 0xef, 0x1b, 0x10, 0x4b, 0x8d, 0xae, 0x79, 0x9c, 0x8d, + 0x7e, 0x1e, 0xe7, 0x88, 0x6f, 0x34, 0x73, 0xa8, 0x6f, 0xf4, 0x12, 0xa0, 0x26, 0x5d, 0x0a, 0x91, + 0x0f, 0x01, 0x08, 0x7f, 0x43, 0xf8, 0x48, 0xb6, 0x07, 0x03, 0x27, 0xd4, 0x32, 0x7f, 0x8f, 0x0b, + 0xab, 0x27, 0x4b, 0xbf, 0x7b, 0x07, 0xb4, 0x21, 0xc7, 0x48, 0x09, 0xa7, 0xcb, 0xd6, 0x68, 0x8b, + 0xbb, 0x37, 0xe7, 0x43, 0x38, 0x90, 0x62, 0xc9, 0x33, 0x6e, 0xe6, 0x77, 0xb9, 0xac, 0x5a, 0x36, + 0xf5, 0x01, 0x64, 0x6d, 0x46, 0x65, 0xbd, 0x98, 0xd6, 0x5e, 0x99, 0x2c, 0x23, 0x5a, 0x06, 0x68, + 0x11, 0xaf, 0x4a, 0x9c, 0x40, 0x86, 0x45, 0xe7, 0xc4, 0x33, 0x12, 0x55, 0x8a, 0x35, 0x0c, 0xf3, + 0x25, 0x03, 0xe6, 0x2a, 0x81, 0x5d, 0xbd, 0x69, 0x3b, 0xfc, 0x59, 0xd4, 0xae, 0x5d, 0xa7, 0xa7, + 0x14, 0x22, 0xbe, 0x8a, 0xc4, 0xdd, 0x60, 0x6a, 0x2b, 0x96, 0x1f, 0x43, 0x92, 0x70, 0x54, 0x82, + 0x59, 0xe9, 0x6d, 0x97, 0xbe, 0x4b, 0xfe, 0x9c, 0x53, 0xf9, 0x4a, 0x56, 0xa3, 0x60, 0x1c, 0xc7, + 0x37, 0x3f, 0x09, 0x93, 0xda, 0xfe, 0xca, 0xb6, 0xa2, 0xdb, 0x56, 0x35, 0x88, 0x2f, 0xe1, 0x73, + 0xb4, 0x10, 0x73, 0x18, 0x73, 0xb1, 0xf2, 0xb8, 0xd9, 0xd8, 0x12, 0x16, 0xd1, 0xb2, 0x02, 0x4a, + 0x89, 0x79, 0xa4, 0x4e, 0x6e, 0xcb, 0x0c, 0x9f, 0x92, 0x18, 0xa6, 0x85, 0x98, 0xc3, 0xcc, 0x6b, + 0x90, 0x97, 0x8f, 0xee, 0xd9, 0xcb, 0x55, 0xe9, 0xfe, 0xd3, 0x5f, 0xae, 0xba, 0x5e, 0x80, 0x19, + 0x84, 0xae, 0x13, 0xdf, 0xb1, 0x2f, 0xba, 0x7e, 0x20, 0x33, 0x05, 0x70, 0x27, 0xff, 0xe6, 0x1a, + 0x2b, 0xc3, 0x0a, 0x6a, 0xce, 0xc3, 0xac, 0xf2, 0xde, 0x8b, 0xd0, 0xc4, 0x6f, 0x66, 0x61, 0x2a, + 0xf2, 0x8d, 0xdd, 0xbb, 0x4f, 0xa0, 0xc1, 0xd7, 0x65, 0x82, 0x17, 0x3e, 0x3b, 0xa4, 0x17, 0x5e, + 0xbf, 0xf6, 0x18, 0x3b, 0xde, 0x6b, 0x8f, 0x5c, 0x3a, 0xd7, 0x1e, 0x01, 0x4c, 0xf8, 0x42, 0xf5, + 0x8c, 0xa7, 0xe1, 0x1e, 0x89, 0x8d, 0x18, 0xb7, 0x3a, 0xa5, 0x06, 0x93, 0xac, 0xcc, 0xaf, 0xe5, + 0x60, 0x26, 0x9a, 0x6e, 0x68, 0x80, 0x91, 0x7c, 0x47, 0xcf, 0x48, 0x0e, 0xe9, 0x85, 0xcc, 0x8e, + 0xea, 0x85, 0x1c, 0x1b, 0xd5, 0x0b, 0x99, 0x3b, 0x82, 0x17, 0xb2, 0xd7, 0x87, 0x38, 0x3e, 0xb0, + 0x0f, 0xf1, 0x7d, 0x2a, 0x84, 0x66, 0x22, 0x72, 0xe7, 0x1c, 0x86, 0xd0, 0xa0, 0xe8, 0x30, 0xac, + 0xb8, 0xb5, 0xc4, 0x50, 0xa4, 0xfc, 0x5d, 0xbc, 0x2d, 0x5e, 0x62, 0xc4, 0xcb, 0xf0, 0x17, 0x1d, + 0x6f, 0x19, 0x22, 0xda, 0xe5, 0x49, 0x98, 0x14, 0xf3, 0x89, 0x59, 0x3f, 0x10, 0xb5, 0x9c, 0x2a, + 0x21, 0x08, 0xeb, 0x78, 0xec, 0x33, 0x90, 0xd1, 0xef, 0x5e, 0x32, 0xa7, 0xae, 0xfe, 0x19, 0xc8, + 0xd8, 0x77, 0x32, 0xe3, 0xf8, 0xe6, 0xc7, 0xe1, 0x64, 0xe2, 0x19, 0x8b, 0x39, 0x9d, 0x98, 0x62, + 0x26, 0x35, 0x81, 0xa0, 0x89, 0x11, 0xcb, 0x46, 0xbb, 0x74, 0xbd, 0x2f, 0x26, 0x3e, 0x84, 0x8a, + 0xf9, 0xd5, 0x2c, 0xcc, 0x44, 0xbf, 0x21, 0x84, 0x6e, 0x29, 0x8f, 0x4c, 0x2a, 0xce, 0x20, 0x4e, + 0x56, 0x4b, 0x61, 0xd3, 0xd7, 0xbd, 0x7a, 0x8b, 0xcd, 0xaf, 0x1d, 0x95, 0x4f, 0xe7, 0xf8, 0x18, + 0x0b, 0xbf, 0xa6, 0x60, 0xc7, 0x3e, 0x13, 0x14, 0x3e, 0x60, 0x10, 0x07, 0xa9, 0xd4, 0xb9, 0x87, + 0x4f, 0x12, 0x14, 0x2b, 0xac, 0xb1, 0xa5, 0xba, 0x65, 0x9f, 0x78, 0xf6, 0xae, 0xad, 0xbe, 0x7f, + 0xc8, 0x76, 0xee, 0x6b, 0xa2, 0x0c, 0x2b, 0xa8, 0xf9, 0x52, 0x06, 0xc2, 0xaf, 0xbd, 0xb2, 0x0f, + 0x6d, 0xf8, 0x9a, 0xd1, 0x2a, 0x86, 0xed, 0xd2, 0xa8, 0x5f, 0xb3, 0x09, 0x29, 0x8a, 0xf0, 0x46, + 0xad, 0x04, 0x47, 0x38, 0xfe, 0x0c, 0xbe, 0xf2, 0x6a, 0xc1, 0x6c, 0xec, 0x59, 0x67, 0xea, 0x31, + 0xe4, 0x5f, 0xca, 0x42, 0x41, 0x3d, 0x8c, 0x45, 0xef, 0x89, 0x78, 0x10, 0x0a, 0xe5, 0xb7, 0x6a, + 0x39, 0xe5, 0xf7, 0xdc, 0xda, 0x9d, 0x4e, 0x71, 0x56, 0x21, 0xc7, 0xbc, 0x01, 0xa7, 0x21, 0xdb, + 0xf6, 0x1a, 0xf1, 0x23, 0xc2, 0x55, 0xbc, 0x8e, 0x69, 0x39, 0xba, 0x1d, 0x3f, 0xc2, 0x6f, 0xa4, + 0xf4, 0x98, 0x97, 0xdb, 0xd2, 0xfd, 0x8f, 0xee, 0x54, 0x4b, 0xee, 0xb8, 0xb5, 0x83, 0x78, 0x0e, + 0xfa, 0xb2, 0x5b, 0x3b, 0xc0, 0x0c, 0x82, 0x9e, 0x81, 0x99, 0xc0, 0x6e, 0x12, 0xb7, 0x1d, 0xe8, + 0xdf, 0xd2, 0xcc, 0x86, 0xd7, 0x85, 0xdb, 0x11, 0x28, 0x8e, 0x61, 0x53, 0x2d, 0x7b, 0xc3, 0x77, + 0x1d, 0x96, 0x58, 0x6e, 0x3c, 0x7a, 0xb7, 0x70, 0xa9, 0x72, 0x79, 0x93, 0x79, 0x32, 0x14, 0x06, + 0xc5, 0xb6, 0xd9, 0x2b, 0x38, 0x8f, 0x88, 0xdb, 0xfa, 0xb9, 0x30, 0x47, 0x02, 0x2f, 0xc7, 0x0a, + 0xc3, 0xbc, 0x0a, 0xb3, 0xb1, 0xa6, 0xca, 0xc3, 0x98, 0x91, 0x7c, 0x18, 0x1b, 0x2c, 0xe1, 0xfb, + 0x1f, 0x19, 0x30, 0xdf, 0xb3, 0x78, 0x07, 0x7d, 0xdc, 0x10, 0x57, 0x23, 0x99, 0xa3, 0xab, 0x91, + 0xec, 0x70, 0x6a, 0xa4, 0xbc, 0xfc, 0xed, 0x37, 0xce, 0xdc, 0xf7, 0x9d, 0x37, 0xce, 0xdc, 0xf7, + 0xfd, 0x37, 0xce, 0xdc, 0xf7, 0x52, 0xf7, 0x8c, 0xf1, 0xed, 0xee, 0x19, 0xe3, 0x3b, 0xdd, 0x33, + 0xc6, 0xf7, 0xbb, 0x67, 0x8c, 0x7f, 0xec, 0x9e, 0x31, 0x5e, 0xfb, 0xd1, 0x99, 0xfb, 0x9e, 0xcb, + 0xcb, 0x69, 0xf2, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xd0, 0x87, 0xc1, 0x24, 0x34, 0x92, 0x00, + 0x00, } func (m *ALBStatus) Marshal() (dAtA []byte, err error) { @@ -4702,9 +4802,21 @@ func (m *CanaryStep) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.SetHeaderRouting != nil { + if m.SetMirrorRoute != nil { { - size, err := m.SetHeaderRouting.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.SetMirrorRoute.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } + if m.SetHeaderRoute != nil { + { + size, err := m.SetHeaderRoute.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -5879,16 +5991,18 @@ func (m *HeaderRoutingMatch) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - { - size, err := m.HeaderValue.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + if m.HeaderValue != nil { + { + size, err := m.HeaderValue.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 } - i-- - dAtA[i] = 0x12 i -= len(m.HeaderName) copy(dAtA[i:], m.HeaderName) i = encodeVarintGenerated(dAtA, i, uint64(len(m.HeaderName))) @@ -6277,6 +6391,34 @@ func (m *KayentaThreshold) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *MangedRoutes) 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 *MangedRoutes) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MangedRoutes) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *Measurement) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -8090,6 +8232,20 @@ func (m *RolloutTrafficRouting) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.ManagedRoutes) > 0 { + for iNdEx := len(m.ManagedRoutes) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ManagedRoutes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } + } if m.Traefik != nil { { size, err := m.Traefik.MarshalToSizedBuffer(dAtA[:i]) @@ -8177,7 +8333,7 @@ func (m *RolloutTrafficRouting) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *RunSummary) Marshal() (dAtA []byte, err error) { +func (m *RouteMatch) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -8187,47 +8343,123 @@ func (m *RunSummary) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *RunSummary) MarshalTo(dAtA []byte) (int, error) { +func (m *RouteMatch) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *RunSummary) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *RouteMatch) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - i = encodeVarintGenerated(dAtA, i, uint64(m.Error)) - i-- - dAtA[i] = 0x28 - i = encodeVarintGenerated(dAtA, i, uint64(m.Inconclusive)) - i-- - dAtA[i] = 0x20 - i = encodeVarintGenerated(dAtA, i, uint64(m.Failed)) - i-- - dAtA[i] = 0x18 - i = encodeVarintGenerated(dAtA, i, uint64(m.Successful)) - i-- - dAtA[i] = 0x10 - i = encodeVarintGenerated(dAtA, i, uint64(m.Count)) - i-- - dAtA[i] = 0x8 - return len(dAtA) - i, nil -} - -func (m *SMITrafficRouting) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err + if len(m.Headers) > 0 { + keysForHeaders := make([]string, 0, len(m.Headers)) + for k := range m.Headers { + keysForHeaders = append(keysForHeaders, string(k)) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForHeaders) + for iNdEx := len(keysForHeaders) - 1; iNdEx >= 0; iNdEx-- { + v := m.Headers[string(keysForHeaders[iNdEx])] + baseI := i + { + size, err := (&v).MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + i -= len(keysForHeaders[iNdEx]) + copy(dAtA[i:], keysForHeaders[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(keysForHeaders[iNdEx]))) + i-- + dAtA[i] = 0xa + i = encodeVarintGenerated(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x1a + } } - return dAtA[:n], nil -} - -func (m *SMITrafficRouting) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) + if m.Path != nil { + { + size, err := m.Path.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.Method != nil { + { + size, err := m.Method.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *RunSummary) 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 *RunSummary) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RunSummary) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i = encodeVarintGenerated(dAtA, i, uint64(m.Error)) + i-- + dAtA[i] = 0x28 + i = encodeVarintGenerated(dAtA, i, uint64(m.Inconclusive)) + i-- + dAtA[i] = 0x20 + i = encodeVarintGenerated(dAtA, i, uint64(m.Failed)) + i-- + dAtA[i] = 0x18 + i = encodeVarintGenerated(dAtA, i, uint64(m.Successful)) + i-- + dAtA[i] = 0x10 + i = encodeVarintGenerated(dAtA, i, uint64(m.Count)) + i-- + dAtA[i] = 0x8 + return len(dAtA) - i, nil +} + +func (m *SMITrafficRouting) 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 *SMITrafficRouting) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) } func (m *SMITrafficRouting) MarshalToSizedBuffer(dAtA []byte) (int, error) { @@ -8368,7 +8600,7 @@ func (m *SetCanaryScale) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *SetHeaderRouting) Marshal() (dAtA []byte, err error) { +func (m *SetHeaderRoute) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -8378,12 +8610,12 @@ func (m *SetHeaderRouting) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *SetHeaderRouting) MarshalTo(dAtA []byte) (int, error) { +func (m *SetHeaderRoute) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *SetHeaderRouting) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *SetHeaderRoute) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -8399,9 +8631,61 @@ func (m *SetHeaderRouting) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintGenerated(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0xa + dAtA[i] = 0x12 + } + } + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *SetMirrorRoute) 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 *SetMirrorRoute) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SetMirrorRoute) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Percentage != nil { + i = encodeVarintGenerated(dAtA, i, uint64(*m.Percentage)) + i-- + dAtA[i] = 0x20 + } + if len(m.Match) > 0 { + for iNdEx := len(m.Match) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Match[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 } } + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa return len(dAtA) - i, nil } @@ -9498,8 +9782,12 @@ func (m *CanaryStep) Size() (n int) { l = m.SetCanaryScale.Size() n += 1 + l + sovGenerated(uint64(l)) } - if m.SetHeaderRouting != nil { - l = m.SetHeaderRouting.Size() + if m.SetHeaderRoute != nil { + l = m.SetHeaderRoute.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + if m.SetMirrorRoute != nil { + l = m.SetMirrorRoute.Size() n += 1 + l + sovGenerated(uint64(l)) } return n @@ -9918,8 +10206,10 @@ func (m *HeaderRoutingMatch) Size() (n int) { _ = l l = len(m.HeaderName) n += 1 + l + sovGenerated(uint64(l)) - l = m.HeaderValue.Size() - n += 1 + l + sovGenerated(uint64(l)) + if m.HeaderValue != nil { + l = m.HeaderValue.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -10065,6 +10355,17 @@ func (m *KayentaThreshold) Size() (n int) { return n } +func (m *MangedRoutes) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + func (m *Measurement) Size() (n int) { if m == nil { return 0 @@ -10734,6 +11035,38 @@ func (m *RolloutTrafficRouting) Size() (n int) { l = m.Traefik.Size() n += 1 + l + sovGenerated(uint64(l)) } + if len(m.ManagedRoutes) > 0 { + for _, e := range m.ManagedRoutes { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + +func (m *RouteMatch) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Method != nil { + l = m.Method.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + if m.Path != nil { + l = m.Path.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + if len(m.Headers) > 0 { + for k, v := range m.Headers { + _ = k + _ = v + l = v.Size() + mapEntrySize := 1 + len(k) + sovGenerated(uint64(len(k))) + 1 + l + sovGenerated(uint64(l)) + n += mapEntrySize + 1 + sovGenerated(uint64(mapEntrySize)) + } + } return n } @@ -10811,18 +11144,40 @@ func (m *SetCanaryScale) Size() (n int) { return n } -func (m *SetHeaderRouting) Size() (n int) { +func (m *SetHeaderRoute) Size() (n int) { if m == nil { return 0 } var l int _ = l + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + if len(m.Match) > 0 { + for _, e := range m.Match { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + +func (m *SetMirrorRoute) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) if len(m.Match) > 0 { for _, e := range m.Match { l = e.Size() n += 1 + l + sovGenerated(uint64(l)) } } + if m.Percentage != nil { + n += 1 + sovGenerated(uint64(*m.Percentage)) + } return n } @@ -11403,7 +11758,8 @@ func (this *CanaryStep) String() string { `Experiment:` + strings.Replace(this.Experiment.String(), "RolloutExperimentStep", "RolloutExperimentStep", 1) + `,`, `Analysis:` + strings.Replace(this.Analysis.String(), "RolloutAnalysis", "RolloutAnalysis", 1) + `,`, `SetCanaryScale:` + strings.Replace(this.SetCanaryScale.String(), "SetCanaryScale", "SetCanaryScale", 1) + `,`, - `SetHeaderRouting:` + strings.Replace(this.SetHeaderRouting.String(), "SetHeaderRouting", "SetHeaderRouting", 1) + `,`, + `SetHeaderRoute:` + strings.Replace(this.SetHeaderRoute.String(), "SetHeaderRoute", "SetHeaderRoute", 1) + `,`, + `SetMirrorRoute:` + strings.Replace(this.SetMirrorRoute.String(), "SetMirrorRoute", "SetMirrorRoute", 1) + `,`, `}`, }, "") return s @@ -11726,7 +12082,7 @@ func (this *HeaderRoutingMatch) String() string { } s := strings.Join([]string{`&HeaderRoutingMatch{`, `HeaderName:` + fmt.Sprintf("%v", this.HeaderName) + `,`, - `HeaderValue:` + strings.Replace(strings.Replace(this.HeaderValue.String(), "StringMatch", "StringMatch", 1), `&`, ``, 1) + `,`, + `HeaderValue:` + strings.Replace(this.HeaderValue.String(), "StringMatch", "StringMatch", 1) + `,`, `}`, }, "") return s @@ -11844,6 +12200,16 @@ func (this *KayentaThreshold) String() string { }, "") return s } +func (this *MangedRoutes) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&MangedRoutes{`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `}`, + }, "") + return s +} func (this *Measurement) String() string { if this == nil { return "nil" @@ -12339,6 +12705,11 @@ func (this *RolloutTrafficRouting) String() string { if this == nil { return "nil" } + repeatedStringForManagedRoutes := "[]MangedRoutes{" + for _, f := range this.ManagedRoutes { + repeatedStringForManagedRoutes += strings.Replace(strings.Replace(f.String(), "MangedRoutes", "MangedRoutes", 1), `&`, ``, 1) + "," + } + repeatedStringForManagedRoutes += "}" s := strings.Join([]string{`&RolloutTrafficRouting{`, `Istio:` + strings.Replace(this.Istio.String(), "IstioTrafficRouting", "IstioTrafficRouting", 1) + `,`, `Nginx:` + strings.Replace(this.Nginx.String(), "NginxTrafficRouting", "NginxTrafficRouting", 1) + `,`, @@ -12347,6 +12718,29 @@ func (this *RolloutTrafficRouting) String() string { `Ambassador:` + strings.Replace(this.Ambassador.String(), "AmbassadorTrafficRouting", "AmbassadorTrafficRouting", 1) + `,`, `AppMesh:` + strings.Replace(this.AppMesh.String(), "AppMeshTrafficRouting", "AppMeshTrafficRouting", 1) + `,`, `Traefik:` + strings.Replace(this.Traefik.String(), "TraefikTrafficRouting", "TraefikTrafficRouting", 1) + `,`, + `ManagedRoutes:` + repeatedStringForManagedRoutes + `,`, + `}`, + }, "") + return s +} +func (this *RouteMatch) String() string { + if this == nil { + return "nil" + } + keysForHeaders := make([]string, 0, len(this.Headers)) + for k := range this.Headers { + keysForHeaders = append(keysForHeaders, k) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForHeaders) + mapStringForHeaders := "map[string]StringMatch{" + for _, k := range keysForHeaders { + mapStringForHeaders += fmt.Sprintf("%v: %v,", k, this.Headers[k]) + } + mapStringForHeaders += "}" + s := strings.Join([]string{`&RouteMatch{`, + `Method:` + strings.Replace(this.Method.String(), "StringMatch", "StringMatch", 1) + `,`, + `Path:` + strings.Replace(this.Path.String(), "StringMatch", "StringMatch", 1) + `,`, + `Headers:` + mapStringForHeaders + `,`, `}`, }, "") return s @@ -12413,7 +12807,7 @@ func (this *SetCanaryScale) String() string { }, "") return s } -func (this *SetHeaderRouting) String() string { +func (this *SetHeaderRoute) String() string { if this == nil { return "nil" } @@ -12422,8 +12816,26 @@ func (this *SetHeaderRouting) String() string { repeatedStringForMatch += strings.Replace(strings.Replace(f.String(), "HeaderRoutingMatch", "HeaderRoutingMatch", 1), `&`, ``, 1) + "," } repeatedStringForMatch += "}" - s := strings.Join([]string{`&SetHeaderRouting{`, + s := strings.Join([]string{`&SetHeaderRoute{`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `Match:` + repeatedStringForMatch + `,`, + `}`, + }, "") + return s +} +func (this *SetMirrorRoute) String() string { + if this == nil { + return "nil" + } + repeatedStringForMatch := "[]RouteMatch{" + for _, f := range this.Match { + repeatedStringForMatch += strings.Replace(strings.Replace(f.String(), "RouteMatch", "RouteMatch", 1), `&`, ``, 1) + "," + } + repeatedStringForMatch += "}" + s := strings.Join([]string{`&SetMirrorRoute{`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, `Match:` + repeatedStringForMatch + `,`, + `Percentage:` + valueToStringGenerated(this.Percentage) + `,`, `}`, }, "") return s @@ -16443,7 +16855,43 @@ func (m *CanaryStep) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 6: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SetHeaderRouting", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field SetHeaderRoute", 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.SetHeaderRoute == nil { + m.SetHeaderRoute = &SetHeaderRoute{} + } + if err := m.SetHeaderRoute.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SetMirrorRoute", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -16470,10 +16918,10 @@ func (m *CanaryStep) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.SetHeaderRouting == nil { - m.SetHeaderRouting = &SetHeaderRouting{} + if m.SetMirrorRoute == nil { + m.SetMirrorRoute = &SetMirrorRoute{} } - if err := m.SetHeaderRouting.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.SetMirrorRoute.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -19935,6 +20383,9 @@ func (m *HeaderRoutingMatch) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } + if m.HeaderValue == nil { + m.HeaderValue = &StringMatch{} + } if err := m.HeaderValue.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -21185,7 +21636,7 @@ func (m *KayentaThreshold) Unmarshal(dAtA []byte) error { } return nil } -func (m *Measurement) Unmarshal(dAtA []byte) error { +func (m *MangedRoutes) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -21208,15 +21659,15 @@ func (m *Measurement) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: Measurement: wiretype end group for non-group") + return fmt.Errorf("proto: MangedRoutes: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: Measurement: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MangedRoutes: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Phase", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -21244,14 +21695,96 @@ func (m *Measurement) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Phase = AnalysisPhase(dAtA[iNdEx:postIndex]) + m.Name = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Message", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Measurement) 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: Measurement: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Measurement: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Phase", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Phase = AnalysisPhase(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Message", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated } @@ -27391,6 +27924,291 @@ func (m *RolloutTrafficRouting) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ManagedRoutes", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ManagedRoutes = append(m.ManagedRoutes, MangedRoutes{}) + if err := m.ManagedRoutes[len(m.ManagedRoutes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RouteMatch) 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: RouteMatch: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RouteMatch: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Method", 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.Method == nil { + m.Method = &StringMatch{} + } + if err := m.Method.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Path", 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.Path == nil { + m.Path = &StringMatch{} + } + if err := m.Path.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Headers", 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.Headers == nil { + m.Headers = make(map[string]StringMatch) + } + var mapkey string + mapvalue := &StringMatch{} + for iNdEx < postIndex { + entryPreIndex := 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) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthGenerated + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthGenerated + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var mapmsglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + mapmsglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if mapmsglen < 0 { + return ErrInvalidLengthGenerated + } + postmsgIndex := iNdEx + mapmsglen + if postmsgIndex < 0 { + return ErrInvalidLengthGenerated + } + if postmsgIndex > l { + return io.ErrUnexpectedEOF + } + mapvalue = &StringMatch{} + if err := mapvalue.Unmarshal(dAtA[iNdEx:postmsgIndex]); err != nil { + return err + } + iNdEx = postmsgIndex + } else { + iNdEx = entryPreIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Headers[mapkey] = *mapvalue + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -28092,7 +28910,7 @@ func (m *SetCanaryScale) Unmarshal(dAtA []byte) error { } return nil } -func (m *SetHeaderRouting) Unmarshal(dAtA []byte) error { +func (m *SetHeaderRoute) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -28115,13 +28933,45 @@ func (m *SetHeaderRouting) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: SetHeaderRouting: wiretype end group for non-group") + return fmt.Errorf("proto: SetHeaderRoute: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: SetHeaderRouting: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: SetHeaderRoute: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Match", wireType) } @@ -28176,6 +29026,142 @@ func (m *SetHeaderRouting) Unmarshal(dAtA []byte) error { } return nil } +func (m *SetMirrorRoute) 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: SetMirrorRoute: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SetMirrorRoute: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Match", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Match = append(m.Match, RouteMatch{}) + if err := m.Match[len(m.Match)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Percentage", 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.Percentage = &v + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *StickinessConfig) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/pkg/apis/rollouts/v1alpha1/generated.proto b/pkg/apis/rollouts/v1alpha1/generated.proto index fe49259724..7194886619 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.proto +++ b/pkg/apis/rollouts/v1alpha1/generated.proto @@ -403,8 +403,13 @@ message CanaryStep { // +optional optional SetCanaryScale setCanaryScale = 5; - // SetHeaderRouting defines the route with specified header name to send 100% of traffic to the canary service - optional SetHeaderRouting setHeaderRouting = 6; + // SetHeaderRoute defines the route with specified header name to send 100% of traffic to the canary service + // +optional + optional SetHeaderRoute setHeaderRoute = 6; + + // SetMirrorRoutes Mirrors traffic that matches rules to a particular destination + // +optional + optional SetMirrorRoute setMirrorRoute = 8; } // CanaryStrategy defines parameters for a Replica Based Canary @@ -833,6 +838,10 @@ message KayentaThreshold { optional int64 marginal = 2; } +message MangedRoutes { + optional string name = 1; +} + // Measurement is a point in time result value of a single metric, and the time it was measured message Measurement { // Phase is the status of this single measurement @@ -1424,6 +1433,24 @@ message RolloutTrafficRouting { // Traefik holds specific configuration to use Traefik to route traffic optional TraefikTrafficRouting traefik = 7; + + // A list of HTTP routes that Argo Rollouts manages, the order of this array also becomes the precedence in the upstream + // traffic router. + repeated MangedRoutes managedRoutes = 8; +} + +message RouteMatch { + // Method What http methods should be mirrored + // +optional + optional StringMatch method = 1; + + // Path What url paths should be mirrored + // +optional + optional StringMatch path = 2; + + // Headers What request with matching headers should be mirrored + // +optional + map headers = 3; } // RunSummary contains the final results from the metric executions @@ -1490,9 +1517,28 @@ message SetCanaryScale { optional bool matchTrafficWeight = 3; } -// SetHeaderRouting defines the route with specified header name to send 100% of traffic to the canary service -message SetHeaderRouting { - repeated HeaderRoutingMatch match = 1; +// SetHeaderRoute defines the route with specified header name to send 100% of traffic to the canary service +message SetHeaderRoute { + // Name this is the name of the route to use for the mirroring of traffic this also needs + // to be included in the `spec.strategy.canary.trafficRouting.managedRoutes` field + optional string name = 1; + + repeated HeaderRoutingMatch match = 2; +} + +message SetMirrorRoute { + // Name this is the name of the route to use for the mirroring of traffic this also needs + // to be included in the `spec.strategy.canary.trafficRouting.managedRoutes` field + optional string name = 1; + + // Match Contains a list of rules that if mated will mirror the traffic to the services + // +optional + repeated RouteMatch match = 2; + + // Services The list of services to mirror the traffic to if the method, path, headers match + // Service string `json:"service" protobuf:"bytes,3,opt,name=service"` + // Percentage What percent of the traffic that matched the rules should be mirrored + optional int32 percentage = 4; } message StickinessConfig { diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index 3572f2f360..fa929300aa 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -82,6 +82,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.KayentaMetric": schema_pkg_apis_rollouts_v1alpha1_KayentaMetric(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.KayentaScope": schema_pkg_apis_rollouts_v1alpha1_KayentaScope(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.KayentaThreshold": schema_pkg_apis_rollouts_v1alpha1_KayentaThreshold(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.MangedRoutes": schema_pkg_apis_rollouts_v1alpha1_MangedRoutes(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Measurement": schema_pkg_apis_rollouts_v1alpha1_Measurement(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.MeasurementRetention": schema_pkg_apis_rollouts_v1alpha1_MeasurementRetention(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.Metric": schema_pkg_apis_rollouts_v1alpha1_Metric(ref), @@ -111,12 +112,14 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutStatus": schema_pkg_apis_rollouts_v1alpha1_RolloutStatus(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutStrategy": schema_pkg_apis_rollouts_v1alpha1_RolloutStrategy(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutTrafficRouting": schema_pkg_apis_rollouts_v1alpha1_RolloutTrafficRouting(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RouteMatch": schema_pkg_apis_rollouts_v1alpha1_RouteMatch(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RunSummary": schema_pkg_apis_rollouts_v1alpha1_RunSummary(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SMITrafficRouting": schema_pkg_apis_rollouts_v1alpha1_SMITrafficRouting(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ScopeDetail": schema_pkg_apis_rollouts_v1alpha1_ScopeDetail(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SecretKeyRef": schema_pkg_apis_rollouts_v1alpha1_SecretKeyRef(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetCanaryScale": schema_pkg_apis_rollouts_v1alpha1_SetCanaryScale(ref), - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetHeaderRouting": schema_pkg_apis_rollouts_v1alpha1_SetHeaderRouting(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetHeaderRoute": schema_pkg_apis_rollouts_v1alpha1_SetHeaderRoute(ref), + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetMirrorRoute": schema_pkg_apis_rollouts_v1alpha1_SetMirrorRoute(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.StickinessConfig": schema_pkg_apis_rollouts_v1alpha1_StickinessConfig(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.StringMatch": schema_pkg_apis_rollouts_v1alpha1_StringMatch(ref), "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TLSRoute": schema_pkg_apis_rollouts_v1alpha1_TLSRoute(ref), @@ -1234,17 +1237,23 @@ func schema_pkg_apis_rollouts_v1alpha1_CanaryStep(ref common.ReferenceCallback) Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetCanaryScale"), }, }, - "setHeaderRouting": { + "setHeaderRoute": { SchemaProps: spec.SchemaProps{ - Description: "SetHeaderRouting defines the route with specified header name to send 100% of traffic to the canary service", - Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetHeaderRouting"), + Description: "SetHeaderRoute defines the route with specified header name to send 100% of traffic to the canary service", + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetHeaderRoute"), + }, + }, + "setMirrorRoute": { + SchemaProps: spec.SchemaProps{ + Description: "SetMirrorRoutes Mirrors traffic that matches rules to a particular destination", + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetMirrorRoute"), }, }, }, }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutAnalysis", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutExperimentStep", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutPause", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetCanaryScale", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetHeaderRouting"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutAnalysis", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutExperimentStep", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RolloutPause", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetCanaryScale", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetHeaderRoute", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SetMirrorRoute"}, } } @@ -2225,7 +2234,6 @@ func schema_pkg_apis_rollouts_v1alpha1_HeaderRoutingMatch(ref common.ReferenceCa "headerValue": { SchemaProps: spec.SchemaProps{ Description: "HeaderValue the value of the header", - Default: map[string]interface{}{}, Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.StringMatch"), }, }, @@ -2562,6 +2570,26 @@ func schema_pkg_apis_rollouts_v1alpha1_KayentaThreshold(ref common.ReferenceCall } } +func schema_pkg_apis_rollouts_v1alpha1_MangedRoutes(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"name"}, + }, + }, + } +} + func schema_pkg_apis_rollouts_v1alpha1_Measurement(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -4193,11 +4221,66 @@ func schema_pkg_apis_rollouts_v1alpha1_RolloutTrafficRouting(ref common.Referenc Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TraefikTrafficRouting"), }, }, + "managedRoutes": { + SchemaProps: spec.SchemaProps{ + Description: "A list of HTTP routes that Argo Rollouts manages, the order of this array also becomes the precedence in the upstream traffic router.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.MangedRoutes"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ALBTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AmbassadorTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AppMeshTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.IstioTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.MangedRoutes", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.NginxTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SMITrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TraefikTrafficRouting"}, + } +} + +func schema_pkg_apis_rollouts_v1alpha1_RouteMatch(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "method": { + SchemaProps: spec.SchemaProps{ + Description: "Method What http methods should be mirrored", + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.StringMatch"), + }, + }, + "path": { + SchemaProps: spec.SchemaProps{ + Description: "Path What url paths should be mirrored", + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.StringMatch"), + }, + }, + "headers": { + SchemaProps: spec.SchemaProps{ + Description: "Headers What request with matching headers should be mirrored", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.StringMatch"), + }, + }, + }, + }, + }, }, }, }, Dependencies: []string{ - "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ALBTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AmbassadorTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AppMeshTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.IstioTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.NginxTrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.SMITrafficRouting", "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.TraefikTrafficRouting"}, + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.StringMatch"}, } } @@ -4387,13 +4470,20 @@ func schema_pkg_apis_rollouts_v1alpha1_SetCanaryScale(ref common.ReferenceCallba } } -func schema_pkg_apis_rollouts_v1alpha1_SetHeaderRouting(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_pkg_apis_rollouts_v1alpha1_SetHeaderRoute(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "SetHeaderRouting defines the route with specified header name to send 100% of traffic to the canary service", + Description: "SetHeaderRoute defines the route with specified header name to send 100% of traffic to the canary service", Type: []string{"object"}, Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "Name this is the name of the route to use for the mirroring of traffic this also needs to be included in the `spec.strategy.canary.trafficRouting.managedRoutes` field", + Type: []string{"string"}, + Format: "", + }, + }, "match": { SchemaProps: spec.SchemaProps{ Type: []string{"array"}, @@ -4415,6 +4505,50 @@ func schema_pkg_apis_rollouts_v1alpha1_SetHeaderRouting(ref common.ReferenceCall } } +func schema_pkg_apis_rollouts_v1alpha1_SetMirrorRoute(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "Name this is the name of the route to use for the mirroring of traffic this also needs to be included in the `spec.strategy.canary.trafficRouting.managedRoutes` field", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "match": { + SchemaProps: spec.SchemaProps{ + Description: "Match Contains a list of rules that if mated will mirror the traffic to the services", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RouteMatch"), + }, + }, + }, + }, + }, + "percentage": { + SchemaProps: spec.SchemaProps{ + Description: "Services The list of services to mirror the traffic to if the method, path, headers match Service string `json:\"service\" protobuf:\"bytes,3,opt,name=service\"` Percentage What percent of the traffic that matched the rules should be mirrored", + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + Required: []string{"name"}, + }, + }, + Dependencies: []string{ + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.RouteMatch"}, + } +} + func schema_pkg_apis_rollouts_v1alpha1_StickinessConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/pkg/apis/rollouts/v1alpha1/types.go b/pkg/apis/rollouts/v1alpha1/types.go index 04d45fddcd..d83a23d639 100644 --- a/pkg/apis/rollouts/v1alpha1/types.go +++ b/pkg/apis/rollouts/v1alpha1/types.go @@ -363,6 +363,15 @@ type RolloutTrafficRouting struct { AppMesh *AppMeshTrafficRouting `json:"appMesh,omitempty" protobuf:"bytes,6,opt,name=appMesh"` // Traefik holds specific configuration to use Traefik to route traffic Traefik *TraefikTrafficRouting `json:"traefik,omitempty" protobuf:"bytes,7,opt,name=traefik"` + // A list of HTTP routes that Argo Rollouts manages, the order of this array also becomes the precedence in the upstream + // traffic router. + ManagedRoutes []MangedRoutes `json:"managedRoutes,omitempty" protobuf:"bytes,8,rep,name=managedRoutes"` +} + +type MangedRoutes struct { + Name string `json:"name" protobuf:"bytes,1,opt,name=name"` + //Possibly name for future use + //canaryRoute bool } // TraefikTrafficRouting defines the configuration required to use Traefik as traffic router @@ -554,20 +563,38 @@ type CanaryStep struct { // SetCanaryScale defines how to scale the newRS without changing traffic weight // +optional SetCanaryScale *SetCanaryScale `json:"setCanaryScale,omitempty" protobuf:"bytes,5,opt,name=setCanaryScale"` - // SetHeaderRouting defines the route with specified header name to send 100% of traffic to the canary service - SetHeaderRouting *SetHeaderRouting `json:"setHeaderRouting,omitempty" protobuf:"bytes,6,opt,name=setHeaderRouting"` + // SetHeaderRoute defines the route with specified header name to send 100% of traffic to the canary service + // +optional + SetHeaderRoute *SetHeaderRoute `json:"setHeaderRoute,omitempty" protobuf:"bytes,6,opt,name=setHeaderRoute"` + // SetMirrorRoutes Mirrors traffic that matches rules to a particular destination + // +optional + SetMirrorRoute *SetMirrorRoute `json:"setMirrorRoute,omitempty" protobuf:"bytes,8,opt,name=setMirrorRoute"` } -// SetHeaderRouting defines the route with specified header name to send 100% of traffic to the canary service -type SetHeaderRouting struct { - Match []HeaderRoutingMatch `json:"match,omitempty" protobuf:"bytes,1,rep,name=match"` +type SetMirrorRoute struct { + // Name this is the name of the route to use for the mirroring of traffic this also needs + // to be included in the `spec.strategy.canary.trafficRouting.managedRoutes` field + Name string `json:"name" protobuf:"bytes,1,opt,name=name"` + // Match Contains a list of rules that if mated will mirror the traffic to the services + // +optional + Match []RouteMatch `json:"match,omitempty" protobuf:"bytes,2,opt,name=match"` + + // Services The list of services to mirror the traffic to if the method, path, headers match + //Service string `json:"service" protobuf:"bytes,3,opt,name=service"` + // Percentage What percent of the traffic that matched the rules should be mirrored + Percentage *int32 `json:"percentage,omitempty" protobuf:"varint,4,opt,name=percentage"` } -type HeaderRoutingMatch struct { - // HeaderName the name of the request header - HeaderName string `json:"headerName" protobuf:"bytes,1,opt,name=headerName"` - // HeaderValue the value of the header - HeaderValue StringMatch `json:"headerValue" protobuf:"bytes,2,opt,name=headerValue"` +type RouteMatch struct { + // Method What http methods should be mirrored + // +optional + Method *StringMatch `json:"method,omitempty" protobuf:"bytes,1,opt,name=method"` + // Path What url paths should be mirrored + // +optional + Path *StringMatch `json:"path,omitempty" protobuf:"bytes,2,opt,name=path"` + // Headers What request with matching headers should be mirrored + // +optional + Headers map[string]StringMatch `json:"headers,omitempty" protobuf:"bytes,3,opt,name=headers"` } // StringMatch Used to define what type of matching we will use exact, prefix, or regular expression @@ -580,6 +607,21 @@ type StringMatch struct { Regex string `json:"regex,omitempty" protobuf:"bytes,3,opt,name=regex"` } +// SetHeaderRoute defines the route with specified header name to send 100% of traffic to the canary service +type SetHeaderRoute struct { + // Name this is the name of the route to use for the mirroring of traffic this also needs + // to be included in the `spec.strategy.canary.trafficRouting.managedRoutes` field + Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"` + Match []HeaderRoutingMatch `json:"match,omitempty" protobuf:"bytes,2,rep,name=match"` +} + +type HeaderRoutingMatch struct { + // HeaderName the name of the request header + HeaderName string `json:"headerName" protobuf:"bytes,1,opt,name=headerName"` + // HeaderValue the value of the header + HeaderValue *StringMatch `json:"headerValue" protobuf:"bytes,2,opt,name=headerValue"` +} + // SetCanaryScale defines how to scale the newRS without changing traffic weight type SetCanaryScale struct { // Weight sets the percentage of replicas the newRS should have diff --git a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go index e628726898..809e6e5c51 100644 --- a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go @@ -708,9 +708,14 @@ func (in *CanaryStep) DeepCopyInto(out *CanaryStep) { *out = new(SetCanaryScale) (*in).DeepCopyInto(*out) } - if in.SetHeaderRouting != nil { - in, out := &in.SetHeaderRouting, &out.SetHeaderRouting - *out = new(SetHeaderRouting) + if in.SetHeaderRoute != nil { + in, out := &in.SetHeaderRoute, &out.SetHeaderRoute + *out = new(SetHeaderRoute) + (*in).DeepCopyInto(*out) + } + if in.SetMirrorRoute != nil { + in, out := &in.SetMirrorRoute, &out.SetMirrorRoute + *out = new(SetMirrorRoute) (*in).DeepCopyInto(*out) } return @@ -1262,7 +1267,11 @@ func (in *GraphiteMetric) DeepCopy() *GraphiteMetric { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *HeaderRoutingMatch) DeepCopyInto(out *HeaderRoutingMatch) { *out = *in - out.HeaderValue = in.HeaderValue + if in.HeaderValue != nil { + in, out := &in.HeaderValue, &out.HeaderValue + *out = new(StringMatch) + **out = **in + } return } @@ -1443,6 +1452,22 @@ func (in *KayentaThreshold) DeepCopy() *KayentaThreshold { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MangedRoutes) DeepCopyInto(out *MangedRoutes) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MangedRoutes. +func (in *MangedRoutes) DeepCopy() *MangedRoutes { + if in == nil { + return nil + } + out := new(MangedRoutes) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Measurement) DeepCopyInto(out *Measurement) { *out = *in @@ -2241,6 +2266,11 @@ func (in *RolloutTrafficRouting) DeepCopyInto(out *RolloutTrafficRouting) { *out = new(TraefikTrafficRouting) **out = **in } + if in.ManagedRoutes != nil { + in, out := &in.ManagedRoutes, &out.ManagedRoutes + *out = make([]MangedRoutes, len(*in)) + copy(*out, *in) + } return } @@ -2254,6 +2284,39 @@ func (in *RolloutTrafficRouting) DeepCopy() *RolloutTrafficRouting { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RouteMatch) DeepCopyInto(out *RouteMatch) { + *out = *in + if in.Method != nil { + in, out := &in.Method, &out.Method + *out = new(StringMatch) + **out = **in + } + if in.Path != nil { + in, out := &in.Path, &out.Path + *out = new(StringMatch) + **out = **in + } + if in.Headers != nil { + in, out := &in.Headers, &out.Headers + *out = make(map[string]StringMatch, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RouteMatch. +func (in *RouteMatch) DeepCopy() *RouteMatch { + if in == nil { + return nil + } + out := new(RouteMatch) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RunSummary) DeepCopyInto(out *RunSummary) { *out = *in @@ -2345,22 +2408,52 @@ func (in *SetCanaryScale) DeepCopy() *SetCanaryScale { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SetHeaderRouting) DeepCopyInto(out *SetHeaderRouting) { +func (in *SetHeaderRoute) DeepCopyInto(out *SetHeaderRoute) { *out = *in if in.Match != nil { in, out := &in.Match, &out.Match *out = make([]HeaderRoutingMatch, len(*in)) - copy(*out, *in) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SetHeaderRoute. +func (in *SetHeaderRoute) DeepCopy() *SetHeaderRoute { + if in == nil { + return nil + } + out := new(SetHeaderRoute) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SetMirrorRoute) DeepCopyInto(out *SetMirrorRoute) { + *out = *in + if in.Match != nil { + in, out := &in.Match, &out.Match + *out = make([]RouteMatch, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Percentage != nil { + in, out := &in.Percentage, &out.Percentage + *out = new(int32) + **out = **in } return } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SetHeaderRouting. -func (in *SetHeaderRouting) DeepCopy() *SetHeaderRouting { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SetMirrorRoute. +func (in *SetMirrorRoute) DeepCopy() *SetMirrorRoute { if in == nil { return nil } - out := new(SetHeaderRouting) + out := new(SetMirrorRoute) in.DeepCopyInto(out) return out } diff --git a/pkg/apis/rollouts/validation/validation.go b/pkg/apis/rollouts/validation/validation.go index 15d10ea7c1..de07fa9581 100644 --- a/pkg/apis/rollouts/validation/validation.go +++ b/pkg/apis/rollouts/validation/validation.go @@ -34,11 +34,13 @@ const ( // InvalidSetCanaryScaleTrafficPolicy indicates that TrafficRouting, required for SetCanaryScale, is missing InvalidSetCanaryScaleTrafficPolicy = "SetCanaryScale requires TrafficRouting to be set" // InvalidSetHeaderRoutingTrafficPolicy indicates that TrafficRouting, required for SetCanaryScale, is missing - InvalidSetHeaderRoutingTrafficPolicy = "SetHeaderRouting requires TrafficRouting, supports Istio only" - // InvalidSetHeaderRoutingMultipleValuePolicy indicates that SetCanaryScale, has multiple values set - InvalidSetHeaderRoutingMultipleValuePolicy = "SetHeaderRouting match value must have one of the following: exact, regex, prefix" - // InvalidSetHeaderRoutingMissedValuePolicy indicates that SetCanaryScale, has multiple values set - InvalidSetHeaderRoutingMissedValuePolicy = "SetHeaderRouting value missed, match value must have one of the following: exact, regex, prefix" + InvalidSetHeaderRoutingTrafficPolicy = "SetHeaderRoute requires TrafficRouting, supports Istio only" + // InvalidSetMirrorRouteTrafficPolicy indicates that TrafficRouting, required for SetCanaryScale, is missing + InvalidSetMirrorRouteTrafficPolicy = "SetMirrorRoute requires TrafficRouting, supports Istio only" + // InvalidStringMatchMultipleValuePolicy indicates that SetCanaryScale, has multiple values set + InvalidStringMatchMultipleValuePolicy = "StringMatch match value must have exactly one of the following: exact, regex, prefix" + // InvalidStringMatchMissedValuePolicy indicates that SetCanaryScale, has multiple values set + InvalidStringMatchMissedValuePolicy = "StringMatch value missed, match value must have one of the following: exact, regex, prefix" // InvalidDurationMessage indicates the Duration value needs to be greater than 0 InvalidDurationMessage = "Duration needs to be greater than 0" // InvalidMaxSurgeMaxUnavailable indicates both maxSurge and MaxUnavailable can not be set to zero @@ -76,6 +78,11 @@ const ( MissedAlbRootServiceMessage = "Root service field is required for the configuration with ALB and ping-pong feature enabled" // PingPongWithAlbOnlyMessage At this moment ping-pong feature works with the ALB traffic routing only PingPongWithAlbOnlyMessage = "Ping-pong feature works with the ALB traffic routing only" + // InvalidStepMissingManagedRoutesField We have a step configured that requires managedRoutes to be configured which is not. + InvalidStepMissingManagedRoutesField = "Step requires spec.strategy.canary.trafficRouting.managedRoutes to be configured" + // InvalideStepRouteNameNotFoundInManagedRoutes A step has been configured that requires managedRoutes and the route name + // is missing from managedRoutes + InvalideStepRouteNameNotFoundInManagedRoutes = "Steps define a route that does not exist in spec.strategy.canary.trafficRouting.managedRoutes" ) // allowAllPodValidationOptions allows all pod options to be true for the purposes of rollout pod @@ -280,9 +287,10 @@ func ValidateRolloutStrategyCanary(rollout *v1alpha1.Rollout, fldPath *field.Pat for i, step := range canary.Steps { stepFldPath := fldPath.Child("steps").Index(i) allErrs = append(allErrs, hasMultipleStepsType(step, stepFldPath)...) - if step.Experiment == nil && step.Pause == nil && step.SetWeight == nil && step.Analysis == nil && step.SetCanaryScale == nil && step.SetHeaderRouting == nil { - errVal := fmt.Sprintf("step.Experiment: %t step.Pause: %t step.SetWeight: %t step.Analysis: %t step.SetCanaryScale: %t step.SetHeaderRouting: %t", - step.Experiment == nil, step.Pause == nil, step.SetWeight == nil, step.Analysis == nil, step.SetCanaryScale == nil, step.SetHeaderRouting == nil) + if step.Experiment == nil && step.Pause == nil && step.SetWeight == nil && step.Analysis == nil && step.SetCanaryScale == nil && + step.SetHeaderRoute == nil && step.SetMirrorRoute == nil { + errVal := fmt.Sprintf("step.Experiment: %t step.Pause: %t step.SetWeight: %t step.Analysis: %t step.SetCanaryScale: %t step.SetHeaderRoute: %t step.SetMirrorRoutes: %t", + step.Experiment == nil, step.Pause == nil, step.SetWeight == nil, step.Analysis == nil, step.SetCanaryScale == nil, step.SetHeaderRoute == nil, step.SetMirrorRoute == nil) allErrs = append(allErrs, field.Invalid(stepFldPath, errVal, InvalidStepMessage)) } if step.SetWeight != nil && (*step.SetWeight < 0 || *step.SetWeight > 100) { @@ -294,19 +302,57 @@ func ValidateRolloutStrategyCanary(rollout *v1alpha1.Rollout, fldPath *field.Pat if step.SetCanaryScale != nil && canary.TrafficRouting == nil { allErrs = append(allErrs, field.Required(fldPath.Child("trafficRouting"), InvalidSetCanaryScaleTrafficPolicy)) } - if step.SetHeaderRouting != nil { + + if step.SetHeaderRoute != nil { trafficRouting := rollout.Spec.Strategy.Canary.TrafficRouting if trafficRouting == nil || trafficRouting.Istio == nil { - allErrs = append(allErrs, field.Invalid(stepFldPath.Child("setHeaderRouting"), step.SetHeaderRouting, InvalidSetHeaderRoutingTrafficPolicy)) + allErrs = append(allErrs, field.Invalid(stepFldPath.Child("setHeaderRoute"), step.SetHeaderRoute, InvalidSetHeaderRoutingTrafficPolicy)) } - if step.SetHeaderRouting.Match != nil && len(step.SetHeaderRouting.Match) > 0 { - for j, match := range step.SetHeaderRouting.Match { - matchFld := stepFldPath.Child("setHeaderRouting").Child("match").Index(j) + if step.SetHeaderRoute.Match != nil && len(step.SetHeaderRoute.Match) > 0 { + for j, match := range step.SetHeaderRoute.Match { + matchFld := stepFldPath.Child("setHeaderRoute").Child("match").Index(j) allErrs = append(allErrs, hasMultipleMatchValues(match.HeaderValue, matchFld)...) } } } + if step.SetMirrorRoute != nil { + trafficRouting := rollout.Spec.Strategy.Canary.TrafficRouting + if trafficRouting == nil || trafficRouting.Istio == nil { + allErrs = append(allErrs, field.Invalid(stepFldPath.Child("setMirrorRoute"), step.SetMirrorRoute, "SetMirrorRoute requires TrafficRouting, supports Istio only")) + } + if step.SetMirrorRoute.Match != nil && len(step.SetMirrorRoute.Match) > 0 { + for j, match := range step.SetMirrorRoute.Match { + matchFld := stepFldPath.Child("setMirrorRoute").Child("match").Index(j) + if match.Method != nil { + allErrs = append(allErrs, hasMultipleMatchValues(match.Method, matchFld)...) + } + if match.Path != nil { + allErrs = append(allErrs, hasMultipleMatchValues(match.Path, matchFld)...) + } + if match.Method != nil { + allErrs = append(allErrs, hasMultipleMatchValues(match.Method, matchFld)...) + } + } + } + } + + if rollout.Spec.Strategy.Canary.TrafficRouting != nil { + if step.SetHeaderRoute != nil || step.SetMirrorRoute != nil { + if rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes == nil { + allErrs = append(allErrs, field.Invalid(stepFldPath, step, InvalidStepMissingManagedRoutesField)) + } + } + } + if rollout.Spec.Strategy.Canary.TrafficRouting != nil && rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes != nil { + if step.SetHeaderRoute != nil { + allErrs = append(allErrs, ValidateStepRouteFoundInManagedRoute(stepFldPath.Child("setHeaderRoute"), step.SetHeaderRoute.Name, rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes)...) + } + if step.SetMirrorRoute != nil { + allErrs = append(allErrs, ValidateStepRouteFoundInManagedRoute(stepFldPath.Child("setMirrorRoute"), step.SetMirrorRoute.Name, rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes)...) + } + } + analysisRunArgs := make([]v1alpha1.AnalysisRunArgument, 0) if step.Experiment != nil { for tmplIndex, template := range step.Experiment.Templates { @@ -346,6 +392,20 @@ func ValidateRolloutStrategyCanary(rollout *v1alpha1.Rollout, fldPath *field.Pat return allErrs } +func ValidateStepRouteFoundInManagedRoute(stepFldPath *field.Path, stepRoutName string, roManagedRoutes []v1alpha1.MangedRoutes) field.ErrorList { + allErrs := field.ErrorList{} + found := false + for _, managedRoute := range roManagedRoutes { + if stepRoutName == managedRoute.Name { + found = true + } + } + if !found { + allErrs = append(allErrs, field.Invalid(stepFldPath, stepRoutName, InvalideStepRouteNameNotFoundInManagedRoutes)) + } + return allErrs +} + func ValidateRolloutStrategyAntiAffinity(antiAffinity *v1alpha1.AntiAffinity, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if antiAffinity != nil { @@ -413,9 +473,16 @@ func hasMultipleStepsType(s v1alpha1.CanaryStep, fldPath *field.Path) field.Erro return allErrs } -func hasMultipleMatchValues(match v1alpha1.StringMatch, fldPath *field.Path) field.ErrorList { +func hasMultipleMatchValues(match *v1alpha1.StringMatch, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} - oneOf := make([]bool, 3) + + if match == nil { + e := field.Invalid(fldPath, match, InvalidStringMatchMissedValuePolicy) + allErrs = append(allErrs, e) + return allErrs + } + + var oneOf []bool oneOf = append(oneOf, match.Exact != "") oneOf = append(oneOf, match.Regex != "") oneOf = append(oneOf, match.Prefix != "") @@ -423,7 +490,7 @@ func hasMultipleMatchValues(match v1alpha1.StringMatch, fldPath *field.Path) fie for i := range oneOf { if oneOf[i] { if hasValue { - e := field.Invalid(fldPath, match, InvalidSetHeaderRoutingMultipleValuePolicy) + e := field.Invalid(fldPath, match, InvalidStringMatchMultipleValuePolicy) allErrs = append(allErrs, e) break } @@ -431,7 +498,7 @@ func hasMultipleMatchValues(match v1alpha1.StringMatch, fldPath *field.Path) fie } } if !hasValue { - e := field.Invalid(fldPath, match, InvalidSetHeaderRoutingMissedValuePolicy) + e := field.Invalid(fldPath, match, InvalidStringMatchMissedValuePolicy) allErrs = append(allErrs, e) } return allErrs diff --git a/pkg/apis/rollouts/validation/validation_test.go b/pkg/apis/rollouts/validation/validation_test.go index fead009023..8888ac29ac 100644 --- a/pkg/apis/rollouts/validation/validation_test.go +++ b/pkg/apis/rollouts/validation/validation_test.go @@ -281,7 +281,7 @@ func TestValidateRolloutStrategyAntiAffinity(t *testing.T) { assert.Equal(t, InvalidAntiAffinityWeightMessage, allErrs[0].Detail) } -func TestValidateRolloutStrategyCanary_SetHeaderRoutingIstio(t *testing.T) { +func TestValidateRolloutStrategyCanarySetHeaderRouteIstio(t *testing.T) { ro := &v1alpha1.Rollout{} ro.Spec.Strategy.Canary = &v1alpha1.CanaryStrategy{ CanaryService: "canary", @@ -293,15 +293,15 @@ func TestValidateRolloutStrategyCanary_SetHeaderRoutingIstio(t *testing.T) { }, } - t.Run("using SetHeaderRouting step without the traffic routing", func(t *testing.T) { + t.Run("using SetHeaderRoute step without the traffic routing", func(t *testing.T) { invalidRo := ro.DeepCopy() invalidRo.Spec.Strategy.Canary.TrafficRouting = nil invalidRo.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{ - SetHeaderRouting: &v1alpha1.SetHeaderRouting{ + SetHeaderRoute: &v1alpha1.SetHeaderRoute{ Match: []v1alpha1.HeaderRoutingMatch{ { HeaderName: "agent", - HeaderValue: v1alpha1.StringMatch{Exact: "chrome"}, + HeaderValue: &v1alpha1.StringMatch{Exact: "chrome"}, }, }, }, @@ -310,14 +310,14 @@ func TestValidateRolloutStrategyCanary_SetHeaderRoutingIstio(t *testing.T) { assert.Equal(t, InvalidSetHeaderRoutingTrafficPolicy, allErrs[0].Detail) }) - t.Run("using SetHeaderRouting step with multiple values", func(t *testing.T) { + t.Run("using SetHeaderRoute step with multiple values", func(t *testing.T) { invalidRo := ro.DeepCopy() invalidRo.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{ - SetHeaderRouting: &v1alpha1.SetHeaderRouting{ + SetHeaderRoute: &v1alpha1.SetHeaderRoute{ Match: []v1alpha1.HeaderRoutingMatch{ { HeaderName: "agent", - HeaderValue: v1alpha1.StringMatch{ + HeaderValue: &v1alpha1.StringMatch{ Exact: "chrome", Regex: "chrome(.*)", }, @@ -326,13 +326,13 @@ func TestValidateRolloutStrategyCanary_SetHeaderRoutingIstio(t *testing.T) { }, }} allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) - assert.Equal(t, InvalidSetHeaderRoutingMultipleValuePolicy, allErrs[0].Detail) + assert.Equal(t, InvalidStringMatchMultipleValuePolicy, allErrs[0].Detail) }) - t.Run("using SetHeaderRouting step with missed values", func(t *testing.T) { + t.Run("using SetHeaderRoute step with missed values", func(t *testing.T) { invalidRo := ro.DeepCopy() invalidRo.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{ - SetHeaderRouting: &v1alpha1.SetHeaderRouting{ + SetHeaderRoute: &v1alpha1.SetHeaderRoute{ Match: []v1alpha1.HeaderRoutingMatch{ { HeaderName: "agent", @@ -341,7 +341,153 @@ func TestValidateRolloutStrategyCanary_SetHeaderRoutingIstio(t *testing.T) { }, }} allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) - assert.Equal(t, InvalidSetHeaderRoutingMissedValuePolicy, allErrs[0].Detail) + assert.Equal(t, InvalidStringMatchMissedValuePolicy, allErrs[0].Detail) + }) + + t.Run("using SetHeaderRoute step without managedRoutes defined but missing route", func(t *testing.T) { + invalidRo := ro.DeepCopy() + invalidRo.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{ + SetHeaderRoute: &v1alpha1.SetHeaderRoute{ + Match: []v1alpha1.HeaderRoutingMatch{ + { + HeaderName: "agent", + HeaderValue: &v1alpha1.StringMatch{Exact: "exact"}, + }, + }, + }, + }} + invalidRo.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes = append(invalidRo.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes, v1alpha1.MangedRoutes{ + Name: "not-in-steps", + }) + allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) + assert.Equal(t, InvalideStepRouteNameNotFoundInManagedRoutes, allErrs[0].Detail) + }) +} + +func TestValidateRolloutStrategyCanarySetMirrorRouteIstio(t *testing.T) { + ro := &v1alpha1.Rollout{} + ro.Spec.Strategy.Canary = &v1alpha1.CanaryStrategy{ + CanaryService: "canary", + StableService: "stable", + TrafficRouting: &v1alpha1.RolloutTrafficRouting{ + Istio: &v1alpha1.IstioTrafficRouting{ + VirtualService: &v1alpha1.IstioVirtualService{Name: "virtual-service"}, + }, + }, + } + + t.Run("using SetMirrorRoute step without the traffic routing", func(t *testing.T) { + invalidRo := ro.DeepCopy() + invalidRo.Spec.Strategy.Canary.TrafficRouting = nil + invalidRo.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{ + SetMirrorRoute: &v1alpha1.SetMirrorRoute{ + Name: "test-mirror-1", + Match: nil, + Percentage: nil, + }, + }} + allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) + assert.Equal(t, InvalidSetMirrorRouteTrafficPolicy, allErrs[0].Detail) + }) + + t.Run("using SetMirrorRoute step with multiple values", func(t *testing.T) { + invalidRo := ro.DeepCopy() + invalidRo.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{ + SetMirrorRoute: &v1alpha1.SetMirrorRoute{ + Name: "test-mirror-1", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{ + Exact: "test", + Prefix: "test", + }, + Path: nil, + Headers: nil, + }}, + Percentage: nil, + }, + }} + allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) + assert.Equal(t, InvalidStringMatchMultipleValuePolicy, allErrs[0].Detail) + }) + + t.Run("using SetMirrorRoute step with missed match and no kind", func(t *testing.T) { + invalidRo := ro.DeepCopy() + invalidRo.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{ + SetMirrorRoute: &v1alpha1.SetMirrorRoute{ + Name: "test-mirror-1", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{}, + Path: nil, + Headers: nil, + }}, + Percentage: nil, + }, + }} + allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) + assert.Equal(t, InvalidStringMatchMissedValuePolicy, allErrs[0].Detail) + }) + + t.Run("using SetMirrorRoute step without managedRoutes not defined", func(t *testing.T) { + invalidRo := ro.DeepCopy() + invalidRo.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{ + SetMirrorRoute: &v1alpha1.SetMirrorRoute{ + Name: "test-mirror-1", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{ + Exact: "exact", + }, + }}, + Percentage: nil, + }, + }} + allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) + assert.Equal(t, InvalidStepMissingManagedRoutesField, allErrs[0].Detail) + }) + + t.Run("using SetMirrorRoute step without managedRoutes defined but missing route", func(t *testing.T) { + invalidRo := ro.DeepCopy() + invalidRo.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{ + SetMirrorRoute: &v1alpha1.SetMirrorRoute{ + Name: "test-mirror-1", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{ + Exact: "GET", + }, + Path: &v1alpha1.StringMatch{ + Prefix: "/", + }, + }}, + Percentage: nil, + }, + }} + invalidRo.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes = append(invalidRo.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes, v1alpha1.MangedRoutes{ + Name: "not-in-steps", + }) + allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) + assert.Equal(t, InvalideStepRouteNameNotFoundInManagedRoutes, allErrs[0].Detail) + }) + + t.Run("using SetMirrorRoute step with managedRoutes defined", func(t *testing.T) { + invalidRo := ro.DeepCopy() + invalidRo.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{ + SetMirrorRoute: &v1alpha1.SetMirrorRoute{ + Name: "test-mirror-1", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{ + Exact: "GET", + }, + Path: &v1alpha1.StringMatch{ + Prefix: "/", + }, + }}, + Percentage: nil, + }, + }} + invalidRo.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes = append(invalidRo.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes, v1alpha1.MangedRoutes{ + Name: "test-mirror-1", + }) + allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) + assert.Len(t, allErrs, 0) }) } diff --git a/rollout/canary.go b/rollout/canary.go index d428ca49b9..87228499ab 100644 --- a/rollout/canary.go +++ b/rollout/canary.go @@ -337,7 +337,9 @@ func (c *rolloutContext) completedCurrentCanaryStep() bool { currentStepAr := c.currentArs.CanaryStep analysisExistsAndCompleted := currentStepAr != nil && currentStepAr.Status.Phase.Completed() return analysisExistsAndCompleted && currentStepAr.Status.Phase == v1alpha1.AnalysisPhaseSuccessful - case currentStep.SetHeaderRouting != nil: + case currentStep.SetHeaderRoute != nil: + return true + case currentStep.SetMirrorRoute != nil: return true } return false diff --git a/rollout/mocks/TrafficRoutingReconciler.go b/rollout/mocks/TrafficRoutingReconciler.go index 0e4d6ab1cc..278fbbd37c 100644 --- a/rollout/mocks/TrafficRoutingReconciler.go +++ b/rollout/mocks/TrafficRoutingReconciler.go @@ -13,13 +13,41 @@ type TrafficRoutingReconciler struct { mock.Mock } -// SetHeaderRouting provides a mock function with given fields: headerRouting -func (_m *TrafficRoutingReconciler) SetHeaderRouting(headerRouting *v1alpha1.SetHeaderRouting) error { - ret := _m.Called(headerRouting) +// RemoveManagedRoutes provides a mock function with given fields: +func (_m *TrafficRoutingReconciler) RemoveManagedRoutes() error { + ret := _m.Called() + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// SetHeaderRoute provides a mock function with given fields: setHeaderRoute +func (_m *TrafficRoutingReconciler) SetHeaderRoute(setHeaderRoute *v1alpha1.SetHeaderRoute) error { + ret := _m.Called(setHeaderRoute) + + var r0 error + if rf, ok := ret.Get(0).(func(*v1alpha1.SetHeaderRoute) error); ok { + r0 = rf(setHeaderRoute) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// SetMirrorRoute provides a mock function with given fields: setMirrorRoute +func (_m *TrafficRoutingReconciler) SetMirrorRoute(setMirrorRoute *v1alpha1.SetMirrorRoute) error { + ret := _m.Called(setMirrorRoute) var r0 error - if rf, ok := ret.Get(0).(func(*v1alpha1.SetHeaderRouting) error); ok { - r0 = rf(headerRouting) + if rf, ok := ret.Get(0).(func(*v1alpha1.SetMirrorRoute) error); ok { + r0 = rf(setMirrorRoute) } else { r0 = ret.Error(0) } diff --git a/rollout/trafficrouting.go b/rollout/trafficrouting.go index 4e1ff4d305..8c3598e9ce 100644 --- a/rollout/trafficrouting.go +++ b/rollout/trafficrouting.go @@ -126,7 +126,6 @@ func (c *rolloutContext) reconcileTrafficRouting() error { currentStep, index := replicasetutil.GetCurrentCanaryStep(c.rollout) desiredWeight := int32(0) - var setHeaderRouting *v1alpha1.SetHeaderRouting weightDestinations := make([]v1alpha1.WeightDestination, 0) var canaryHash, stableHash string @@ -139,6 +138,10 @@ func (c *rolloutContext) reconcileTrafficRouting() error { if rolloututil.IsFullyPromoted(c.rollout) { // when we are fully promoted. desired canary weight should be 0 + err := reconciler.RemoveManagedRoutes() + if err != nil { + return err + } } else if c.pauseContext.IsAborted() { // when aborted, desired canary weight should immediately be 0 (100% to stable), *unless* // we are using dynamic stable scaling. In that case, we are dynamically decreasing the @@ -151,6 +154,11 @@ func (c *rolloutContext) reconcileTrafficRouting() error { desiredWeight = minInt(desiredWeight, c.rollout.Status.Canary.Weights.Canary.Weight) } } + err := reconciler.RemoveManagedRoutes() + if err != nil { + return err + } + } else if c.newRS == nil || c.newRS.Status.AvailableReplicas == 0 { // when newRS is not available or replicas num is 0. never weight to canary weightDestinations = append(weightDestinations, c.calculateWeightDestinationsFromExperiment()...) @@ -163,9 +171,13 @@ func (c *rolloutContext) reconcileTrafficRouting() error { } else if c.rollout.Status.Canary.Weights != nil { desiredWeight = c.rollout.Status.Canary.Weights.Canary.Weight } + + err := reconciler.RemoveManagedRoutes() + if err != nil { + return err + } } else if index != nil { atDesiredReplicaCount := replicasetutil.AtDesiredReplicaCountsForCanary(c.rollout, c.newRS, c.stableRS, c.otherRSs, nil) - setHeaderRouting = replicasetutil.GetCurrentSetHeaderRouting(c.rollout, *index) if !atDesiredReplicaCount && !c.rollout.Status.PromoteFull { // Use the previous weight since the new RS is not ready for a new weight for i := *index - 1; i >= 0; i-- { @@ -187,6 +199,21 @@ func (c *rolloutContext) reconcileTrafficRouting() error { } } + // We need to check for Generation > 1 because when we first install the rollout we run step 0 this prevents that. + // We could also probably use c.newRS == nil || c.newRS.Status.AvailableReplicas == 0 + if currentStep != nil && c.rollout.ObjectMeta.Generation > 1 { + if currentStep.SetHeaderRoute != nil { + if err = reconciler.SetHeaderRoute(currentStep.SetHeaderRoute); err != nil { + return err + } + } + if currentStep.SetMirrorRoute != nil { + if err = reconciler.SetMirrorRoute(currentStep.SetMirrorRoute); err != nil { + return err + } + } + } + err = reconciler.UpdateHash(canaryHash, stableHash, weightDestinations...) if err != nil { return err @@ -198,10 +225,6 @@ func (c *rolloutContext) reconcileTrafficRouting() error { return err } - if err = reconciler.SetHeaderRouting(setHeaderRouting); err != nil { - return err - } - if modified, newWeights := calculateWeightStatus(c.rollout, canaryHash, stableHash, desiredWeight, weightDestinations...); modified { c.log.Infof("Previous weights: %v", c.rollout.Status.Canary.Weights) c.log.Infof("New weights: %v", newWeights) diff --git a/rollout/trafficrouting/alb/alb.go b/rollout/trafficrouting/alb/alb.go index bc1f4c7de9..55fd0b83be 100644 --- a/rollout/trafficrouting/alb/alb.go +++ b/rollout/trafficrouting/alb/alb.go @@ -113,7 +113,7 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 return nil } -func (r *Reconciler) SetHeaderRouting(headerRouting *v1alpha1.SetHeaderRouting) error { +func (r *Reconciler) SetHeaderRoute(headerRouting *v1alpha1.SetHeaderRoute) error { return nil } @@ -292,3 +292,11 @@ func getDesiredAnnotations(current *ingressutil.Ingress, r *v1alpha1.Rollout, po func (r *Reconciler) UpdateHash(canaryHash, stableHash string, additionalDestinations ...v1alpha1.WeightDestination) error { return nil } + +func (r *Reconciler) SetMirrorRoute(setMirrorRoute *v1alpha1.SetMirrorRoute) error { + return nil +} + +func (r *Reconciler) RemoveManagedRoutes() error { + return nil +} diff --git a/rollout/trafficrouting/alb/alb_test.go b/rollout/trafficrouting/alb/alb_test.go index 469be0c4b9..e455926836 100644 --- a/rollout/trafficrouting/alb/alb_test.go +++ b/rollout/trafficrouting/alb/alb_test.go @@ -829,3 +829,69 @@ func TestVerifyWeightWithAdditionalDestinations(t *testing.T) { assert.Equal(t, *status.ALB, *fakeClient.getAlbStatus()) } } + +func TestSetHeaderRoute(t *testing.T) { + ro := fakeRollout(STABLE_SVC, CANARY_SVC, nil, "ingress", 443) + i := ingress("ingress", STABLE_SVC, CANARY_SVC, STABLE_SVC, 443, 10, ro.Name, false) + client := fake.NewSimpleClientset() + k8sI := kubeinformers.NewSharedInformerFactory(client, 0) + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } + r, err := NewReconciler(ReconcilerConfig{ + Rollout: ro, + Client: client, + Recorder: record.NewFakeEventRecorder(), + ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, + IngressWrapper: ingressWrapper, + }) + assert.NoError(t, err) + err = r.SetHeaderRoute(&v1alpha1.SetHeaderRoute{ + Name: "set-header", + Match: []v1alpha1.HeaderRoutingMatch{{ + HeaderName: "header-name", + HeaderValue: &v1alpha1.StringMatch{ + Exact: "value", + }, + }}, + }) + assert.Nil(t, err) + + err = r.RemoveManagedRoutes() + assert.Nil(t, err) + + assert.Len(t, client.Actions(), 0) +} + +func TestSetMirrorRoute(t *testing.T) { + ro := fakeRollout(STABLE_SVC, CANARY_SVC, nil, "ingress", 443) + i := ingress("ingress", STABLE_SVC, CANARY_SVC, STABLE_SVC, 443, 10, ro.Name, false) + client := fake.NewSimpleClientset() + k8sI := kubeinformers.NewSharedInformerFactory(client, 0) + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } + r, err := NewReconciler(ReconcilerConfig{ + Rollout: ro, + Client: client, + Recorder: record.NewFakeEventRecorder(), + ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, + IngressWrapper: ingressWrapper, + }) + assert.NoError(t, err) + err = r.SetMirrorRoute(&v1alpha1.SetMirrorRoute{ + Name: "mirror-route", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{Exact: "GET"}, + }}, + }) + assert.Nil(t, err) + err = r.RemoveManagedRoutes() + assert.Nil(t, err) + + assert.Len(t, client.Actions(), 0) +} diff --git a/rollout/trafficrouting/ambassador/ambassador.go b/rollout/trafficrouting/ambassador/ambassador.go index 6ed6c56743..5c50f38f26 100644 --- a/rollout/trafficrouting/ambassador/ambassador.go +++ b/rollout/trafficrouting/ambassador/ambassador.go @@ -115,7 +115,7 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 return formatErrors(errs) } -func (r *Reconciler) SetHeaderRouting(headerRouting *v1alpha1.SetHeaderRouting) error { +func (r *Reconciler) SetHeaderRoute(headerRouting *v1alpha1.SetHeaderRoute) error { return nil } @@ -331,3 +331,11 @@ func (r *Reconciler) sendEvent(eventType, id, msg string) { func (r *Reconciler) UpdateHash(canaryHash, stableHash string, additionalDestinations ...v1alpha1.WeightDestination) error { return nil } + +func (r *Reconciler) SetMirrorRoute(setMirrorRoute *v1alpha1.SetMirrorRoute) error { + return nil +} + +func (r *Reconciler) RemoveManagedRoutes() error { + return nil +} diff --git a/rollout/trafficrouting/ambassador/ambassador_test.go b/rollout/trafficrouting/ambassador/ambassador_test.go index 5a558ff25a..bd6e4613de 100644 --- a/rollout/trafficrouting/ambassador/ambassador_test.go +++ b/rollout/trafficrouting/ambassador/ambassador_test.go @@ -519,6 +519,105 @@ func TestReconciler_SetWeight(t *testing.T) { }) } +func TestReconcilerSetHeaderRoute(t *testing.T) { + type fixture struct { + rollout *v1alpha1.Rollout + fakeClient *fakeClient + recorder record.EventRecorder + reconciler *ambassador.Reconciler + } + + setup := func() *fixture { + r := rollout("main-service", "canary-service", []string{"myapp-mapping"}) + fakeClient := &fakeClient{} + rec := record.NewFakeEventRecorder() + l, _ := test.NewNullLogger() + return &fixture{ + rollout: r, + fakeClient: fakeClient, + recorder: rec, + reconciler: &ambassador.Reconciler{ + Rollout: r, + Client: fakeClient, + Recorder: rec, + Log: l.WithContext(context.TODO()), + }, + } + } + t.Run("SetHeaderRoute", func(t *testing.T) { + t.Run("will always return nil", func(t *testing.T) { + // given + t.Parallel() + f := setup() + + // when + err := f.reconciler.SetHeaderRoute(&v1alpha1.SetHeaderRoute{ + Name: "set-header", + Match: []v1alpha1.HeaderRoutingMatch{{ + HeaderName: "header-name", + HeaderValue: &v1alpha1.StringMatch{ + Exact: "value", + }, + }}, + }) + + // then + assert.Nil(t, err) + + err = f.reconciler.RemoveManagedRoutes() + assert.Nil(t, err) + }) + }) +} + +func TestReconcilerSetMirrorRoute(t *testing.T) { + type fixture struct { + rollout *v1alpha1.Rollout + fakeClient *fakeClient + recorder record.EventRecorder + reconciler *ambassador.Reconciler + } + + setup := func() *fixture { + r := rollout("main-service", "canary-service", []string{"myapp-mapping"}) + fakeClient := &fakeClient{} + rec := record.NewFakeEventRecorder() + l, _ := test.NewNullLogger() + return &fixture{ + rollout: r, + fakeClient: fakeClient, + recorder: rec, + reconciler: &ambassador.Reconciler{ + Rollout: r, + Client: fakeClient, + Recorder: rec, + Log: l.WithContext(context.TODO()), + }, + } + } + t.Run("SetMirrorRoute", func(t *testing.T) { + t.Run("will always return nil", func(t *testing.T) { + // given + t.Parallel() + f := setup() + + // when + err := f.reconciler.SetMirrorRoute(&v1alpha1.SetMirrorRoute{ + Name: "mirror-route", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{Exact: "GET"}, + }}, + }) + + // then + assert.Nil(t, err) + + err = f.reconciler.RemoveManagedRoutes() + assert.Nil(t, err) + }) + }) +} + func TestGetMappingService(t *testing.T) { t.Run("will return empty string if service not found", func(t *testing.T) { // given diff --git a/rollout/trafficrouting/appmesh/appmesh.go b/rollout/trafficrouting/appmesh/appmesh.go index cbf2d589f6..f0528f779a 100644 --- a/rollout/trafficrouting/appmesh/appmesh.go +++ b/rollout/trafficrouting/appmesh/appmesh.go @@ -136,7 +136,7 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 return nil } -func (r *Reconciler) SetHeaderRouting(headerRouting *v1alpha1.SetHeaderRouting) error { +func (r *Reconciler) SetHeaderRoute(headerRouting *v1alpha1.SetHeaderRoute) error { return nil } @@ -391,3 +391,11 @@ func GetRouteRule(route map[string]interface{}) (map[string]interface{}, string, return routeRule, routeType, nil } + +func (r *Reconciler) SetMirrorRoute(setMirrorRoute *v1alpha1.SetMirrorRoute) error { + return nil +} + +func (r *Reconciler) RemoveManagedRoutes() error { + return nil +} diff --git a/rollout/trafficrouting/appmesh/appmesh_test.go b/rollout/trafficrouting/appmesh/appmesh_test.go index d64974bcc7..5f7ed41843 100644 --- a/rollout/trafficrouting/appmesh/appmesh_test.go +++ b/rollout/trafficrouting/appmesh/appmesh_test.go @@ -482,6 +482,63 @@ func TestUpdateHash(t *testing.T) { } } +func TestSetHeaderRoute(t *testing.T) { + t.Run("not implemented check", func(t *testing.T) { + t.Parallel() + client := testutil.NewFakeDynamicClient() + cfg := ReconcilerConfig{ + Rollout: fakeRollout(), + Client: client, + Recorder: record.NewFakeEventRecorder(), + } + r := NewReconciler(cfg) + + err := r.SetHeaderRoute(&v1alpha1.SetHeaderRoute{ + Name: "set-header", + Match: []v1alpha1.HeaderRoutingMatch{{ + HeaderName: "header-name", + HeaderValue: &v1alpha1.StringMatch{ + Exact: "value", + }, + }}, + }) + assert.Nil(t, err) + + err = r.RemoveManagedRoutes() + assert.Nil(t, err) + + actions := client.Actions() + assert.Len(t, actions, 0) + }) +} + +func TestSetMirrorRoute(t *testing.T) { + t.Run("not implemented check", func(t *testing.T) { + t.Parallel() + client := testutil.NewFakeDynamicClient() + cfg := ReconcilerConfig{ + Rollout: fakeRollout(), + Client: client, + Recorder: record.NewFakeEventRecorder(), + } + r := NewReconciler(cfg) + + err := r.SetMirrorRoute(&v1alpha1.SetMirrorRoute{ + Name: "mirror-route", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{Exact: "GET"}, + }}, + }) + assert.Nil(t, err) + + err = r.RemoveManagedRoutes() + assert.Nil(t, err) + + actions := client.Actions() + assert.Len(t, actions, 0) + }) +} + func TestUpdateHashWhenGetStableVirtualNodeFails(t *testing.T) { canaryHash := sampleNewCanaryHash stableHash := sampleNewStableHash diff --git a/rollout/trafficrouting/istio/istio.go b/rollout/trafficrouting/istio/istio.go index b6a63251dd..f001c585a3 100644 --- a/rollout/trafficrouting/istio/istio.go +++ b/rollout/trafficrouting/istio/istio.go @@ -25,7 +25,8 @@ import ( const Http = "http" const Tls = "tls" const Type = "Istio" -const HeaderRouteName = "argo-rollouts-header-based-route" + +const SpecHttpNotFound = "spec.http not found" // NewReconciler returns a reconciler struct that brings the Virtual Service into the desired state func NewReconciler(r *v1alpha1.Rollout, client dynamic.Interface, recorder record.EventRecorder, virtualServiceLister, destinationRuleLister dynamiclister.Lister) *Reconciler { @@ -50,22 +51,6 @@ type Reconciler struct { destinationRuleLister dynamiclister.Lister } -type routePatchAction string - -const ( - DeleteRoute routePatchAction = "DeleteRoute" - InsertHeaderRoute routePatchAction = "InsertRoute" -) - -type virtualServiceRoutePatch struct { - routeIndex int - host string - subset string - patchAction routePatchAction -} - -type virtualServiceRoutePatches []virtualServiceRoutePatch - type virtualServicePatch struct { routeIndex int routeType string @@ -142,6 +127,21 @@ func (r *Reconciler) generateVirtualServicePatches(rolloutVsvcRouteNames []strin stableSubset = r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.DestinationRule.StableSubsetName } + // Go through all the routes on the Istio Virtual Service looking for routes that are Istio mirror routes as well as on the + // managedRoutes field on the rollout object so that we can update the Istio mirror upon set weight calls + if r.rollout.Spec.Strategy.Canary.TrafficRouting != nil && r.rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes != nil { + for _, httpRoute := range httpRoutes { + if httpRoute.Mirror != nil { + for _, managedRoute := range r.rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes { + //Make sure we only add mirror routes from the managedRoutes field to the list of routes to update for setWeight + if managedRoute.Name == httpRoute.Name { + rolloutVsvcRouteNames = append(rolloutVsvcRouteNames, httpRoute.Name) + } + } + } + } + } + // err can be ignored because we already called ValidateHTTPRoutes earlier httpRouteIndexesToPatch, _ := getHttpRouteIndexesToPatch(rolloutVsvcRouteNames, httpRoutes) tlsRouteIndexesToPatch, _ := getTlsRouteIndexesToPatch(rolloutVsvcTLSRoutes, tlsRoutes) @@ -268,8 +268,7 @@ func (r *Reconciler) reconcileVirtualService(obj *unstructured.Unstructured, vsv // Set HTTP Route Slice if len(httpRoutes) > 0 { - err = unstructured.SetNestedSlice(newObj.Object, httpRoutesI, "spec", Http) - if err != nil { + if err := unstructured.SetNestedSlice(newObj.Object, httpRoutesI, "spec", Http); err != nil { return newObj, len(patches) > 0, err } } @@ -536,7 +535,7 @@ func jsonBytesToDestinationRule(dRuleBytes []byte) (*DestinationRule, error) { func GetHttpRoutesI(obj *unstructured.Unstructured) ([]interface{}, error) { httpRoutesI, notFound, err := unstructured.NestedSlice(obj.Object, "spec", Http) if !notFound { - return nil, fmt.Errorf(".spec.http is not defined") + return nil, fmt.Errorf(SpecHttpNotFound) } if err != nil { return nil, err @@ -547,7 +546,7 @@ func GetHttpRoutesI(obj *unstructured.Unstructured) ([]interface{}, error) { func GetTlsRoutesI(obj *unstructured.Unstructured) ([]interface{}, error) { tlsRoutesI, notFound, err := unstructured.NestedSlice(obj.Object, "spec", Tls) if !notFound { - return nil, fmt.Errorf(".spec.tls is not defined") + return nil, fmt.Errorf(SpecHttpNotFound) } if err != nil { return nil, err @@ -613,6 +612,10 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 if !modified { continue } + + if err := r.orderRoutes(modifiedVirtualService); err != nil && err.Error() != SpecHttpNotFound { + return fmt.Errorf("[SetWeight] failed to order routes: %w", err) + } _, err = client.Update(ctx, modifiedVirtualService, metav1.UpdateOptions{}) if err == nil { r.log.Debugf("Updated VirtualService: %s", modifiedVirtualService) @@ -649,45 +652,51 @@ func (r *Reconciler) getVirtualService(namespace string, vsvcName string, client return vsvc, err } -func (r *Reconciler) reconcileVirtualServiceRoutes(obj *unstructured.Unstructured, headerRouting *v1alpha1.SetHeaderRouting) (*unstructured.Unstructured, bool, error) { - newObj := obj.DeepCopy() - +func (r *Reconciler) reconcileVirtualServiceHeaderRoutes(obj *unstructured.Unstructured, headerRouting *v1alpha1.SetHeaderRoute) error { // HTTP Routes - var httpRoutes []VirtualServiceHTTPRoute - httpRoutesI, err := GetHttpRoutesI(newObj) - if err == nil { - httpRoutes, err = GetHttpRoutes(httpRoutesI) - if err != nil { - return nil, false, err - } + httpRoutesI, err := GetHttpRoutesI(obj) + if err != nil { + return err } destRuleHost, err := r.getDestinationRuleHost() if err != nil { - return nil, false, err + return err } - // Generate Patches - patches := r.generateHeaderBasedPatches(httpRoutes, headerRouting, destRuleHost) - for _, patch := range patches { - if patch.patchAction == InsertHeaderRoute { - httpRoutesI = append(httpRoutesI[:patch.routeIndex+1], httpRoutesI[patch.routeIndex:]...) - httpRoutesI[patch.routeIndex] = createHeaderRoute(headerRouting, patch) - } else if patch.patchAction == DeleteRoute { - httpRoutesI = append(httpRoutesI[:patch.routeIndex], httpRoutesI[patch.routeIndex+1:]...) - } + canarySvc := r.rollout.Spec.Strategy.Canary.CanaryService + if destRuleHost != "" { + canarySvc = destRuleHost + } + var canarySubset string + if r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.DestinationRule != nil { + canarySubset = r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.DestinationRule.CanarySubsetName } - // Set HTTP Route Slice - if len(httpRoutes) > 0 && len(patches) > 0 { - err = unstructured.SetNestedSlice(newObj.Object, httpRoutesI, "spec", Http) + if headerRouting.Match == nil { + //Remove mirror route + err := removeRoute(obj, headerRouting.Name) if err != nil { - return newObj, len(patches) > 0, err + return fmt.Errorf("[reconcileVirtualServiceHeaderRoutes] failed to remove route from virtual service: %w", err) } + return nil } - return newObj, len(patches) > 0, err + + //Remove route first to avoid duplicates + err = removeRoute(obj, headerRouting.Name) + if err != nil { + return fmt.Errorf("[reconcileVirtualServiceHeaderRoutes] failed to remove http route from virtual service: %w", err) + } + + httpRoutesI = append(httpRoutesI, createHeaderRoute(headerRouting, canarySvc, canarySubset)) + + err = unstructured.SetNestedSlice(obj.Object, httpRoutesI, "spec", Http) + if err != nil { + return err + } + return nil } -func (r *Reconciler) SetHeaderRouting(headerRouting *v1alpha1.SetHeaderRouting) error { +func (r *Reconciler) SetHeaderRoute(headerRouting *v1alpha1.SetHeaderRoute) error { ctx := context.TODO() virtualServices := r.getVirtualServices() for _, virtualService := range virtualServices { @@ -700,21 +709,23 @@ func (r *Reconciler) SetHeaderRouting(headerRouting *v1alpha1.SetHeaderRouting) client := r.client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(namespace) vsvc, err := r.getVirtualService(namespace, vsvcName, client, ctx) if err != nil { - return err + return fmt.Errorf("[SetHeaderRoute] failed to get istio virtual service: %w", err) } - modifiedVirtualService, modified, err := r.reconcileVirtualServiceRoutes(vsvc, headerRouting) + + err = r.reconcileVirtualServiceHeaderRoutes(vsvc, headerRouting) if err != nil { - return err + return fmt.Errorf("[SetHeaderRoute] failed to reconcile header routes: %w", err) } - if !modified { - continue + + if err := r.orderRoutes(vsvc); err != nil && err.Error() != SpecHttpNotFound { + return fmt.Errorf("[SetHeaderRoute] failed to order routes: %w", err) } - _, err = client.Update(ctx, modifiedVirtualService, metav1.UpdateOptions{}) + _, err = client.Update(ctx, vsvc, metav1.UpdateOptions{}) if err == nil { - r.log.Debugf("Updated VirtualService: %s", modifiedVirtualService) - r.recorder.Eventf(r.rollout, record.EventOptions{EventReason: "Updated VirtualService"}, "VirtualService `%s` set headerRouting '%v'", vsvcName, headerRouting) + r.log.Debugf("Updated VirtualService: %s", vsvc) + r.recorder.Eventf(r.rollout, record.EventOptions{EventReason: "Updated VirtualService"}, "VirtualService `%s` set headerRoute '%v'", vsvcName, headerRouting.Name) } else { - return err + return fmt.Errorf("[SetHeaderRoute] failed to update routes: %w", err) } } return nil @@ -754,73 +765,20 @@ func (r *Reconciler) getDestinationRule(dRuleSpec *v1alpha1.IstioDestinationRule return origBytes, dRule, dRuleNew, nil } -func (r *Reconciler) generateHeaderBasedPatches(httpRoutes []VirtualServiceHTTPRoute, headerRouting *v1alpha1.SetHeaderRouting, destRuleHost string) virtualServiceRoutePatches { - canarySvc := r.rollout.Spec.Strategy.Canary.CanaryService - if destRuleHost != "" { - canarySvc = destRuleHost - } - var canarySubset string - if r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.DestinationRule != nil { - canarySubset = r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.DestinationRule.CanarySubsetName - } - - patches := virtualServiceRoutePatches{} - headerRouteExist := hasHeaderRoute(httpRoutes) - - if headerRouteExist { - if headerRouting == nil || headerRouting.Match == nil { - deleteHeaderRoute(&patches) - } else { - deleteHeaderRoute(&patches) - insertHeaderRoute(&patches, canarySvc, canarySubset) - } - } else if headerRouting != nil && headerRouting.Match != nil { - insertHeaderRoute(&patches, canarySvc, canarySubset) - } - return patches -} - -func hasHeaderRoute(httpRoutes []VirtualServiceHTTPRoute) bool { - for _, route := range httpRoutes { - if route.Name == HeaderRouteName { - return true - } - } - return false -} - -func deleteHeaderRoute(patches *virtualServiceRoutePatches) { - patch := virtualServiceRoutePatch{ - routeIndex: 0, - patchAction: DeleteRoute, - } - *patches = append(*patches, patch) -} - -func insertHeaderRoute(patches *virtualServiceRoutePatches, host, subset string) { - insertPatch := virtualServiceRoutePatch{ - routeIndex: 0, - host: host, - subset: subset, - patchAction: InsertHeaderRoute, - } - *patches = append(*patches, insertPatch) -} - -func createHeaderRoute(headerRouting *v1alpha1.SetHeaderRouting, patch virtualServiceRoutePatch) map[string]interface{} { +func createHeaderRoute(headerRouting *v1alpha1.SetHeaderRoute, host string, subset string) map[string]interface{} { var routeMatches []interface{} for _, hrm := range headerRouting.Match { - routeMatches = append(routeMatches, createRouteMatch(hrm)) + routeMatches = append(routeMatches, createHeaderRouteMatch(hrm)) } - canaryDestination := routeDestination(patch.host, patch.subset, 100) + canaryDestination := routeDestination(host, subset, 100) return map[string]interface{}{ - "name": HeaderRouteName, + "name": headerRouting.Name, "match": routeMatches, "route": []interface{}{canaryDestination}, } } -func createRouteMatch(hrm v1alpha1.HeaderRoutingMatch) interface{} { +func createHeaderRouteMatch(hrm v1alpha1.HeaderRoutingMatch) interface{} { res := map[string]interface{}{} value := hrm.HeaderValue setMapValueIfNotEmpty(res, "exact", value.Exact) @@ -857,8 +815,14 @@ func (r *Reconciler) VerifyWeight(desiredWeight int32, additionalDestinations .. // getHttpRouteIndexesToPatch returns array indices of the httpRoutes which need to be patched when updating weights func getHttpRouteIndexesToPatch(routeNames []string, httpRoutes []VirtualServiceHTTPRoute) ([]int, error) { + //We have no routes listed in spec.strategy.canary.trafficRouting.istio.virtualService.routes so find index + //of the first empty named route if len(routeNames) == 0 { - return []int{0}, nil + for i, route := range httpRoutes { + if route.Name == "" { + return []int{i}, nil + } + } } var routeIndexesToPatch []int @@ -955,7 +919,23 @@ func ValidateHTTPRoutes(r *v1alpha1.Rollout, routeNames []string, httpRoutes []V return err } } - if len(routeNames) == 0 && len(httpRoutes) > 1 { + + httpRoutesBytes, err := json.Marshal(httpRoutes) + if err != nil { + return fmt.Errorf("[ValidateHTTPRoutes] failed to marshal http routes: %w", err) + } + var httpRoutesI []interface{} + err = json.Unmarshal(httpRoutesBytes, &httpRoutesI) + if err != nil { + return fmt.Errorf("[ValidateHTTPRoutes] failed to marshal http routes to []interface{}: %w", err) + } + + _, httpRoutesNotWithinManagedRoutes, err := splitManagedRoutesAndNonManagedRoutes(r.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes, httpRoutesI) + if err != nil { + return fmt.Errorf("[ValidateHTTPRoutes] failed to split managed and non-managed routes: %w", err) + } + + if len(routeNames) == 0 && len(httpRoutesNotWithinManagedRoutes) > 1 { return fmt.Errorf("spec.http[] should be set in VirtualService and it must have exactly one route when omitting spec.strategy.canary.trafficRouting.istio.virtualService.routes") } return nil @@ -1029,3 +1009,362 @@ func validateDestinationRule(dRule *v1alpha1.IstioDestinationRule, hasCanarySubs } return nil } + +func (r *Reconciler) SetMirrorRoute(setMirrorRoute *v1alpha1.SetMirrorRoute) error { + ctx := context.TODO() + virtualServices := r.getVirtualServices() + + for _, virtualService := range virtualServices { + name := virtualService.Name + namespace, vsvcName := istioutil.GetVirtualServiceNamespaceName(name) + if namespace == "" { + namespace = r.rollout.Namespace + } + + client := r.client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(namespace) + istioVirtualSvc, err := r.getVirtualService(namespace, vsvcName, client, ctx) + if err != nil { + return fmt.Errorf("[SetMirrorRoute] failed to get virtual service: %w", err) + } + + err = r.reconcileVirtualServiceMirrorRoutes(virtualService, istioVirtualSvc, setMirrorRoute) + if err != nil { + return fmt.Errorf("[SetMirrorRoute] failed reconcile virtual service for mirror routes: %w", err) + } + + if err := r.orderRoutes(istioVirtualSvc); err != nil && err.Error() != SpecHttpNotFound { + return fmt.Errorf("[SetMirrorRoute] failed to order routes based on managedRoute order: %w", err) + } + _, err = client.Update(ctx, istioVirtualSvc, metav1.UpdateOptions{}) + if err == nil { + r.log.Debugf("Updated VirtualService: %s", istioVirtualSvc) + r.recorder.Eventf(r.rollout, record.EventOptions{EventReason: "Updated VirtualService"}, "VirtualService `%s` set mirrorRoute '%v'", vsvcName, setMirrorRoute.Name) + } else { + return fmt.Errorf("[SetMirrorRoute] failed to update virtual service %w", err) + } + + } + return nil +} + +func (r *Reconciler) reconcileVirtualServiceMirrorRoutes(virtualService v1alpha1.IstioVirtualService, istioVirtualService *unstructured.Unstructured, mirrorRoute *v1alpha1.SetMirrorRoute) error { + destRuleHost, err := r.getDestinationRuleHost() + if err != nil { + return fmt.Errorf("[reconcileVirtualServiceMirrorRoutes] failed to get destination rule host: %w", err) + } + canarySvc := r.rollout.Spec.Strategy.Canary.CanaryService + if destRuleHost != "" { + canarySvc = destRuleHost + } + var canarySubset string + if r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.DestinationRule != nil { + canarySubset = r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.DestinationRule.CanarySubsetName + } + + //Remove mirror route when there is no match rules we require a match on routes for safety so a none listed match + //acts like a removal of the route instead of say routing all traffic + if mirrorRoute.Match == nil { + //Remove mirror route + err := removeRoute(istioVirtualService, mirrorRoute.Name) + if err != nil { + return fmt.Errorf("[reconcileVirtualServiceMirrorRoutes] failed to remove route from virtual service: %w", err) + } + return nil + } + + //Remove route first to avoid duplicates + err = removeRoute(istioVirtualService, mirrorRoute.Name) + if err != nil { + return fmt.Errorf("[reconcileVirtualServiceMirrorRoutes] failed to remove http route from virtual service: %w", err) + } + + httpRoutes, _, err := getVirtualServiceHttpRoutes(istioVirtualService) + if err != nil { + return fmt.Errorf("[reconcileVirtualServiceMirrorRoutes] failed to get virtual service http routes: %w", err) + } + + mR, err := createMirrorRoute(virtualService, httpRoutes, mirrorRoute, canarySvc, canarySubset) + if err != nil { + return fmt.Errorf("[reconcileVirtualServiceMirrorRoutes] failed to create mirror route: %w", err) + } + + vsRoutes, found, err := unstructured.NestedSlice(istioVirtualService.Object, "spec", Http) + if err != nil { + return fmt.Errorf("[reconcileVirtualServiceMirrorRoutes] failed to get http routes from virtual service: %w", err) + } + if !found { + return fmt.Errorf(SpecHttpNotFound) + } + vsRoutes = append([]interface{}{mR}, vsRoutes...) + if err := unstructured.SetNestedSlice(istioVirtualService.Object, vsRoutes, "spec", Http); err != nil { + return fmt.Errorf("[reconcileVirtualServiceMirrorRoutes] failed to update virtual service routes via set nested slice: %w", err) + } + + return nil +} + +// getVirtualServiceHttpRoutes This returns all the http routes from an istio virtual service as both a rollouts wrapped type +// []VirtualServiceHTTPRoute and a []interface{} of VirtualServiceHTTPRoute +func getVirtualServiceHttpRoutes(obj *unstructured.Unstructured) ([]VirtualServiceHTTPRoute, []interface{}, error) { + httpRoutesI, err := GetHttpRoutesI(obj) + if err != nil { + return nil, nil, fmt.Errorf("[getVirtualServiceHttpRoutes] failed to get http route interfaces: %w", err) + } + routes, err := GetHttpRoutes(httpRoutesI) + if err != nil { + return nil, httpRoutesI, fmt.Errorf("[getVirtualServiceHttpRoutes] failed to get http route types: %w", err) + } + return routes, httpRoutesI, nil +} + +// createMirrorRoute This returns a map[string]interface{} of an istio virtual service mirror route configuration using the last +// set weight as values for the non-matching destinations and canary service for the matching destination. +func createMirrorRoute(virtualService v1alpha1.IstioVirtualService, httpRoutes []VirtualServiceHTTPRoute, mirrorRouting *v1alpha1.SetMirrorRoute, canarySvc string, subset string) (map[string]interface{}, error) { + var percent int32 + if mirrorRouting.Percentage == nil { + percent = 100 + } else { + percent = *mirrorRouting.Percentage + } + + route, err := getVirtualServiceSetWeightRoute(virtualService.Routes, httpRoutes) + if err != nil { + return nil, fmt.Errorf("[createMirrorRoute] failed to get virtual service http route for keeping non-mirror weights set: %w", err) + } + + var istioMatch []RouteMatch + for _, match := range mirrorRouting.Match { + istioMatch = append(istioMatch, RouteMatch{ + Method: match.Method, + Uri: match.Path, + Headers: match.Headers, + }) + } + + mirrorRoute := map[string]interface{}{ + "name": mirrorRouting.Name, + "match": istioMatch, + "route": route, + "mirror": VirtualServiceDestination{ + Host: canarySvc, + Subset: subset, + }, + "mirrorPercentage": map[string]interface{}{"value": float64(percent)}, + } + + mirrorRouteBytes, err := json.Marshal(mirrorRoute) + if err != nil { + return nil, fmt.Errorf("[createMirrorRoute] failed to marshal mirror route: %w", err) + } + + var mirrorRouteI map[string]interface{} + err = json.Unmarshal(mirrorRouteBytes, &mirrorRouteI) + if err != nil { + return nil, fmt.Errorf("[createMirrorRoute] failed to unmarshal mirror route: %w", err) + } + + return mirrorRouteI, nil +} + +// getVirtualServiceSetWeightRoute This functions goes through the list of Istio Virtual service routes and finds the first +// match from the trafficRouting.istio.virtualService[s].routes field and returns the []VirtualServiceRouteDestination array +// from the istio virtual service this can be useful to get the last set destination percentages on the canary route. +func getVirtualServiceSetWeightRoute(rolloutVsvcRouteNames []string, httpRoutes []VirtualServiceHTTPRoute) ([]VirtualServiceRouteDestination, error) { + routeIndexesToPatch, err := getHttpRouteIndexesToPatch(rolloutVsvcRouteNames, httpRoutes) + if err != nil { + return nil, fmt.Errorf("[getVirtualServiceSetWeightRoute] failed to get routes that need to be patch when set weight is called: %w", err) + } + for _, routeIndex := range routeIndexesToPatch { + route := httpRoutes[routeIndex] + return route.Route, nil + } + return nil, nil +} + +// removeRoute This functions removes the `routeName` route from the Istio Virtual Service +func removeRoute(istioVirtualService *unstructured.Unstructured, routeName string) error { + vsRoutes, found, err := unstructured.NestedSlice(istioVirtualService.Object, "spec", Http) + if err != nil { + return fmt.Errorf("[removeRoute] failed to get http routes from virtual service: %w", err) + } + if !found { + return fmt.Errorf(SpecHttpNotFound) + } + + var newVsRoutes []interface{} + for _, route := range vsRoutes { + routeMap, ok := route.(map[string]interface{}) + if !ok { + return fmt.Errorf("Could not cast type to map[string]interface{} to find route name in Istio Virtual Service") + } + routeNameIstioSvc, ok := routeMap["name"].(string) + if !ok { + log.Debugf("Could not cast type to string to find route name in Istio Virtual Service, route probably has no name set") + } + if routeName != routeNameIstioSvc { + newVsRoutes = append(newVsRoutes, route) + } + } + if err := unstructured.SetNestedSlice(istioVirtualService.Object, newVsRoutes, "spec", Http); err != nil { + return fmt.Errorf("[removeRoute] failed to set http routes on virtual service: %w", err) + } + return nil +} + +// orderRoutes Is a function that orders the routes based on the managedRoute field in the rollout spec. It then places +// the sorted routes ontop of any other route that is already defined on the Istio Virtual Service. +func (r *Reconciler) orderRoutes(istioVirtualService *unstructured.Unstructured) error { + httpRouteI, found, err := unstructured.NestedSlice(istioVirtualService.Object, "spec", Http) + if err != nil { + return fmt.Errorf("[orderRoutes] failed to get virtual service http routes: %w", err) + } + if !found { + return fmt.Errorf(SpecHttpNotFound) + } + + if r.rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes == nil { + return nil //Not really and error there is just nothing to sort on + } + + managedRoutes := r.rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes + httpRoutesWithinManagedRoutes, httpRoutesNotWithinManagedRoutes, err := splitManagedRoutesAndNonManagedRoutes(managedRoutes, httpRouteI) + if err != nil { + return fmt.Errorf("[orderRoutes] could not split routes between managed and non managed: %w", err) + } + + finalRoutes, err := getOrderedVirtualServiceRoutes(managedRoutes, httpRoutesWithinManagedRoutes, httpRoutesNotWithinManagedRoutes) + if err != nil { + return fmt.Errorf("[orderRoutes] could not get ordered virtual service routes: %w", err) + } + + if err := unstructured.SetNestedSlice(istioVirtualService.Object, finalRoutes, "spec", Http); err != nil { + return fmt.Errorf("[orderRoutes] set nested slice failed: %w", err) + } + + return nil +} + +// splitManagedRoutesAndNonManagedRoutes This splits the routes from an istio virtual service into two slices +// one slice contains all the routes that are also in the rollouts managedRoutes object and one that contains routes +// that where only in the virtual service (aka routes that where manually added by user) +func splitManagedRoutesAndNonManagedRoutes(managedRoutes []v1alpha1.MangedRoutes, httpRouteI []interface{}) (httpRoutesWithinManagedRoutes []VirtualServiceHTTPRoute, httpRoutesNotWithinManagedRoutes []VirtualServiceHTTPRoute, err error) { + var httpRoutes []VirtualServiceHTTPRoute + + jsonHttpRoutes, err := json.Marshal(httpRouteI) + if err != nil { + return nil, nil, fmt.Errorf("[splitManagedRoutesAndNonManagedRoutes] failed to marsharl http route interface: %w", err) + } + + if err := json.Unmarshal(jsonHttpRoutes, &httpRoutes); err != nil { + return nil, nil, fmt.Errorf("[splitManagedRoutesAndNonManagedRoutes] failed to unmarsharl http route interface: %w", err) + } + + for _, route := range httpRoutes { + var found bool = false + for _, managedRoute := range managedRoutes { + if route.Name == managedRoute.Name { + httpRoutesWithinManagedRoutes = append(httpRoutesWithinManagedRoutes, route) + found = true + break + } + } + if !found { + httpRoutesNotWithinManagedRoutes = append(httpRoutesNotWithinManagedRoutes, route) + } + } + + return httpRoutesWithinManagedRoutes, httpRoutesNotWithinManagedRoutes, nil +} + +// getOrderedVirtualServiceRoutes This returns an []interface{} of istio virtual routes where the routes are ordered based +// on the rollouts managedRoutes field. We take the routes from the rollouts managedRoutes field order them and place them on top +// of routes that are manually defined within the virtual service (aka. routes that users have defined manually) +func getOrderedVirtualServiceRoutes(managedRoutes []v1alpha1.MangedRoutes, httpRoutesWithinManagedRoutes []VirtualServiceHTTPRoute, httpRoutesNotWithinManagedRoutes []VirtualServiceHTTPRoute) ([]interface{}, error) { + var orderedManagedRoutes []VirtualServiceHTTPRoute + for _, route := range managedRoutes { + for _, managedRoute := range httpRoutesWithinManagedRoutes { + if route.Name == managedRoute.Name { + orderedManagedRoutes = append(orderedManagedRoutes, managedRoute) + } + } + } + + allIstioRoutes := append(orderedManagedRoutes, httpRoutesNotWithinManagedRoutes...) + + jsonAllIstioRoutes, err := json.Marshal(allIstioRoutes) + if err != nil { + return nil, fmt.Errorf("[getOrderedVirtualServiceRoutes] failed to marsharl istio routes: %w", err) + } + var orderedRoutes []interface{} + if err := json.Unmarshal(jsonAllIstioRoutes, &orderedRoutes); err != nil { + return nil, fmt.Errorf("[getOrderedVirtualServiceRoutes] failed to unmarsharl istio routes: %w", err) + } + + return orderedRoutes, nil +} + +// RemoveManagedRoutes this removes all the routes in all the istio virtual services rollouts is managing by getting two slices +// from the splitManagedRoutesAndNonManagedRoutes function and setting the Istio Virtual Service routes to just the ones not managed +// by rollouts +func (r *Reconciler) RemoveManagedRoutes() error { + ctx := context.TODO() + virtualServices := r.getVirtualServices() + + for _, virtualService := range virtualServices { + name := virtualService.Name + namespace, vsvcName := istioutil.GetVirtualServiceNamespaceName(name) + if namespace == "" { + namespace = r.rollout.Namespace + } + + client := r.client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(namespace) + istioVirtualService, err := r.getVirtualService(namespace, vsvcName, client, ctx) + if err != nil { + return fmt.Errorf("[RemoveManagedRoutes] failed to get virtual service: %w", err) + } + + httpRouteI, found, err := unstructured.NestedSlice(istioVirtualService.Object, "spec", Http) + if err != nil { + return fmt.Errorf("[RemoveManagedRoutes] failed to get http routes from virtual service: %w", err) + } + if !found { + return fmt.Errorf("[RemoveManagedRoutes] %s: %w", SpecHttpNotFound, err) + } + + managedRoutes := r.rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes + if len(managedRoutes) == 0 { + return nil + } + httpRoutesWithinManagedRoutes, httpRoutesNotWithinManagedRoutes, err := splitManagedRoutesAndNonManagedRoutes(managedRoutes, httpRouteI) + if err != nil { + return fmt.Errorf("[RemoveManagedRoutes] failed to split managaed and non-managed routes: %w", err) + } + + if len(httpRoutesWithinManagedRoutes) == 0 { + //no routes to remove + return nil + } + + jsonNonManagedRoutes, err := json.Marshal(httpRoutesNotWithinManagedRoutes) + if err != nil { + return fmt.Errorf("[RemoveManagedRoutes] failed to marshal non-managed routes: %w", err) + } + var nonManagedRoutesI []interface{} + if err := json.Unmarshal(jsonNonManagedRoutes, &nonManagedRoutesI); err != nil { + return fmt.Errorf("[RemoveManagedRoutes] failed to split managaed and non-managed routes: %w", err) + } + + if err := unstructured.SetNestedSlice(istioVirtualService.Object, nonManagedRoutesI, "spec", Http); err != nil { + return fmt.Errorf("[RemoveManagedRoutes] failed to set nested slice on virtual service to remove managed routes: %w", err) + } + + _, err = client.Update(ctx, istioVirtualService, metav1.UpdateOptions{}) + if err == nil { + r.log.Debugf("Updated VirtualService: %s", istioVirtualService) + r.recorder.Eventf(r.rollout, record.EventOptions{EventReason: "Updated VirtualService"}, "VirtualService `%s` removed all managed routes.", vsvcName) + } else { + return fmt.Errorf("[RemoveManagedRoutes] failed to update kubernetes virtual service: %w", err) + } + } + return nil +} diff --git a/rollout/trafficrouting/istio/istio_test.go b/rollout/trafficrouting/istio/istio_test.go index 939c16beb0..3c57dcfbdb 100644 --- a/rollout/trafficrouting/istio/istio_test.go +++ b/rollout/trafficrouting/istio/istio_test.go @@ -486,90 +486,156 @@ func TestHttpReconcileWeightsBaseCase(t *testing.T) { } } -func TestHttpReconcileHeaderRoute_HostBased(t *testing.T) { - r := &Reconciler{ - rollout: rolloutWithHttpRoutes("stable", "canary", "vsvc", []string{"primary"}), - } +func TestHttpReconcileHeaderRouteHostBased(t *testing.T) { + ro := rolloutWithHttpRoutes("stable", "canary", "vsvc", []string{"primary"}) + obj := unstructuredutil.StrToUnstructuredUnsafe(regularVsvc) + client := testutil.NewFakeDynamicClient(obj) + vsvcLister, druleLister := getIstioListers(client) + r := NewReconciler(ro, client, record.NewFakeEventRecorder(), vsvcLister, druleLister) + client.ClearActions() + + const headerName = "test-header-route" + r.rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes = append(r.rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes, []v1alpha1.MangedRoutes{{ + Name: headerName, + }, + }...) // Test for both the HTTP VS & Mixed VS - vsObj := unstructuredutil.StrToUnstructuredUnsafe(regularVsvc) - hr := &v1alpha1.SetHeaderRouting{ + hr := &v1alpha1.SetHeaderRoute{ + Name: headerName, Match: []v1alpha1.HeaderRoutingMatch{ { HeaderName: "agent", - HeaderValue: v1alpha1.StringMatch{Exact: "firefox"}, + HeaderValue: &v1alpha1.StringMatch{Exact: "firefox"}, }, }, } - modifiedVsObj, _, err := r.reconcileVirtualServiceRoutes(vsObj, hr) + + err := r.SetHeaderRoute(hr) assert.Nil(t, err) - assert.NotNil(t, modifiedVsObj) + + iVirtualService, err := client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(r.rollout.Namespace).Get(context.TODO(), ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name, metav1.GetOptions{}) + assert.NoError(t, err) // HTTP Routes - httpRoutes := extractHttpRoutes(t, modifiedVsObj) + httpRoutes := extractHttpRoutes(t, iVirtualService) // Assertions - assert.Equal(t, httpRoutes[0].Name, HeaderRouteName) + assert.Equal(t, httpRoutes[0].Name, headerName) checkDestination(t, httpRoutes[0].Route, "canary", 100) assert.Equal(t, len(httpRoutes[0].Route), 1) assert.Equal(t, httpRoutes[1].Name, "primary") checkDestination(t, httpRoutes[1].Route, "stable", 100) assert.Equal(t, httpRoutes[2].Name, "secondary") - // Reset header routing, expecting removing of the header route - - modifiedVsObj, _, err = r.reconcileVirtualServiceRoutes(vsObj, nil) + err = r.SetHeaderRoute(&v1alpha1.SetHeaderRoute{ + Name: headerName, + }) assert.Nil(t, err) - assert.NotNil(t, modifiedVsObj) + + iVirtualService, err = client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(r.rollout.Namespace).Get(context.TODO(), ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name, metav1.GetOptions{}) + assert.NoError(t, err) // HTTP Routes - httpRoutes = extractHttpRoutes(t, modifiedVsObj) + httpRoutes = extractHttpRoutes(t, iVirtualService) // Assertions assert.Equal(t, httpRoutes[0].Name, "primary") assert.Equal(t, httpRoutes[1].Name, "secondary") } -func TestHttpReconcileHeaderRoute_SubsetBased(t *testing.T) { +func TestHttpReconcileHeaderRouteSubsetBased(t *testing.T) { ro := rolloutWithDestinationRule() - obj := unstructuredutil.StrToUnstructuredUnsafe(` + const RolloutService = "rollout-service" + const StableSubsetName = "stable-subset" + const CanarySubsetName = "canary-subset" + ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name = "vsvc" + ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Routes = nil + ro.Spec.Strategy.Canary.TrafficRouting.Istio.DestinationRule.StableSubsetName = StableSubsetName + ro.Spec.Strategy.Canary.TrafficRouting.Istio.DestinationRule.CanarySubsetName = CanarySubsetName + dRule := unstructuredutil.StrToUnstructuredUnsafe(` apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: istio-destrule namespace: default spec: - host: root-service + host: rollout-service subsets: - - name: stable - - name: canary + - name: stable-subset + - name: canary-subset `) - client := testutil.NewFakeDynamicClient(obj) - r := NewReconciler(ro, client, record.NewFakeEventRecorder(), nil, nil) + obj := unstructuredutil.StrToUnstructuredUnsafe(singleRouteSubsetVsvc) + client := testutil.NewFakeDynamicClient(obj, dRule) + vsvcLister, druleLister := getIstioListers(client) + r := NewReconciler(ro, client, record.NewFakeEventRecorder(), vsvcLister, druleLister) client.ClearActions() - // Test for both the HTTP VS & Mixed VS - vsObj := unstructuredutil.StrToUnstructuredUnsafe(singleRouteSubsetVsvc) - hr := &v1alpha1.SetHeaderRouting{ + const headerName = "test-header-route" + r.rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes = append(r.rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes, []v1alpha1.MangedRoutes{{ + Name: headerName, + }, + }...) + + hr := &v1alpha1.SetHeaderRoute{ + Name: headerName, Match: []v1alpha1.HeaderRoutingMatch{ { HeaderName: "agent", - HeaderValue: v1alpha1.StringMatch{ + HeaderValue: &v1alpha1.StringMatch{ Regex: "firefox", }, }, }, } - modifiedVsObj, _, err := r.reconcileVirtualServiceRoutes(vsObj, hr) + + err := r.SetHeaderRoute(hr) assert.Nil(t, err) - assert.NotNil(t, modifiedVsObj) + + iVirtualService, err := client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(r.rollout.Namespace).Get(context.TODO(), ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name, metav1.GetOptions{}) + assert.NoError(t, err) // HTTP Routes - httpRoutes := extractHttpRoutes(t, modifiedVsObj) + httpRoutes := extractHttpRoutes(t, iVirtualService) // Assertions - assert.Equal(t, httpRoutes[0].Name, HeaderRouteName) - assert.Equal(t, httpRoutes[0].Route[0].Destination.Host, "root-service") - assert.Equal(t, httpRoutes[0].Route[0].Destination.Subset, "canary") + assert.Equal(t, httpRoutes[0].Name, headerName) + assert.Equal(t, httpRoutes[0].Route[0].Destination.Host, "rollout-service") + assert.Equal(t, httpRoutes[0].Route[0].Destination.Subset, "canary-subset") +} + +func TestReconcileUpdateHeader(t *testing.T) { + ro := rolloutWithHttpRoutes("stable", "canary", "vsvc", []string{"primary"}) + ro.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes = append(ro.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes, v1alpha1.MangedRoutes{ + Name: "test-mirror-1", + }) + AssertReconcileUpdateHeader(t, regularVsvc, ro) +} +func AssertReconcileUpdateHeader(t *testing.T, vsvc string, ro *v1alpha1.Rollout) *dynamicfake.FakeDynamicClient { + obj := unstructuredutil.StrToUnstructuredUnsafe(vsvc) + client := testutil.NewFakeDynamicClient(obj) + vsvcLister, druleLister := getIstioListers(client) + r := NewReconciler(ro, client, record.NewFakeEventRecorder(), vsvcLister, druleLister) + client.ClearActions() + + var setHeader = &v1alpha1.SetHeaderRoute{ + Name: "test-mirror-1", + Match: []v1alpha1.HeaderRoutingMatch{ + { + HeaderName: "browser", + HeaderValue: &v1alpha1.StringMatch{ + Prefix: "Firefox", + }, + }, + }, + } + err := r.SetHeaderRoute(setHeader) + + assert.Nil(t, err) + + actions := client.Actions() + assert.Len(t, actions, 1) + assert.Equal(t, "update", actions[0].GetVerb()) + return client } func TestTlsReconcileWeightsBaseCase(t *testing.T) { @@ -1719,3 +1785,385 @@ func TestMultipleVirtualServiceReconcileInferredSingleRoute(t *testing.T) { assertHttpRouteWeightChanges(t, httpRoutes[0], "", 10, 90) } } + +func TestHttpReconcileMirrorRoute(t *testing.T) { + ro := rolloutWithHttpRoutes("stable", "canary", "vsvc", []string{"primary"}) + obj := unstructuredutil.StrToUnstructuredUnsafe(regularVsvc) + client := testutil.NewFakeDynamicClient(obj) + vsvcLister, druleLister := getIstioListers(client) + r := NewReconciler(ro, client, record.NewFakeEventRecorder(), vsvcLister, druleLister) + client.ClearActions() + + // Test for both the HTTP VS & Mixed VS + setMirror1 := &v1alpha1.SetMirrorRoute{ + Name: "test-mirror-1", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{ + Exact: "GET", + }, + }}, + } + var percentage int32 = 90 + setMirror2 := &v1alpha1.SetMirrorRoute{ + Name: "test-mirror-2", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{ + Exact: "GET", + }, + }}, + Percentage: &percentage, + } + r.rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes = append(r.rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes, []v1alpha1.MangedRoutes{{ + Name: "test-mirror-1", + }, { + Name: "test-mirror-2", + }, + }...) + + err := r.SetMirrorRoute(setMirror1) + assert.Nil(t, err) + iVirtualService, err := client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(r.rollout.Namespace).Get(context.TODO(), ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name, metav1.GetOptions{}) + assert.NoError(t, err) + // HTTP Routes + httpRoutes := extractHttpRoutes(t, iVirtualService) + assert.Equal(t, len(httpRoutes), 3) + + // Assertions + assert.Equal(t, httpRoutes[0].Name, "test-mirror-1") + checkDestination(t, httpRoutes[0].Route, "canary", 0) + assert.Equal(t, httpRoutes[0].Mirror.Host, "canary") + assert.Equal(t, httpRoutes[0].Mirror.Subset, "") + assert.Equal(t, httpRoutes[0].MirrorPercentage.Value, float64(100)) + assert.Equal(t, len(httpRoutes[0].Route), 2) + assert.Equal(t, httpRoutes[1].Name, "primary") + checkDestination(t, httpRoutes[1].Route, "stable", 100) + assert.Equal(t, httpRoutes[2].Name, "secondary") + checkDestination(t, httpRoutes[2].Route, "stable", 100) + + //Delete mirror route + deleteSetMirror := &v1alpha1.SetMirrorRoute{ + Name: "test-mirror-1", + } + err = r.SetMirrorRoute(deleteSetMirror) + assert.Nil(t, err) + iVirtualService, err = client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(r.rollout.Namespace).Get(context.TODO(), ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name, metav1.GetOptions{}) + assert.NoError(t, err) + httpRoutes = extractHttpRoutes(t, iVirtualService) + assert.Equal(t, len(httpRoutes), 2) + assert.Equal(t, httpRoutes[0].Name, "primary") + assert.Equal(t, httpRoutes[1].Name, "secondary") + + //Test adding two routes using fake client then cleaning them up with RemoveManagedRoutes + err = r.SetMirrorRoute(setMirror1) + assert.Nil(t, err) + err = r.SetMirrorRoute(setMirror2) + assert.Nil(t, err) + iVirtualService, err = client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(r.rollout.Namespace).Get(context.TODO(), ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name, metav1.GetOptions{}) + assert.NoError(t, err) + + httpRoutes = extractHttpRoutes(t, iVirtualService) + assert.Equal(t, len(httpRoutes), 4) + assert.Equal(t, httpRoutes[1].MirrorPercentage.Value, float64(90)) + + r.RemoveManagedRoutes() + iVirtualService, err = client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(r.rollout.Namespace).Get(context.TODO(), ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name, metav1.GetOptions{}) + assert.NoError(t, err) + + httpRoutes = extractHttpRoutes(t, iVirtualService) + assert.Equal(t, len(httpRoutes), 2) + +} + +func TestHttpReconcileMirrorRouteOrder(t *testing.T) { + ro := rolloutWithHttpRoutes("stable", "canary", "vsvc", []string{"primary", "secondary"}) + obj := unstructuredutil.StrToUnstructuredUnsafe(regularVsvc) + client := testutil.NewFakeDynamicClient(obj) + vsvcLister, druleLister := getIstioListers(client) + r := NewReconciler(ro, client, record.NewFakeEventRecorder(), vsvcLister, druleLister) + client.ClearActions() + + setMirror1 := &v1alpha1.SetMirrorRoute{ + Name: "test-mirror-1", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{ + Exact: "GET", + }, + }}, + } + var percentage int32 = 90 + setMirror2 := &v1alpha1.SetMirrorRoute{ + Name: "test-mirror-2", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{ + Exact: "POST", + }, + }}, + Percentage: &percentage, + } + setMirror3 := &v1alpha1.SetMirrorRoute{ + Name: "test-mirror-3", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{ + Exact: "GET", + }, + }}, + Percentage: &percentage, + } + r.rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes = append(r.rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes, []v1alpha1.MangedRoutes{{ + Name: "test-mirror-2", + }, { + Name: "test-mirror-3", + }, { + Name: "test-mirror-1", + }, + }...) + + err := r.SetMirrorRoute(setMirror1) + assert.Nil(t, err) + err = r.SetMirrorRoute(setMirror2) + assert.Nil(t, err) + err = r.SetMirrorRoute(setMirror3) + assert.Nil(t, err) + err = r.SetWeight(40) + assert.Nil(t, err) + iVirtualService, err := client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(r.rollout.Namespace).Get(context.TODO(), ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name, metav1.GetOptions{}) + assert.NoError(t, err) + // HTTP Routes + httpRoutes := extractHttpRoutes(t, iVirtualService) + assert.Equal(t, len(httpRoutes), 5) + assert.Equal(t, httpRoutes[0].Name, "test-mirror-2") + checkDestination(t, httpRoutes[0].Route, "canary", 40) + checkDestination(t, httpRoutes[0].Route, "stable", 60) + assert.Equal(t, httpRoutes[1].Name, "test-mirror-3") + assert.Equal(t, httpRoutes[2].Name, "test-mirror-1") + assert.Equal(t, httpRoutes[3].Name, "primary") + assert.Equal(t, httpRoutes[4].Name, "secondary") + + //Delete mirror route + deleteSetMirror := &v1alpha1.SetMirrorRoute{ + Name: "test-mirror-3", + } + err = r.SetMirrorRoute(deleteSetMirror) + assert.Nil(t, err) + iVirtualService, err = client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(r.rollout.Namespace).Get(context.TODO(), ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name, metav1.GetOptions{}) + assert.NoError(t, err) + httpRoutes = extractHttpRoutes(t, iVirtualService) + assert.Equal(t, len(httpRoutes), 4) + assert.Equal(t, httpRoutes[0].Name, "test-mirror-2") + assert.Equal(t, httpRoutes[1].Name, "test-mirror-1") + assert.Equal(t, httpRoutes[2].Name, "primary") + assert.Equal(t, httpRoutes[3].Name, "secondary") + + r.RemoveManagedRoutes() + iVirtualService, err = client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(r.rollout.Namespace).Get(context.TODO(), ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name, metav1.GetOptions{}) + assert.NoError(t, err) + + httpRoutes = extractHttpRoutes(t, iVirtualService) + assert.Equal(t, len(httpRoutes), 2) +} + +func TestHttpReconcileMirrorRouteOrderSingleRouteNoName(t *testing.T) { + ro := rolloutWithHttpRoutes("stable", "canary", "vsvc", []string{}) + obj := unstructuredutil.StrToUnstructuredUnsafe(singleRouteVsvc) + client := testutil.NewFakeDynamicClient(obj) + _, druleLister := getIstioListers(client) + r := NewReconciler(ro, client, record.NewFakeEventRecorder(), nil, druleLister) + client.ClearActions() + + setMirror1 := &v1alpha1.SetMirrorRoute{ + Name: "test-mirror-1", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{ + Exact: "GET", + }, + }}, + } + var percentage int32 = 90 + setMirror2 := &v1alpha1.SetMirrorRoute{ + Name: "test-mirror-2", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{ + Exact: "POST", + }, + }}, + Percentage: &percentage, + } + setMirror3 := &v1alpha1.SetMirrorRoute{ + Name: "test-mirror-3", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{ + Exact: "GET", + }, + }}, + Percentage: &percentage, + } + r.rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes = append(r.rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes, []v1alpha1.MangedRoutes{{ + Name: "test-mirror-2", + }, { + Name: "test-mirror-3", + }, { + Name: "test-mirror-1", + }, + }...) + + err := r.SetWeight(30) + assert.Nil(t, err) + err = r.SetMirrorRoute(setMirror1) + assert.Nil(t, err) + err = r.SetMirrorRoute(setMirror2) + assert.Nil(t, err) + err = r.SetMirrorRoute(setMirror3) + assert.Nil(t, err) + + iVirtualService, err := client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(r.rollout.Namespace).Get(context.TODO(), ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name, metav1.GetOptions{}) + assert.NoError(t, err) + // HTTP Routes + httpRoutes := extractHttpRoutes(t, iVirtualService) + assert.Equal(t, len(httpRoutes), 4) + assert.Equal(t, httpRoutes[0].Name, "test-mirror-2") + assert.Equal(t, httpRoutes[1].Name, "test-mirror-3") + assert.Equal(t, httpRoutes[2].Name, "test-mirror-1") + assert.Equal(t, httpRoutes[3].Name, "") + assert.Equal(t, httpRoutes[3].Route[0].Weight, int64(70)) + assert.Equal(t, httpRoutes[3].Route[1].Weight, int64(30)) + checkDestination(t, httpRoutes[0].Route, "canary", 30) + checkDestination(t, httpRoutes[1].Route, "stable", 70) + + err = r.SetWeight(40) + assert.Nil(t, err) + iVirtualService, err = client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(r.rollout.Namespace).Get(context.TODO(), ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name, metav1.GetOptions{}) + assert.NoError(t, err) + // HTTP Routes + httpRoutes = extractHttpRoutes(t, iVirtualService) + checkDestination(t, httpRoutes[0].Route, "canary", 40) + checkDestination(t, httpRoutes[1].Route, "stable", 60) + + //Delete mirror route + deleteSetMirror := &v1alpha1.SetMirrorRoute{ + Name: "test-mirror-3", + } + err = r.SetMirrorRoute(deleteSetMirror) + assert.Nil(t, err) + iVirtualService, err = client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(r.rollout.Namespace).Get(context.TODO(), ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name, metav1.GetOptions{}) + assert.NoError(t, err) + httpRoutes = extractHttpRoutes(t, iVirtualService) + assert.Equal(t, len(httpRoutes), 3) + assert.Equal(t, httpRoutes[0].Name, "test-mirror-2") + assert.Equal(t, httpRoutes[1].Name, "test-mirror-1") + assert.Equal(t, httpRoutes[2].Name, "") + + r.RemoveManagedRoutes() + iVirtualService, err = client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(r.rollout.Namespace).Get(context.TODO(), ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name, metav1.GetOptions{}) + assert.NoError(t, err) + + httpRoutes = extractHttpRoutes(t, iVirtualService) + assert.Equal(t, len(httpRoutes), 1) +} + +func TestHttpReconcileMirrorRouteSubset(t *testing.T) { + + ro := rolloutWithDestinationRule() + const RolloutService = "rollout-service" + const StableSubsetName = "stable-subset" + const CanarySubsetName = "canary-subset" + ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name = "vsvc" + ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Routes = nil + ro.Spec.Strategy.Canary.TrafficRouting.Istio.DestinationRule.StableSubsetName = StableSubsetName + ro.Spec.Strategy.Canary.TrafficRouting.Istio.DestinationRule.CanarySubsetName = CanarySubsetName + dRule := unstructuredutil.StrToUnstructuredUnsafe(` +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-destrule + namespace: default +spec: + host: rollout-service + subsets: + - name: stable-subset + - name: canary-subset +`) + + //ro := rolloutWithHttpRoutes("stable", "canary", "vsvc", []string{"primary"}) + obj := unstructuredutil.StrToUnstructuredUnsafe(singleRouteSubsetVsvc) + client := testutil.NewFakeDynamicClient(obj, dRule) + vsvcLister, druleLister := getIstioListers(client) + r := NewReconciler(ro, client, record.NewFakeEventRecorder(), vsvcLister, druleLister) + client.ClearActions() + + // Test for both the HTTP VS & Mixed VS + setMirror1 := &v1alpha1.SetMirrorRoute{ + Name: "test-mirror-1", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{ + Exact: "GET", + }, + }}, + } + r.rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes = append(r.rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes, []v1alpha1.MangedRoutes{{ + Name: "test-mirror-1", + }, + }...) + + err := r.SetMirrorRoute(setMirror1) + assert.Nil(t, err) + iVirtualService, err := client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(r.rollout.Namespace).Get(context.TODO(), ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name, metav1.GetOptions{}) + assert.NoError(t, err) + // HTTP Routes + httpRoutes := extractHttpRoutes(t, iVirtualService) + assert.Equal(t, len(httpRoutes), 2) + + // Assertions + assert.Equal(t, httpRoutes[0].Name, "test-mirror-1") + assert.Equal(t, httpRoutes[0].Mirror.Host, RolloutService) + assert.Equal(t, httpRoutes[0].Mirror.Subset, CanarySubsetName) + assert.Equal(t, httpRoutes[0].Route[0].Destination.Host, RolloutService) + assert.Equal(t, httpRoutes[0].Route[0].Destination.Subset, StableSubsetName) + assert.Equal(t, httpRoutes[0].Route[1].Destination.Host, RolloutService) + assert.Equal(t, httpRoutes[0].Route[1].Destination.Subset, CanarySubsetName) + assert.Equal(t, len(httpRoutes[0].Route), 2) + + assert.Equal(t, httpRoutes[1].Name, "") + assert.Nil(t, httpRoutes[1].Mirror) + assert.Equal(t, httpRoutes[1].Route[0].Destination.Host, RolloutService) + assert.Equal(t, httpRoutes[1].Route[0].Destination.Subset, StableSubsetName) + assert.Equal(t, httpRoutes[1].Route[1].Destination.Host, RolloutService) + assert.Equal(t, httpRoutes[1].Route[1].Destination.Subset, CanarySubsetName) + assert.Equal(t, len(httpRoutes[1].Route), 2) + + r.RemoveManagedRoutes() + iVirtualService, err = client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(r.rollout.Namespace).Get(context.TODO(), ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name, metav1.GetOptions{}) + assert.NoError(t, err) + httpRoutes = extractHttpRoutes(t, iVirtualService) + assert.Equal(t, len(httpRoutes), 1) +} + +func TestReconcileUpdateMirror(t *testing.T) { + ro := rolloutWithHttpRoutes("stable", "canary", "vsvc", []string{"primary"}) + ro.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes = append(ro.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes, v1alpha1.MangedRoutes{ + Name: "test-mirror-1", + }) + AssertReconcileUpdateMirror(t, regularVsvc, ro) +} +func AssertReconcileUpdateMirror(t *testing.T, vsvc string, ro *v1alpha1.Rollout) *dynamicfake.FakeDynamicClient { + obj := unstructuredutil.StrToUnstructuredUnsafe(vsvc) + client := testutil.NewFakeDynamicClient(obj) + vsvcLister, druleLister := getIstioListers(client) + r := NewReconciler(ro, client, record.NewFakeEventRecorder(), vsvcLister, druleLister) + client.ClearActions() + + setMirror := &v1alpha1.SetMirrorRoute{ + Name: "test-mirror-1", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{ + Exact: "GET", + }, + }}, + } + err := r.SetMirrorRoute(setMirror) + assert.Nil(t, err) + + actions := client.Actions() + assert.Len(t, actions, 1) + assert.Equal(t, "update", actions[0].GetVerb()) + return client +} diff --git a/rollout/trafficrouting/istio/istio_types.go b/rollout/trafficrouting/istio/istio_types.go index 4e14a60bdf..ce714757d2 100644 --- a/rollout/trafficrouting/istio/istio_types.go +++ b/rollout/trafficrouting/istio/istio_types.go @@ -1,6 +1,7 @@ package istio import ( + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -17,8 +18,27 @@ type VirtualServiceSpec struct { // VirtualServiceHTTPRoute is a HTTP route in a VirtualService type VirtualServiceHTTPRoute struct { - Name string `json:"name,omitempty"` - Route []VirtualServiceRouteDestination `json:"route,omitempty"` + Name string `json:"name,omitempty"` + Match []RouteMatch `json:"match,omitempty"` + Route []VirtualServiceRouteDestination `json:"route,omitempty"` + Mirror *VirtualServiceDestination `json:"mirror,omitempty"` + MirrorPercentage *Percent `json:"mirrorPercentage,omitempty"` +} + +type RouteMatch struct { + // Method What http methods should be mirrored + // +optional + Method *v1alpha1.StringMatch `json:"method,omitempty" protobuf:"bytes,1,opt,name=method"` + // Uri What url paths should be mirrored + // +optional + Uri *v1alpha1.StringMatch `json:"uri,omitempty" protobuf:"bytes,2,opt,name=uri"` + // Headers What request with matching headers should be mirrored + // +optional + Headers map[string]v1alpha1.StringMatch `json:"headers,omitempty" protobuf:"bytes,3,opt,name=headers"` +} + +type Percent struct { + Value float64 `json:"value,omitempty"` } // VirtualServiceTLSRoute is a TLS route in a VirtualService diff --git a/rollout/trafficrouting/nginx/nginx.go b/rollout/trafficrouting/nginx/nginx.go index a0d291c121..8bb6353ef3 100644 --- a/rollout/trafficrouting/nginx/nginx.go +++ b/rollout/trafficrouting/nginx/nginx.go @@ -307,7 +307,7 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 return nil } -func (r *Reconciler) SetHeaderRouting(headerRouting *v1alpha1.SetHeaderRouting) error { +func (r *Reconciler) SetHeaderRoute(headerRouting *v1alpha1.SetHeaderRoute) error { return nil } @@ -319,3 +319,11 @@ func (r *Reconciler) VerifyWeight(desiredWeight int32, additionalDestinations .. func (r *Reconciler) UpdateHash(canaryHash, stableHash string, additionalDestinations ...v1alpha1.WeightDestination) error { return nil } + +func (r *Reconciler) SetMirrorRoute(setMirrorRoute *v1alpha1.SetMirrorRoute) error { + return nil +} + +func (r *Reconciler) RemoveManagedRoutes() error { + return nil +} diff --git a/rollout/trafficrouting/nginx/nginx_test.go b/rollout/trafficrouting/nginx/nginx_test.go index 2b3a7cf328..a8d3517d8d 100644 --- a/rollout/trafficrouting/nginx/nginx_test.go +++ b/rollout/trafficrouting/nginx/nginx_test.go @@ -678,3 +678,42 @@ func TestReconcileCanaryCreateErrorAlreadyExistsPatch(t *testing.T) { assert.Equal(t, schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "ingresses"}, actions[2].GetResource(), "action: patch canary ingress") } } + +func TestSetHeaderRoute(t *testing.T) { + r := Reconciler{ + cfg: ReconcilerConfig{ + Rollout: fakeRollout("stable-service", "canary-service", "stable-ingress"), + }, + } + err := r.SetHeaderRoute(&v1alpha1.SetHeaderRoute{ + Name: "set-header", + Match: []v1alpha1.HeaderRoutingMatch{{ + HeaderName: "header-name", + HeaderValue: &v1alpha1.StringMatch{ + Exact: "value", + }, + }}, + }) + assert.Nil(t, err) + + err = r.RemoveManagedRoutes() + assert.Nil(t, err) +} + +func TestSetMirrorRoute(t *testing.T) { + r := Reconciler{ + cfg: ReconcilerConfig{ + Rollout: fakeRollout("stable-service", "canary-service", "stable-ingress"), + }, + } + err := r.SetMirrorRoute(&v1alpha1.SetMirrorRoute{ + Name: "mirror-route", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{Exact: "GET"}, + }}, + }) + assert.Nil(t, err) + + err = r.RemoveManagedRoutes() + assert.Nil(t, err) +} diff --git a/rollout/trafficrouting/smi/smi.go b/rollout/trafficrouting/smi/smi.go index 8be3584abf..c781799f87 100644 --- a/rollout/trafficrouting/smi/smi.go +++ b/rollout/trafficrouting/smi/smi.go @@ -218,7 +218,7 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 return r.patchTrafficSplit(existingTrafficSplit, trafficSplits) } -func (r *Reconciler) SetHeaderRouting(headerRouting *v1alpha1.SetHeaderRouting) error { +func (r *Reconciler) SetHeaderRoute(headerRouting *v1alpha1.SetHeaderRoute) error { return nil } @@ -351,3 +351,11 @@ func trafficSplitV1Alpha3(ro *v1alpha1.Rollout, objectMeta metav1.ObjectMeta, ro func (r *Reconciler) UpdateHash(canaryHash, stableHash string, additionalDestinations ...v1alpha1.WeightDestination) error { return nil } + +func (r *Reconciler) SetMirrorRoute(setMirrorRoute *v1alpha1.SetMirrorRoute) error { + return nil +} + +func (r *Reconciler) RemoveManagedRoutes() error { + return nil +} diff --git a/rollout/trafficrouting/smi/smi_test.go b/rollout/trafficrouting/smi/smi_test.go index 22a69d6098..136e006a14 100644 --- a/rollout/trafficrouting/smi/smi_test.go +++ b/rollout/trafficrouting/smi/smi_test.go @@ -576,3 +576,62 @@ func TestCreateTrafficSplitForMultipleBackends(t *testing.T) { assert.Equal(t, 80, ts3.Spec.Backends[3].Weight) }) } + +func TestReconcileSetHeaderRoute(t *testing.T) { + t.Run("not implemented", func(t *testing.T) { + ro := fakeRollout("stable-service", "canary-service", "", "") + client := fake.NewSimpleClientset() + r, err := NewReconciler(ReconcilerConfig{ + Rollout: ro, + Client: client, + Recorder: record.NewFakeEventRecorder(), + ControllerKind: schema.GroupVersionKind{}, + }) + assert.Nil(t, err) + + err = r.SetHeaderRoute(&v1alpha1.SetHeaderRoute{ + Name: "set-header", + Match: []v1alpha1.HeaderRoutingMatch{{ + HeaderName: "header-name", + HeaderValue: &v1alpha1.StringMatch{ + Exact: "value", + }, + }}, + }) + assert.Nil(t, err) + + err = r.RemoveManagedRoutes() + assert.Nil(t, err) + + actions := client.Actions() + assert.Len(t, actions, 0) + }) +} + +func TestReconcileSetMirrorRoute(t *testing.T) { + t.Run("not implemented", func(t *testing.T) { + ro := fakeRollout("stable-service", "canary-service", "", "") + client := fake.NewSimpleClientset() + r, err := NewReconciler(ReconcilerConfig{ + Rollout: ro, + Client: client, + Recorder: record.NewFakeEventRecorder(), + ControllerKind: schema.GroupVersionKind{}, + }) + assert.Nil(t, err) + + err = r.SetMirrorRoute(&v1alpha1.SetMirrorRoute{ + Name: "mirror-route", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{Exact: "GET"}, + }}, + }) + assert.Nil(t, err) + + err = r.RemoveManagedRoutes() + assert.Nil(t, err) + + actions := client.Actions() + assert.Len(t, actions, 0) + }) +} diff --git a/rollout/trafficrouting/traefik/traefik.go b/rollout/trafficrouting/traefik/traefik.go index 22c3f56875..f5b507207f 100644 --- a/rollout/trafficrouting/traefik/traefik.go +++ b/rollout/trafficrouting/traefik/traefik.go @@ -156,7 +156,7 @@ func getService(serviceName string, services []interface{}) (map[string]interfac return selectedService, nil } -func (r *Reconciler) SetHeaderRouting(headerRouting *v1alpha1.SetHeaderRouting) error { +func (r *Reconciler) SetHeaderRoute(headerRouting *v1alpha1.SetHeaderRoute) error { return nil } @@ -167,3 +167,11 @@ func (r *Reconciler) VerifyWeight(desiredWeight int32, additionalDestinations .. func (r *Reconciler) Type() string { return Type } + +func (r *Reconciler) SetMirrorRoute(setMirrorRoute *v1alpha1.SetMirrorRoute) error { + return nil +} + +func (r *Reconciler) RemoveManagedRoutes() error { + return nil +} diff --git a/rollout/trafficrouting/traefik/traefik_test.go b/rollout/trafficrouting/traefik/traefik_test.go index e3c0b5e774..d7dbbbd297 100644 --- a/rollout/trafficrouting/traefik/traefik_test.go +++ b/rollout/trafficrouting/traefik/traefik_test.go @@ -196,6 +196,61 @@ func TestSetWeight(t *testing.T) { }) } +func TestSetHeaderRoute(t *testing.T) { + t.Run("SetHeaderRoute", func(t *testing.T) { + // Given + t.Parallel() + cfg := ReconcilerConfig{ + Rollout: newRollout(stableServiceName, canaryServiceName, traefikServiceName), + Client: client, + } + r := NewReconciler(&cfg) + + // When + err := r.SetHeaderRoute(&v1alpha1.SetHeaderRoute{ + Name: "set-header", + Match: []v1alpha1.HeaderRoutingMatch{{ + HeaderName: "header-name", + HeaderValue: &v1alpha1.StringMatch{ + Exact: "value", + }, + }}, + }) + + // Then + assert.NoError(t, err) + + err = r.RemoveManagedRoutes() + assert.Nil(t, err) + }) +} + +func TestSetMirrorRoute(t *testing.T) { + t.Run("SetMirrorRoute", func(t *testing.T) { + // Given + t.Parallel() + cfg := ReconcilerConfig{ + Rollout: newRollout(stableServiceName, canaryServiceName, traefikServiceName), + Client: client, + } + r := NewReconciler(&cfg) + + // When + err := r.SetMirrorRoute(&v1alpha1.SetMirrorRoute{ + Name: "mirror-route", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{Exact: "GET"}, + }}, + }) + + // Then + assert.NoError(t, err) + + err = r.RemoveManagedRoutes() + assert.Nil(t, err) + }) +} + func toUnstructured(t *testing.T, manifest string) *unstructured.Unstructured { t.Helper() obj := &unstructured.Unstructured{} diff --git a/rollout/trafficrouting/trafficroutingutil.go b/rollout/trafficrouting/trafficroutingutil.go index 08569c4a16..3ff9c9c4ec 100644 --- a/rollout/trafficrouting/trafficroutingutil.go +++ b/rollout/trafficrouting/trafficroutingutil.go @@ -10,11 +10,15 @@ type TrafficRoutingReconciler interface { UpdateHash(canaryHash, stableHash string, additionalDestinations ...v1alpha1.WeightDestination) error // SetWeight sets the canary weight to the desired weight SetWeight(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) error - // SetHeaderRouting sets the header routing step - SetHeaderRouting(headerRouting *v1alpha1.SetHeaderRouting) error + // SetHeaderRoute sets the header routing step + SetHeaderRoute(setHeaderRoute *v1alpha1.SetHeaderRoute) error + // SetMirrorRoute sets up the traffic router to mirror traffic to a service + SetMirrorRoute(setMirrorRoute *v1alpha1.SetMirrorRoute) error // VerifyWeight returns true if the canary is at the desired weight and additionalDestinations are at the weights specified // Returns nil if weight verification is not supported or not applicable VerifyWeight(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) (*bool, error) + // RemoveAllRoutes Removes all routes that are managed by rollouts by looking at spec.strategy.canary.trafficRouting.managedRoutes + RemoveManagedRoutes() error // Type returns the type of the traffic routing reconciler Type() string } diff --git a/rollout/trafficrouting_test.go b/rollout/trafficrouting_test.go index 11941a9aea..ac7d9b6516 100644 --- a/rollout/trafficrouting_test.go +++ b/rollout/trafficrouting_test.go @@ -35,9 +35,11 @@ func newFakeSingleTrafficRoutingReconciler() *mocks.TrafficRoutingReconciler { trafficRoutingReconciler := mocks.TrafficRoutingReconciler{} trafficRoutingReconciler.On("Type").Return("fake") trafficRoutingReconciler.On("SetWeight", mock.Anything, mock.Anything).Return(nil) - trafficRoutingReconciler.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) + trafficRoutingReconciler.On("SetHeaderRoute", mock.Anything, mock.Anything).Return(nil) + trafficRoutingReconciler.On("SetMirrorRoute", mock.Anything, mock.Anything).Return(nil) trafficRoutingReconciler.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) trafficRoutingReconciler.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) + trafficRoutingReconciler.On("RemoveManagedRoutes", mock.Anything, mock.Anything).Return(nil) return &trafficRoutingReconciler } @@ -99,7 +101,7 @@ func TestReconcileTrafficRoutingVerifyWeightErr(t *testing.T) { f.fakeTrafficRouting = newUnmockedFakeTrafficRoutingReconciler() f.fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(nil) - f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetHeaderRoute", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(false), errors.New("Error message")) f.expectPatchRolloutAction(ro) f.run(getKey(ro, t)) @@ -112,7 +114,7 @@ func TestReconcileTrafficRoutingVerifyWeightFalse(t *testing.T) { f.fakeTrafficRouting = newUnmockedFakeTrafficRoutingReconciler() f.fakeTrafficRouting.On("UpdateHash", mock.Anything, mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("SetWeight", mock.Anything, mock.Anything).Return(nil) - f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetHeaderRoute", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(false), nil) c, i, k8sI := f.newController(noResyncPeriodFunc) enqueued := false @@ -174,7 +176,7 @@ func TestRolloutUseDesiredWeight(t *testing.T) { assert.Equal(t, int32(10), desiredWeight) return nil }) - f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetHeaderRoute", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(true, nil) f.run(getKey(r2, t)) } @@ -223,7 +225,7 @@ func TestRolloutUseDesiredWeight100(t *testing.T) { assert.Equal(t, int32(100), desiredWeight) return nil }) - f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetHeaderRoute", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(true, nil) f.run(getKey(r2, t)) } @@ -291,7 +293,7 @@ func TestRolloutWithExperimentStep(t *testing.T) { assert.Equal(t, ex.Status.TemplateStatuses[0].PodTemplateHash, weightDestinations[0].PodTemplateHash) return nil }) - f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetHeaderRoute", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(func(desiredWeight int32, weightDestinations ...v1alpha1.WeightDestination) error { assert.Equal(t, int32(10), desiredWeight) assert.Equal(t, int32(5), weightDestinations[0].Weight) @@ -312,7 +314,7 @@ func TestRolloutWithExperimentStep(t *testing.T) { assert.Len(t, weightDestinations, 0) return nil }) - f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetHeaderRoute", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(func(desiredWeight int32, weightDestinations ...v1alpha1.WeightDestination) error { assert.Equal(t, int32(10), desiredWeight) assert.Len(t, weightDestinations, 0) @@ -367,7 +369,7 @@ func TestRolloutUsePreviousSetWeight(t *testing.T) { assert.Equal(t, int32(10), desiredWeight) return nil }) - f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetHeaderRoute", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything, mock.Anything).Return(pointer.BoolPtr(true), nil) f.fakeTrafficRouting.On("error patching alb ingress", mock.Anything, mock.Anything).Return(true, nil) f.run(getKey(r2, t)) @@ -433,7 +435,8 @@ func TestRolloutUseDynamicWeightOnPromoteFull(t *testing.T) { assert.Equal(t, int32(50), desiredWeight) return nil }) - f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetHeaderRoute", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("RemoveManagedRoutes", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) f.run(getKey(r2, t)) }) @@ -446,7 +449,8 @@ func TestRolloutUseDynamicWeightOnPromoteFull(t *testing.T) { assert.Equal(t, int32(5), desiredWeight) return nil }) - f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetHeaderRoute", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("RemoveManagedRoutes", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) f.run(getKey(r2, t)) }) @@ -490,7 +494,8 @@ func TestRolloutSetWeightToZeroWhenFullyRolledOut(t *testing.T) { assert.Equal(t, int32(0), desiredWeight) return nil }) - f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetHeaderRoute", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("RemoveManagedRoutes", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) f.run(getKey(r1, t)) } @@ -863,7 +868,8 @@ func TestDynamicScalingDontIncreaseWeightWhenAborted(t *testing.T) { assert.Equal(t, int32(0), desiredWeight) return nil }) - f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetHeaderRoute", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("RemoveManagedRoutes", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) f.run(getKey(r1, t)) } @@ -933,7 +939,8 @@ func TestDynamicScalingDecreaseWeightAccordingToStableAvailabilityWhenAborted(t assert.Equal(t, int32(80), desiredWeight) return nil }) - f.fakeTrafficRouting.On("SetHeaderRouting", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("SetHeaderRoute", mock.Anything, mock.Anything).Return(nil) + f.fakeTrafficRouting.On("RemoveManagedRoutes", mock.Anything, mock.Anything).Return(nil) f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) f.run(getKey(r1, t)) } diff --git a/test/e2e/header-routing/istio-hr-host.yaml b/test/e2e/header-routing/istio-hr-host.yaml index 6c3fa050bb..8b1036fb42 100644 --- a/test/e2e/header-routing/istio-hr-host.yaml +++ b/test/e2e/header-routing/istio-hr-host.yaml @@ -76,6 +76,8 @@ spec: canaryService: canary-service stableService: stable-service trafficRouting: + managedRoutes: + - name: set-header-1 istio: virtualService: name: rollouts-demo-vsvc @@ -83,20 +85,23 @@ spec: - primary steps: - setWeight: 20 - - setHeaderRouting: + - setHeaderRoute: + name: set-header-1 match: - headerName: agent headerValue: regex: firefox(.*) - pause: { } - - setHeaderRouting: + - setHeaderRoute: + name: set-header-1 match: - headerName: agent headerValue: regex: chrome(.*) - pause: { } - setWeight: 40 - - setHeaderRouting: {} + - setHeaderRoute: + name: set-header-1 - pause: {} --- apiVersion: networking.istio.io/v1alpha3 diff --git a/test/e2e/header_routing_test.go b/test/e2e/header_route_test.go similarity index 85% rename from test/e2e/header_routing_test.go rename to test/e2e/header_route_test.go index a1aab16999..5b9fe7cd16 100644 --- a/test/e2e/header_routing_test.go +++ b/test/e2e/header_route_test.go @@ -15,22 +15,22 @@ import ( "github.com/argoproj/argo-rollouts/test/fixtures" ) -type HeaderRoutingSuite struct { +type HeaderRouteSuite struct { fixtures.E2ESuite } func TestHeaderRoutingSuite(t *testing.T) { - suite.Run(t, new(HeaderRoutingSuite)) + suite.Run(t, new(HeaderRouteSuite)) } -func (s *HeaderRoutingSuite) SetupSuite() { +func (s *HeaderRouteSuite) SetupSuite() { s.E2ESuite.SetupSuite() if !s.IstioEnabled { s.T().SkipNow() } } -func (s *HeaderRoutingSuite) TestIstioHostHeaderRoute() { +func (s *HeaderRouteSuite) TestIstioHostHeaderRoute() { s.Given(). RolloutObjects("@header-routing/istio-hr-host.yaml"). When(). @@ -48,7 +48,7 @@ func (s *HeaderRoutingSuite) TestIstioHostHeaderRoute() { Then(). Assert(func(t *fixtures.Then) { vsvc := t.GetVirtualService() - assert.Equal(s.T(), istio.HeaderRouteName, vsvc.Spec.HTTP[0].Name) + assert.Equal(s.T(), "set-header-1", vsvc.Spec.HTTP[0].Name) assertDestination(s, vsvc.Spec.HTTP[0], "canary-service", int64(100)) assertDestination(s, vsvc.Spec.HTTP[1], "stable-service", int64(80)) assertDestination(s, vsvc.Spec.HTTP[1], "canary-service", int64(20)) @@ -80,7 +80,7 @@ func (s *HeaderRoutingSuite) TestIstioHostHeaderRoute() { }) } -func assertDestination(s *HeaderRoutingSuite, route istio.VirtualServiceHTTPRoute, service string, weight int64) { +func assertDestination(s *HeaderRouteSuite, route istio.VirtualServiceHTTPRoute, service string, weight int64) { for _, destination := range route.Route { if destination.Destination.Host == service { assert.Equal(s.T(), weight, destination.Weight) diff --git a/test/e2e/mirror-route/istio-mirror-host.yaml b/test/e2e/mirror-route/istio-mirror-host.yaml new file mode 100644 index 0000000000..d3f20b0352 --- /dev/null +++ b/test/e2e/mirror-route/istio-mirror-host.yaml @@ -0,0 +1,124 @@ +apiVersion: v1 +kind: Service +metadata: + name: canary-service +spec: + selector: + app: rollouts-demo + ports: + - name: http + port: 80 + protocol: TCP + targetPort: http +--- +apiVersion: v1 +kind: Service +metadata: + name: stable-service +spec: + selector: + app: rollouts-demo + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + +--- +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +metadata: + name: rollouts-demo-vsvc +spec: + gateways: + - rollouts-demo-gateway + hosts: + - rollouts-demo.com + http: + - name: primary + route: + - destination: + host: stable-service + weight: 80 + - destination: + host: canary-service + weight: 20 + +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollouts-demo +spec: + replicas: 5 + selector: + matchLabels: + app: rollouts-demo + template: + metadata: + labels: + app: rollouts-demo + spec: + containers: + - name: rollouts-demo + image: "nginx:1.19-alpine" + ports: + - name: http + containerPort: 8080 + protocol: TCP + strategy: + canary: + canaryService: canary-service + stableService: stable-service + trafficRouting: + managedRoutes: + - name: mirror-route-1 + - name: mirror-route-2 + istio: + virtualService: + name: rollouts-demo-vsvc + routes: + - primary + steps: + - setWeight: 20 + - setMirrorRoute: + name: mirror-route-1 + percentage: 100 + match: + - path: + prefix: / + - setMirrorRoute: + name: mirror-route-2 + percentage: 80 + match: + - path: + prefix: / + method: + exact: GET + - pause: { } + - setMirrorRoute: + name: mirror-route-1 + percentage: 100 + match: + - path: + prefix: /rewrite + - pause: { } + - setWeight: 40 + - setMirrorRoute: + name: mirror-route-1 + - pause: {} +--- +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: rollouts-demo-gateway +spec: + selector: + istio: ingressgateway + servers: + - hosts: + - '*' + port: + name: http + number: 80 + protocol: HTTP diff --git a/test/e2e/mirror_route_test.go b/test/e2e/mirror_route_test.go new file mode 100644 index 0000000000..5190a985f0 --- /dev/null +++ b/test/e2e/mirror_route_test.go @@ -0,0 +1,102 @@ +//go:build e2e +// +build e2e + +package e2e + +import ( + "github.com/argoproj/argo-rollouts/rollout/trafficrouting/istio" + "testing" + "time" + + "github.com/stretchr/testify/suite" + "github.com/tj/assert" + + "github.com/argoproj/argo-rollouts/test/fixtures" +) + +type MirrorRouteSuite struct { + fixtures.E2ESuite +} + +func TestMirrorRouteSuite(t *testing.T) { + suite.Run(t, new(MirrorRouteSuite)) +} + +func (s *MirrorRouteSuite) SetupSuite() { + s.E2ESuite.SetupSuite() + if !s.IstioEnabled { + s.T().SkipNow() + } +} + +func (s *MirrorRouteSuite) TestIstioHostMirrorRoute() { + s.Given(). + RolloutObjects("@mirror-route/istio-mirror-host.yaml"). + When(). + ApplyManifests(). + WaitForRolloutStatus("Healthy"). + Then(). + Assert(func(t *fixtures.Then) { + vsvc := t.GetVirtualService() + assert.Equal(s.T(), "primary", vsvc.Spec.HTTP[0].Name) + }). + When(). + UpdateSpec(). + WaitForRolloutStatus("Paused"). + Sleep(1 * time.Second). + Then(). + Assert(func(t *fixtures.Then) { + vsvc := t.GetVirtualService() + assert.Equal(s.T(), "mirror-route-1", vsvc.Spec.HTTP[0].Name) + assert.Equal(s.T(), float64(100), vsvc.Spec.HTTP[0].MirrorPercentage.Value) + assert.Equal(s.T(), "mirror-route-2", vsvc.Spec.HTTP[1].Name) + assert.Equal(s.T(), float64(80), vsvc.Spec.HTTP[1].MirrorPercentage.Value) + assertMirrorDestination(s, vsvc.Spec.HTTP[0], "stable-service", int64(80)) + assertMirrorDestination(s, vsvc.Spec.HTTP[0], "canary-service", int64(20)) + assertMirrorDestination(s, vsvc.Spec.HTTP[1], "stable-service", int64(80)) + assertMirrorDestination(s, vsvc.Spec.HTTP[1], "canary-service", int64(20)) + + assertMirrorDestination(s, vsvc.Spec.HTTP[2], "stable-service", int64(80)) + assertMirrorDestination(s, vsvc.Spec.HTTP[2], "canary-service", int64(20)) + }). + When(). + PromoteRollout(). + WaitForRolloutStatus("Paused"). + Sleep(1 * time.Second). + Then(). + When(). + PromoteRollout(). + WaitForRolloutStatus("Paused"). + Sleep(1 * time.Second). + Then(). + Assert(func(t *fixtures.Then) { + vsvc := t.GetVirtualService() + assert.Equal(s.T(), "mirror-route-2", vsvc.Spec.HTTP[0].Name) + assertMirrorDestination(s, vsvc.Spec.HTTP[0], "stable-service", int64(60)) + assertMirrorDestination(s, vsvc.Spec.HTTP[0], "canary-service", int64(40)) + assert.Equal(s.T(), "primary", vsvc.Spec.HTTP[1].Name) + assertMirrorDestination(s, vsvc.Spec.HTTP[1], "stable-service", int64(60)) + assertMirrorDestination(s, vsvc.Spec.HTTP[1], "canary-service", int64(40)) + }). + When(). + PromoteRolloutFull(). + WaitForRolloutStatus("Healthy"). + Sleep(1 * time.Second). + Then(). + Assert(func(t *fixtures.Then) { + vsvc := t.GetVirtualService() + assert.Equal(s.T(), 1, len(vsvc.Spec.HTTP)) + assertMirrorDestination(s, vsvc.Spec.HTTP[0], "stable-service", int64(100)) + assertMirrorDestination(s, vsvc.Spec.HTTP[0], "canary-service", int64(0)) + }) +} + +func assertMirrorDestination(s *MirrorRouteSuite, route istio.VirtualServiceHTTPRoute, service string, weight int64) { + for _, destination := range route.Route { + if destination.Destination.Host == service { + assert.Equal(s.T(), weight, destination.Weight) + return + } + } + assert.Fail(s.T(), "Could not find the destination for service: %s", service) +} diff --git a/test/fixtures/e2e_suite.go b/test/fixtures/e2e_suite.go index fdac7fcd3f..f9ab48c1ee 100644 --- a/test/fixtures/e2e_suite.go +++ b/test/fixtures/e2e_suite.go @@ -52,7 +52,7 @@ const ( ) var ( - E2EWaitTimeout time.Duration = time.Second * 90 + E2EWaitTimeout time.Duration = time.Second * 120 E2EPodDelay = 0 E2EALBIngressAnnotations map[string]string diff --git a/ui/package.json b/ui/package.json index 898f96cf6b..15627c8da8 100644 --- a/ui/package.json +++ b/ui/package.json @@ -5,6 +5,7 @@ "dependencies": { "argo-ui": "git+https://github.com/argoproj/argo-ui.git", "classnames": "2.2.6", + "isomorphic-fetch": "^3.0.0", "moment": "^2.29.1", "moment-timezone": "^0.5.33", "portable-fetch": "^3.0.0", diff --git a/ui/src/app/components/rollout/rollout.tsx b/ui/src/app/components/rollout/rollout.tsx index 9b2a962244..6c3f3a0393 100644 --- a/ui/src/app/components/rollout/rollout.tsx +++ b/ui/src/app/components/rollout/rollout.tsx @@ -5,7 +5,9 @@ import {Key, KeybindingContext} from 'react-keyhooks'; import {useHistory, useParams} from 'react-router-dom'; import { GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStep, + GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1HeaderRoutingMatch, GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutExperimentTemplate, + GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetMirrorRoute, RolloutReplicaSetInfo, RolloutRolloutInfo, RolloutServiceApi, @@ -128,11 +130,11 @@ export const RolloutWidget = (props: {rollout: RolloutRolloutInfo; interactive?: interactive={ interactive ? { - editState: interactive.editState, - setImage: (container, image, tag) => { - interactive.api.rolloutServiceSetRolloutImage({}, interactive.namespace, rollout.objectMeta?.name, container, image, tag); - }, - } + editState: interactive.editState, + setImage: (container, image, tag) => { + interactive.api.rolloutServiceSetRolloutImage({}, interactive.namespace, rollout.objectMeta?.name, container, image, tag); + }, + } : null } /> @@ -279,6 +281,8 @@ const Step = (props: {step: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1 const [openedTemplate, setOpenedTemplate] = React.useState(''); const [openCanary, setOpenCanary] = React.useState(false); const [openAnalysis, setOpenAnalysis] = React.useState(false); + const [openHeader, setOpenHeader] = React.useState(false); + const [openMirror, setOpenMirror] = React.useState(false); let icon: string; let content = ''; @@ -308,12 +312,27 @@ const Step = (props: {step: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1 icon = 'fa-flask'; } + if (props.step.setMirrorRoute) { + content = `Set Mirror: ${props.step.setMirrorRoute.name}`; + if(!props.step.setMirrorRoute.match) { + content = `Remove Mirror: ${props.step.setMirrorRoute.name}`; + } + } + + if (props.step.setHeaderRoute) { + content = `Set Header: ${props.step.setHeaderRoute.name}`; + if (!props.step.setHeaderRoute.match) { + content = `Remove Header: ${props.step.setHeaderRoute.name}`; + } + } + return (
{icon && } {content} {unit} @@ -327,6 +346,17 @@ const Step = (props: {step: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1 )} + + {props.step.setHeaderRoute && props.step.setHeaderRoute.match &&( + setOpenHeader(!openHeader)}> + + + )} + {props.step.setMirrorRoute && props.step.setMirrorRoute.match && ( + setOpenMirror(!openMirror)}> + + + )}
{props.step.experiment?.templates && (
@@ -351,17 +381,15 @@ const Step = (props: {step: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1
)} {props.step?.setCanaryScale && openCanary && } + {props.step?.setHeaderRoute && openHeader && } + {props.step?.setMirrorRoute && openMirror && }
{!props.last && }
); }; -const ExperimentWidget = ({ - template, - opened, - onToggle, -}: { +const ExperimentWidget = ({template, opened, onToggle}: { template: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutExperimentTemplate; opened: boolean; onToggle: (name: string) => void; @@ -395,3 +423,81 @@ const WidgetItem = ({values}: {values: Record}) => { ); }; + +const WidgetItemSetMirror = ({value}: {value: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetMirrorRoute}) => { + if (!value) return null; + return ( + + +
Name
+
{value.name}
+
Percentage
+
{value.percentage}
+ {Object.values(value.match).map((val, index) => { + if (!val) return null; + let stringMatcherValue = "" + let stringMatcherType = "" + let fragments = [] + if (val.path != null) { + if(val.path.exact != null) {stringMatcherValue = val.path.exact; stringMatcherType="Exact"} + if(val.path.prefix != null) {stringMatcherValue = val.path.prefix; stringMatcherType="Prefix"} + if(val.path.regex != null) {stringMatcherValue = val.path.regex; stringMatcherType="Regex"} + fragments.push( + +
{index} - Path ({stringMatcherType})
+
{stringMatcherValue}
+
+ ); + } + if (val.method != null) { + if(val.method.exact != null) {stringMatcherValue = val.method.exact; stringMatcherType="Exact"} + if(val.method.prefix != null) {stringMatcherValue = val.method.prefix; stringMatcherType="Prefix"} + if(val.method.regex != null) {stringMatcherValue = val.method.regex; stringMatcherType="Regex"} + fragments.push( + +
{index} - Method ({stringMatcherType})
+
{stringMatcherValue}
+
+ ); + } + return fragments + })} +
+
+ ); +}; + +const WidgetItemSetHeader = ({values}: {values: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1HeaderRoutingMatch[]}) => { + if (!values) return null; + return ( + + {values.map((record) => { + if (!record.headerName) return null; + if (!record.headerValue) return null; + + let headerValue = "" + let headerValueType = "" + if (record.headerValue.regex) { + headerValue = record.headerValue.regex + headerValueType = "Regex" + } + if (record.headerValue.prefix) { + headerValue = record.headerValue.prefix + headerValueType = "Prefix" + } + if (record.headerValue.exact) { + headerValue = record.headerValue.exact + headerValueType = "Exact" + } + return ( + +
Name
+
{record.headerName}
+
{headerValueType}
+
{headerValue}
+
+ ); + })} +
+ ); +}; diff --git a/ui/src/models/rollout/generated/api.ts b/ui/src/models/rollout/generated/api.ts index 1b4336be76..dcfeec0a3e 100644 --- a/ui/src/models/rollout/generated/api.ts +++ b/ui/src/models/rollout/generated/api.ts @@ -526,10 +526,16 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStep setCanaryScale?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetCanaryScale; /** * - * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetHeaderRouting} + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetHeaderRoute} * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStep */ - setHeaderRouting?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetHeaderRouting; + setHeaderRoute?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetHeaderRoute; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetMirrorRoute} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1CanaryStep + */ + setMirrorRoute?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetMirrorRoute; } /** * @@ -748,6 +754,19 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1IstioVirtua */ tlsRoutes?: Array; } +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MangedRoutes + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MangedRoutes { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1MangedRoutes + */ + name?: string; +} /** * MeasurementRetention defines the settings for retaining the number of measurements during the analysis. * @export @@ -1477,6 +1496,37 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutTraf * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutTrafficRouting */ traefik?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1TraefikTrafficRouting; + /** + * A list of HTTP routes that Argo Rollouts manages, the order of this array also becomes the precedence in the upstream traffic router. + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RolloutTrafficRouting + */ + managedRoutes?: Array; +} +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RouteMatch + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RouteMatch { + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RouteMatch + */ + method?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch; + /** + * + * @type {GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RouteMatch + */ + path?: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch; + /** + * + * @type {{ [key: string]: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch; }} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1RouteMatch + */ + headers?: { [key: string]: GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1StringMatch; }; } /** * @@ -1525,16 +1575,47 @@ export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetCanarySc /** * * @export - * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetHeaderRouting + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetHeaderRoute */ -export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetHeaderRouting { +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetHeaderRoute { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetHeaderRoute + */ + name?: string; /** * * @type {Array} - * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetHeaderRouting + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetHeaderRoute */ match?: Array; } +/** + * + * @export + * @interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetMirrorRoute + */ +export interface GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetMirrorRoute { + /** + * + * @type {string} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetMirrorRoute + */ + name?: string; + /** + * + * @type {Array} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetMirrorRoute + */ + match?: Array; + /** + * + * @type {number} + * @memberof GithubComArgoprojArgoRolloutsPkgApisRolloutsV1alpha1SetMirrorRoute + */ + percentage?: number; +} /** * * @export diff --git a/utils/replicaset/canary.go b/utils/replicaset/canary.go index 8a015f7b7d..ae77bc04f0 100644 --- a/utils/replicaset/canary.go +++ b/utils/replicaset/canary.go @@ -474,19 +474,6 @@ func GetCurrentSetWeight(rollout *v1alpha1.Rollout) int32 { return 0 } -func GetCurrentSetHeaderRouting(rollout *v1alpha1.Rollout, index int32) *v1alpha1.SetHeaderRouting { - if int32(len(rollout.Spec.Strategy.Canary.Steps)) == index { - index-- - } - for i := index; i >= 0; i-- { - step := rollout.Spec.Strategy.Canary.Steps[i] - if step.SetHeaderRouting != nil { - return step.SetHeaderRouting - } - } - return nil -} - // UseSetCanaryScale will return a SetCanaryScale if specified and should be used, returns nil otherwise. // TrafficRouting is required to be set for SetCanaryScale to be applicable. // If MatchTrafficWeight is set after a previous SetCanaryScale step, it will likewise be ignored. diff --git a/utils/replicaset/canary_test.go b/utils/replicaset/canary_test.go index e111043362..b341bb06e6 100644 --- a/utils/replicaset/canary_test.go +++ b/utils/replicaset/canary_test.go @@ -4,7 +4,6 @@ import ( "fmt" "testing" - "github.com/aws/smithy-go/ptr" "github.com/stretchr/testify/assert" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -1015,41 +1014,6 @@ func TestGetCurrentSetWeight(t *testing.T) { } -func TestGetCurrentSetHeaderRouting(t *testing.T) { - rollout := newRollout(10, 10, intstr.FromInt(0), intstr.FromInt(1), "", "", nil, nil) - setHeaderRoutingStep := v1alpha1.SetHeaderRouting{ - Match: []v1alpha1.HeaderRoutingMatch{ - { - HeaderName: "agent", - }, - { - HeaderName: "agent2", - HeaderValue: v1alpha1.StringMatch{Exact: "value"}, - }, - { - HeaderName: "agent3", - HeaderValue: v1alpha1.StringMatch{Regex: "regexValue(.*)"}, - }, - }, - } - rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{ - {SetWeight: ptr.Int32(20)}, - {Pause: &v1alpha1.RolloutPause{}}, - {SetHeaderRouting: &setHeaderRoutingStep}, - {SetWeight: ptr.Int32(40)}, - {Pause: &v1alpha1.RolloutPause{}}, - {SetHeaderRouting: &v1alpha1.SetHeaderRouting{}}, - } - - assert.Nil(t, GetCurrentSetHeaderRouting(rollout, 0)) - assert.Nil(t, GetCurrentSetHeaderRouting(rollout, 1)) - assert.Equal(t, &setHeaderRoutingStep, GetCurrentSetHeaderRouting(rollout, 2)) - assert.Equal(t, &setHeaderRoutingStep, GetCurrentSetHeaderRouting(rollout, 3)) - assert.Equal(t, &setHeaderRoutingStep, GetCurrentSetHeaderRouting(rollout, 4)) - assert.Nil(t, GetCurrentSetHeaderRouting(rollout, 5).Match) - assert.Nil(t, GetCurrentSetHeaderRouting(rollout, 6).Match) -} - func TestAtDesiredReplicaCountsForCanary(t *testing.T) { t.Run("we are at desired replica counts and availability", func(t *testing.T) { From 26813cff6f0c70dbe4c0ed90527068a5ba2d72b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Bezerra?= Date: Thu, 30 Jun 2022 14:59:48 -0300 Subject: [PATCH 149/175] chore: improve openapi schema (#2081) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: include all CRDs to the OpenAPI schema Signed-off-by: Mário Bezerra * feat: use kube-openapi naming convention in the OpenAPI schema Signed-off-by: Mário Bezerra * chore: generate OpenAPI schema Signed-off-by: Mário Bezerra --- .../features/kustomize/rollout_cr_schema.json | 16594 +++++++++++++++- hack/gen-crd-spec/main.go | 7 +- 2 files changed, 16596 insertions(+), 5 deletions(-) diff --git a/docs/features/kustomize/rollout_cr_schema.json b/docs/features/kustomize/rollout_cr_schema.json index 7b57b232e1..729c0bfdf0 100644 --- a/docs/features/kustomize/rollout_cr_schema.json +++ b/docs/features/kustomize/rollout_cr_schema.json @@ -1,6 +1,16598 @@ { "definitions": { - "v1alpha1.Rollout": { + "io.argoproj.v1alpha1.AnalysisRun": { + "properties": { + "spec": { + "properties": { + "args": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "properties": { + "fieldRef": { + "properties": { + "fieldPath": { + "type": "string" + } + }, + "required": [ + "fieldPath" + ], + "type": "object" + }, + "secretKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "key", + "name" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "name", + "x-kubernetes-patch-strategy": "merge" + }, + "dryRun": { + "items": { + "properties": { + "metricName": { + "type": "string" + } + }, + "required": [ + "metricName" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge" + }, + "measurementRetention": { + "items": { + "properties": { + "limit": { + "format": "int32", + "type": "integer" + }, + "metricName": { + "type": "string" + } + }, + "required": [ + "limit", + "metricName" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge" + }, + "metrics": { + "items": { + "properties": { + "consecutiveErrorLimit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "failureCondition": { + "type": "string" + }, + "failureLimit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "inconclusiveLimit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "initialDelay": { + "type": "string" + }, + "interval": { + "type": "string" + }, + "name": { + "type": "string" + }, + "provider": { + "properties": { + "cloudWatch": { + "properties": { + "interval": { + "type": "string" + }, + "metricDataQueries": { + "items": { + "properties": { + "expression": { + "type": "string" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "metricStat": { + "properties": { + "metric": { + "properties": { + "dimensions": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "metricName": { + "type": "string" + }, + "namespace": { + "type": "string" + } + }, + "type": "object" + }, + "period": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "stat": { + "type": "string" + }, + "unit": { + "type": "string" + } + }, + "type": "object" + }, + "period": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "returnData": { + "type": "boolean" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "metricDataQueries" + ], + "type": "object" + }, + "datadog": { + "properties": { + "interval": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "required": [ + "query" + ], + "type": "object" + }, + "graphite": { + "properties": { + "address": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "type": "object" + }, + "job": { + "properties": { + "metadata": { + "properties": { + "annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + "labels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "spec": { + "properties": { + "activeDeadlineSeconds": { + "format": "int64", + "type": "integer" + }, + "backoffLimit": { + "format": "int32", + "type": "integer" + }, + "completionMode": { + "type": "string" + }, + "completions": { + "format": "int32", + "type": "integer" + }, + "manualSelector": { + "type": "boolean" + }, + "parallelism": { + "format": "int32", + "type": "integer" + }, + "selector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "suspend": { + "type": "boolean" + }, + "template": { + "properties": { + "metadata": { + "properties": { + "annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + "labels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "spec": { + "properties": { + "activeDeadlineSeconds": { + "format": "int64", + "type": "integer" + }, + "affinity": { + "properties": { + "nodeAffinity": { + "properties": { + "preferredDuringSchedulingIgnoredDuringExecution": { + "items": { + "properties": { + "preference": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchFields": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "weight": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "preference", + "weight" + ], + "type": "object" + }, + "type": "array" + }, + "requiredDuringSchedulingIgnoredDuringExecution": { + "properties": { + "nodeSelectorTerms": { + "items": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchFields": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "nodeSelectorTerms" + ], + "type": "object" + } + }, + "type": "object" + }, + "podAffinity": { + "properties": { + "preferredDuringSchedulingIgnoredDuringExecution": { + "items": { + "properties": { + "podAffinityTerm": { + "properties": { + "labelSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaceSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaces": { + "items": { + "type": "string" + }, + "type": "array" + }, + "topologyKey": { + "type": "string" + } + }, + "required": [ + "topologyKey" + ], + "type": "object" + }, + "weight": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "podAffinityTerm", + "weight" + ], + "type": "object" + }, + "type": "array" + }, + "requiredDuringSchedulingIgnoredDuringExecution": { + "items": { + "properties": { + "labelSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaceSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaces": { + "items": { + "type": "string" + }, + "type": "array" + }, + "topologyKey": { + "type": "string" + } + }, + "required": [ + "topologyKey" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "podAntiAffinity": { + "properties": { + "preferredDuringSchedulingIgnoredDuringExecution": { + "items": { + "properties": { + "podAffinityTerm": { + "properties": { + "labelSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaceSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaces": { + "items": { + "type": "string" + }, + "type": "array" + }, + "topologyKey": { + "type": "string" + } + }, + "required": [ + "topologyKey" + ], + "type": "object" + }, + "weight": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "podAffinityTerm", + "weight" + ], + "type": "object" + }, + "type": "array" + }, + "requiredDuringSchedulingIgnoredDuringExecution": { + "items": { + "properties": { + "labelSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaceSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaces": { + "items": { + "type": "string" + }, + "type": "array" + }, + "topologyKey": { + "type": "string" + } + }, + "required": [ + "topologyKey" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "automountServiceAccountToken": { + "type": "boolean" + }, + "containers": { + "items": { + "properties": { + "args": { + "items": { + "type": "string" + }, + "type": "array" + }, + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "properties": { + "configMapKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + }, + "fieldRef": { + "properties": { + "apiVersion": { + "type": "string" + }, + "fieldPath": { + "type": "string" + } + }, + "required": [ + "fieldPath" + ], + "type": "object" + }, + "resourceFieldRef": { + "properties": { + "containerName": { + "type": "string" + }, + "divisor": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "x-kubernetes-int-or-string": true + }, + "resource": { + "type": "string" + } + }, + "required": [ + "resource" + ], + "type": "object" + }, + "secretKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "envFrom": { + "items": { + "properties": { + "configMapRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + }, + "prefix": { + "type": "string" + }, + "secretRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "image": { + "type": "string" + }, + "imagePullPolicy": { + "type": "string" + }, + "lifecycle": { + "properties": { + "postStart": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + }, + "preStop": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "livenessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "ports": { + "items": { + "properties": { + "containerPort": { + "format": "int32", + "type": "integer" + }, + "hostIP": { + "type": "string" + }, + "hostPort": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "protocol": { + "default": "TCP", + "type": "string" + } + }, + "required": [ + "containerPort" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-map-keys": [ + "containerPort", + "protocol" + ], + "x-kubernetes-list-type": "map" + }, + "readinessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "resources": { + "properties": { + "limits": { + "x-kubernetes-preserve-unknown-fields": true + }, + "requests": { + "x-kubernetes-preserve-unknown-fields": true + } + }, + "type": "object" + }, + "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "properties": { + "add": { + "items": { + "type": "string" + }, + "type": "array" + }, + "drop": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "privileged": { + "type": "boolean" + }, + "procMount": { + "type": "string" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "format": "int64", + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "format": "int64", + "type": "integer" + }, + "seLinuxOptions": { + "properties": { + "level": { + "type": "string" + }, + "role": { + "type": "string" + }, + "type": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + }, + "seccompProfile": { + "properties": { + "localhostProfile": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "windowsOptions": { + "properties": { + "gmsaCredentialSpec": { + "type": "string" + }, + "gmsaCredentialSpecName": { + "type": "string" + }, + "hostProcess": { + "type": "boolean" + }, + "runAsUserName": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "startupProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "stdin": { + "type": "boolean" + }, + "stdinOnce": { + "type": "boolean" + }, + "terminationMessagePath": { + "type": "string" + }, + "terminationMessagePolicy": { + "type": "string" + }, + "tty": { + "type": "boolean" + }, + "volumeDevices": { + "items": { + "properties": { + "devicePath": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "devicePath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "volumeMounts": { + "items": { + "properties": { + "mountPath": { + "type": "string" + }, + "mountPropagation": { + "type": "string" + }, + "name": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + }, + "subPath": { + "type": "string" + }, + "subPathExpr": { + "type": "string" + } + }, + "required": [ + "mountPath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "workingDir": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "dnsConfig": { + "properties": { + "nameservers": { + "items": { + "type": "string" + }, + "type": "array" + }, + "options": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "searches": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "dnsPolicy": { + "type": "string" + }, + "enableServiceLinks": { + "type": "boolean" + }, + "ephemeralContainers": { + "items": { + "properties": { + "args": { + "items": { + "type": "string" + }, + "type": "array" + }, + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "properties": { + "configMapKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + }, + "fieldRef": { + "properties": { + "apiVersion": { + "type": "string" + }, + "fieldPath": { + "type": "string" + } + }, + "required": [ + "fieldPath" + ], + "type": "object" + }, + "resourceFieldRef": { + "properties": { + "containerName": { + "type": "string" + }, + "divisor": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "x-kubernetes-int-or-string": true + }, + "resource": { + "type": "string" + } + }, + "required": [ + "resource" + ], + "type": "object" + }, + "secretKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "envFrom": { + "items": { + "properties": { + "configMapRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + }, + "prefix": { + "type": "string" + }, + "secretRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "image": { + "type": "string" + }, + "imagePullPolicy": { + "type": "string" + }, + "lifecycle": { + "properties": { + "postStart": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + }, + "preStop": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "livenessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "ports": { + "items": { + "properties": { + "containerPort": { + "format": "int32", + "type": "integer" + }, + "hostIP": { + "type": "string" + }, + "hostPort": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "protocol": { + "default": "TCP", + "type": "string" + } + }, + "required": [ + "containerPort" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-map-keys": [ + "containerPort", + "protocol" + ], + "x-kubernetes-list-type": "map" + }, + "readinessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "resources": { + "properties": { + "limits": { + "x-kubernetes-preserve-unknown-fields": true + }, + "requests": { + "x-kubernetes-preserve-unknown-fields": true + } + }, + "type": "object" + }, + "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "properties": { + "add": { + "items": { + "type": "string" + }, + "type": "array" + }, + "drop": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "privileged": { + "type": "boolean" + }, + "procMount": { + "type": "string" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "format": "int64", + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "format": "int64", + "type": "integer" + }, + "seLinuxOptions": { + "properties": { + "level": { + "type": "string" + }, + "role": { + "type": "string" + }, + "type": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + }, + "seccompProfile": { + "properties": { + "localhostProfile": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "windowsOptions": { + "properties": { + "gmsaCredentialSpec": { + "type": "string" + }, + "gmsaCredentialSpecName": { + "type": "string" + }, + "hostProcess": { + "type": "boolean" + }, + "runAsUserName": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "startupProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "stdin": { + "type": "boolean" + }, + "stdinOnce": { + "type": "boolean" + }, + "targetContainerName": { + "type": "string" + }, + "terminationMessagePath": { + "type": "string" + }, + "terminationMessagePolicy": { + "type": "string" + }, + "tty": { + "type": "boolean" + }, + "volumeDevices": { + "items": { + "properties": { + "devicePath": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "devicePath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "volumeMounts": { + "items": { + "properties": { + "mountPath": { + "type": "string" + }, + "mountPropagation": { + "type": "string" + }, + "name": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + }, + "subPath": { + "type": "string" + }, + "subPathExpr": { + "type": "string" + } + }, + "required": [ + "mountPath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "workingDir": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "hostAliases": { + "items": { + "properties": { + "hostnames": { + "items": { + "type": "string" + }, + "type": "array" + }, + "ip": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "hostIPC": { + "type": "boolean" + }, + "hostNetwork": { + "type": "boolean" + }, + "hostPID": { + "type": "boolean" + }, + "hostname": { + "type": "string" + }, + "imagePullSecrets": { + "items": { + "properties": { + "name": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "initContainers": { + "items": { + "properties": { + "args": { + "items": { + "type": "string" + }, + "type": "array" + }, + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "properties": { + "configMapKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + }, + "fieldRef": { + "properties": { + "apiVersion": { + "type": "string" + }, + "fieldPath": { + "type": "string" + } + }, + "required": [ + "fieldPath" + ], + "type": "object" + }, + "resourceFieldRef": { + "properties": { + "containerName": { + "type": "string" + }, + "divisor": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "x-kubernetes-int-or-string": true + }, + "resource": { + "type": "string" + } + }, + "required": [ + "resource" + ], + "type": "object" + }, + "secretKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "envFrom": { + "items": { + "properties": { + "configMapRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + }, + "prefix": { + "type": "string" + }, + "secretRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "image": { + "type": "string" + }, + "imagePullPolicy": { + "type": "string" + }, + "lifecycle": { + "properties": { + "postStart": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + }, + "preStop": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "livenessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "ports": { + "items": { + "properties": { + "containerPort": { + "format": "int32", + "type": "integer" + }, + "hostIP": { + "type": "string" + }, + "hostPort": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "protocol": { + "default": "TCP", + "type": "string" + } + }, + "required": [ + "containerPort" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-map-keys": [ + "containerPort", + "protocol" + ], + "x-kubernetes-list-type": "map" + }, + "readinessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "resources": { + "properties": { + "limits": { + "x-kubernetes-preserve-unknown-fields": true + }, + "requests": { + "x-kubernetes-preserve-unknown-fields": true + } + }, + "type": "object" + }, + "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "properties": { + "add": { + "items": { + "type": "string" + }, + "type": "array" + }, + "drop": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "privileged": { + "type": "boolean" + }, + "procMount": { + "type": "string" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "format": "int64", + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "format": "int64", + "type": "integer" + }, + "seLinuxOptions": { + "properties": { + "level": { + "type": "string" + }, + "role": { + "type": "string" + }, + "type": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + }, + "seccompProfile": { + "properties": { + "localhostProfile": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "windowsOptions": { + "properties": { + "gmsaCredentialSpec": { + "type": "string" + }, + "gmsaCredentialSpecName": { + "type": "string" + }, + "hostProcess": { + "type": "boolean" + }, + "runAsUserName": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "startupProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "stdin": { + "type": "boolean" + }, + "stdinOnce": { + "type": "boolean" + }, + "terminationMessagePath": { + "type": "string" + }, + "terminationMessagePolicy": { + "type": "string" + }, + "tty": { + "type": "boolean" + }, + "volumeDevices": { + "items": { + "properties": { + "devicePath": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "devicePath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "volumeMounts": { + "items": { + "properties": { + "mountPath": { + "type": "string" + }, + "mountPropagation": { + "type": "string" + }, + "name": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + }, + "subPath": { + "type": "string" + }, + "subPathExpr": { + "type": "string" + } + }, + "required": [ + "mountPath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "workingDir": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "nodeName": { + "type": "string" + }, + "nodeSelector": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "x-kubernetes-map-type": "atomic" + }, + "os": { + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "overhead": { + "additionalProperties": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "x-kubernetes-int-or-string": true + }, + "type": "object" + }, + "preemptionPolicy": { + "type": "string" + }, + "priority": { + "format": "int32", + "type": "integer" + }, + "priorityClassName": { + "type": "string" + }, + "readinessGates": { + "items": { + "properties": { + "conditionType": { + "type": "string" + } + }, + "required": [ + "conditionType" + ], + "type": "object" + }, + "type": "array" + }, + "restartPolicy": { + "type": "string" + }, + "runtimeClassName": { + "type": "string" + }, + "schedulerName": { + "type": "string" + }, + "securityContext": { + "properties": { + "fsGroup": { + "format": "int64", + "type": "integer" + }, + "fsGroupChangePolicy": { + "type": "string" + }, + "runAsGroup": { + "format": "int64", + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "format": "int64", + "type": "integer" + }, + "seLinuxOptions": { + "properties": { + "level": { + "type": "string" + }, + "role": { + "type": "string" + }, + "type": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + }, + "seccompProfile": { + "properties": { + "localhostProfile": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "supplementalGroups": { + "items": { + "format": "int64", + "type": "integer" + }, + "type": "array" + }, + "sysctls": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "windowsOptions": { + "properties": { + "gmsaCredentialSpec": { + "type": "string" + }, + "gmsaCredentialSpecName": { + "type": "string" + }, + "hostProcess": { + "type": "boolean" + }, + "runAsUserName": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "serviceAccount": { + "type": "string" + }, + "serviceAccountName": { + "type": "string" + }, + "setHostnameAsFQDN": { + "type": "boolean" + }, + "shareProcessNamespace": { + "type": "boolean" + }, + "subdomain": { + "type": "string" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "tolerations": { + "items": { + "properties": { + "effect": { + "type": "string" + }, + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "tolerationSeconds": { + "format": "int64", + "type": "integer" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "topologySpreadConstraints": { + "items": { + "properties": { + "labelSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "maxSkew": { + "format": "int32", + "type": "integer" + }, + "topologyKey": { + "type": "string" + }, + "whenUnsatisfiable": { + "type": "string" + } + }, + "required": [ + "maxSkew", + "topologyKey", + "whenUnsatisfiable" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-map-keys": [ + "topologyKey", + "whenUnsatisfiable" + ], + "x-kubernetes-list-type": "map" + }, + "volumes": { + "x-kubernetes-preserve-unknown-fields": true + } + }, + "required": [ + "containers" + ], + "type": "object" + } + }, + "type": "object" + }, + "ttlSecondsAfterFinished": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "template" + ], + "type": "object" + } + }, + "required": [ + "spec" + ], + "type": "object" + }, + "kayenta": { + "properties": { + "address": { + "type": "string" + }, + "application": { + "type": "string" + }, + "canaryConfigName": { + "type": "string" + }, + "configurationAccountName": { + "type": "string" + }, + "metricsAccountName": { + "type": "string" + }, + "scopes": { + "items": { + "properties": { + "controlScope": { + "properties": { + "end": { + "type": "string" + }, + "region": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "start": { + "type": "string" + }, + "step": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "end", + "region", + "scope", + "start", + "step" + ], + "type": "object" + }, + "experimentScope": { + "properties": { + "end": { + "type": "string" + }, + "region": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "start": { + "type": "string" + }, + "step": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "end", + "region", + "scope", + "start", + "step" + ], + "type": "object" + }, + "name": { + "type": "string" + } + }, + "required": [ + "controlScope", + "experimentScope", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "storageAccountName": { + "type": "string" + }, + "threshold": { + "properties": { + "marginal": { + "format": "int64", + "type": "integer" + }, + "pass": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "marginal", + "pass" + ], + "type": "object" + } + }, + "required": [ + "address", + "application", + "canaryConfigName", + "configurationAccountName", + "metricsAccountName", + "scopes", + "storageAccountName", + "threshold" + ], + "type": "object" + }, + "newRelic": { + "properties": { + "profile": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "required": [ + "query" + ], + "type": "object" + }, + "prometheus": { + "properties": { + "address": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "type": "object" + }, + "wavefront": { + "properties": { + "address": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "type": "object" + }, + "web": { + "properties": { + "body": { + "type": "string" + }, + "headers": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "key", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "insecure": { + "type": "boolean" + }, + "jsonPath": { + "type": "string" + }, + "method": { + "type": "string" + }, + "timeoutSeconds": { + "format": "int64", + "type": "integer" + }, + "url": { + "type": "string" + } + }, + "required": [ + "url" + ], + "type": "object" + } + }, + "type": "object" + }, + "successCondition": { + "type": "string" + } + }, + "required": [ + "name", + "provider" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "name", + "x-kubernetes-patch-strategy": "merge" + } + }, + "required": [ + "metrics" + ], + "type": "object" + } + }, + "x-kubernetes-group-version-kind": [ + { + "group": "argoproj.io", + "kind": "AnalysisRun", + "version": "v1alpha1" + } + ] + }, + "io.argoproj.v1alpha1.AnalysisTemplate": { + "properties": { + "spec": { + "properties": { + "args": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "properties": { + "fieldRef": { + "properties": { + "fieldPath": { + "type": "string" + } + }, + "required": [ + "fieldPath" + ], + "type": "object" + }, + "secretKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "key", + "name" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "name", + "x-kubernetes-patch-strategy": "merge" + }, + "dryRun": { + "items": { + "properties": { + "metricName": { + "type": "string" + } + }, + "required": [ + "metricName" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge" + }, + "measurementRetention": { + "items": { + "properties": { + "limit": { + "format": "int32", + "type": "integer" + }, + "metricName": { + "type": "string" + } + }, + "required": [ + "limit", + "metricName" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge" + }, + "metrics": { + "items": { + "properties": { + "consecutiveErrorLimit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "failureCondition": { + "type": "string" + }, + "failureLimit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "inconclusiveLimit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "initialDelay": { + "type": "string" + }, + "interval": { + "type": "string" + }, + "name": { + "type": "string" + }, + "provider": { + "properties": { + "cloudWatch": { + "properties": { + "interval": { + "type": "string" + }, + "metricDataQueries": { + "items": { + "properties": { + "expression": { + "type": "string" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "metricStat": { + "properties": { + "metric": { + "properties": { + "dimensions": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "metricName": { + "type": "string" + }, + "namespace": { + "type": "string" + } + }, + "type": "object" + }, + "period": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "stat": { + "type": "string" + }, + "unit": { + "type": "string" + } + }, + "type": "object" + }, + "period": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "returnData": { + "type": "boolean" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "metricDataQueries" + ], + "type": "object" + }, + "datadog": { + "properties": { + "interval": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "required": [ + "query" + ], + "type": "object" + }, + "graphite": { + "properties": { + "address": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "type": "object" + }, + "job": { + "properties": { + "metadata": { + "properties": { + "annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + "labels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "spec": { + "properties": { + "activeDeadlineSeconds": { + "format": "int64", + "type": "integer" + }, + "backoffLimit": { + "format": "int32", + "type": "integer" + }, + "completionMode": { + "type": "string" + }, + "completions": { + "format": "int32", + "type": "integer" + }, + "manualSelector": { + "type": "boolean" + }, + "parallelism": { + "format": "int32", + "type": "integer" + }, + "selector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "suspend": { + "type": "boolean" + }, + "template": { + "properties": { + "metadata": { + "properties": { + "annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + "labels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "spec": { + "properties": { + "activeDeadlineSeconds": { + "format": "int64", + "type": "integer" + }, + "affinity": { + "properties": { + "nodeAffinity": { + "properties": { + "preferredDuringSchedulingIgnoredDuringExecution": { + "items": { + "properties": { + "preference": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchFields": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "weight": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "preference", + "weight" + ], + "type": "object" + }, + "type": "array" + }, + "requiredDuringSchedulingIgnoredDuringExecution": { + "properties": { + "nodeSelectorTerms": { + "items": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchFields": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "nodeSelectorTerms" + ], + "type": "object" + } + }, + "type": "object" + }, + "podAffinity": { + "properties": { + "preferredDuringSchedulingIgnoredDuringExecution": { + "items": { + "properties": { + "podAffinityTerm": { + "properties": { + "labelSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaceSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaces": { + "items": { + "type": "string" + }, + "type": "array" + }, + "topologyKey": { + "type": "string" + } + }, + "required": [ + "topologyKey" + ], + "type": "object" + }, + "weight": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "podAffinityTerm", + "weight" + ], + "type": "object" + }, + "type": "array" + }, + "requiredDuringSchedulingIgnoredDuringExecution": { + "items": { + "properties": { + "labelSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaceSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaces": { + "items": { + "type": "string" + }, + "type": "array" + }, + "topologyKey": { + "type": "string" + } + }, + "required": [ + "topologyKey" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "podAntiAffinity": { + "properties": { + "preferredDuringSchedulingIgnoredDuringExecution": { + "items": { + "properties": { + "podAffinityTerm": { + "properties": { + "labelSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaceSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaces": { + "items": { + "type": "string" + }, + "type": "array" + }, + "topologyKey": { + "type": "string" + } + }, + "required": [ + "topologyKey" + ], + "type": "object" + }, + "weight": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "podAffinityTerm", + "weight" + ], + "type": "object" + }, + "type": "array" + }, + "requiredDuringSchedulingIgnoredDuringExecution": { + "items": { + "properties": { + "labelSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaceSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaces": { + "items": { + "type": "string" + }, + "type": "array" + }, + "topologyKey": { + "type": "string" + } + }, + "required": [ + "topologyKey" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "automountServiceAccountToken": { + "type": "boolean" + }, + "containers": { + "items": { + "properties": { + "args": { + "items": { + "type": "string" + }, + "type": "array" + }, + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "properties": { + "configMapKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + }, + "fieldRef": { + "properties": { + "apiVersion": { + "type": "string" + }, + "fieldPath": { + "type": "string" + } + }, + "required": [ + "fieldPath" + ], + "type": "object" + }, + "resourceFieldRef": { + "properties": { + "containerName": { + "type": "string" + }, + "divisor": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "x-kubernetes-int-or-string": true + }, + "resource": { + "type": "string" + } + }, + "required": [ + "resource" + ], + "type": "object" + }, + "secretKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "envFrom": { + "items": { + "properties": { + "configMapRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + }, + "prefix": { + "type": "string" + }, + "secretRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "image": { + "type": "string" + }, + "imagePullPolicy": { + "type": "string" + }, + "lifecycle": { + "properties": { + "postStart": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + }, + "preStop": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "livenessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "ports": { + "items": { + "properties": { + "containerPort": { + "format": "int32", + "type": "integer" + }, + "hostIP": { + "type": "string" + }, + "hostPort": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "protocol": { + "default": "TCP", + "type": "string" + } + }, + "required": [ + "containerPort" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-map-keys": [ + "containerPort", + "protocol" + ], + "x-kubernetes-list-type": "map" + }, + "readinessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "resources": { + "properties": { + "limits": { + "x-kubernetes-preserve-unknown-fields": true + }, + "requests": { + "x-kubernetes-preserve-unknown-fields": true + } + }, + "type": "object" + }, + "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "properties": { + "add": { + "items": { + "type": "string" + }, + "type": "array" + }, + "drop": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "privileged": { + "type": "boolean" + }, + "procMount": { + "type": "string" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "format": "int64", + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "format": "int64", + "type": "integer" + }, + "seLinuxOptions": { + "properties": { + "level": { + "type": "string" + }, + "role": { + "type": "string" + }, + "type": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + }, + "seccompProfile": { + "properties": { + "localhostProfile": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "windowsOptions": { + "properties": { + "gmsaCredentialSpec": { + "type": "string" + }, + "gmsaCredentialSpecName": { + "type": "string" + }, + "hostProcess": { + "type": "boolean" + }, + "runAsUserName": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "startupProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "stdin": { + "type": "boolean" + }, + "stdinOnce": { + "type": "boolean" + }, + "terminationMessagePath": { + "type": "string" + }, + "terminationMessagePolicy": { + "type": "string" + }, + "tty": { + "type": "boolean" + }, + "volumeDevices": { + "items": { + "properties": { + "devicePath": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "devicePath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "volumeMounts": { + "items": { + "properties": { + "mountPath": { + "type": "string" + }, + "mountPropagation": { + "type": "string" + }, + "name": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + }, + "subPath": { + "type": "string" + }, + "subPathExpr": { + "type": "string" + } + }, + "required": [ + "mountPath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "workingDir": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "dnsConfig": { + "properties": { + "nameservers": { + "items": { + "type": "string" + }, + "type": "array" + }, + "options": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "searches": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "dnsPolicy": { + "type": "string" + }, + "enableServiceLinks": { + "type": "boolean" + }, + "ephemeralContainers": { + "items": { + "properties": { + "args": { + "items": { + "type": "string" + }, + "type": "array" + }, + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "properties": { + "configMapKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + }, + "fieldRef": { + "properties": { + "apiVersion": { + "type": "string" + }, + "fieldPath": { + "type": "string" + } + }, + "required": [ + "fieldPath" + ], + "type": "object" + }, + "resourceFieldRef": { + "properties": { + "containerName": { + "type": "string" + }, + "divisor": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "x-kubernetes-int-or-string": true + }, + "resource": { + "type": "string" + } + }, + "required": [ + "resource" + ], + "type": "object" + }, + "secretKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "envFrom": { + "items": { + "properties": { + "configMapRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + }, + "prefix": { + "type": "string" + }, + "secretRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "image": { + "type": "string" + }, + "imagePullPolicy": { + "type": "string" + }, + "lifecycle": { + "properties": { + "postStart": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + }, + "preStop": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "livenessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "ports": { + "items": { + "properties": { + "containerPort": { + "format": "int32", + "type": "integer" + }, + "hostIP": { + "type": "string" + }, + "hostPort": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "protocol": { + "default": "TCP", + "type": "string" + } + }, + "required": [ + "containerPort" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-map-keys": [ + "containerPort", + "protocol" + ], + "x-kubernetes-list-type": "map" + }, + "readinessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "resources": { + "properties": { + "limits": { + "x-kubernetes-preserve-unknown-fields": true + }, + "requests": { + "x-kubernetes-preserve-unknown-fields": true + } + }, + "type": "object" + }, + "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "properties": { + "add": { + "items": { + "type": "string" + }, + "type": "array" + }, + "drop": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "privileged": { + "type": "boolean" + }, + "procMount": { + "type": "string" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "format": "int64", + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "format": "int64", + "type": "integer" + }, + "seLinuxOptions": { + "properties": { + "level": { + "type": "string" + }, + "role": { + "type": "string" + }, + "type": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + }, + "seccompProfile": { + "properties": { + "localhostProfile": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "windowsOptions": { + "properties": { + "gmsaCredentialSpec": { + "type": "string" + }, + "gmsaCredentialSpecName": { + "type": "string" + }, + "hostProcess": { + "type": "boolean" + }, + "runAsUserName": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "startupProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "stdin": { + "type": "boolean" + }, + "stdinOnce": { + "type": "boolean" + }, + "targetContainerName": { + "type": "string" + }, + "terminationMessagePath": { + "type": "string" + }, + "terminationMessagePolicy": { + "type": "string" + }, + "tty": { + "type": "boolean" + }, + "volumeDevices": { + "items": { + "properties": { + "devicePath": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "devicePath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "volumeMounts": { + "items": { + "properties": { + "mountPath": { + "type": "string" + }, + "mountPropagation": { + "type": "string" + }, + "name": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + }, + "subPath": { + "type": "string" + }, + "subPathExpr": { + "type": "string" + } + }, + "required": [ + "mountPath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "workingDir": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "hostAliases": { + "items": { + "properties": { + "hostnames": { + "items": { + "type": "string" + }, + "type": "array" + }, + "ip": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "hostIPC": { + "type": "boolean" + }, + "hostNetwork": { + "type": "boolean" + }, + "hostPID": { + "type": "boolean" + }, + "hostname": { + "type": "string" + }, + "imagePullSecrets": { + "items": { + "properties": { + "name": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "initContainers": { + "items": { + "properties": { + "args": { + "items": { + "type": "string" + }, + "type": "array" + }, + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "properties": { + "configMapKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + }, + "fieldRef": { + "properties": { + "apiVersion": { + "type": "string" + }, + "fieldPath": { + "type": "string" + } + }, + "required": [ + "fieldPath" + ], + "type": "object" + }, + "resourceFieldRef": { + "properties": { + "containerName": { + "type": "string" + }, + "divisor": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "x-kubernetes-int-or-string": true + }, + "resource": { + "type": "string" + } + }, + "required": [ + "resource" + ], + "type": "object" + }, + "secretKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "envFrom": { + "items": { + "properties": { + "configMapRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + }, + "prefix": { + "type": "string" + }, + "secretRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "image": { + "type": "string" + }, + "imagePullPolicy": { + "type": "string" + }, + "lifecycle": { + "properties": { + "postStart": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + }, + "preStop": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "livenessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "ports": { + "items": { + "properties": { + "containerPort": { + "format": "int32", + "type": "integer" + }, + "hostIP": { + "type": "string" + }, + "hostPort": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "protocol": { + "default": "TCP", + "type": "string" + } + }, + "required": [ + "containerPort" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-map-keys": [ + "containerPort", + "protocol" + ], + "x-kubernetes-list-type": "map" + }, + "readinessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "resources": { + "properties": { + "limits": { + "x-kubernetes-preserve-unknown-fields": true + }, + "requests": { + "x-kubernetes-preserve-unknown-fields": true + } + }, + "type": "object" + }, + "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "properties": { + "add": { + "items": { + "type": "string" + }, + "type": "array" + }, + "drop": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "privileged": { + "type": "boolean" + }, + "procMount": { + "type": "string" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "format": "int64", + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "format": "int64", + "type": "integer" + }, + "seLinuxOptions": { + "properties": { + "level": { + "type": "string" + }, + "role": { + "type": "string" + }, + "type": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + }, + "seccompProfile": { + "properties": { + "localhostProfile": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "windowsOptions": { + "properties": { + "gmsaCredentialSpec": { + "type": "string" + }, + "gmsaCredentialSpecName": { + "type": "string" + }, + "hostProcess": { + "type": "boolean" + }, + "runAsUserName": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "startupProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "stdin": { + "type": "boolean" + }, + "stdinOnce": { + "type": "boolean" + }, + "terminationMessagePath": { + "type": "string" + }, + "terminationMessagePolicy": { + "type": "string" + }, + "tty": { + "type": "boolean" + }, + "volumeDevices": { + "items": { + "properties": { + "devicePath": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "devicePath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "volumeMounts": { + "items": { + "properties": { + "mountPath": { + "type": "string" + }, + "mountPropagation": { + "type": "string" + }, + "name": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + }, + "subPath": { + "type": "string" + }, + "subPathExpr": { + "type": "string" + } + }, + "required": [ + "mountPath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "workingDir": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "nodeName": { + "type": "string" + }, + "nodeSelector": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "x-kubernetes-map-type": "atomic" + }, + "os": { + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "overhead": { + "additionalProperties": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "x-kubernetes-int-or-string": true + }, + "type": "object" + }, + "preemptionPolicy": { + "type": "string" + }, + "priority": { + "format": "int32", + "type": "integer" + }, + "priorityClassName": { + "type": "string" + }, + "readinessGates": { + "items": { + "properties": { + "conditionType": { + "type": "string" + } + }, + "required": [ + "conditionType" + ], + "type": "object" + }, + "type": "array" + }, + "restartPolicy": { + "type": "string" + }, + "runtimeClassName": { + "type": "string" + }, + "schedulerName": { + "type": "string" + }, + "securityContext": { + "properties": { + "fsGroup": { + "format": "int64", + "type": "integer" + }, + "fsGroupChangePolicy": { + "type": "string" + }, + "runAsGroup": { + "format": "int64", + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "format": "int64", + "type": "integer" + }, + "seLinuxOptions": { + "properties": { + "level": { + "type": "string" + }, + "role": { + "type": "string" + }, + "type": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + }, + "seccompProfile": { + "properties": { + "localhostProfile": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "supplementalGroups": { + "items": { + "format": "int64", + "type": "integer" + }, + "type": "array" + }, + "sysctls": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "windowsOptions": { + "properties": { + "gmsaCredentialSpec": { + "type": "string" + }, + "gmsaCredentialSpecName": { + "type": "string" + }, + "hostProcess": { + "type": "boolean" + }, + "runAsUserName": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "serviceAccount": { + "type": "string" + }, + "serviceAccountName": { + "type": "string" + }, + "setHostnameAsFQDN": { + "type": "boolean" + }, + "shareProcessNamespace": { + "type": "boolean" + }, + "subdomain": { + "type": "string" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "tolerations": { + "items": { + "properties": { + "effect": { + "type": "string" + }, + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "tolerationSeconds": { + "format": "int64", + "type": "integer" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "topologySpreadConstraints": { + "items": { + "properties": { + "labelSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "maxSkew": { + "format": "int32", + "type": "integer" + }, + "topologyKey": { + "type": "string" + }, + "whenUnsatisfiable": { + "type": "string" + } + }, + "required": [ + "maxSkew", + "topologyKey", + "whenUnsatisfiable" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-map-keys": [ + "topologyKey", + "whenUnsatisfiable" + ], + "x-kubernetes-list-type": "map" + }, + "volumes": { + "x-kubernetes-preserve-unknown-fields": true + } + }, + "required": [ + "containers" + ], + "type": "object" + } + }, + "type": "object" + }, + "ttlSecondsAfterFinished": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "template" + ], + "type": "object" + } + }, + "required": [ + "spec" + ], + "type": "object" + }, + "kayenta": { + "properties": { + "address": { + "type": "string" + }, + "application": { + "type": "string" + }, + "canaryConfigName": { + "type": "string" + }, + "configurationAccountName": { + "type": "string" + }, + "metricsAccountName": { + "type": "string" + }, + "scopes": { + "items": { + "properties": { + "controlScope": { + "properties": { + "end": { + "type": "string" + }, + "region": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "start": { + "type": "string" + }, + "step": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "end", + "region", + "scope", + "start", + "step" + ], + "type": "object" + }, + "experimentScope": { + "properties": { + "end": { + "type": "string" + }, + "region": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "start": { + "type": "string" + }, + "step": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "end", + "region", + "scope", + "start", + "step" + ], + "type": "object" + }, + "name": { + "type": "string" + } + }, + "required": [ + "controlScope", + "experimentScope", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "storageAccountName": { + "type": "string" + }, + "threshold": { + "properties": { + "marginal": { + "format": "int64", + "type": "integer" + }, + "pass": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "marginal", + "pass" + ], + "type": "object" + } + }, + "required": [ + "address", + "application", + "canaryConfigName", + "configurationAccountName", + "metricsAccountName", + "scopes", + "storageAccountName", + "threshold" + ], + "type": "object" + }, + "newRelic": { + "properties": { + "profile": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "required": [ + "query" + ], + "type": "object" + }, + "prometheus": { + "properties": { + "address": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "type": "object" + }, + "wavefront": { + "properties": { + "address": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "type": "object" + }, + "web": { + "properties": { + "body": { + "type": "string" + }, + "headers": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "key", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "insecure": { + "type": "boolean" + }, + "jsonPath": { + "type": "string" + }, + "method": { + "type": "string" + }, + "timeoutSeconds": { + "format": "int64", + "type": "integer" + }, + "url": { + "type": "string" + } + }, + "required": [ + "url" + ], + "type": "object" + } + }, + "type": "object" + }, + "successCondition": { + "type": "string" + } + }, + "required": [ + "name", + "provider" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "name", + "x-kubernetes-patch-strategy": "merge" + } + }, + "required": [ + "metrics" + ], + "type": "object" + } + }, + "x-kubernetes-group-version-kind": [ + { + "group": "argoproj.io", + "kind": "AnalysisTemplate", + "version": "v1alpha1" + } + ] + }, + "io.argoproj.v1alpha1.ClusterAnalysisTemplate": { + "properties": { + "spec": { + "properties": { + "args": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "properties": { + "fieldRef": { + "properties": { + "fieldPath": { + "type": "string" + } + }, + "required": [ + "fieldPath" + ], + "type": "object" + }, + "secretKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "key", + "name" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "name", + "x-kubernetes-patch-strategy": "merge" + }, + "dryRun": { + "items": { + "properties": { + "metricName": { + "type": "string" + } + }, + "required": [ + "metricName" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge" + }, + "measurementRetention": { + "items": { + "properties": { + "limit": { + "format": "int32", + "type": "integer" + }, + "metricName": { + "type": "string" + } + }, + "required": [ + "limit", + "metricName" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge" + }, + "metrics": { + "items": { + "properties": { + "consecutiveErrorLimit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "failureCondition": { + "type": "string" + }, + "failureLimit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "inconclusiveLimit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "initialDelay": { + "type": "string" + }, + "interval": { + "type": "string" + }, + "name": { + "type": "string" + }, + "provider": { + "properties": { + "cloudWatch": { + "properties": { + "interval": { + "type": "string" + }, + "metricDataQueries": { + "items": { + "properties": { + "expression": { + "type": "string" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "metricStat": { + "properties": { + "metric": { + "properties": { + "dimensions": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "metricName": { + "type": "string" + }, + "namespace": { + "type": "string" + } + }, + "type": "object" + }, + "period": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "stat": { + "type": "string" + }, + "unit": { + "type": "string" + } + }, + "type": "object" + }, + "period": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "returnData": { + "type": "boolean" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "metricDataQueries" + ], + "type": "object" + }, + "datadog": { + "properties": { + "interval": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "required": [ + "query" + ], + "type": "object" + }, + "graphite": { + "properties": { + "address": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "type": "object" + }, + "job": { + "properties": { + "metadata": { + "properties": { + "annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + "labels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "spec": { + "properties": { + "activeDeadlineSeconds": { + "format": "int64", + "type": "integer" + }, + "backoffLimit": { + "format": "int32", + "type": "integer" + }, + "completionMode": { + "type": "string" + }, + "completions": { + "format": "int32", + "type": "integer" + }, + "manualSelector": { + "type": "boolean" + }, + "parallelism": { + "format": "int32", + "type": "integer" + }, + "selector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "suspend": { + "type": "boolean" + }, + "template": { + "properties": { + "metadata": { + "properties": { + "annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + "labels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "spec": { + "properties": { + "activeDeadlineSeconds": { + "format": "int64", + "type": "integer" + }, + "affinity": { + "properties": { + "nodeAffinity": { + "properties": { + "preferredDuringSchedulingIgnoredDuringExecution": { + "items": { + "properties": { + "preference": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchFields": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "weight": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "preference", + "weight" + ], + "type": "object" + }, + "type": "array" + }, + "requiredDuringSchedulingIgnoredDuringExecution": { + "properties": { + "nodeSelectorTerms": { + "items": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchFields": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "nodeSelectorTerms" + ], + "type": "object" + } + }, + "type": "object" + }, + "podAffinity": { + "properties": { + "preferredDuringSchedulingIgnoredDuringExecution": { + "items": { + "properties": { + "podAffinityTerm": { + "properties": { + "labelSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaceSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaces": { + "items": { + "type": "string" + }, + "type": "array" + }, + "topologyKey": { + "type": "string" + } + }, + "required": [ + "topologyKey" + ], + "type": "object" + }, + "weight": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "podAffinityTerm", + "weight" + ], + "type": "object" + }, + "type": "array" + }, + "requiredDuringSchedulingIgnoredDuringExecution": { + "items": { + "properties": { + "labelSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaceSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaces": { + "items": { + "type": "string" + }, + "type": "array" + }, + "topologyKey": { + "type": "string" + } + }, + "required": [ + "topologyKey" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "podAntiAffinity": { + "properties": { + "preferredDuringSchedulingIgnoredDuringExecution": { + "items": { + "properties": { + "podAffinityTerm": { + "properties": { + "labelSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaceSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaces": { + "items": { + "type": "string" + }, + "type": "array" + }, + "topologyKey": { + "type": "string" + } + }, + "required": [ + "topologyKey" + ], + "type": "object" + }, + "weight": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "podAffinityTerm", + "weight" + ], + "type": "object" + }, + "type": "array" + }, + "requiredDuringSchedulingIgnoredDuringExecution": { + "items": { + "properties": { + "labelSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaceSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaces": { + "items": { + "type": "string" + }, + "type": "array" + }, + "topologyKey": { + "type": "string" + } + }, + "required": [ + "topologyKey" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "automountServiceAccountToken": { + "type": "boolean" + }, + "containers": { + "items": { + "properties": { + "args": { + "items": { + "type": "string" + }, + "type": "array" + }, + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "properties": { + "configMapKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + }, + "fieldRef": { + "properties": { + "apiVersion": { + "type": "string" + }, + "fieldPath": { + "type": "string" + } + }, + "required": [ + "fieldPath" + ], + "type": "object" + }, + "resourceFieldRef": { + "properties": { + "containerName": { + "type": "string" + }, + "divisor": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "x-kubernetes-int-or-string": true + }, + "resource": { + "type": "string" + } + }, + "required": [ + "resource" + ], + "type": "object" + }, + "secretKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "envFrom": { + "items": { + "properties": { + "configMapRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + }, + "prefix": { + "type": "string" + }, + "secretRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "image": { + "type": "string" + }, + "imagePullPolicy": { + "type": "string" + }, + "lifecycle": { + "properties": { + "postStart": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + }, + "preStop": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "livenessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "ports": { + "items": { + "properties": { + "containerPort": { + "format": "int32", + "type": "integer" + }, + "hostIP": { + "type": "string" + }, + "hostPort": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "protocol": { + "default": "TCP", + "type": "string" + } + }, + "required": [ + "containerPort" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-map-keys": [ + "containerPort", + "protocol" + ], + "x-kubernetes-list-type": "map" + }, + "readinessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "resources": { + "properties": { + "limits": { + "x-kubernetes-preserve-unknown-fields": true + }, + "requests": { + "x-kubernetes-preserve-unknown-fields": true + } + }, + "type": "object" + }, + "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "properties": { + "add": { + "items": { + "type": "string" + }, + "type": "array" + }, + "drop": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "privileged": { + "type": "boolean" + }, + "procMount": { + "type": "string" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "format": "int64", + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "format": "int64", + "type": "integer" + }, + "seLinuxOptions": { + "properties": { + "level": { + "type": "string" + }, + "role": { + "type": "string" + }, + "type": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + }, + "seccompProfile": { + "properties": { + "localhostProfile": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "windowsOptions": { + "properties": { + "gmsaCredentialSpec": { + "type": "string" + }, + "gmsaCredentialSpecName": { + "type": "string" + }, + "hostProcess": { + "type": "boolean" + }, + "runAsUserName": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "startupProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "stdin": { + "type": "boolean" + }, + "stdinOnce": { + "type": "boolean" + }, + "terminationMessagePath": { + "type": "string" + }, + "terminationMessagePolicy": { + "type": "string" + }, + "tty": { + "type": "boolean" + }, + "volumeDevices": { + "items": { + "properties": { + "devicePath": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "devicePath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "volumeMounts": { + "items": { + "properties": { + "mountPath": { + "type": "string" + }, + "mountPropagation": { + "type": "string" + }, + "name": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + }, + "subPath": { + "type": "string" + }, + "subPathExpr": { + "type": "string" + } + }, + "required": [ + "mountPath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "workingDir": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "dnsConfig": { + "properties": { + "nameservers": { + "items": { + "type": "string" + }, + "type": "array" + }, + "options": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "searches": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "dnsPolicy": { + "type": "string" + }, + "enableServiceLinks": { + "type": "boolean" + }, + "ephemeralContainers": { + "items": { + "properties": { + "args": { + "items": { + "type": "string" + }, + "type": "array" + }, + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "properties": { + "configMapKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + }, + "fieldRef": { + "properties": { + "apiVersion": { + "type": "string" + }, + "fieldPath": { + "type": "string" + } + }, + "required": [ + "fieldPath" + ], + "type": "object" + }, + "resourceFieldRef": { + "properties": { + "containerName": { + "type": "string" + }, + "divisor": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "x-kubernetes-int-or-string": true + }, + "resource": { + "type": "string" + } + }, + "required": [ + "resource" + ], + "type": "object" + }, + "secretKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "envFrom": { + "items": { + "properties": { + "configMapRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + }, + "prefix": { + "type": "string" + }, + "secretRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "image": { + "type": "string" + }, + "imagePullPolicy": { + "type": "string" + }, + "lifecycle": { + "properties": { + "postStart": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + }, + "preStop": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "livenessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "ports": { + "items": { + "properties": { + "containerPort": { + "format": "int32", + "type": "integer" + }, + "hostIP": { + "type": "string" + }, + "hostPort": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "protocol": { + "default": "TCP", + "type": "string" + } + }, + "required": [ + "containerPort" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-map-keys": [ + "containerPort", + "protocol" + ], + "x-kubernetes-list-type": "map" + }, + "readinessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "resources": { + "properties": { + "limits": { + "x-kubernetes-preserve-unknown-fields": true + }, + "requests": { + "x-kubernetes-preserve-unknown-fields": true + } + }, + "type": "object" + }, + "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "properties": { + "add": { + "items": { + "type": "string" + }, + "type": "array" + }, + "drop": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "privileged": { + "type": "boolean" + }, + "procMount": { + "type": "string" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "format": "int64", + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "format": "int64", + "type": "integer" + }, + "seLinuxOptions": { + "properties": { + "level": { + "type": "string" + }, + "role": { + "type": "string" + }, + "type": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + }, + "seccompProfile": { + "properties": { + "localhostProfile": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "windowsOptions": { + "properties": { + "gmsaCredentialSpec": { + "type": "string" + }, + "gmsaCredentialSpecName": { + "type": "string" + }, + "hostProcess": { + "type": "boolean" + }, + "runAsUserName": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "startupProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "stdin": { + "type": "boolean" + }, + "stdinOnce": { + "type": "boolean" + }, + "targetContainerName": { + "type": "string" + }, + "terminationMessagePath": { + "type": "string" + }, + "terminationMessagePolicy": { + "type": "string" + }, + "tty": { + "type": "boolean" + }, + "volumeDevices": { + "items": { + "properties": { + "devicePath": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "devicePath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "volumeMounts": { + "items": { + "properties": { + "mountPath": { + "type": "string" + }, + "mountPropagation": { + "type": "string" + }, + "name": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + }, + "subPath": { + "type": "string" + }, + "subPathExpr": { + "type": "string" + } + }, + "required": [ + "mountPath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "workingDir": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "hostAliases": { + "items": { + "properties": { + "hostnames": { + "items": { + "type": "string" + }, + "type": "array" + }, + "ip": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "hostIPC": { + "type": "boolean" + }, + "hostNetwork": { + "type": "boolean" + }, + "hostPID": { + "type": "boolean" + }, + "hostname": { + "type": "string" + }, + "imagePullSecrets": { + "items": { + "properties": { + "name": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "initContainers": { + "items": { + "properties": { + "args": { + "items": { + "type": "string" + }, + "type": "array" + }, + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "properties": { + "configMapKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + }, + "fieldRef": { + "properties": { + "apiVersion": { + "type": "string" + }, + "fieldPath": { + "type": "string" + } + }, + "required": [ + "fieldPath" + ], + "type": "object" + }, + "resourceFieldRef": { + "properties": { + "containerName": { + "type": "string" + }, + "divisor": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "x-kubernetes-int-or-string": true + }, + "resource": { + "type": "string" + } + }, + "required": [ + "resource" + ], + "type": "object" + }, + "secretKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "envFrom": { + "items": { + "properties": { + "configMapRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + }, + "prefix": { + "type": "string" + }, + "secretRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "image": { + "type": "string" + }, + "imagePullPolicy": { + "type": "string" + }, + "lifecycle": { + "properties": { + "postStart": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + }, + "preStop": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "livenessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "ports": { + "items": { + "properties": { + "containerPort": { + "format": "int32", + "type": "integer" + }, + "hostIP": { + "type": "string" + }, + "hostPort": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "protocol": { + "default": "TCP", + "type": "string" + } + }, + "required": [ + "containerPort" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-map-keys": [ + "containerPort", + "protocol" + ], + "x-kubernetes-list-type": "map" + }, + "readinessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "resources": { + "properties": { + "limits": { + "x-kubernetes-preserve-unknown-fields": true + }, + "requests": { + "x-kubernetes-preserve-unknown-fields": true + } + }, + "type": "object" + }, + "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "properties": { + "add": { + "items": { + "type": "string" + }, + "type": "array" + }, + "drop": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "privileged": { + "type": "boolean" + }, + "procMount": { + "type": "string" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "format": "int64", + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "format": "int64", + "type": "integer" + }, + "seLinuxOptions": { + "properties": { + "level": { + "type": "string" + }, + "role": { + "type": "string" + }, + "type": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + }, + "seccompProfile": { + "properties": { + "localhostProfile": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "windowsOptions": { + "properties": { + "gmsaCredentialSpec": { + "type": "string" + }, + "gmsaCredentialSpecName": { + "type": "string" + }, + "hostProcess": { + "type": "boolean" + }, + "runAsUserName": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "startupProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "stdin": { + "type": "boolean" + }, + "stdinOnce": { + "type": "boolean" + }, + "terminationMessagePath": { + "type": "string" + }, + "terminationMessagePolicy": { + "type": "string" + }, + "tty": { + "type": "boolean" + }, + "volumeDevices": { + "items": { + "properties": { + "devicePath": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "devicePath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "volumeMounts": { + "items": { + "properties": { + "mountPath": { + "type": "string" + }, + "mountPropagation": { + "type": "string" + }, + "name": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + }, + "subPath": { + "type": "string" + }, + "subPathExpr": { + "type": "string" + } + }, + "required": [ + "mountPath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "workingDir": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "nodeName": { + "type": "string" + }, + "nodeSelector": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "x-kubernetes-map-type": "atomic" + }, + "os": { + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "overhead": { + "additionalProperties": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "x-kubernetes-int-or-string": true + }, + "type": "object" + }, + "preemptionPolicy": { + "type": "string" + }, + "priority": { + "format": "int32", + "type": "integer" + }, + "priorityClassName": { + "type": "string" + }, + "readinessGates": { + "items": { + "properties": { + "conditionType": { + "type": "string" + } + }, + "required": [ + "conditionType" + ], + "type": "object" + }, + "type": "array" + }, + "restartPolicy": { + "type": "string" + }, + "runtimeClassName": { + "type": "string" + }, + "schedulerName": { + "type": "string" + }, + "securityContext": { + "properties": { + "fsGroup": { + "format": "int64", + "type": "integer" + }, + "fsGroupChangePolicy": { + "type": "string" + }, + "runAsGroup": { + "format": "int64", + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "format": "int64", + "type": "integer" + }, + "seLinuxOptions": { + "properties": { + "level": { + "type": "string" + }, + "role": { + "type": "string" + }, + "type": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + }, + "seccompProfile": { + "properties": { + "localhostProfile": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "supplementalGroups": { + "items": { + "format": "int64", + "type": "integer" + }, + "type": "array" + }, + "sysctls": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "windowsOptions": { + "properties": { + "gmsaCredentialSpec": { + "type": "string" + }, + "gmsaCredentialSpecName": { + "type": "string" + }, + "hostProcess": { + "type": "boolean" + }, + "runAsUserName": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "serviceAccount": { + "type": "string" + }, + "serviceAccountName": { + "type": "string" + }, + "setHostnameAsFQDN": { + "type": "boolean" + }, + "shareProcessNamespace": { + "type": "boolean" + }, + "subdomain": { + "type": "string" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "tolerations": { + "items": { + "properties": { + "effect": { + "type": "string" + }, + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "tolerationSeconds": { + "format": "int64", + "type": "integer" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "topologySpreadConstraints": { + "items": { + "properties": { + "labelSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "maxSkew": { + "format": "int32", + "type": "integer" + }, + "topologyKey": { + "type": "string" + }, + "whenUnsatisfiable": { + "type": "string" + } + }, + "required": [ + "maxSkew", + "topologyKey", + "whenUnsatisfiable" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-map-keys": [ + "topologyKey", + "whenUnsatisfiable" + ], + "x-kubernetes-list-type": "map" + }, + "volumes": { + "x-kubernetes-preserve-unknown-fields": true + } + }, + "required": [ + "containers" + ], + "type": "object" + } + }, + "type": "object" + }, + "ttlSecondsAfterFinished": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "template" + ], + "type": "object" + } + }, + "required": [ + "spec" + ], + "type": "object" + }, + "kayenta": { + "properties": { + "address": { + "type": "string" + }, + "application": { + "type": "string" + }, + "canaryConfigName": { + "type": "string" + }, + "configurationAccountName": { + "type": "string" + }, + "metricsAccountName": { + "type": "string" + }, + "scopes": { + "items": { + "properties": { + "controlScope": { + "properties": { + "end": { + "type": "string" + }, + "region": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "start": { + "type": "string" + }, + "step": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "end", + "region", + "scope", + "start", + "step" + ], + "type": "object" + }, + "experimentScope": { + "properties": { + "end": { + "type": "string" + }, + "region": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "start": { + "type": "string" + }, + "step": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "end", + "region", + "scope", + "start", + "step" + ], + "type": "object" + }, + "name": { + "type": "string" + } + }, + "required": [ + "controlScope", + "experimentScope", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "storageAccountName": { + "type": "string" + }, + "threshold": { + "properties": { + "marginal": { + "format": "int64", + "type": "integer" + }, + "pass": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "marginal", + "pass" + ], + "type": "object" + } + }, + "required": [ + "address", + "application", + "canaryConfigName", + "configurationAccountName", + "metricsAccountName", + "scopes", + "storageAccountName", + "threshold" + ], + "type": "object" + }, + "newRelic": { + "properties": { + "profile": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "required": [ + "query" + ], + "type": "object" + }, + "prometheus": { + "properties": { + "address": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "type": "object" + }, + "wavefront": { + "properties": { + "address": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "type": "object" + }, + "web": { + "properties": { + "body": { + "type": "string" + }, + "headers": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "key", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "insecure": { + "type": "boolean" + }, + "jsonPath": { + "type": "string" + }, + "method": { + "type": "string" + }, + "timeoutSeconds": { + "format": "int64", + "type": "integer" + }, + "url": { + "type": "string" + } + }, + "required": [ + "url" + ], + "type": "object" + } + }, + "type": "object" + }, + "successCondition": { + "type": "string" + } + }, + "required": [ + "name", + "provider" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "name", + "x-kubernetes-patch-strategy": "merge" + } + }, + "required": [ + "metrics" + ], + "type": "object" + } + }, + "x-kubernetes-group-version-kind": [ + { + "group": "argoproj.io", + "kind": "ClusterAnalysisTemplate", + "version": "v1alpha1" + } + ] + }, + "io.argoproj.v1alpha1.Experiment": { + "properties": { + "spec": { + "properties": { + "analyses": { + "items": { + "properties": { + "args": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "properties": { + "fieldRef": { + "properties": { + "fieldPath": { + "type": "string" + } + }, + "required": [ + "fieldPath" + ], + "type": "object" + }, + "secretKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "key", + "name" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "clusterScope": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "requiredForCompletion": { + "type": "boolean" + }, + "templateName": { + "type": "string" + } + }, + "required": [ + "name", + "templateName" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "name", + "x-kubernetes-patch-strategy": "merge" + }, + "dryRun": { + "items": { + "properties": { + "metricName": { + "type": "string" + } + }, + "required": [ + "metricName" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge" + }, + "measurementRetention": { + "items": { + "properties": { + "limit": { + "format": "int32", + "type": "integer" + }, + "metricName": { + "type": "string" + } + }, + "required": [ + "limit", + "metricName" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "metricName", + "x-kubernetes-patch-strategy": "merge" + }, + "templates": { + "items": { + "properties": { + "minReadySeconds": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "replicas": { + "format": "int32", + "type": "integer" + }, + "selector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "service": { + "type": "object" + }, + "template": { + "properties": { + "metadata": { + "properties": { + "annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + "labels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "spec": { + "properties": { + "activeDeadlineSeconds": { + "format": "int64", + "type": "integer" + }, + "affinity": { + "properties": { + "nodeAffinity": { + "properties": { + "preferredDuringSchedulingIgnoredDuringExecution": { + "items": { + "properties": { + "preference": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchFields": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "weight": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "preference", + "weight" + ], + "type": "object" + }, + "type": "array" + }, + "requiredDuringSchedulingIgnoredDuringExecution": { + "properties": { + "nodeSelectorTerms": { + "items": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchFields": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "nodeSelectorTerms" + ], + "type": "object" + } + }, + "type": "object" + }, + "podAffinity": { + "properties": { + "preferredDuringSchedulingIgnoredDuringExecution": { + "items": { + "properties": { + "podAffinityTerm": { + "properties": { + "labelSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaceSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaces": { + "items": { + "type": "string" + }, + "type": "array" + }, + "topologyKey": { + "type": "string" + } + }, + "required": [ + "topologyKey" + ], + "type": "object" + }, + "weight": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "podAffinityTerm", + "weight" + ], + "type": "object" + }, + "type": "array" + }, + "requiredDuringSchedulingIgnoredDuringExecution": { + "items": { + "properties": { + "labelSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaceSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaces": { + "items": { + "type": "string" + }, + "type": "array" + }, + "topologyKey": { + "type": "string" + } + }, + "required": [ + "topologyKey" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "podAntiAffinity": { + "properties": { + "preferredDuringSchedulingIgnoredDuringExecution": { + "items": { + "properties": { + "podAffinityTerm": { + "properties": { + "labelSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaceSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaces": { + "items": { + "type": "string" + }, + "type": "array" + }, + "topologyKey": { + "type": "string" + } + }, + "required": [ + "topologyKey" + ], + "type": "object" + }, + "weight": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "podAffinityTerm", + "weight" + ], + "type": "object" + }, + "type": "array" + }, + "requiredDuringSchedulingIgnoredDuringExecution": { + "items": { + "properties": { + "labelSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaceSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "namespaces": { + "items": { + "type": "string" + }, + "type": "array" + }, + "topologyKey": { + "type": "string" + } + }, + "required": [ + "topologyKey" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "automountServiceAccountToken": { + "type": "boolean" + }, + "containers": { + "items": { + "properties": { + "args": { + "items": { + "type": "string" + }, + "type": "array" + }, + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "properties": { + "configMapKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + }, + "fieldRef": { + "properties": { + "apiVersion": { + "type": "string" + }, + "fieldPath": { + "type": "string" + } + }, + "required": [ + "fieldPath" + ], + "type": "object" + }, + "resourceFieldRef": { + "properties": { + "containerName": { + "type": "string" + }, + "divisor": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "x-kubernetes-int-or-string": true + }, + "resource": { + "type": "string" + } + }, + "required": [ + "resource" + ], + "type": "object" + }, + "secretKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "envFrom": { + "items": { + "properties": { + "configMapRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + }, + "prefix": { + "type": "string" + }, + "secretRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "image": { + "type": "string" + }, + "imagePullPolicy": { + "type": "string" + }, + "lifecycle": { + "properties": { + "postStart": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + }, + "preStop": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "livenessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "ports": { + "items": { + "properties": { + "containerPort": { + "format": "int32", + "type": "integer" + }, + "hostIP": { + "type": "string" + }, + "hostPort": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "protocol": { + "default": "TCP", + "type": "string" + } + }, + "required": [ + "containerPort" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-map-keys": [ + "containerPort", + "protocol" + ], + "x-kubernetes-list-type": "map" + }, + "readinessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "resources": { + "properties": { + "limits": { + "x-kubernetes-preserve-unknown-fields": true + }, + "requests": { + "x-kubernetes-preserve-unknown-fields": true + } + }, + "type": "object" + }, + "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "properties": { + "add": { + "items": { + "type": "string" + }, + "type": "array" + }, + "drop": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "privileged": { + "type": "boolean" + }, + "procMount": { + "type": "string" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "format": "int64", + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "format": "int64", + "type": "integer" + }, + "seLinuxOptions": { + "properties": { + "level": { + "type": "string" + }, + "role": { + "type": "string" + }, + "type": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + }, + "seccompProfile": { + "properties": { + "localhostProfile": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "windowsOptions": { + "properties": { + "gmsaCredentialSpec": { + "type": "string" + }, + "gmsaCredentialSpecName": { + "type": "string" + }, + "hostProcess": { + "type": "boolean" + }, + "runAsUserName": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "startupProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "stdin": { + "type": "boolean" + }, + "stdinOnce": { + "type": "boolean" + }, + "terminationMessagePath": { + "type": "string" + }, + "terminationMessagePolicy": { + "type": "string" + }, + "tty": { + "type": "boolean" + }, + "volumeDevices": { + "items": { + "properties": { + "devicePath": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "devicePath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "volumeMounts": { + "items": { + "properties": { + "mountPath": { + "type": "string" + }, + "mountPropagation": { + "type": "string" + }, + "name": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + }, + "subPath": { + "type": "string" + }, + "subPathExpr": { + "type": "string" + } + }, + "required": [ + "mountPath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "workingDir": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "dnsConfig": { + "properties": { + "nameservers": { + "items": { + "type": "string" + }, + "type": "array" + }, + "options": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "searches": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "dnsPolicy": { + "type": "string" + }, + "enableServiceLinks": { + "type": "boolean" + }, + "ephemeralContainers": { + "items": { + "properties": { + "args": { + "items": { + "type": "string" + }, + "type": "array" + }, + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "properties": { + "configMapKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + }, + "fieldRef": { + "properties": { + "apiVersion": { + "type": "string" + }, + "fieldPath": { + "type": "string" + } + }, + "required": [ + "fieldPath" + ], + "type": "object" + }, + "resourceFieldRef": { + "properties": { + "containerName": { + "type": "string" + }, + "divisor": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "x-kubernetes-int-or-string": true + }, + "resource": { + "type": "string" + } + }, + "required": [ + "resource" + ], + "type": "object" + }, + "secretKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "envFrom": { + "items": { + "properties": { + "configMapRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + }, + "prefix": { + "type": "string" + }, + "secretRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "image": { + "type": "string" + }, + "imagePullPolicy": { + "type": "string" + }, + "lifecycle": { + "properties": { + "postStart": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + }, + "preStop": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "livenessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "ports": { + "items": { + "properties": { + "containerPort": { + "format": "int32", + "type": "integer" + }, + "hostIP": { + "type": "string" + }, + "hostPort": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "protocol": { + "default": "TCP", + "type": "string" + } + }, + "required": [ + "containerPort" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-map-keys": [ + "containerPort", + "protocol" + ], + "x-kubernetes-list-type": "map" + }, + "readinessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "resources": { + "properties": { + "limits": { + "x-kubernetes-preserve-unknown-fields": true + }, + "requests": { + "x-kubernetes-preserve-unknown-fields": true + } + }, + "type": "object" + }, + "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "properties": { + "add": { + "items": { + "type": "string" + }, + "type": "array" + }, + "drop": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "privileged": { + "type": "boolean" + }, + "procMount": { + "type": "string" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "format": "int64", + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "format": "int64", + "type": "integer" + }, + "seLinuxOptions": { + "properties": { + "level": { + "type": "string" + }, + "role": { + "type": "string" + }, + "type": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + }, + "seccompProfile": { + "properties": { + "localhostProfile": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "windowsOptions": { + "properties": { + "gmsaCredentialSpec": { + "type": "string" + }, + "gmsaCredentialSpecName": { + "type": "string" + }, + "hostProcess": { + "type": "boolean" + }, + "runAsUserName": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "startupProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "stdin": { + "type": "boolean" + }, + "stdinOnce": { + "type": "boolean" + }, + "targetContainerName": { + "type": "string" + }, + "terminationMessagePath": { + "type": "string" + }, + "terminationMessagePolicy": { + "type": "string" + }, + "tty": { + "type": "boolean" + }, + "volumeDevices": { + "items": { + "properties": { + "devicePath": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "devicePath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "volumeMounts": { + "items": { + "properties": { + "mountPath": { + "type": "string" + }, + "mountPropagation": { + "type": "string" + }, + "name": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + }, + "subPath": { + "type": "string" + }, + "subPathExpr": { + "type": "string" + } + }, + "required": [ + "mountPath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "workingDir": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "hostAliases": { + "items": { + "properties": { + "hostnames": { + "items": { + "type": "string" + }, + "type": "array" + }, + "ip": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "hostIPC": { + "type": "boolean" + }, + "hostNetwork": { + "type": "boolean" + }, + "hostPID": { + "type": "boolean" + }, + "hostname": { + "type": "string" + }, + "imagePullSecrets": { + "items": { + "properties": { + "name": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "initContainers": { + "items": { + "properties": { + "args": { + "items": { + "type": "string" + }, + "type": "array" + }, + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "properties": { + "configMapKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + }, + "fieldRef": { + "properties": { + "apiVersion": { + "type": "string" + }, + "fieldPath": { + "type": "string" + } + }, + "required": [ + "fieldPath" + ], + "type": "object" + }, + "resourceFieldRef": { + "properties": { + "containerName": { + "type": "string" + }, + "divisor": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "x-kubernetes-int-or-string": true + }, + "resource": { + "type": "string" + } + }, + "required": [ + "resource" + ], + "type": "object" + }, + "secretKeyRef": { + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "required": [ + "key" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "envFrom": { + "items": { + "properties": { + "configMapRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + }, + "prefix": { + "type": "string" + }, + "secretRef": { + "properties": { + "name": { + "type": "string" + }, + "optional": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "image": { + "type": "string" + }, + "imagePullPolicy": { + "type": "string" + }, + "lifecycle": { + "properties": { + "postStart": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + }, + "preStop": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "livenessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "ports": { + "items": { + "properties": { + "containerPort": { + "format": "int32", + "type": "integer" + }, + "hostIP": { + "type": "string" + }, + "hostPort": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "protocol": { + "default": "TCP", + "type": "string" + } + }, + "required": [ + "containerPort" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-map-keys": [ + "containerPort", + "protocol" + ], + "x-kubernetes-list-type": "map" + }, + "readinessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "resources": { + "properties": { + "limits": { + "x-kubernetes-preserve-unknown-fields": true + }, + "requests": { + "x-kubernetes-preserve-unknown-fields": true + } + }, + "type": "object" + }, + "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "properties": { + "add": { + "items": { + "type": "string" + }, + "type": "array" + }, + "drop": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "privileged": { + "type": "boolean" + }, + "procMount": { + "type": "string" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "format": "int64", + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "format": "int64", + "type": "integer" + }, + "seLinuxOptions": { + "properties": { + "level": { + "type": "string" + }, + "role": { + "type": "string" + }, + "type": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + }, + "seccompProfile": { + "properties": { + "localhostProfile": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "windowsOptions": { + "properties": { + "gmsaCredentialSpec": { + "type": "string" + }, + "gmsaCredentialSpecName": { + "type": "string" + }, + "hostProcess": { + "type": "boolean" + }, + "runAsUserName": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "startupProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "failureThreshold": { + "format": "int32", + "type": "integer" + }, + "grpc": { + "properties": { + "port": { + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "httpGet": { + "properties": { + "host": { + "type": "string" + }, + "httpHeaders": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "scheme": { + "type": "string" + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "initialDelaySeconds": { + "format": "int32", + "type": "integer" + }, + "periodSeconds": { + "format": "int32", + "type": "integer" + }, + "successThreshold": { + "format": "int32", + "type": "integer" + }, + "tcpSocket": { + "properties": { + "host": { + "type": "string" + }, + "port": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "timeoutSeconds": { + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "stdin": { + "type": "boolean" + }, + "stdinOnce": { + "type": "boolean" + }, + "terminationMessagePath": { + "type": "string" + }, + "terminationMessagePolicy": { + "type": "string" + }, + "tty": { + "type": "boolean" + }, + "volumeDevices": { + "items": { + "properties": { + "devicePath": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "devicePath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "volumeMounts": { + "items": { + "properties": { + "mountPath": { + "type": "string" + }, + "mountPropagation": { + "type": "string" + }, + "name": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + }, + "subPath": { + "type": "string" + }, + "subPathExpr": { + "type": "string" + } + }, + "required": [ + "mountPath", + "name" + ], + "type": "object" + }, + "type": "array" + }, + "workingDir": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "nodeName": { + "type": "string" + }, + "nodeSelector": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "x-kubernetes-map-type": "atomic" + }, + "os": { + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "overhead": { + "additionalProperties": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "x-kubernetes-int-or-string": true + }, + "type": "object" + }, + "preemptionPolicy": { + "type": "string" + }, + "priority": { + "format": "int32", + "type": "integer" + }, + "priorityClassName": { + "type": "string" + }, + "readinessGates": { + "items": { + "properties": { + "conditionType": { + "type": "string" + } + }, + "required": [ + "conditionType" + ], + "type": "object" + }, + "type": "array" + }, + "restartPolicy": { + "type": "string" + }, + "runtimeClassName": { + "type": "string" + }, + "schedulerName": { + "type": "string" + }, + "securityContext": { + "properties": { + "fsGroup": { + "format": "int64", + "type": "integer" + }, + "fsGroupChangePolicy": { + "type": "string" + }, + "runAsGroup": { + "format": "int64", + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "format": "int64", + "type": "integer" + }, + "seLinuxOptions": { + "properties": { + "level": { + "type": "string" + }, + "role": { + "type": "string" + }, + "type": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + }, + "seccompProfile": { + "properties": { + "localhostProfile": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "supplementalGroups": { + "items": { + "format": "int64", + "type": "integer" + }, + "type": "array" + }, + "sysctls": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "windowsOptions": { + "properties": { + "gmsaCredentialSpec": { + "type": "string" + }, + "gmsaCredentialSpecName": { + "type": "string" + }, + "hostProcess": { + "type": "boolean" + }, + "runAsUserName": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "serviceAccount": { + "type": "string" + }, + "serviceAccountName": { + "type": "string" + }, + "setHostnameAsFQDN": { + "type": "boolean" + }, + "shareProcessNamespace": { + "type": "boolean" + }, + "subdomain": { + "type": "string" + }, + "terminationGracePeriodSeconds": { + "format": "int64", + "type": "integer" + }, + "tolerations": { + "items": { + "properties": { + "effect": { + "type": "string" + }, + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "tolerationSeconds": { + "format": "int64", + "type": "integer" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "topologySpreadConstraints": { + "items": { + "properties": { + "labelSelector": { + "properties": { + "matchExpressions": { + "items": { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "key", + "operator" + ], + "type": "object" + }, + "type": "array" + }, + "matchLabels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "maxSkew": { + "format": "int32", + "type": "integer" + }, + "topologyKey": { + "type": "string" + }, + "whenUnsatisfiable": { + "type": "string" + } + }, + "required": [ + "maxSkew", + "topologyKey", + "whenUnsatisfiable" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-map-keys": [ + "topologyKey", + "whenUnsatisfiable" + ], + "x-kubernetes-list-type": "map" + }, + "volumes": { + "x-kubernetes-preserve-unknown-fields": true + } + }, + "required": [ + "containers" + ], + "type": "object" + } + }, + "type": "object" + } + }, + "required": [ + "name", + "selector", + "template" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "name", + "x-kubernetes-patch-strategy": "merge" + } + }, + "required": [ + "templates" + ], + "type": "object" + } + }, + "x-kubernetes-group-version-kind": [ + { + "group": "argoproj.io", + "kind": "Experiment", + "version": "v1alpha1" + } + ] + }, + "io.argoproj.v1alpha1.Rollout": { "properties": { "spec": { "properties": { diff --git a/hack/gen-crd-spec/main.go b/hack/gen-crd-spec/main.go index 193de108d7..22b893c663 100644 --- a/hack/gen-crd-spec/main.go +++ b/hack/gen-crd-spec/main.go @@ -16,6 +16,7 @@ import ( "github.com/ghodss/yaml" extensionsobj "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + kubeopenapiutil "k8s.io/kube-openapi/pkg/util" spec "k8s.io/kube-openapi/pkg/validation/spec" ) @@ -398,9 +399,6 @@ func generateKustomizeSchema(crds []*extensionsobj.CustomResourceDefinition, out definitions := map[string]interface{}{} for _, crd := range crds { - if crd.Spec.Names.Kind != "Rollout" { - continue - } var version string var props map[string]extensionsobj.JSONSchemaProps for _, v := range crd.Spec.Versions { @@ -434,7 +432,8 @@ func generateKustomizeSchema(crds []*extensionsobj.CustomResourceDefinition, out } } - definitions[fmt.Sprintf("%s.%s", version, crd.Spec.Names.Kind)] = map[string]interface{}{ + definitionName := kubeopenapiutil.ToRESTFriendlyName(fmt.Sprintf("%s/%s.%s", crd.Spec.Group, version, crd.Spec.Names.Kind)) + definitions[definitionName] = map[string]interface{}{ "properties": propsMap, "x-kubernetes-group-version-kind": []map[string]string{{ "group": crd.Spec.Group, From 935a825918b338be5c94d826911ad95dce1c6804 Mon Sep 17 00:00:00 2001 From: Jesse Antoszyk <22500761+jcantosz@users.noreply.github.com> Date: Thu, 30 Jun 2022 14:00:42 -0400 Subject: [PATCH 150/175] feat(grafana): Allow selecting datasource for grafana dashboard (#1988) Signed-off-by: Jesse Antoszyk <22500761+jcantosz@users.noreply.github.com> --- examples/dashboard.json | 61 +++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/examples/dashboard.json b/examples/dashboard.json index 05f60be4f6..b73151f669 100644 --- a/examples/dashboard.json +++ b/examples/dashboard.json @@ -28,7 +28,7 @@ "rgba(237, 129, 40, 0.89)", "#d44a3a" ], - "datasource": "Prometheus", + "datasource": "$datasource", "fieldConfig": { "defaults": { "custom": {} @@ -107,7 +107,7 @@ }, { "cacheTimeout": null, - "datasource": null, + "datasource": "$datasource", "fieldConfig": { "defaults": { "color": { @@ -185,7 +185,7 @@ "cacheTimeout": null, "dashLength": 10, "dashes": false, - "datasource": null, + "datasource": "$datasource", "fieldConfig": { "defaults": { "custom": {} @@ -279,7 +279,7 @@ }, { "collapsed": true, - "datasource": null, + "datasource": "$datasource", "gridPos": { "h": 1, "w": 24, @@ -290,7 +290,7 @@ "panels": [ { "cacheTimeout": null, - "datasource": "Prometheus", + "datasource": "$datasource", "fieldConfig": { "defaults": { "color": { @@ -370,7 +370,7 @@ }, { "cacheTimeout": null, - "datasource": "Prometheus", + "datasource": "$datasource", "fieldConfig": { "defaults": { "color": { @@ -450,7 +450,7 @@ }, { "cacheTimeout": null, - "datasource": "Prometheus", + "datasource": "$datasource", "fieldConfig": { "defaults": { "color": { @@ -530,7 +530,7 @@ }, { "cacheTimeout": null, - "datasource": "Prometheus", + "datasource": "$datasource", "fieldConfig": { "defaults": { "color": { @@ -607,7 +607,7 @@ }, { "cacheTimeout": null, - "datasource": "Prometheus", + "datasource": "$datasource", "fieldConfig": { "defaults": { "color": { @@ -687,7 +687,7 @@ }, { "cacheTimeout": null, - "datasource": "Prometheus", + "datasource": "$datasource", "fieldConfig": { "defaults": { "color": { @@ -764,7 +764,7 @@ }, { "cacheTimeout": null, - "datasource": "Prometheus", + "datasource": "$datasource", "fieldConfig": { "defaults": { "color": { @@ -846,7 +846,7 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": null, + "datasource": "$datasource", "fieldConfig": { "defaults": { "custom": {} @@ -952,7 +952,7 @@ "mode": "spectrum" }, "dataFormat": "tsbuckets", - "datasource": null, + "datasource": "$datasource", "fieldConfig": { "defaults": { "custom": {} @@ -1014,7 +1014,7 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": null, + "datasource": "$datasource", "fieldConfig": { "defaults": { "custom": {} @@ -1112,7 +1112,7 @@ }, { "collapsed": true, - "datasource": null, + "datasource": "$datasource", "gridPos": { "h": 1, "w": 24, @@ -1122,7 +1122,7 @@ "id": 32, "panels": [ { - "datasource": null, + "datasource": "$datasource", "fieldConfig": { "defaults": { "color": { @@ -1186,7 +1186,7 @@ "type": "table" }, { - "datasource": null, + "datasource": "$datasource", "fieldConfig": { "defaults": { "color": { @@ -1246,7 +1246,7 @@ "type": "stat" }, { - "datasource": null, + "datasource": "$datasource", "fieldConfig": { "defaults": { "color": { @@ -1309,7 +1309,7 @@ "type": "stat" }, { - "datasource": null, + "datasource": "$datasource", "fieldConfig": { "defaults": { "color": { @@ -1382,6 +1382,25 @@ "tags": [], "templating": { "list": [ + { + "current": { + "selected": false, + "text": "prometheus", + "value": "prometheus" + }, + "hide": 0, + "definition": "datasource(prometheus)", + "description": "rollout datasource", + "multi": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, { "allValue": null, "current": { @@ -1389,7 +1408,7 @@ "text": "default", "value": "default" }, - "datasource": null, + "datasource": "$datasource", "definition": "label_values(rollout_info,namespace)", "description": "rollout namespace", "error": null, @@ -1420,7 +1439,7 @@ "text": "", "value": "" }, - "datasource": null, + "datasource": "$datasource", "definition": "label_values(rollout_info{namespace=\"$rollout_namespace\"},name)", "description": "rollout name", "error": null, From 03b7f5e5cc6ee92581ad5c5612d87c70faf5cc6d Mon Sep 17 00:00:00 2001 From: Simon Ninon Date: Thu, 30 Jun 2022 11:04:47 -0700 Subject: [PATCH 151/175] feat: support /rollouts/:namespace?q=... and /rollout/:namespace/:name (#1902) Signed-off-by: Simon Ninon --- USERS.md | 1 + ui/src/app/App.tsx | 6 +++--- ui/src/app/components/header/header.tsx | 14 +++++++++++--- .../app/components/rollouts-list/rollouts-list.tsx | 13 +++++++++++-- 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/USERS.md b/USERS.md index cc59fd3382..9d7d511bbe 100644 --- a/USERS.md +++ b/USERS.md @@ -19,6 +19,7 @@ Organizations below are **officially** using Argo Rollouts. Please send a PR wit 1. [New Relic](https://newrelic.com/) 1. [Nitro](https://www.gonitro.com) 1. [Nozzle](https://nozzle.io) +1. [PagerDuty](https://www.pagerduty.com/) 1. [PayPal](https://www.paypal.com/) 1. [PayPay](https://paypay.ne.jp/) 1. [Quipper](https://www.quipper.com/) diff --git a/ui/src/app/App.tsx b/ui/src/app/App.tsx index 644aa3b4e7..b1d28fa5d5 100644 --- a/ui/src/app/App.tsx +++ b/ui/src/app/App.tsx @@ -92,7 +92,7 @@ const App = () => { } shortcuts={[ {key: '/', description: 'Search'}, @@ -102,7 +102,7 @@ const App = () => { ]} changeNamespace={changeNamespace} /> - } changeNamespace={changeNamespace} /> + } changeNamespace={changeNamespace} /> @@ -112,4 +112,4 @@ const App = () => { ); }; -export default App; \ No newline at end of file +export default App; diff --git a/ui/src/app/components/header/header.tsx b/ui/src/app/components/header/header.tsx index 90d51ee7c8..edda274ea8 100644 --- a/ui/src/app/components/header/header.tsx +++ b/ui/src/app/components/header/header.tsx @@ -13,6 +13,7 @@ export const Header = (props: {pageHasShortcuts: boolean; changeNamespace: (val: const history = useHistory(); const namespaceInfo = React.useContext(NamespaceContext); const {name} = useParams<{name: string}>(); + const {namespace} = useParams<{namespace: string}>(); const api = React.useContext(RolloutAPIContext); const [version, setVersion] = React.useState('v?'); const [nsInput, setNsInput] = React.useState(namespaceInfo.namespace); @@ -23,6 +24,12 @@ export const Header = (props: {pageHasShortcuts: boolean; changeNamespace: (val: }; getVersion(); }, []); + React.useEffect(() => { + if (namespace && namespace != namespaceInfo.namespace) { + props.changeNamespace(namespace); + setNsInput(namespace); + } + }, []); return ( @@ -54,8 +61,9 @@ export const Header = (props: {pageHasShortcuts: boolean; changeNamespace: (val: placeholder='Namespace' onChange={(el) => setNsInput(el.target.value)} onItemClick={(val) => { - props.changeNamespace(val ? val : nsInput); - history.push(`/`); + const selectedNamespace = val ? val : nsInput; + props.changeNamespace(selectedNamespace); + history.push(`/${selectedNamespace}`); }} value={nsInput} /> @@ -65,4 +73,4 @@ export const Header = (props: {pageHasShortcuts: boolean; changeNamespace: (val: ); -}; \ No newline at end of file +}; diff --git a/ui/src/app/components/rollouts-list/rollouts-list.tsx b/ui/src/app/components/rollouts-list/rollouts-list.tsx index dfbcb1d515..bd660ff471 100644 --- a/ui/src/app/components/rollouts-list/rollouts-list.tsx +++ b/ui/src/app/components/rollouts-list/rollouts-list.tsx @@ -29,6 +29,12 @@ export const RolloutsList = () => { const [filteredRollouts, setFilteredRollouts] = React.useState(rollouts); const [pos, nav, reset] = useNav(filteredRollouts.length); const [searchString, setSearchString, searchInput] = useAutocomplete(''); + const searchParam = new URLSearchParams(window.location.search).get('q'); + React.useEffect(() => { + if (searchParam && searchParam != searchString) { + setSearchString(searchParam); + } + }, []); const {useKeybinding, keybindingState} = React.useContext(KeybindingContext); @@ -81,6 +87,9 @@ export const RolloutsList = () => { if ((filtered || []).length > 0) { setFilteredRollouts(filtered); } + if (searchString) { + history.replace(`/${namespaceCtx.namespace}?q=${searchString}`); + } }, [searchString, rollouts]); const namespaceCtx = React.useContext(NamespaceContext); @@ -97,7 +106,7 @@ export const RolloutsList = () => { className='rollouts-list__search' placeholder='Search...' style={{marginBottom: '1.5em'}} - onItemClick={(item) => history.push(`/rollout/${item}`)} + onItemClick={(item) => history.push(`/rollout/${namespaceCtx.namespace}/${item}`)} icon='fa-search' {...searchInput} /> @@ -176,7 +185,7 @@ export const RolloutWidget = (props: {rollout: RolloutInfo; deselect: () => void return ( - + { From c4205e85ecd08c8f06824aa30de5141f916724c6 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Mon, 11 Jul 2022 17:15:23 -0500 Subject: [PATCH 152/175] chore: Add e2e and unit test comment reports (#2123) Signed-off-by: zachaller --- .github/workflows/e2e-test-results.yml | 43 +++++++++++++++++++ .github/workflows/e2e.yaml | 19 ++++++++ .github/workflows/go.yml | 19 +++++++- Makefile | 17 ++++++-- .../features/kustomize/rollout_cr_schema.json | 33 ++++++++++++++ hack/installers/install-dev-tools.sh | 24 +++++++++++ 6 files changed, 150 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/e2e-test-results.yml create mode 100755 hack/installers/install-dev-tools.sh diff --git a/.github/workflows/e2e-test-results.yml b/.github/workflows/e2e-test-results.yml new file mode 100644 index 0000000000..7130f3503a --- /dev/null +++ b/.github/workflows/e2e-test-results.yml @@ -0,0 +1,43 @@ +name: Test Results + +on: + workflow_run: + workflows: ["E2E Tests", "Go"] + types: + - completed +permissions: {} + +jobs: + test-results: + name: "${{ github.event.workflow.name }} Test Results" + runs-on: ubuntu-latest + if: github.event.workflow_run.conclusion != 'skipped' + permissions: + checks: write + pull-requests: write + actions: read + steps: + - name: Download and Extract Artifacts + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + run: | + mkdir -p artifacts && cd artifacts + artifacts_url=${{ github.event.workflow_run.artifacts_url }} + gh api "$artifacts_url" -q '.artifacts[] | [.name, .archive_download_url] | @tsv' | while read artifact + do + IFS=$'\t' read name url <<< "$artifact" + gh api $url > "$name.zip" + unzip -d "$name" "$name.zip" + done + + - name: Publish Test Results + uses: EnricoMi/publish-unit-test-result-action@v1 + with: + check_name: "${{ github.event.workflow.name }} Published Test Results" + commit: ${{ github.event.workflow_run.head_sha }} + event_file: artifacts/Event File/event.json + event_name: ${{ github.event.workflow_run.event }} + files: "artifacts/**/*.xml" + compare_to_earlier_commit: false + test_changes_limit: 0 + fail_on: "errors" diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 43620453b6..f65aeac991 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -21,6 +21,15 @@ concurrency: cancel-in-progress: true jobs: + event_file: + name: "Event File" + runs-on: ubuntu-latest + steps: + - name: Upload + uses: actions/upload-artifact@v2 + with: + name: Event File + path: ${{ github.event_path }} test-e2e: name: Run end-to-end tests runs-on: ubuntu-latest @@ -58,6 +67,16 @@ jobs: - name: Run e2e tests run: make test-e2e if: ${{ !(github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled) }} + - name: Output Rerun Overview + run: | + [[ -f rerunreport.txt ]] && cat rerunreport.txt || echo "No rerun report found" + - name: Upload E2E Test Results + if: always() + uses: actions/upload-artifact@v2 + with: + name: E2E Test Results + path: | + junit.xml - name: Upload e2e-controller logs uses: actions/upload-artifact@v2 with: diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 1e064f306f..19925d9628 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -16,6 +16,15 @@ concurrency: cancel-in-progress: true jobs: + event_file: + name: "Event File" + runs-on: ubuntu-latest + steps: + - name: Upload + uses: actions/upload-artifact@v2 + with: + name: Event File + path: ${{ github.event_path }} lint-go: name: Lint Go code runs-on: ubuntu-latest @@ -58,7 +67,15 @@ jobs: run: make controller plugin - name: Test - run: go test -failfast -covermode=count -coverprofile=coverage.out ./... + run: make test-unit + + - name: Upload Unit Test Results + if: always() + uses: actions/upload-artifact@v2 + with: + name: Unit Test Results + path: | + junit.xml - name: Generate code coverage artifacts uses: actions/upload-artifact@v2 diff --git a/Makefile b/Makefile index 61f91da345..df2542169b 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ DEV_IMAGE=false # E2E variables E2E_INSTANCE_ID ?= argo-rollouts-e2e E2E_TEST_OPTIONS ?= -E2E_PARALLEL ?= 4 +E2E_PARALLEL ?= 1 E2E_WAIT_TIMEOUT ?= 120 override LDFLAGS += \ @@ -79,9 +79,13 @@ install-go-tools-local: go-mod-vendor install-protoc-local: ./hack/installers/install-protoc.sh +.PHONY: install-devtools-local +install-devtools-local: + ./hack/installers/install-dev-tools.sh + # Installs all tools required to build and test locally .PHONY: install-tools-local -install-tools-local: install-go-tools-local install-protoc-local +install-tools-local: install-go-tools-local install-protoc-local install-devtools-local TYPES := $(shell find pkg/apis/rollouts/v1alpha1 -type f -name '*.go' -not -name openapi_generated.go -not -name '*generated*' -not -name '*test.go') APIMACHINERY_PKGS=k8s.io/apimachinery/pkg/util/intstr,+k8s.io/apimachinery/pkg/api/resource,+k8s.io/apimachinery/pkg/runtime/schema,+k8s.io/apimachinery/pkg/runtime,k8s.io/apimachinery/pkg/apis/meta/v1,k8s.io/api/core/v1,k8s.io/api/batch/v1 @@ -212,8 +216,13 @@ start-e2e: go run ./cmd/rollouts-controller/main.go --instance-id ${E2E_INSTANCE_ID} --loglevel debug --kloglevel 6 .PHONY: test-e2e -test-e2e: - go test -timeout 30m -v -count 1 --tags e2e -p ${E2E_PARALLEL} --short ./test/e2e ${E2E_TEST_OPTIONS} +test-e2e: install-devtools-local + ${DIST_DIR}/gotestsum --rerun-fails-report=rerunreport.txt --junitfile=junit.xml --format=testname --packages="./test/e2e" --rerun-fails=5 -- -timeout 60m -count 1 --tags e2e -p ${E2E_PARALLEL} -parallel ${E2E_PARALLEL} -v --short ./test/e2e ${E2E_TEST_OPTIONS} + +.PHONY: test-unit + test-unit: install-devtools-local + ${DIST_DIR}/gotestsum --junitfile=junit.xml --format=testname --packages="./..." -- -covermode=count -coverprofile=coverage.out ./... + .PHONY: coverage coverage: test diff --git a/docs/features/kustomize/rollout_cr_schema.json b/docs/features/kustomize/rollout_cr_schema.json index 729c0bfdf0..385b85ba63 100644 --- a/docs/features/kustomize/rollout_cr_schema.json +++ b/docs/features/kustomize/rollout_cr_schema.json @@ -266,6 +266,17 @@ }, "type": "object" }, + "influxdb": { + "properties": { + "profile": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "type": "object" + }, "job": { "properties": { "metadata": { @@ -4515,6 +4526,17 @@ }, "type": "object" }, + "influxdb": { + "properties": { + "profile": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "type": "object" + }, "job": { "properties": { "metadata": { @@ -8764,6 +8786,17 @@ }, "type": "object" }, + "influxdb": { + "properties": { + "profile": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "type": "object" + }, "job": { "properties": { "metadata": { diff --git a/hack/installers/install-dev-tools.sh b/hack/installers/install-dev-tools.sh new file mode 100755 index 0000000000..0e5f67f00a --- /dev/null +++ b/hack/installers/install-dev-tools.sh @@ -0,0 +1,24 @@ +#!/bin/bash +set -eux -o pipefail + +PROJECT_ROOT=$(cd $(dirname ${BASH_SOURCE})/../..; pwd) +DIST_PATH="${PROJECT_ROOT}/dist" +PATH="${DIST_PATH}:${PATH}" + +mkdir -p ${DIST_PATH} + +gotestsum_version=1.8.1 + +OS=$(go env GOOS) +ARCH=$(go env GOARCH) + +export TARGET_FILE=gotestsum_${gotestsum_version}_${OS}_${ARCH}.tar.gz +temp_path="/tmp/${TARGET_FILE}" +url=https://github.com/gotestyourself/gotestsum/releases/download/v${gotestsum_version}/gotestsum_${gotestsum_version}_${OS}_${ARCH}.tar.gz +[ -e ${temp_path} ] || curl -sLf --retry 3 -o ${temp_path} ${url} + +mkdir -p /tmp/gotestsum-${gotestsum_version} +tar -xvzf ${temp_path} -C /tmp/gotestsum-${gotestsum_version} +cp /tmp/gotestsum-${gotestsum_version}/gotestsum ${DIST_PATH}/gotestsum +chmod +x ${DIST_PATH}/gotestsum +gotestsum --version From f2c1d8a576fed904f8b95dff25e7c39276d9aadb Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Tue, 12 Jul 2022 17:06:43 -0500 Subject: [PATCH 153/175] chore: upgrade deps (#2136) Signed-off-by: zachaller --- .../features/kustomize/rollout_cr_schema.json | 20 + go.mod | 258 +++-- go.sum | 689 +++++++++---- manifests/crds/analysis-run-crd.yaml | 3 + manifests/crds/analysis-template-crd.yaml | 3 + .../crds/cluster-analysis-template-crd.yaml | 3 + manifests/crds/experiment-crd.yaml | 3 + manifests/crds/rollout-crd.yaml | 3 + manifests/install.yaml | 15 + manifests/namespace-install.yaml | 15 + pkg/apiclient/rollout/rollout.swagger.json | 385 +++---- pkg/apis/rollouts/v1alpha1/generated.pb.go | 945 +++++++++--------- pkg/apis/rollouts/v1alpha1/generated.proto | 2 +- pkg/client/clientset/versioned/clientset.go | 4 + ui/src/models/rollout/generated/api.ts | 46 +- 15 files changed, 1360 insertions(+), 1034 deletions(-) diff --git a/docs/features/kustomize/rollout_cr_schema.json b/docs/features/kustomize/rollout_cr_schema.json index 385b85ba63..4ec83fccff 100644 --- a/docs/features/kustomize/rollout_cr_schema.json +++ b/docs/features/kustomize/rollout_cr_schema.json @@ -3976,6 +3976,10 @@ "format": "int32", "type": "integer" }, + "minDomains": { + "format": "int32", + "type": "integer" + }, "topologyKey": { "type": "string" }, @@ -8236,6 +8240,10 @@ "format": "int32", "type": "integer" }, + "minDomains": { + "format": "int32", + "type": "integer" + }, "topologyKey": { "type": "string" }, @@ -12496,6 +12504,10 @@ "format": "int32", "type": "integer" }, + "minDomains": { + "format": "int32", + "type": "integer" + }, "topologyKey": { "type": "string" }, @@ -16565,6 +16577,10 @@ "format": "int32", "type": "integer" }, + "minDomains": { + "format": "int32", + "type": "integer" + }, "topologyKey": { "type": "string" }, @@ -19695,6 +19711,10 @@ "format": "int32", "type": "integer" }, + "minDomains": { + "format": "int32", + "type": "integer" + }, "topologyKey": { "type": "string" }, diff --git a/go.mod b/go.mod index d3d30f19e4..11388b57a3 100644 --- a/go.mod +++ b/go.mod @@ -5,11 +5,11 @@ go 1.17 require ( github.com/antonmedv/expr v1.9.0 github.com/argoproj/notifications-engine v0.3.1-0.20220129012210-32519f8f68ec - github.com/argoproj/pkg v0.11.1-0.20211203175135-36c59d8fafe0 - github.com/aws/aws-sdk-go-v2 v1.13.0 - github.com/aws/aws-sdk-go-v2/config v1.13.1 - github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.15.0 - github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.16.0 + github.com/argoproj/pkg v0.13.6 + github.com/aws/aws-sdk-go-v2 v1.16.7 + github.com/aws/aws-sdk-go-v2/config v1.15.14 + github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.18.6 + github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.18.8 github.com/blang/semver v3.5.1+incompatible github.com/evanphx/json-patch/v5 v5.6.0 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 @@ -17,103 +17,101 @@ require ( github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.2 github.com/grpc-ecosystem/grpc-gateway v1.16.0 - github.com/influxdata/influxdb-client-go/v2 v2.8.1 - github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a - github.com/mitchellh/mapstructure v1.4.3 - github.com/newrelic/newrelic-client-go v0.72.0 + github.com/influxdata/influxdb-client-go/v2 v2.9.1 + github.com/juju/ansiterm v1.0.0 + github.com/mitchellh/mapstructure v1.5.0 + github.com/newrelic/newrelic-client-go v0.86.5 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.12.1 + github.com/prometheus/client_golang v1.12.2 github.com/prometheus/client_model v0.2.0 - github.com/prometheus/common v0.32.1 - github.com/servicemeshinterface/smi-sdk-go v0.4.1 + github.com/prometheus/common v0.36.0 + github.com/servicemeshinterface/smi-sdk-go v0.5.0 github.com/sirupsen/logrus v1.8.1 github.com/soheilhy/cmux v0.1.5 github.com/spaceapegames/go-wavefront v1.8.1 - github.com/spf13/cobra v1.3.0 - github.com/stretchr/testify v1.7.0 + github.com/spf13/cobra v1.5.0 + github.com/stretchr/testify v1.8.0 github.com/tj/assert v0.0.3 github.com/valyala/fasttemplate v1.2.1 - google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa - google.golang.org/grpc v1.42.0 - google.golang.org/protobuf v1.27.1 + google.golang.org/genproto v0.0.0-20220712132514-bdd2acd4974d + google.golang.org/grpc v1.47.0 + google.golang.org/protobuf v1.28.0 gopkg.in/yaml.v2 v2.4.0 - k8s.io/api v0.23.3 - k8s.io/apiextensions-apiserver v0.23.1 - k8s.io/apimachinery v0.23.3 - k8s.io/apiserver v0.23.1 - k8s.io/cli-runtime v0.23.1 - k8s.io/client-go v0.23.3 - k8s.io/code-generator v0.23.2-rc.0 - k8s.io/component-base v0.23.1 - k8s.io/klog/v2 v2.30.0 - k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 - k8s.io/kubectl v0.23.1 - k8s.io/kubernetes v1.23.1 - k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b + k8s.io/api v0.24.2 + k8s.io/apiextensions-apiserver v0.24.2 + k8s.io/apimachinery v0.24.2 + k8s.io/apiserver v0.24.2 + k8s.io/cli-runtime v0.24.2 + k8s.io/client-go v0.24.2 + k8s.io/code-generator v0.24.2 + k8s.io/component-base v0.24.2 + k8s.io/klog/v2 v2.70.1 + k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8 + k8s.io/kubectl v0.24.2 + k8s.io/kubernetes v1.24.2 + k8s.io/utils v0.0.0-20220706174534-f6158b442e7c + ) require ( - cloud.google.com/go v0.99.0 // indirect + cloud.google.com/go/compute v1.7.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect - github.com/Azure/go-autorest/autorest v0.11.18 // indirect - github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect + github.com/Azure/go-autorest/autorest v0.11.27 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.20 // indirect github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect - github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd // indirect - github.com/Masterminds/goutils v1.1.0 // indirect + github.com/MakeNowJust/heredoc v1.0.0 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/sprig v2.22.0+incompatible // indirect - github.com/PuerkitoBio/purell v1.1.1 // indirect - github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect - github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.8.0 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.10.0 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.4 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.2.0 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.5 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.9.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.14.0 // indirect - github.com/aws/smithy-go v1.10.0 // indirect + github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20220708192748-b73dcb041214 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.12.9 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.8 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.14 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.8 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.15 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.8 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.11.12 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.16.9 // indirect + github.com/aws/smithy-go v1.12.0 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect github.com/bradleyfalzon/ghinstallation/v2 v2.0.4 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect - github.com/cyphar/filepath-securejoin v0.2.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/deepmap/oapi-codegen v1.9.1 // indirect - github.com/docker/distribution v2.7.1+incompatible // indirect - github.com/emicklei/go-restful v2.9.5+incompatible // indirect - github.com/evanphx/json-patch v4.12.0+incompatible // indirect - github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect - github.com/felixge/httpsnoop v1.0.1 // indirect - github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect - github.com/go-errors/errors v1.0.1 // indirect - github.com/go-logr/logr v1.2.0 // indirect + github.com/deepmap/oapi-codegen v1.11.0 // indirect + github.com/docker/distribution v2.8.1+incompatible // indirect + github.com/emicklei/go-restful/v3 v3.8.0 // indirect + github.com/evanphx/json-patch v5.6.0+incompatible // indirect + github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect + github.com/felixge/httpsnoop v1.0.3 // indirect + github.com/go-errors/errors v1.4.2 // indirect + github.com/go-logr/logr v1.2.3 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.19.5 // indirect - github.com/go-openapi/swag v0.19.14 // indirect - github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.4.0 // indirect - github.com/golang-jwt/jwt/v4 v4.0.0 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/swag v0.21.1 // indirect + github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 // indirect + github.com/golang-jwt/jwt/v4 v4.4.2 // indirect github.com/golang/glog v1.0.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/google/btree v1.0.1 // indirect - github.com/google/go-cmp v0.5.6 // indirect + github.com/google/btree v1.1.2 // indirect + github.com/google/gnostic v0.6.9 // indirect + github.com/google/go-cmp v0.5.8 // indirect github.com/google/go-github/v41 v41.0.0 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/gofuzz v1.1.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect - github.com/google/uuid v1.1.2 // indirect - github.com/googleapis/gnostic v0.5.5 // indirect - github.com/gorilla/websocket v1.4.2 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect github.com/gregdel/pushover v1.1.0 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-retryablehttp v0.7.0 // indirect + github.com/hashicorp/go-retryablehttp v0.7.1 // indirect github.com/huandu/xstrings v1.3.2 // indirect - github.com/imdario/mergo v0.3.12 // indirect + github.com/imdario/mergo v0.3.13 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect @@ -121,91 +119,87 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/lunixbochs/vtclean v1.0.0 // indirect - github.com/mailru/easyjson v0.7.6 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect - github.com/mitchellh/copystructure v1.0.0 // indirect - github.com/mitchellh/go-wordwrap v1.0.0 // indirect - github.com/mitchellh/reflectwalk v1.0.1 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-wordwrap v1.0.1 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/spdystream v0.2.0 // indirect - github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 // indirect + github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/onsi/ginkgo v1.16.4 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/runc v1.0.2 // indirect - github.com/opsgenie/opsgenie-go-sdk-v2 v1.0.5 // indirect + github.com/opsgenie/opsgenie-go-sdk-v2 v1.2.13 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/procfs v0.7.3 // indirect - github.com/russross/blackfriday v1.5.2 // indirect - github.com/slack-go/slack v0.10.1 // indirect + github.com/russross/blackfriday v1.6.0 // indirect + github.com/slack-go/slack v0.11.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/objx v0.2.0 // indirect + github.com/stretchr/objx v0.4.0 // indirect github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/whilp/git-urls v0.0.0-20191001220047-6db9661140c0 // indirect - github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect - go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect - golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect - golang.org/x/mod v0.5.1 // indirect - golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 // indirect - golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect - golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect - golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect + github.com/valyala/fastjson v1.6.3 // indirect + github.com/whilp/git-urls v1.0.0 // indirect + github.com/xlab/treeprint v1.1.0 // indirect + go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd // indirect + golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect + golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect + golang.org/x/net v0.0.0-20220708220712-1185a9018129 // indirect + golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 // indirect + golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e // indirect + golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect golang.org/x/text v0.3.7 // indirect - golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect - golang.org/x/tools v0.1.9 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect + golang.org/x/tools v0.1.10 // indirect + golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect gomodules.xyz/envconfig v1.3.1-0.20190308184047-426f31af0d45 // indirect - gomodules.xyz/notify v0.1.0 // indirect + gomodules.xyz/notify v0.1.1 // indirect google.golang.org/appengine v1.6.7 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect - k8s.io/cluster-bootstrap v0.0.0 // indirect - k8s.io/component-helpers v0.23.1 // indirect - k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c // indirect - sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect - sigs.k8s.io/kustomize/api v0.10.1 // indirect - sigs.k8s.io/kustomize/kyaml v0.13.0 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect - sigs.k8s.io/yaml v1.2.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/cluster-bootstrap v0.24.2 // indirect + k8s.io/component-helpers v0.24.2 // indirect + k8s.io/gengo v0.0.0-20211129171323-c02415ce4185 // indirect + sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124 // indirect + sigs.k8s.io/kustomize/api v0.11.5 // indirect + sigs.k8s.io/kustomize/kyaml v0.13.7 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) replace ( github.com/go-check/check => github.com/go-check/check v0.0.0-20180628173108-788fd7840127 - github.com/grpc-ecosystem/grpc-gateway => github.com/grpc-ecosystem/grpc-gateway v1.16.0 - github.com/miekg/dns => github.com/miekg/dns v1.1.45 - k8s.io/api => k8s.io/api v0.23.1 - k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.23.1 - k8s.io/apimachinery => k8s.io/apimachinery v0.23.2-rc.0 - k8s.io/apiserver => k8s.io/apiserver v0.23.1 - k8s.io/cli-runtime => k8s.io/cli-runtime v0.23.1 - k8s.io/client-go => k8s.io/client-go v0.23.1 - k8s.io/cloud-provider => k8s.io/cloud-provider v0.23.1 - k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.23.1 - k8s.io/code-generator => k8s.io/code-generator v0.23.2-rc.0 - k8s.io/component-base => k8s.io/component-base v0.23.1 - k8s.io/component-helpers => k8s.io/component-helpers v0.23.1 - k8s.io/controller-manager => k8s.io/controller-manager v0.23.1 - k8s.io/cri-api => k8s.io/cri-api v0.23.2-rc.0 - k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.23.1 - k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.23.1 - k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.23.1 - k8s.io/kube-proxy => k8s.io/kube-proxy v0.23.1 - k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.23.1 - k8s.io/kubectl => k8s.io/kubectl v0.23.1 - k8s.io/kubelet => k8s.io/kubelet v0.23.1 - k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.23.1 - k8s.io/metrics => k8s.io/metrics v0.23.1 - k8s.io/mount-utils => k8s.io/mount-utils v0.23.2-rc.0 - k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.23.1 - k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.23.1 - k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.23.1 - k8s.io/sample-controller => k8s.io/sample-controller v0.23.1 + k8s.io/api v0.0.0 => k8s.io/api v0.24.2 + k8s.io/apiextensions-apiserver v0.0.0 => k8s.io/apiextensions-apiserver v0.24.2 + k8s.io/apimachinery v0.0.0 => k8s.io/apimachinery v0.24.2 + k8s.io/apiserver v0.0.0 => k8s.io/apiserver v0.24.2 + k8s.io/cli-runtime v0.0.0 => k8s.io/cli-runtime v0.24.2 + k8s.io/client-go v0.0.0 => k8s.io/client-go v0.24.2 + k8s.io/cloud-provider v0.0.0 => k8s.io/cloud-provider v0.24.2 + k8s.io/cluster-bootstrap v0.0.0 => k8s.io/cluster-bootstrap v0.24.2 + k8s.io/code-generator v0.0.0 => k8s.io/code-generator v0.24.2 + k8s.io/component-base v0.0.0 => k8s.io/component-base v0.24.2 + k8s.io/component-helpers v0.0.0 => k8s.io/component-helpers v0.24.2 + k8s.io/controller-manager v0.0.0 => k8s.io/controller-manager v0.24.2 + k8s.io/cri-api v0.0.0 => k8s.io/cri-api v0.24.2 + k8s.io/csi-translation-lib v0.0.0 => k8s.io/csi-translation-lib v0.24.2 + k8s.io/kube-aggregator v0.0.0 => k8s.io/kube-aggregator v0.24.2 + k8s.io/kube-controller-manager v0.0.0 => k8s.io/kube-controller-manager v0.24.2 + k8s.io/kube-proxy v0.0.0 => k8s.io/kube-proxy v0.24.2 + k8s.io/kube-scheduler v0.0.0 => k8s.io/kube-scheduler v0.24.2 + k8s.io/kubectl v0.0.0 => k8s.io/kubectl v0.24.2 + k8s.io/kubelet v0.0.0 => k8s.io/kubelet v0.24.2 + k8s.io/legacy-cloud-providers v0.0.0 => k8s.io/legacy-cloud-providers v0.24.2 + k8s.io/metrics v0.0.0 => k8s.io/metrics v0.24.2 + k8s.io/mount-utils v0.0.0 => k8s.io/mount-utils v0.24.2 + k8s.io/pod-security-admission v0.0.0 => k8s.io/pod-security-admission v0.24.2 + k8s.io/sample-apiserver v0.0.0 => k8s.io/sample-apiserver v0.24.2 ) - -replace github.com/matryer/moq => github.com/matryer/moq v0.1.6 diff --git a/go.sum b/go.sum index 2a1b73ff4c..895aa0e1fe 100644 --- a/go.sum +++ b/go.sum @@ -28,18 +28,28 @@ cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+Y cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= -cloud.google.com/go v0.99.0 h1:y/cM2iqGgGi5D5DQZl6D9STN/3dR/Vx5Mp8s752oJTY= cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0 h1:DAq3r8y4mDgyB/ZPJ9v/5VJNqjgJAxTn6ZYLlUywOu8= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0 h1:v/k9Eueb8aAJ0vZuxKMrgm6kPhCLZU9HxFU+AFDs9Uk= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -49,27 +59,37 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-sdk-for-go v55.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.11.18 h1:90Y4srNYrwOtAgVo3ndrQkTYn6kf1Eg/AjTFJ8Is2aM= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= -github.com/Azure/go-autorest/autorest/adal v0.9.13 h1:Mp5hbtOePIzM8pJVRa3YLrWWmZtoxRXqUEzCfJt3+/Q= +github.com/Azure/go-autorest/autorest v0.11.27 h1:F3R3q42aWytozkV8ihzcgMO4OA4cuqr3bNlsEuF6//A= +github.com/Azure/go-autorest/autorest v0.11.27/go.mod h1:7l8ybrIdUmGqZMTD0sRtAr8NvbHjfofbf8RSP2q7w7U= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= +github.com/Azure/go-autorest/autorest/adal v0.9.20 h1:gJ3E98kMpFB1MFqQCvA1yFab8vthOeD4VlFRQULxahg= +github.com/Azure/go-autorest/autorest/adal v0.9.20/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw= +github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU= github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -80,10 +100,12 @@ github.com/GoogleCloudPlatform/k8s-cloud-provider v1.16.1-0.20210702024009-ea616 github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5hodBMJ5+l/7J4xAyMeuM2PNuepvHlGs8yilUCA= github.com/Jeffail/gabs v1.4.0 h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo= github.com/Jeffail/gabs v1.4.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= -github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= -github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= +github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= @@ -94,12 +116,13 @@ github.com/Microsoft/hcsshim v0.8.22/go.mod h1:91uVCVzvX2QD16sMCenoxxXo6L1wJnLMX github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60 h1:prBTRx78AQnXzivNT9Crhu564W/zPPr3ibSlpT9xKcE= github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60/go.mod h1:rjP7sIipbZcagro/6TCk6X0ZeFT2eyudH5+fve/cbBA= +github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20220708192748-b73dcb041214 h1:MdZskg1II+YVe+9ss935i8+paqqf4KEuYcTYUWSwABI= +github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20220708192748-b73dcb041214/go.mod h1:rjP7sIipbZcagro/6TCk6X0ZeFT2eyudH5+fve/cbBA= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -112,47 +135,50 @@ github.com/antonmedv/expr v1.8.9/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmH github.com/antonmedv/expr v1.9.0 h1:j4HI3NHEdgDnN9p6oI6Ndr0G5QryMY0FNxT4ONrFDGU= github.com/antonmedv/expr v1.9.0/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmHhwGEk8= github.com/appscode/go v0.0.0-20190808133642-1d4ef1f1c1e0/go.mod h1:iy07dV61Z7QQdCKJCIvUoDL21u6AIceRhZzyleh2ymc= +github.com/appscode/go v0.0.0-20191119085241-0887d8ec2ecc/go.mod h1:OawnOmAL4ZX3YaPdN+8HTNwBveT1jMsqP74moa9XUbE= github.com/argoproj/notifications-engine v0.3.1-0.20220129012210-32519f8f68ec h1:ulv8ieYQZLyQrTVR4za1ucLFnemS0Dksz8y5e91xxak= github.com/argoproj/notifications-engine v0.3.1-0.20220129012210-32519f8f68ec/go.mod h1:QF4tr3wfWOnhkKSaRpx7k/KEErQAh8iwKQ2pYFu/SfA= -github.com/argoproj/pkg v0.11.1-0.20211203175135-36c59d8fafe0 h1:Cfp7rO/HpVxnwlRqJe0jHiBbZ77ZgXhB6HWlYD02Xdc= -github.com/argoproj/pkg v0.11.1-0.20211203175135-36c59d8fafe0/go.mod h1:ra+bQPmbVAoEL+gYSKesuigt4m49i3Qa3mE/xQcjCiA= +github.com/argoproj/pkg v0.13.6 h1:36WPD9MNYECHcO1/R1pj6teYspiK7uMQLCgLGft2abM= +github.com/argoproj/pkg v0.13.6/go.mod h1:I698DoJBKuvNFaixh4vFl2C88cNIT1WS7KCbz5ewyF8= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/auth0/go-jwt-middleware v1.0.1/go.mod h1:YSeUX3z6+TF2H+7padiEqNJ73Zy9vXW72U//IgN0BIM= -github.com/aws/aws-sdk-go v1.33.16/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.35.24/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k= github.com/aws/aws-sdk-go v1.38.49/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go-v2 v1.13.0 h1:1XIXAfxsEmbhbj5ry3D3vX+6ZcUYvIqSm4CWWEuGZCA= -github.com/aws/aws-sdk-go-v2 v1.13.0/go.mod h1:L6+ZpqHaLbAaxsqV0L4cvxZY7QupWJB4fhkf8LXvC7w= -github.com/aws/aws-sdk-go-v2/config v1.13.1 h1:yLv8bfNoT4r+UvUKQKqRtdnvuWGMK5a82l4ru9Jvnuo= -github.com/aws/aws-sdk-go-v2/config v1.13.1/go.mod h1:Ba5Z4yL/UGbjQUzsiaN378YobhFo0MLfueXGiOsYtEs= -github.com/aws/aws-sdk-go-v2/credentials v1.8.0 h1:8Ow0WcyDesGNL0No11jcgb1JAtE+WtubqXjgxau+S0o= -github.com/aws/aws-sdk-go-v2/credentials v1.8.0/go.mod h1:gnMo58Vwx3Mu7hj1wpcG8DI0s57c9o42UQ6wgTQT5to= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.10.0 h1:NITDuUZO34mqtOwFWZiXo7yAHj7kf+XPE+EiKuCBNUI= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.10.0/go.mod h1:I6/fHT/fH460v09eg2gVrd8B/IqskhNdpcLH0WNO3QI= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.4 h1:CRiQJ4E2RhfDdqbie1ZYDo8QtIo75Mk7oTdJSfwJTMQ= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.4/go.mod h1:XHgQ7Hz2WY2GAn//UXHofLfPXWh+s62MbMOijrg12Lw= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.2.0 h1:3ADoioDMOtF4uiK59vCpplpCwugEU+v4ZFD29jDL3RQ= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.2.0/go.mod h1:BsCSJHx5DnDXIrOcqB8KN1/B+hXLG/bi4Y6Vjcx/x9E= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.5 h1:ixotxbfTCFpqbuwFv/RcZwyzhkxPSYDYEMcj4niB5Uk= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.5/go.mod h1:R3sWUqPcfXSiF/LSFJhjyJmpg9uV6yP2yv3YZZjldVI= -github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.15.0 h1:5WstmcviZ9X/h5nORkGT4akyLmWjrLxE9s8oKkFhkD4= -github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.15.0/go.mod h1:bPS4S6vXEGUVMabXYHOJRFvoWrztb38v4i84i8Hd6ZY= -github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.16.0 h1:4NawSD1qP7RPEqtCoahFNwkTa4MHtoKF08mhy+Y2Kok= -github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.16.0/go.mod h1:5rsn/Fxs9Rnq28KLB8n1pJcRR3UtrHY787uapxrvDRA= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0 h1:4QAOB3KrvI1ApJK14sliGr3Ie2pjyvNypn/lfzDHfUw= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0/go.mod h1:K/qPe6AP2TGYv4l6n7c88zh9jWBDf6nHhvg1fx/EWfU= -github.com/aws/aws-sdk-go-v2/service/sso v1.9.0 h1:1qLJeQGBmNQW3mBNzK2CFmrQNmoXWrscPqsrAaU1aTA= -github.com/aws/aws-sdk-go-v2/service/sso v1.9.0/go.mod h1:vCV4glupK3tR7pw7ks7Y4jYRL86VvxS+g5qk04YeWrU= -github.com/aws/aws-sdk-go-v2/service/sts v1.14.0 h1:ksiDXhvNYg0D2/UFkLejsaz3LqpW5yjNQ8Nx9Sn2c0E= -github.com/aws/aws-sdk-go-v2/service/sts v1.14.0/go.mod h1:u0xMJKDvvfocRjiozsoZglVNXRG19043xzp3r2ivLIk= -github.com/aws/smithy-go v1.10.0 h1:gsoZQMNHnX+PaghNw4ynPsyGP7aUCqx5sY2dlPQsZ0w= -github.com/aws/smithy-go v1.10.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/aws/aws-sdk-go v1.44.39/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go-v2 v1.16.7 h1:zfBwXus3u14OszRxGcqCDS4MfMCv10e8SMJ2r8Xm0Ns= +github.com/aws/aws-sdk-go-v2 v1.16.7/go.mod h1:6CpKuLXg2w7If3ABZCl/qZ6rEgwtjZTn4eAf4RcEyuw= +github.com/aws/aws-sdk-go-v2/config v1.15.14 h1:+BqpqlydTq4c2et9Daury7gE+o67P4lbk7eybiCBNc4= +github.com/aws/aws-sdk-go-v2/config v1.15.14/go.mod h1:CQBv+VVv8rR5z2xE+Chdh5m+rFfsqeY4k0veEZeq6QM= +github.com/aws/aws-sdk-go-v2/credentials v1.12.9 h1:DloAJr0/jbvm0iVRFDFh8GlWxrOd9XKyX82U+dfVeZs= +github.com/aws/aws-sdk-go-v2/credentials v1.12.9/go.mod h1:2Vavxl1qqQXJ8MUcQZTsIEW8cwenFCWYXtLRPba3L/o= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.8 h1:VfBdn2AxwMbFyJN/lF/xuT3SakomJ86PZu3rCxb5K0s= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.8/go.mod h1:oL1Q3KuCq1D4NykQnIvtRiBGLUXhcpY5pl6QZB2XEPU= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.14 h1:2C0pYHcUBmdzPj+EKNC4qj97oK6yjrUhc1KoSodglvk= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.14/go.mod h1:kdjrMwHwrC3+FsKhNcCMJ7tUVj/8uSD5CZXeQ4wV6fM= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.8 h1:2J+jdlBJWEmTyAwC82Ym68xCykIvnSnIN18b8xHGlcc= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.8/go.mod h1:ZIV8GYoC6WLBW5KGs+o4rsc65/ozd+eQ0L31XF5VDwk= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.15 h1:QquxR7NH3ULBsKC+NoTpilzbKKS+5AELfNREInbhvas= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.15/go.mod h1:Tkrthp/0sNBShQQsamR7j/zY4p19tVTAs+nnqhH6R3c= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.18.6 h1:3FtKgndLdv919p3V4VStk8y3agcC9yEu9vrhhe+rvfQ= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.18.6/go.mod h1:A9gdtslk61CskUB2nDcY2fuvJ1RNl5bskr1eTJrcUJU= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.18.8 h1:D6Sc+XyjK++NhkJJLvZNcf0xyzNhhC+GVn/MYDeONS4= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.18.8/go.mod h1:8OyausC7+VUBNJFOEDjvSrowuefSkEoJaUzsGLNRXZQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.8 h1:oKnAXxSF2FUvfgw8uzU/v9OTYorJJZ8eBmWhr9TWVVQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.8/go.mod h1:rDVhIMAX9N2r8nWxDUlbubvvaFMnfsm+3jAV7q+rpM4= +github.com/aws/aws-sdk-go-v2/service/sso v1.11.12 h1:760bUnTX/+d693FT6T6Oa7PZHfEQT9XMFZeM5IQIB0A= +github.com/aws/aws-sdk-go-v2/service/sso v1.11.12/go.mod h1:MO4qguFjs3wPGcCSpQ7kOFTwRvb+eu+fn+1vKleGHUk= +github.com/aws/aws-sdk-go-v2/service/sts v1.16.9 h1:yOfILxyjmtr2ubRkRJldlHDFBhf5vw4CzhbwWIBmimQ= +github.com/aws/aws-sdk-go-v2/service/sts v1.16.9/go.mod h1:O1IvkYxr+39hRf960Us6j0x1P8pDqhTX+oXM5kQNl/Y= +github.com/aws/smithy-go v1.12.0 h1:gXpeZel/jPoWQ7OEmLIgCUnhkFftqNfwWUwAHSlp1v0= +github.com/aws/smithy-go v1.12.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -161,15 +187,16 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= -github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/bradleyfalzon/ghinstallation/v2 v2.0.4 h1:tXKVfhE7FcSkhkv0UwkLvPDeZ4kz6OXd0PKPlFqf81M= github.com/bradleyfalzon/ghinstallation/v2 v2.0.4/go.mod h1:B40qPqJxWE0jDZgOR1JmaMy+4AY1eBP+IByOvqyAKp0= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -183,12 +210,12 @@ github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cb github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 h1:7aWHqerlJ41y6FOsEUvknqgXnGmJyJSbjhAWq5pO4F8= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= -github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= -github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -212,14 +239,14 @@ github.com/container-storage-interface/spec v1.5.0/go.mod h1:8K96oQNkJ7pFcC2R9Z1 github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/containerd v1.4.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.4.11/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.12/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= -github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= github.com/coredns/caddy v1.1.0/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4= github.com/coredns/corefile-migration v1.0.14/go.mod h1:XnhgULOEouimnzgn0t4WPuFDN2/PJQcTxdWKC5eXNGE= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -235,12 +262,12 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= -github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= -github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -249,26 +276,32 @@ github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1 github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= -github.com/deepmap/oapi-codegen v1.9.1 h1:yHmEnA7jSTUMQgV+uN02WpZtwHnz2CBW3mZRIxr1vtI= -github.com/deepmap/oapi-codegen v1.9.1/go.mod h1:PLqNAhdedP8ttRpBBkzLKU3bp+Fpy+tTgeAMlztR2cw= +github.com/deepmap/oapi-codegen v1.11.0 h1:f/X2NdIkaBKsSdpeuwLnY/vDI0AtPUrmB5LMgc7YD+A= +github.com/deepmap/oapi-codegen v1.11.0/go.mod h1:k+ujhoQGxmQYBZBbxhOZNZf4j08qv5mC+OH+fFTnKxM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= -github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/distribution v2.8.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v20.10.12+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/elazarl/goproxy v0.0.0-20210801061803-8e322dfb79c4 h1:lS3P5Nw3oPO05Lk2gFiYUOL3QPaH+fRoI1wFOc4G1UY= -github.com/elazarl/goproxy v0.0.0-20210801061803-8e322dfb79c4/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy v0.0.0-20220417044921-416226498f94 h1:VIy7cdK7ufs7ctpTFkXJHm1uP3dJSnCGSPysEICB1so= +github.com/elazarl/goproxy v0.0.0-20220417044921-416226498f94/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw= +github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -278,16 +311,21 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdRwPr2TU5ThnS43puaKEMpja1uw= +github.com/evanphx/json-patch v0.0.0-20200808040245-162e5629780b/go.mod h1:NAJj0yf/KaRKURN6nyi7A9IZydMivZEm9oQLWNjfKDc= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= +github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= +github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= +github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= @@ -296,13 +334,14 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flosch/pongo2 v0.0.0-20181225140029-79872a7b2769/go.mod h1:tbAXHifHQWNSpWbiJHpJTZH5fi3XHhDMdP//vuz9WS4= +github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -314,41 +353,57 @@ github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= -github.com/getkin/kin-openapi v0.87.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= +github.com/getkin/kin-openapi v0.94.0/go.mod h1:LWZfzOd7PRy8GJ1dJ6mCU6tNdSfOwRac1BUPam4aw6Q= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew= github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= +github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= -github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU= +github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= @@ -356,31 +411,37 @@ github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= -github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= -github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-playground/validator/v10 v10.11.0/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.4.0 h1:Mr3JcvBjQEhCN9wld6OHKHuHxWaoXTaQfYKmj7QwP18= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.4.0/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8= +github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc= +github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8= github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/goccy/go-json v0.7.8/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/golang-jwt/jwt/v4 v4.0.0 h1:RAqyYixv1p7uEnocuy8P1nru5wprCh/MH2BIlW5z5/o= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs= +github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -397,6 +458,7 @@ github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71 github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -420,11 +482,15 @@ github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGS github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/cadvisor v0.43.0/go.mod h1:+RdMSbc3FVr5NYCD2dOEJy/LI0jYJ/0xJXkzWXEyiFQ= -github.com/google/cel-go v0.9.0/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/cadvisor v0.44.1/go.mod h1:GQ9KQfz0iNHQk3D6ftzJWK4TXabfIgM10Oy3FkR+Gzg= +github.com/google/cel-go v0.10.1/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w= github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= +github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= +github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -436,16 +502,19 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v41 v41.0.0 h1:HseJrM2JFf2vfiZJ8anY2hqBjdfY1Vlj/K27ueww4gg= github.com/google/go-github/v41 v41.0.0/go.mod h1:XgmCA5H323A9rtgExdTcnDkcqp6S30AVACCBDOonIxg= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -461,6 +530,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= @@ -468,16 +538,23 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= -github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4 h1:4EZlYQIiyecYJlUbVkFXCXHz1QPhVXcHnQKAzBTPfQo= github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4/go.mod h1:lEO7XoHJ/xNRBCxrn4h/CEB67h0kW1B0t4ooP2yrjUA= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= @@ -486,8 +563,9 @@ github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORR github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregdel/pushover v1.1.0 h1:dwHyvrcpZCOS9V1fAnKPaGRRI5OC55cVaKhMybqNsKQ= github.com/gregdel/pushover v1.1.0/go.mod h1:EcaO66Nn1StkpEm1iKtBTV3d2A16SoMsVER1PthX7to= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= @@ -496,6 +574,7 @@ github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:Fecb github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= @@ -518,8 +597,9 @@ github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHh github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-retryablehttp v0.5.1/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4= github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= +github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= @@ -553,19 +633,19 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/influxdb-client-go/v2 v2.8.1 h1:DahMl2iYvr9hEtGZcV4Ud8Z7AQ8cQVbPlX6gEOBBCrE= -github.com/influxdata/influxdb-client-go/v2 v2.8.1/go.mod h1:x7Jo5UHHl+w8wu8UnGiNobDDHygojXwJX4mx7rXGKMk= +github.com/influxdata/influxdb-client-go/v2 v2.9.1 h1:5kbH226fmmiV0MMTs7a8L7/ECCKdJWBi1QZNNv4/TkI= +github.com/influxdata/influxdb-client-go/v2 v2.9.1/go.mod h1:x7Jo5UHHl+w8wu8UnGiNobDDHygojXwJX4mx7rXGKMk= github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf h1:7JTmneyiNEwVBOHSjoMxiWAqB992atOeepeFYegn5RU= github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= github.com/ishidawataru/sctp v0.0.0-20190723014705-7c296d48a2b5/go.mod h1:DM4VvS+hD/kDi1U1QsX2fnZowwBhqD0Dk3bRPKF/Oc8= github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -578,6 +658,7 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -586,8 +667,8 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU= -github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU= +github.com/juju/ansiterm v1.0.0 h1:gmMvnZRq7JZJx6jkfSq9/+2LMrVEwGwt7UR6G+lmDEg= +github.com/juju/ansiterm v1.0.0/go.mod h1:PyXUpnI3olx3bsPcHt98FGPX/KCFZ1Fi+hw1XLI6384= github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= @@ -599,7 +680,9 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -611,21 +694,23 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= -github.com/labstack/echo/v4 v4.6.3/go.mod h1:Hk5OiHj0kDqmFq7aHe7eDqI7CUhuCrfpupQtLGGLm7A= +github.com/labstack/echo/v4 v4.7.2/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= github.com/lestrrat-go/blackmagic v1.0.0/go.mod h1:TNgH//0vYSs8VXDCfkZLgIrVTTXQELZffUV0tz3MtdQ= -github.com/lestrrat-go/codegen v1.0.2/go.mod h1:JhJw6OQAuPEfVKUCLItpaVLumDGWQznd1VaXrBk9TdM= -github.com/lestrrat-go/httpcc v1.0.0/go.mod h1:tGS/u00Vh5N6FHNkExqGGNId8e0Big+++0Gf8MBnAvE= +github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= +github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc= -github.com/lestrrat-go/jwx v1.2.7/go.mod h1:bw24IXWbavc0R2RsOtpXL7RtMyP589yZ1+L7kd09ZGA= +github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= +github.com/lestrrat-go/jwx v1.2.24/go.mod h1:zoNuZymNl5lgdcu6P7K6ie2QRll5HVfF4xwxBBK1NxY= github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/libopenstorage/openstorage v1.0.0/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= @@ -643,12 +728,15 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailgun/mailgun-go v2.0.0+incompatible/go.mod h1:NWTyU+O4aczg/nsGhQnvHL6v2n5Gy6Sv5tNDVvC6FbU= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/matryer/moq v0.1.6/go.mod h1:9RtPYjTnH1bSBIkpvtHkFN7nbWAnO7oRpdJkEIn6UtE= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= +github.com/matryer/moq v0.2.7/go.mod h1:kITsx543GOENm48TUAQyJ9+SAvFSr7iGQXPoth/VUBk= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -656,6 +744,7 @@ github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.10/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= @@ -674,39 +763,43 @@ github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpe github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/miekg/dns v1.1.45/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mindprince/gonvml v0.0.0-20190828220739-9ebdce4bb989/go.mod h1:2eu9pRWp8mo84xCg6KswZ+USQHjwgRhNp06sozOdsTY= github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= -github.com/minio/minio-go/v7 v7.0.2/go.mod h1:dJ80Mv2HeGkYLH1sqS/ksz07ON6csH3S6JUMSQ2zAns= +github.com/minio/minio-go/v7 v7.0.29/go.mod h1:x81+AX5gHSfCSqw7jxRKHvxUXMlE5uKX0Vb75Xk5yYg= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= -github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= -github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/ipvs v1.0.1/go.mod h1:2pngiyseZbIKXNv7hsKj3O9UEz30c53MT9005gt2hxQ= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= -github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= -github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 h1:yH0SvLzcbZxcJXho2yh7CqdENGMQe73Cw3woZBpPli0= -github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= +github.com/moby/sys/mountinfo v0.6.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= +github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= +github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -721,18 +814,20 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mvdan/xurls v1.1.0/go.mod h1:tQlNn3BED8bE/15hnSL2HLkDeLWpNPAwtw7wkEq44oU= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/newrelic/newrelic-client-go v0.72.0 h1:7dv4V+Wq4cKqZ1vq2OkspF9j08Q65D9A19LB6FWn9XM= -github.com/newrelic/newrelic-client-go v0.72.0/go.mod h1:VXjhsfui0rvhM9cVwnKwlidF8NbXlHZvh63ZKi6fImA= +github.com/newrelic/newrelic-client-go v0.86.5 h1:RxjhA/xdjcnMTxl1oq+ms6tGTuZOOL+h8IcfBCD1PVY= +github.com/newrelic/newrelic-client-go v0.86.5/go.mod h1:RYMXt7hgYw7nzuXIGd2BH0F1AivgWw7WrBhNBQZEB4k= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nlopes/slack v0.5.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= @@ -740,28 +835,38 @@ github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852/go.mod h1:eqOVx github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4= github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v1.0.2 h1:opHZMaswlyxz1OuGpBE53Dwe4/xF7EZTY0A2L/FpCOg= -github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v1.1.0/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= +github.com/opencontainers/runc v1.1.1/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opsgenie/opsgenie-go-sdk-v2 v1.0.5 h1:AnS8ZCC5dle8P4X4FZ+IOlX9v0jAkCMiZDIzRnYwBbs= github.com/opsgenie/opsgenie-go-sdk-v2 v1.0.5/go.mod h1:f0ezb0R/mrB9Hpm5RrIS6EX3ydjsR2nAB88nYYXZcNY= +github.com/opsgenie/opsgenie-go-sdk-v2 v1.2.13 h1:nV98dkBpqaYbDnhefmOQ+Rn4hE+jD6AtjYHXaU5WyJI= +github.com/opsgenie/opsgenie-go-sdk-v2 v1.2.13/go.mod h1:4OjcxgwdXzezqytxN534MooNmrxRD50geWZxTD7845s= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= @@ -787,8 +892,9 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34= +github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -800,9 +906,9 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.36.0 h1:78hJTing+BLYLjhXE+Z2BubeEymH5Lr0/Mt8FKkxxYo= +github.com/prometheus/common v0.36.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -818,6 +924,7 @@ github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uY github.com/rivo/tview v0.0.0-20200219210816-cd38d7432498/go.mod h1:6lkG1x+13OShEf0EaOCaTQYyB7d5nSbb181KtjlS+84= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -825,20 +932,22 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rubiojr/go-vhd v0.0.0-20200706105327-02e210299021/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= -github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= +github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/sanity-io/litter v1.2.0/go.mod h1:JF6pZUFgu2Q0sBZ+HSV35P8TVPI1TTzEwyu9FXAw2W4= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/servicemeshinterface/smi-sdk-go v0.4.1 h1:L8nS7WtVlGoEJF7RdCbwh0Oj/JheGY+5fa3R+cA2ReY= -github.com/servicemeshinterface/smi-sdk-go v0.4.1/go.mod h1:9rsLPBNcqfDNmEgyYwpopn93aE9yz46d2EHFBNOYj/w= +github.com/servicemeshinterface/smi-sdk-go v0.5.0 h1:9cZdhvGbGDlmnp9qqmcQL+RL6KZ3IzHfDLoA5Axg8n0= +github.com/servicemeshinterface/smi-sdk-go v0.5.0/go.mod h1:nm1Slf3pfaZPP3g2tE/K5wDmQ1uWVSP0p3uu5rQAQLc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= @@ -847,11 +956,11 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/slack-go/slack v0.10.1 h1:BGbxa0kMsGEvLOEoZmYs8T1wWfoZXwmQFBb6FgYCXUA= github.com/slack-go/slack v0.10.1/go.mod h1:wWL//kk0ho+FcQXcBTmEafUI5dz4qz5f4mMk8oIkioQ= +github.com/slack-go/slack v0.11.0 h1:sBBjQz8LY++6eeWhGJNZpRm5jvLRNnWBFZ/cAq58a6k= +github.com/slack-go/slack v0.11.0/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= -github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -865,7 +974,6 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= @@ -874,8 +982,10 @@ github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3 github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= -github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0= github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= +github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -891,16 +1001,20 @@ github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag github.com/storageos/go-api v2.2.0+incompatible/go.mod h1:ZrLn+e0ZuF3Y65PNF6dIwbJPZqfmtCXxFm9ckv0agOY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= @@ -912,14 +1026,16 @@ github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFy github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0= +github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fastjson v1.6.3 h1:tAKFnnwmeMGPbwJ7IwxcTPCNr3uIzoIj3/Fh90ra4xc= +github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= @@ -927,18 +1043,22 @@ github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYp github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= -github.com/whilp/git-urls v0.0.0-20191001220047-6db9661140c0 h1:qqllXPzXh+So+mmANlX/gCJrgo+1kQyshMoQ+NASzm0= github.com/whilp/git-urls v0.0.0-20191001220047-6db9661140c0/go.mod h1:2rx5KE5FLD0HRfkkpyn8JwbVLBdhgeiOb2D2D9LLKM4= +github.com/whilp/git-urls v1.0.0 h1:95f6UMWN5FKW71ECsXRUd3FVYiXdrE7aX4NZKcPmIjU= +github.com/whilp/git-urls v1.0.0/go.mod h1:J16SAmobsqc3Qcy98brfl5f5+e0clUvg1krgwk/qCfE= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= +github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= +github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= @@ -949,6 +1069,7 @@ go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3 go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/client/v3 v3.5.1/go.mod h1:OnjH4M8OnAotwaB2l9bVgZzRFKru7/ZMoS46OtKyd3Q= go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= @@ -971,8 +1092,9 @@ go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= +go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd h1:Uo/x0Ir5vQJ+683GXB9Ug+4fcjsbp7z7Ul8UaZbhsRM= +go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= @@ -988,19 +1110,25 @@ golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1047,14 +1175,16 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -1069,6 +1199,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1096,17 +1228,25 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 h1:EN5+DfgmRMvRUrMGERW2gQl3Vc+Z7ZMnI/xdEpPSf0c= -golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220513224357-95641704303c/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220708220712-1185a9018129 h1:vucSRfWwTsoXro7P+3Cjlr6flUMtzCwzlvkxEQtHHB0= +golang.org/x/net v0.0.0-20220708220712-1185a9018129/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1125,8 +1265,13 @@ golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 h1:VnGaRqoLmqZH/3TMLJwYCEWkR4j1nuIU1U9TvbqsDUw= +golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1138,6 +1283,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1156,12 +1303,16 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1194,18 +1345,18 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1213,7 +1364,6 @@ golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1223,25 +1373,42 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e h1:NHvCuwuS43lGnYhten69ZWqi2QOj/CiDNcKbVqwVoew= +golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM= +golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1257,11 +1424,15 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U= +golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1275,11 +1446,14 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1310,35 +1484,37 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200815165600-90abf76919f3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM= -golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8= -golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gomodules.xyz/envconfig v1.3.1-0.20190308184047-426f31af0d45 h1:juzzlx91nWAOsHuOVfXZPMXHtJEKouZvY9bBbwlOeYs= gomodules.xyz/envconfig v1.3.1-0.20190308184047-426f31af0d45/go.mod h1:41y72mzHT7+jFNgyBpJRrZWuZJcLmLrTpq6iGgOFJMQ= -gomodules.xyz/notify v0.1.0 h1:lN7CAFKIWxaXJXm3F/7KTbgw3lUy9peh6iyjgj1skvA= gomodules.xyz/notify v0.1.0/go.mod h1:wGy0vLXGpabCg0j9WbjzXf7pM7Khz11FqCLtBbTujP0= +gomodules.xyz/notify v0.1.1 h1:1tTuoyswmPvzqPCTEDQK8SZ3ukCxLsonAAwst2+y1a0= +gomodules.xyz/notify v0.1.1/go.mod h1:QgQyU4xEA/plJcDeT66J2Go2V7U4c0pD9wjo7HfFil4= +gomodules.xyz/version v0.1.0/go.mod h1:Y8xuV02mL/45psyPKG3NCVOwvAOy6T5Kx0l3rCjKSjU= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= gonum.org/v1/gonum v0.6.2/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= @@ -1379,6 +1555,15 @@ google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdr google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1430,6 +1615,7 @@ google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= @@ -1454,8 +1640,28 @@ google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220712132514-bdd2acd4974d h1:YbuF5+kdiC516xIP60RvlHeFbY9sRDR73QsAGHpkeVw= +google.golang.org/genproto v0.0.0-20220712132514-bdd2acd4974d/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1483,8 +1689,13 @@ google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1498,8 +1709,9 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= @@ -1522,10 +1734,12 @@ gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1538,8 +1752,10 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= @@ -1550,61 +1766,88 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.23.1 h1:ncu/qfBfUoClqwkTGbeRqqOqBCRoUAflMuOaOD7J0c8= -k8s.io/api v0.23.1/go.mod h1:WfXnOnwSqNtG62Y1CdjoMxh7r7u9QXGCkA1u0na2jgo= -k8s.io/apiextensions-apiserver v0.23.1 h1:xxE0q1vLOVZiWORu1KwNRQFsGWtImueOrqSl13sS5EU= -k8s.io/apiextensions-apiserver v0.23.1/go.mod h1:0qz4fPaHHsVhRApbtk3MGXNn2Q9M/cVWWhfHdY2SxiM= -k8s.io/apimachinery v0.23.2-rc.0 h1:MnclcThycinuHAhHBk1dAqEOYi85WlXeAbz2tfGjvWM= -k8s.io/apimachinery v0.23.2-rc.0/go.mod h1:SADt2Kl8/sttJ62RRsi9MIV4o8f5S3coArm0Iu3fBno= -k8s.io/apiserver v0.23.1 h1:vWGf8LcV9Pk/z5rdLmCiBDqE21ccbe930dzrtVMhw9g= -k8s.io/apiserver v0.23.1/go.mod h1:Bqt0gWbeM2NefS8CjWswwd2VNAKN6lUKR85Ft4gippY= -k8s.io/cli-runtime v0.23.1 h1:vHUZrq1Oejs0WaJnxs09mLHKScvIIl2hMSthhS8o8Yo= -k8s.io/cli-runtime v0.23.1/go.mod h1:r9r8H/qfXo9w+69vwUL7LokKlLRKW5D6A8vUKCx+YL0= -k8s.io/client-go v0.23.1 h1:Ma4Fhf/p07Nmj9yAB1H7UwbFHEBrSPg8lviR24U2GiQ= -k8s.io/client-go v0.23.1/go.mod h1:6QSI8fEuqD4zgFK0xbdwfB/PthBsIxCJMa3s17WlcO0= -k8s.io/cloud-provider v0.23.1/go.mod h1:kI8AnYwOSru5Bci8pPUWwV5kJMVkY1ICOp1p8KKZWpc= -k8s.io/cluster-bootstrap v0.23.1 h1:zHRsIwMSLWujGHlaXLglbwyiDOKFLXSGz7LTbAez3MM= -k8s.io/cluster-bootstrap v0.23.1/go.mod h1:p2732QxwSa13WPemmyIeykk16qVw15W7lgNRB6x7NpY= -k8s.io/code-generator v0.23.2-rc.0 h1:sG0zykJJ8CvByPs/chc8DThmILi607fnNfW+0YTaOZs= -k8s.io/code-generator v0.23.2-rc.0/go.mod h1:V7yn6VNTCWW8GqodYCESVo95fuiEg713S8B7WacWZDA= -k8s.io/component-base v0.23.1 h1:j/BqdZUWeWKCy2v/jcgnOJAzpRYWSbGcjGVYICko8Uc= -k8s.io/component-base v0.23.1/go.mod h1:6llmap8QtJIXGDd4uIWJhAq0Op8AtQo6bDW2RrNMTeo= -k8s.io/component-helpers v0.23.1 h1:Xrtj0LwXUqYyTPvN2bOE2UcqURX+uSBmKX1koNGhVxI= -k8s.io/component-helpers v0.23.1/go.mod h1:ZK24U+2oXnBPcas2KolLigVVN9g5zOzaHLkHiQMFGr0= -k8s.io/controller-manager v0.23.1/go.mod h1:AFE4qIllvTh+nRwGr3SRSUt7F+xVSzXCeb0hhzYlU4k= -k8s.io/cri-api v0.23.2-rc.0/go.mod h1:REJE3PSU0h/LOV1APBrupxrEJqnoxZC8KWzkBUHwrK4= -k8s.io/csi-translation-lib v0.23.1/go.mod h1:0ZyB0cZBV4ZkqibwilEhKnxOne28rq5FDSjO+0MUVio= +k8s.io/api v0.17.8/go.mod h1:N++Llhs8kCixMUoCaXXAyMMPbo8dDVnh+IQ36xZV2/0= +k8s.io/api v0.18.8/go.mod h1:d/CXqwWv+Z2XEG1LgceeDmHQwpUJhROPx16SlxJgERY= +k8s.io/api v0.23.3/go.mod h1:w258XdGyvCmnBj/vGzQMj6kzdufJZVUwEM1U2fRJwSQ= +k8s.io/api v0.24.2 h1:g518dPU/L7VRLxWfcadQn2OnsiGWVOadTLpdnqgY2OI= +k8s.io/api v0.24.2/go.mod h1:AHqbSkTm6YrQ0ObxjO3Pmp/ubFF/KuM7jU+3khoBsOg= +k8s.io/apiextensions-apiserver v0.24.2 h1:/4NEQHKlEz1MlaK/wHT5KMKC9UKYz6NZz6JE6ov4G6k= +k8s.io/apiextensions-apiserver v0.24.2/go.mod h1:e5t2GMFVngUEHUd0wuCJzw8YDwZoqZfJiGOW6mm2hLQ= +k8s.io/apimachinery v0.17.8/go.mod h1:Lg8zZ5iC/O8UjCqW6DNhcQG2m4TdjF9kwG3891OWbbA= +k8s.io/apimachinery v0.18.8/go.mod h1:6sQd+iHEqmOtALqOFjSWp2KZ9F0wlU/nWm0ZgsYWMig= +k8s.io/apimachinery v0.23.3/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= +k8s.io/apimachinery v0.24.2 h1:5QlH9SL2C8KMcrNJPor+LbXVTaZRReml7svPEh4OKDM= +k8s.io/apimachinery v0.24.2/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= +k8s.io/apiserver v0.24.2 h1:orxipm5elPJSkkFNlwH9ClqaKEDJJA3yR2cAAlCnyj4= +k8s.io/apiserver v0.24.2/go.mod h1:pSuKzr3zV+L+MWqsEo0kHHYwCo77AT5qXbFXP2jbvFI= +k8s.io/cli-runtime v0.24.2 h1:KxY6tSgPGsahA6c1/dmR3uF5jOxXPx2QQY6C5ZrLmtE= +k8s.io/cli-runtime v0.24.2/go.mod h1:1LIhKL2RblkhfG4v5lZEt7FtgFG5mVb8wqv5lE9m5qY= +k8s.io/client-go v0.17.8/go.mod h1:SJsDS64AAtt9VZyeaQMb4Ck5etCitZ/FwajWdzua5eY= +k8s.io/client-go v0.18.8/go.mod h1:HqFqMllQ5NnQJNwjro9k5zMyfhZlOwpuTLVrxjkYSxU= +k8s.io/client-go v0.23.3/go.mod h1:47oMd+YvAOqZM7pcQ6neJtBiFH7alOyfunYN48VsmwE= +k8s.io/client-go v0.24.2 h1:CoXFSf8if+bLEbinDqN9ePIDGzcLtqhfd6jpfnwGOFA= +k8s.io/client-go v0.24.2/go.mod h1:zg4Xaoo+umDsfCWr4fCnmLEtQXyCNXCvJuSsglNcV30= +k8s.io/cloud-provider v0.24.2/go.mod h1:a7jyWjizk+IKbcIf8+mX2cj3NvpRv9ZyGdXDyb8UEkI= +k8s.io/cluster-bootstrap v0.24.2 h1:p177dIhDst4INUWBZgTnqSad8oJiUdKo0cLLVU24AzE= +k8s.io/cluster-bootstrap v0.24.2/go.mod h1:eIHV338K03vBm3u/ROZiNXxWJ4AJRoTR9PEUhcTvYkg= +k8s.io/code-generator v0.18.8/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= +k8s.io/code-generator v0.24.2 h1:EGeRWzJrpwi6T6CvoNl0spM6fnAnOdCr0rz7H4NU1rk= +k8s.io/code-generator v0.24.2/go.mod h1:dpVhs00hTuTdTY6jvVxvTFCk6gSMrtfRydbhZwHI15w= +k8s.io/component-base v0.24.2 h1:kwpQdoSfbcH+8MPN4tALtajLDfSfYxBDYlXobNWI6OU= +k8s.io/component-base v0.24.2/go.mod h1:ucHwW76dajvQ9B7+zecZAP3BVqvrHoOxm8olHEg0nmM= +k8s.io/component-helpers v0.24.2 h1:gtXmI/TjVINtkAdZn7m5p8+Vd0Mk4d1q8kwJMMLBdwY= +k8s.io/component-helpers v0.24.2/go.mod h1:TRQPBQKfmqkmV6c0HAmUs8cXVNYYYLsXy4zu8eODi9g= +k8s.io/controller-manager v0.24.2/go.mod h1:hpwCof4KxP4vrw/M5QiVxU6Zmmggmr1keGXtjGHF+vc= +k8s.io/cri-api v0.24.2/go.mod h1:t3tImFtGeStN+ES69bQUX9sFg67ek38BM9YIJhMmuig= +k8s.io/csi-translation-lib v0.24.2/go.mod h1:pdHc2CYLViQYYsOqOp79hjKYi8J4NZ7vpiVzn1SqBrg= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c h1:GohjlNKauSai7gN4wsJkeZ3WAJx4Sh+oT/b5IYn5suA= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20211129171323-c02415ce4185 h1:TT1WdmqqXareKxZ/oNXEUSwKlLiHzPMyB0t8BaFeBYI= +k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.5.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw= k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-aggregator v0.23.1/go.mod h1:1SPZXYD/je2gKxxLBkYyG3yFxSCUWI5QTyjqP2ZxRDI= -k8s.io/kube-controller-manager v0.23.1/go.mod h1:KbZeNSFsBM5j2ddB5yXJ1nTQx2j/1/Cf7cXzG27aKZ0= +k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.70.1 h1:7aaoSdahviPmR+XkS7FyxlkkXs6tHISSG03RxleQAVQ= +k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-aggregator v0.24.2/go.mod h1:Ju2jNDixn+vqeeKEBfjfpc204bO1pbdXX0N9knCxeMQ= +k8s.io/kube-controller-manager v0.24.2/go.mod h1:KDE0yqiEvxYiO0WRpPA4rVx8AcK1vsWydUF37AJ9lTI= +k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= +k8s.io/kube-openapi v0.0.0-20200410145947-bcb3869e6f29/go.mod h1:F+5wygcW0wmRTnM3cOgIqGivxkwSWIWT5YdsDbeAOaU= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= -k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4= k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= -k8s.io/kube-proxy v0.23.1/go.mod h1:65QJpMrjUMHfgX1q5Pl/KqVRZBMM4qLHNMo5MhKsnp0= -k8s.io/kube-scheduler v0.23.1/go.mod h1:SFPvXnt7KlxTZILrtjH8VNwGDzXcdKKHrv4TkeZdYro= -k8s.io/kubectl v0.23.1 h1:gmscOiV4Y4XIRIn14gQBBADoyyVrDZPbxRCTDga4RSA= -k8s.io/kubectl v0.23.1/go.mod h1:Ui7dJKdUludF8yWAOSN7JZEkOuYixX5yF6E6NjoukKE= -k8s.io/kubelet v0.23.1/go.mod h1:WdvMiehtNPhtiW8sSVVvr8YYU00L0u+0HkfMDEB0LKM= -k8s.io/kubernetes v1.23.1 h1:iJfubd03CDap4m69Ue+u2I6quNUYiYlC8+TakEHATjc= -k8s.io/kubernetes v1.23.1/go.mod h1:baMGbPpwwP0kT/+eAPtdqoWNRoXyyTJ2Zf+fw/Y8t04= -k8s.io/legacy-cloud-providers v0.23.1/go.mod h1:HIt+r/ReEfjS6IGaGfpZ7tCna7hbMBXMOaIp/SWABVE= -k8s.io/metrics v0.23.1/go.mod h1:qXvsM1KANrc+ZZeFwj6Phvf0NLiC+d3RwcsLcdGc+xs= -k8s.io/mount-utils v0.23.2-rc.0/go.mod h1:9pFhzVjxle1osJUo++9MFDat9HPkQUOoHCn+eExZ3Ew= -k8s.io/pod-security-admission v0.23.1/go.mod h1:WDb/vFWf7jKSGe2e07LTEjDZ0MHMDhUIzXNvQ45HytU= -k8s.io/sample-apiserver v0.23.1/go.mod h1:5ZQrkouVpN6GeNMZEJFkIpFwaxgDPJin/cIBXyDboC4= -k8s.io/system-validators v1.6.0/go.mod h1:bPldcLgkIUK22ALflnsXk8pvkTEndYdNuaHH6gRrl0Q= -k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= +k8s.io/kube-openapi v0.0.0-20220401212409-b28bf2818661/go.mod h1:daOouuuwd9JXpv1L7Y34iV3yf6nxzipkKMWWlqlvK9M= +k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8 h1:yEQKdMCjzAOvGeiTwG4hO/hNVNtDOuUFvMUZ0OlaIzs= +k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8/go.mod h1:mbJ+NSUoAhuR14N0S63bPkh8MGVSo3VYSGZtH/mfMe0= +k8s.io/kube-proxy v0.24.2/go.mod h1:bozS2ufl/Ns6s40Ue34eV7rqyLVygi5usSmCgW7rFU8= +k8s.io/kube-scheduler v0.24.2/go.mod h1:DRa+aeXKSYUUOHHIc/9EcaO9+FW5FydaOfPSvaSW5Ko= +k8s.io/kubectl v0.24.2 h1:+RfQVhth8akUmIc2Ge8krMl/pt66V7210ka3RE/p0J4= +k8s.io/kubectl v0.24.2/go.mod h1:+HIFJc0bA6Tzu5O/YcuUt45APAxnNL8LeMuXwoiGsPg= +k8s.io/kubelet v0.24.2/go.mod h1:Xm9DkWQjwOs+uGOUIIGIPMvvmenvj0lDVOErvIKOOt0= +k8s.io/kubernetes v1.24.2 h1:AyjtHzSysliKR04Km91njmk2yaKmOa3ZISQZCIGUnVI= +k8s.io/kubernetes v1.24.2/go.mod h1:8e8maMiZzBR2/8Po5Uulx+MXZUYJuN3vtKwD4Ct1Xi0= +k8s.io/legacy-cloud-providers v0.24.2/go.mod h1:sgkasgIP2ZOew8fzoOq0mQLVXJ4AmB57IUbFUjzPWEo= +k8s.io/metrics v0.24.2/go.mod h1:5NWURxZ6Lz5gj8TFU83+vdWIVASx7W8lwPpHYCqopMo= +k8s.io/mount-utils v0.24.2/go.mod h1:XrSqB3a2e8sq+aU+rlbcBtQ3EgcuDk5RP9ZsGxjoDrI= +k8s.io/pod-security-admission v0.24.2/go.mod h1:znnuDHWWWvh/tpbYYPwTsd4y//qHi3cOX+wGxET/mMI= +k8s.io/sample-apiserver v0.24.2/go.mod h1:mf8qgDdu450wqpCJOkSAmoTgU4PIMAcfa5uTBwmJekE= +k8s.io/system-validators v1.7.0/go.mod h1:gP1Ky+R9wtrSiFbrpEPwWMeYz9yqyy1S/KOh0Vci7WI= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b h1:wxEMGetGMur3J1xuGLQY7GEQYg9bZxKn3tKo5k/eYcs= -k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20220706174534-f6158b442e7c h1:hFZO68mv/0xe8+V0gRT9BAq3/31cKjjeVv4nScriuBk= +k8s.io/utils v0.0.0-20220706174534-f6158b442e7c/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= @@ -1614,18 +1857,26 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.25/go.mod h1:Mlj9PNLmG9bZ6BHFwFKDo5afkpWyUISkb9Me0GnK66I= -sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30/go.mod h1:fEO7lRTdivWO2qYVCVG7dEADOMo/MLDCVr8So2g88Uw= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= -sigs.k8s.io/kustomize/api v0.10.1 h1:KgU7hfYoscuqag84kxtzKdEC3mKMb99DPI3a0eaV1d0= -sigs.k8s.io/kustomize/api v0.10.1/go.mod h1:2FigT1QN6xKdcnGS2Ppp1uIWrtWN28Ms8A3OZUZhwr8= -sigs.k8s.io/kustomize/cmd/config v0.10.2/go.mod h1:K2aW7nXJ0AaT+VA/eO0/dzFLxmpFcTzudmAgDwPY1HQ= -sigs.k8s.io/kustomize/kustomize/v4 v4.4.1/go.mod h1:qOKJMMz2mBP+vcS7vK+mNz4HBLjaQSWRY22EF6Tb7Io= -sigs.k8s.io/kustomize/kyaml v0.13.0 h1:9c+ETyNfSrVhxvphs+K2dzT3dh5oVPPEqPOE/cUpScY= -sigs.k8s.io/kustomize/kyaml v0.13.0/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E= +sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= +sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124 h1:2sgAQQcY0dEW2SsQwTXhQV4vO6+rSslYx8K3XmM5hqQ= +sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= +sigs.k8s.io/kustomize/api v0.11.4/go.mod h1:k+8RsqYbgpkIrJ4p9jcdPqe8DprLxFUUO0yNOq8C+xI= +sigs.k8s.io/kustomize/api v0.11.5 h1:vLDp++YAX7iy2y2CVPJNy9pk9CY8XaUKgHkjbVtnWag= +sigs.k8s.io/kustomize/api v0.11.5/go.mod h1:2UDpxS6AonWXow2ZbySd4AjUxmdXLeTlvGBC46uSiq8= +sigs.k8s.io/kustomize/cmd/config v0.10.6/go.mod h1:/S4A4nUANUa4bZJ/Edt7ZQTyKOY9WCER0uBS1SW2Rco= +sigs.k8s.io/kustomize/kustomize/v4 v4.5.4/go.mod h1:Zo/Xc5FKD6sHl0lilbrieeGeZHVYCA4BzxeAaLI05Bg= +sigs.k8s.io/kustomize/kyaml v0.13.6/go.mod h1:yHP031rn1QX1lr/Xd934Ri/xdVNG8BE2ECa78Ht/kEg= +sigs.k8s.io/kustomize/kyaml v0.13.7 h1:/EZ/nPaLUzeJKF/BuJ4QCuMVJWiEVoI8iftOHY3g3tk= +sigs.k8s.io/kustomize/kyaml v0.13.7/go.mod h1:6K+IUOuir3Y7nucPRAjw9yth04KSWBnP5pqUTGwj/qU= +sigs.k8s.io/structured-merge-diff/v2 v2.0.1/go.mod h1:Wb7vfKAodbKgf6tn1Kl0VvGj7mRH6DGaRcixXEJXTsE= +sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= +sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= -sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/manifests/crds/analysis-run-crd.yaml b/manifests/crds/analysis-run-crd.yaml index b5a2dcc4a8..962db250b3 100644 --- a/manifests/crds/analysis-run-crd.yaml +++ b/manifests/crds/analysis-run-crd.yaml @@ -2572,6 +2572,9 @@ spec: maxSkew: format: int32 type: integer + minDomains: + format: int32 + type: integer topologyKey: type: string whenUnsatisfiable: diff --git a/manifests/crds/analysis-template-crd.yaml b/manifests/crds/analysis-template-crd.yaml index df7cfe08f5..54aad4b66f 100644 --- a/manifests/crds/analysis-template-crd.yaml +++ b/manifests/crds/analysis-template-crd.yaml @@ -2568,6 +2568,9 @@ spec: maxSkew: format: int32 type: integer + minDomains: + format: int32 + type: integer topologyKey: type: string whenUnsatisfiable: diff --git a/manifests/crds/cluster-analysis-template-crd.yaml b/manifests/crds/cluster-analysis-template-crd.yaml index 919c0c5fc5..1551b9d114 100644 --- a/manifests/crds/cluster-analysis-template-crd.yaml +++ b/manifests/crds/cluster-analysis-template-crd.yaml @@ -2568,6 +2568,9 @@ spec: maxSkew: format: int32 type: integer + minDomains: + format: int32 + type: integer topologyKey: type: string whenUnsatisfiable: diff --git a/manifests/crds/experiment-crd.yaml b/manifests/crds/experiment-crd.yaml index 0e163e4991..7af9a81d52 100644 --- a/manifests/crds/experiment-crd.yaml +++ b/manifests/crds/experiment-crd.yaml @@ -2467,6 +2467,9 @@ spec: maxSkew: format: int32 type: integer + minDomains: + format: int32 + type: integer topologyKey: type: string whenUnsatisfiable: diff --git a/manifests/crds/rollout-crd.yaml b/manifests/crds/rollout-crd.yaml index 5c1c374544..67a9b8d7aa 100644 --- a/manifests/crds/rollout-crd.yaml +++ b/manifests/crds/rollout-crd.yaml @@ -3157,6 +3157,9 @@ spec: maxSkew: format: int32 type: integer + minDomains: + format: int32 + type: integer topologyKey: type: string whenUnsatisfiable: diff --git a/manifests/install.yaml b/manifests/install.yaml index 89c74a17a4..d32be4f257 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -2573,6 +2573,9 @@ spec: maxSkew: format: int32 type: integer + minDomains: + format: int32 + type: integer topologyKey: type: string whenUnsatisfiable: @@ -5444,6 +5447,9 @@ spec: maxSkew: format: int32 type: integer + minDomains: + format: int32 + type: integer topologyKey: type: string whenUnsatisfiable: @@ -8201,6 +8207,9 @@ spec: maxSkew: format: int32 type: integer + minDomains: + format: int32 + type: integer topologyKey: type: string whenUnsatisfiable: @@ -10857,6 +10866,9 @@ spec: maxSkew: format: int32 type: integer + minDomains: + format: int32 + type: integer topologyKey: type: string whenUnsatisfiable: @@ -14146,6 +14158,9 @@ spec: maxSkew: format: int32 type: integer + minDomains: + format: int32 + type: integer topologyKey: type: string whenUnsatisfiable: diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index ec026bfcfd..e6370dd98a 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -2573,6 +2573,9 @@ spec: maxSkew: format: int32 type: integer + minDomains: + format: int32 + type: integer topologyKey: type: string whenUnsatisfiable: @@ -5444,6 +5447,9 @@ spec: maxSkew: format: int32 type: integer + minDomains: + format: int32 + type: integer topologyKey: type: string whenUnsatisfiable: @@ -8201,6 +8207,9 @@ spec: maxSkew: format: int32 type: integer + minDomains: + format: int32 + type: integer topologyKey: type: string whenUnsatisfiable: @@ -10857,6 +10866,9 @@ spec: maxSkew: format: int32 type: integer + minDomains: + format: int32 + type: integer topologyKey: type: string whenUnsatisfiable: @@ -14146,6 +14158,9 @@ spec: maxSkew: format: int32 type: integer + minDomains: + format: int32 + type: integer topologyKey: type: string whenUnsatisfiable: diff --git a/pkg/apiclient/rollout/rollout.swagger.json b/pkg/apiclient/rollout/rollout.swagger.json index 42b6c893bc..44e663763e 100644 --- a/pkg/apiclient/rollout/rollout.swagger.json +++ b/pkg/apiclient/rollout/rollout.swagger.json @@ -1823,20 +1823,20 @@ "properties": { "volumeID": { "type": "string", - "title": "Unique ID of the persistent disk resource in AWS (Amazon EBS volume).\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore" + "title": "volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume).\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore" }, "fsType": { "type": "string", - "title": "Filesystem type of the volume that you want to mount.\nTip: Ensure that the filesystem type is supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional" + "title": "fsType is the filesystem type of the volume that you want to mount.\nTip: Ensure that the filesystem type is supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional" }, "partition": { "type": "integer", "format": "int32", - "title": "The partition in the volume that you want to mount.\nIf omitted, the default is to mount by volume name.\nExamples: For volume /dev/sda1, you specify the partition as \"1\".\nSimilarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty).\n+optional" + "title": "partition is the partition in the volume that you want to mount.\nIf omitted, the default is to mount by volume name.\nExamples: For volume /dev/sda1, you specify the partition as \"1\".\nSimilarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty).\n+optional" }, "readOnly": { "type": "boolean", - "title": "Specify \"true\" to force and set the ReadOnly property in VolumeMounts to \"true\".\nIf omitted, the default is \"false\".\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore\n+optional" + "title": "readOnly value true will force the readOnly setting in VolumeMounts.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore\n+optional" } }, "description": "Represents a Persistent Disk resource in AWS.\n\nAn AWS EBS disk must exist before mounting to a container. The disk\nmust also be in the same AWS zone as the kubelet. An AWS EBS disk\ncan only be mounted as read/write once. AWS EBS volumes support\nownership management and SELinux relabeling." @@ -1864,27 +1864,27 @@ "properties": { "diskName": { "type": "string", - "title": "The Name of the data disk in the blob storage" + "title": "diskName is the Name of the data disk in the blob storage" }, "diskURI": { "type": "string", - "title": "The URI the data disk in the blob storage" + "title": "diskURI is the URI of data disk in the blob storage" }, "cachingMode": { "type": "string", - "title": "Host Caching mode: None, Read Only, Read Write.\n+optional" + "title": "cachingMode is the Host Caching mode: None, Read Only, Read Write.\n+optional" }, "fsType": { "type": "string", - "title": "Filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\n+optional" + "title": "fsType is Filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\n+optional" }, "readOnly": { "type": "boolean", - "title": "Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional" + "title": "readOnly Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional" }, "kind": { "type": "string", - "title": "Expected values Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared" + "title": "kind expected values are Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared" } }, "description": "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod." @@ -1894,15 +1894,15 @@ "properties": { "secretName": { "type": "string", - "title": "the name of secret that contains Azure Storage Account Name and Key" + "title": "secretName is the name of secret that contains Azure Storage Account Name and Key" }, "shareName": { "type": "string", - "title": "Share Name" + "title": "shareName is the azure share Name" }, "readOnly": { "type": "boolean", - "title": "Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional" + "title": "readOnly defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional" } }, "description": "AzureFile represents an Azure File Service mount on the host and bind mount to the pod." @@ -1912,26 +1912,26 @@ "properties": { "driver": { "type": "string", - "description": "Driver is the name of the CSI driver that handles this volume.\nConsult with your admin for the correct name as registered in the cluster." + "description": "driver is the name of the CSI driver that handles this volume.\nConsult with your admin for the correct name as registered in the cluster." }, "readOnly": { "type": "boolean", - "title": "Specifies a read-only configuration for the volume.\nDefaults to false (read/write).\n+optional" + "title": "readOnly specifies a read-only configuration for the volume.\nDefaults to false (read/write).\n+optional" }, "fsType": { "type": "string", - "title": "Filesystem type to mount. Ex. \"ext4\", \"xfs\", \"ntfs\".\nIf not provided, the empty value is passed to the associated CSI driver\nwhich will determine the default filesystem to apply.\n+optional" + "title": "fsType to mount. Ex. \"ext4\", \"xfs\", \"ntfs\".\nIf not provided, the empty value is passed to the associated CSI driver\nwhich will determine the default filesystem to apply.\n+optional" }, "volumeAttributes": { "type": "object", "additionalProperties": { "type": "string" }, - "title": "VolumeAttributes stores driver-specific properties that are passed to the CSI\ndriver. Consult your driver's documentation for supported values.\n+optional" + "title": "volumeAttributes stores driver-specific properties that are passed to the CSI\ndriver. Consult your driver's documentation for supported values.\n+optional" }, "nodePublishSecretRef": { "$ref": "#/definitions/k8s.io.api.core.v1.LocalObjectReference", - "title": "NodePublishSecretRef is a reference to the secret object containing\nsensitive information to pass to the CSI driver to complete the CSI\nNodePublishVolume and NodeUnpublishVolume calls.\nThis field is optional, and may be empty if no secret is required. If the\nsecret object contains more than one secret, all secret references are passed.\n+optional" + "title": "nodePublishSecretRef is a reference to the secret object containing\nsensitive information to pass to the CSI driver to complete the CSI\nNodePublishVolume and NodeUnpublishVolume calls.\nThis field is optional, and may be empty if no secret is required. If the\nsecret object contains more than one secret, all secret references are passed.\n+optional" } }, "title": "Represents a source location of a volume to mount, managed by an external CSI driver" @@ -1964,27 +1964,27 @@ "items": { "type": "string" }, - "title": "Required: Monitors is a collection of Ceph monitors\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it" + "title": "monitors is Required: Monitors is a collection of Ceph monitors\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it" }, "path": { "type": "string", - "title": "Optional: Used as the mounted root, rather than the full Ceph tree, default is /\n+optional" + "title": "path is Optional: Used as the mounted root, rather than the full Ceph tree, default is /\n+optional" }, "user": { "type": "string", - "title": "Optional: User is the rados user name, default is admin\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it\n+optional" + "title": "user is optional: User is the rados user name, default is admin\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it\n+optional" }, "secretFile": { "type": "string", - "title": "Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it\n+optional" + "title": "secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it\n+optional" }, "secretRef": { "$ref": "#/definitions/k8s.io.api.core.v1.LocalObjectReference", - "title": "Optional: SecretRef is reference to the authentication secret for User, default is empty.\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it\n+optional" + "title": "secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty.\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it\n+optional" }, "readOnly": { "type": "boolean", - "title": "Optional: Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it\n+optional" + "title": "readOnly is Optional: Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it\n+optional" } }, "description": "Represents a Ceph Filesystem mount that lasts the lifetime of a pod\nCephfs volumes do not support ownership management or SELinux relabeling." @@ -1994,19 +1994,19 @@ "properties": { "volumeID": { "type": "string", - "title": "volume id used to identify the volume in cinder.\nMore info: https://examples.k8s.io/mysql-cinder-pd/README.md" + "title": "volumeID used to identify the volume in cinder.\nMore info: https://examples.k8s.io/mysql-cinder-pd/README.md" }, "fsType": { "type": "string", - "title": "Filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://examples.k8s.io/mysql-cinder-pd/README.md\n+optional" + "title": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://examples.k8s.io/mysql-cinder-pd/README.md\n+optional" }, "readOnly": { "type": "boolean", - "title": "Optional: Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\nMore info: https://examples.k8s.io/mysql-cinder-pd/README.md\n+optional" + "title": "readOnly defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\nMore info: https://examples.k8s.io/mysql-cinder-pd/README.md\n+optional" }, "secretRef": { "$ref": "#/definitions/k8s.io.api.core.v1.LocalObjectReference", - "title": "Optional: points to a secret object containing parameters used to connect\nto OpenStack.\n+optional" + "title": "secretRef is optional: points to a secret object containing parameters used to connect\nto OpenStack.\n+optional" } }, "description": "Represents a cinder volume resource in Openstack.\nA Cinder volume must exist before mounting to a container.\nThe volume must also be in the same region as the kubelet.\nCinder volumes support ownership management and SELinux relabeling." @@ -2054,11 +2054,11 @@ "items": { "$ref": "#/definitions/k8s.io.api.core.v1.KeyToPath" }, - "title": "If unspecified, each key-value pair in the Data field of the referenced\nConfigMap will be projected into the volume as a file whose name is the\nkey and content is the value. If specified, the listed keys will be\nprojected into the specified paths, and unlisted keys will not be\npresent. If a key is specified which is not present in the ConfigMap,\nthe volume setup will error unless it is marked optional. Paths must be\nrelative and may not contain the '..' path or start with '..'.\n+optional" + "title": "items if unspecified, each key-value pair in the Data field of the referenced\nConfigMap will be projected into the volume as a file whose name is the\nkey and content is the value. If specified, the listed keys will be\nprojected into the specified paths, and unlisted keys will not be\npresent. If a key is specified which is not present in the ConfigMap,\nthe volume setup will error unless it is marked optional. Paths must be\nrelative and may not contain the '..' path or start with '..'.\n+optional" }, "optional": { "type": "boolean", - "title": "Specify whether the ConfigMap or its keys must be defined\n+optional" + "title": "optional specify whether the ConfigMap or its keys must be defined\n+optional" } }, "description": "Adapts a ConfigMap into a projected volume.\n\nThe contents of the target ConfigMap's Data field will be presented in a\nprojected volume as files using the keys in the Data field as the file names,\nunless the items element is populated with specific mappings of keys to paths.\nNote that this is identical to a configmap volume source without the default\nmode." @@ -2074,16 +2074,16 @@ "items": { "$ref": "#/definitions/k8s.io.api.core.v1.KeyToPath" }, - "title": "If unspecified, each key-value pair in the Data field of the referenced\nConfigMap will be projected into the volume as a file whose name is the\nkey and content is the value. If specified, the listed keys will be\nprojected into the specified paths, and unlisted keys will not be\npresent. If a key is specified which is not present in the ConfigMap,\nthe volume setup will error unless it is marked optional. Paths must be\nrelative and may not contain the '..' path or start with '..'.\n+optional" + "title": "items if unspecified, each key-value pair in the Data field of the referenced\nConfigMap will be projected into the volume as a file whose name is the\nkey and content is the value. If specified, the listed keys will be\nprojected into the specified paths, and unlisted keys will not be\npresent. If a key is specified which is not present in the ConfigMap,\nthe volume setup will error unless it is marked optional. Paths must be\nrelative and may not contain the '..' path or start with '..'.\n+optional" }, "defaultMode": { "type": "integer", "format": "int32", - "title": "Optional: mode bits used to set permissions on created files by default.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values for mode bits.\nDefaults to 0644.\nDirectories within the path are not affected by this setting.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional" + "title": "defaultMode is optional: mode bits used to set permissions on created files by default.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values for mode bits.\nDefaults to 0644.\nDirectories within the path are not affected by this setting.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional" }, "optional": { "type": "boolean", - "title": "Specify whether the ConfigMap or its keys must be defined\n+optional" + "title": "optional specify whether the ConfigMap or its keys must be defined\n+optional" } }, "description": "Adapts a ConfigMap into a volume.\n\nThe contents of the target ConfigMap's Data field will be presented in a\nvolume as files using the keys in the Data field as the file names, unless\nthe items element is populated with specific mappings of keys to paths.\nConfigMap volumes support ownership management and SELinux relabeling." @@ -2097,21 +2097,21 @@ }, "image": { "type": "string", - "title": "Docker image name.\nMore info: https://kubernetes.io/docs/concepts/containers/images\nThis field is optional to allow higher level config management to default or override\ncontainer images in workload controllers like Deployments and StatefulSets.\n+optional" + "title": "Container image name.\nMore info: https://kubernetes.io/docs/concepts/containers/images\nThis field is optional to allow higher level config management to default or override\ncontainer images in workload controllers like Deployments and StatefulSets.\n+optional" }, "command": { "type": "array", "items": { "type": "string" }, - "title": "Entrypoint array. Not executed within a shell.\nThe docker image's ENTRYPOINT is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will\nproduce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless\nof whether the variable exists or not. Cannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional" + "title": "Entrypoint array. Not executed within a shell.\nThe container image's ENTRYPOINT is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will\nproduce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless\nof whether the variable exists or not. Cannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional" }, "args": { "type": "array", "items": { "type": "string" }, - "title": "Arguments to the entrypoint.\nThe docker image's CMD is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will\nproduce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless\nof whether the variable exists or not. Cannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional" + "title": "Arguments to the entrypoint.\nThe container image's CMD is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will\nproduce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless\nof whether the variable exists or not. Cannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional" }, "workingDir": { "type": "string", @@ -2290,11 +2290,11 @@ "properties": { "medium": { "type": "string", - "title": "What type of storage medium should back this directory.\nThe default is \"\" which means to use the node's default medium.\nMust be an empty string (default) or Memory.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir\n+optional" + "title": "medium represents what type of storage medium should back this directory.\nThe default is \"\" which means to use the node's default medium.\nMust be an empty string (default) or Memory.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir\n+optional" }, "sizeLimit": { "$ref": "#/definitions/k8s.io.apimachinery.pkg.api.resource.Quantity", - "title": "Total amount of local storage required for this EmptyDir volume.\nThe size limit is also applicable for memory medium.\nThe maximum usage on memory medium EmptyDir would be the minimum value between\nthe SizeLimit specified here and the sum of memory limits of all containers in a pod.\nThe default is nil which means that the limit is undefined.\nMore info: http://kubernetes.io/docs/user-guide/volumes#emptydir\n+optional" + "title": "sizeLimit is the total amount of local storage required for this EmptyDir volume.\nThe size limit is also applicable for memory medium.\nThe maximum usage on memory medium EmptyDir would be the minimum value between\nthe SizeLimit specified here and the sum of memory limits of all containers in a pod.\nThe default is nil which means that the limit is undefined.\nMore info: http://kubernetes.io/docs/user-guide/volumes#emptydir\n+optional" } }, "description": "Represents an empty directory for a pod.\nEmpty directory volumes support ownership management and SELinux relabeling." @@ -2380,21 +2380,21 @@ }, "image": { "type": "string", - "title": "Docker image name.\nMore info: https://kubernetes.io/docs/concepts/containers/images" + "title": "Container image name.\nMore info: https://kubernetes.io/docs/concepts/containers/images" }, "command": { "type": "array", "items": { "type": "string" }, - "title": "Entrypoint array. Not executed within a shell.\nThe docker image's ENTRYPOINT is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will\nproduce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless\nof whether the variable exists or not. Cannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional" + "title": "Entrypoint array. Not executed within a shell.\nThe image's ENTRYPOINT is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will\nproduce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless\nof whether the variable exists or not. Cannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional" }, "args": { "type": "array", "items": { "type": "string" }, - "title": "Arguments to the entrypoint.\nThe docker image's CMD is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will\nproduce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless\nof whether the variable exists or not. Cannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional" + "title": "Arguments to the entrypoint.\nThe image's CMD is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will\nproduce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless\nof whether the variable exists or not. Cannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional" }, "workingDir": { "type": "string", @@ -2517,27 +2517,27 @@ "items": { "type": "string" }, - "title": "Optional: FC target worldwide names (WWNs)\n+optional" + "title": "targetWWNs is Optional: FC target worldwide names (WWNs)\n+optional" }, "lun": { "type": "integer", "format": "int32", - "title": "Optional: FC target lun number\n+optional" + "title": "lun is Optional: FC target lun number\n+optional" }, "fsType": { "type": "string", - "title": "Filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional" + "title": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional" }, "readOnly": { "type": "boolean", - "title": "Optional: Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional" + "title": "readOnly is Optional: Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional" }, "wwids": { "type": "array", "items": { "type": "string" }, - "title": "Optional: FC volume world wide identifiers (wwids)\nEither wwids or combination of targetWWNs and lun must be set, but not both simultaneously.\n+optional" + "title": "wwids Optional: FC volume world wide identifiers (wwids)\nEither wwids or combination of targetWWNs and lun must be set, but not both simultaneously.\n+optional" } }, "description": "Represents a Fibre Channel volume.\nFibre Channel volumes can only be mounted as read/write once.\nFibre Channel volumes support ownership management and SELinux relabeling." @@ -2547,26 +2547,26 @@ "properties": { "driver": { "type": "string", - "description": "Driver is the name of the driver to use for this volume." + "description": "driver is the name of the driver to use for this volume." }, "fsType": { "type": "string", - "title": "Filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". The default filesystem depends on FlexVolume script.\n+optional" + "title": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". The default filesystem depends on FlexVolume script.\n+optional" }, "secretRef": { "$ref": "#/definitions/k8s.io.api.core.v1.LocalObjectReference", - "title": "Optional: SecretRef is reference to the secret object containing\nsensitive information to pass to the plugin scripts. This may be\nempty if no secret object is specified. If the secret object\ncontains more than one secret, all secrets are passed to the plugin\nscripts.\n+optional" + "title": "secretRef is Optional: secretRef is reference to the secret object containing\nsensitive information to pass to the plugin scripts. This may be\nempty if no secret object is specified. If the secret object\ncontains more than one secret, all secrets are passed to the plugin\nscripts.\n+optional" }, "readOnly": { "type": "boolean", - "title": "Optional: Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional" + "title": "readOnly is Optional: defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional" }, "options": { "type": "object", "additionalProperties": { "type": "string" }, - "title": "Optional: Extra command options if any.\n+optional" + "title": "options is Optional: this field holds extra command options if any.\n+optional" } }, "description": "FlexVolume represents a generic volume resource that is\nprovisioned/attached using an exec based plugin." @@ -2576,11 +2576,11 @@ "properties": { "datasetName": { "type": "string", - "title": "Name of the dataset stored as metadata -\u003e name on the dataset for Flocker\nshould be considered as deprecated\n+optional" + "title": "datasetName is Name of the dataset stored as metadata -\u003e name on the dataset for Flocker\nshould be considered as deprecated\n+optional" }, "datasetUUID": { "type": "string", - "title": "UUID of the dataset. This is unique identifier of a Flocker dataset\n+optional" + "title": "datasetUUID is the UUID of the dataset. This is unique identifier of a Flocker dataset\n+optional" } }, "description": "Represents a Flocker volume mounted by the Flocker agent.\nOne and only one of datasetName and datasetUUID should be set.\nFlocker volumes do not support ownership management or SELinux relabeling." @@ -2590,20 +2590,20 @@ "properties": { "pdName": { "type": "string", - "title": "Unique name of the PD resource in GCE. Used to identify the disk in GCE.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk" + "title": "pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk" }, "fsType": { "type": "string", - "title": "Filesystem type of the volume that you want to mount.\nTip: Ensure that the filesystem type is supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional" + "title": "fsType is filesystem type of the volume that you want to mount.\nTip: Ensure that the filesystem type is supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional" }, "partition": { "type": "integer", "format": "int32", - "title": "The partition in the volume that you want to mount.\nIf omitted, the default is to mount by volume name.\nExamples: For volume /dev/sda1, you specify the partition as \"1\".\nSimilarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty).\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk\n+optional" + "title": "partition is the partition in the volume that you want to mount.\nIf omitted, the default is to mount by volume name.\nExamples: For volume /dev/sda1, you specify the partition as \"1\".\nSimilarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty).\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk\n+optional" }, "readOnly": { "type": "boolean", - "title": "ReadOnly here will force the ReadOnly setting in VolumeMounts.\nDefaults to false.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk\n+optional" + "title": "readOnly here will force the ReadOnly setting in VolumeMounts.\nDefaults to false.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk\n+optional" } }, "description": "Represents a Persistent Disk resource in Google Compute Engine.\n\nA GCE PD must exist before mounting to a container. The disk must\nalso be in the same GCE project and zone as the kubelet. A GCE PD\ncan only be mounted as read/write once or read-only many times. GCE\nPDs support ownership management and SELinux relabeling." @@ -2627,15 +2627,15 @@ "properties": { "repository": { "type": "string", - "title": "Repository URL" + "title": "repository is the URL" }, "revision": { "type": "string", - "title": "Commit hash for the specified revision.\n+optional" + "title": "revision is the commit hash for the specified revision.\n+optional" }, "directory": { "type": "string", - "title": "Target directory name.\nMust not contain or start with '..'. If '.' is supplied, the volume directory will be the\ngit repository. Otherwise, if specified, the volume will contain the git repository in\nthe subdirectory with the given name.\n+optional" + "title": "directory is the target directory name.\nMust not contain or start with '..'. If '.' is supplied, the volume directory will be the\ngit repository. Otherwise, if specified, the volume will contain the git repository in\nthe subdirectory with the given name.\n+optional" } }, "description": "Represents a volume that is populated with the contents of a git repository.\nGit repo volumes do not support ownership management.\nGit repo volumes support SELinux relabeling.\n\nDEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an\nEmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir\ninto the Pod's container." @@ -2645,15 +2645,15 @@ "properties": { "endpoints": { "type": "string", - "title": "EndpointsName is the endpoint name that details Glusterfs topology.\nMore info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod" + "title": "endpoints is the endpoint name that details Glusterfs topology.\nMore info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod" }, "path": { "type": "string", - "title": "Path is the Glusterfs volume path.\nMore info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod" + "title": "path is the Glusterfs volume path.\nMore info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod" }, "readOnly": { "type": "boolean", - "title": "ReadOnly here will force the Glusterfs volume to be mounted with read-only permissions.\nDefaults to false.\nMore info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod\n+optional" + "title": "readOnly here will force the Glusterfs volume to be mounted with read-only permissions.\nDefaults to false.\nMore info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod\n+optional" } }, "description": "Represents a Glusterfs mount that lasts the lifetime of a pod.\nGlusterfs volumes do not support ownership management or SELinux relabeling." @@ -2723,11 +2723,11 @@ "properties": { "path": { "type": "string", - "title": "Path of the directory on the host.\nIf the path is a symlink, it will follow the link to the real path.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath" + "title": "path of the directory on the host.\nIf the path is a symlink, it will follow the link to the real path.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath" }, "type": { "type": "string", - "title": "Type for HostPath Volume\nDefaults to \"\"\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath\n+optional" + "title": "type for HostPath Volume\nDefaults to \"\"\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath\n+optional" } }, "description": "Represents a host path mapped into a pod.\nHost path volumes do not support ownership management or SELinux relabeling." @@ -2737,51 +2737,51 @@ "properties": { "targetPortal": { "type": "string", - "description": "iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port\nis other than default (typically TCP ports 860 and 3260)." + "description": "targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port\nis other than default (typically TCP ports 860 and 3260)." }, "iqn": { "type": "string", - "description": "Target iSCSI Qualified Name." + "description": "iqn is the target iSCSI Qualified Name." }, "lun": { "type": "integer", "format": "int32", - "description": "iSCSI Target Lun number." + "description": "lun represents iSCSI Target Lun number." }, "iscsiInterface": { "type": "string", - "title": "iSCSI Interface Name that uses an iSCSI transport.\nDefaults to 'default' (tcp).\n+optional" + "title": "iscsiInterface is the interface Name that uses an iSCSI transport.\nDefaults to 'default' (tcp).\n+optional" }, "fsType": { "type": "string", - "title": "Filesystem type of the volume that you want to mount.\nTip: Ensure that the filesystem type is supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional" + "title": "fsType is the filesystem type of the volume that you want to mount.\nTip: Ensure that the filesystem type is supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional" }, "readOnly": { "type": "boolean", - "title": "ReadOnly here will force the ReadOnly setting in VolumeMounts.\nDefaults to false.\n+optional" + "title": "readOnly here will force the ReadOnly setting in VolumeMounts.\nDefaults to false.\n+optional" }, "portals": { "type": "array", "items": { "type": "string" }, - "title": "iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port\nis other than default (typically TCP ports 860 and 3260).\n+optional" + "title": "portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port\nis other than default (typically TCP ports 860 and 3260).\n+optional" }, "chapAuthDiscovery": { "type": "boolean", - "title": "whether support iSCSI Discovery CHAP authentication\n+optional" + "title": "chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication\n+optional" }, "chapAuthSession": { "type": "boolean", - "title": "whether support iSCSI Session CHAP authentication\n+optional" + "title": "chapAuthSession defines whether support iSCSI Session CHAP authentication\n+optional" }, "secretRef": { "$ref": "#/definitions/k8s.io.api.core.v1.LocalObjectReference", - "title": "CHAP Secret for iSCSI target and initiator authentication\n+optional" + "title": "secretRef is the CHAP Secret for iSCSI target and initiator authentication\n+optional" }, "initiatorName": { "type": "string", - "title": "Custom iSCSI Initiator Name.\nIf initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface\n\u003ctarget portal\u003e:\u003cvolume name\u003e will be created for the connection.\n+optional" + "title": "initiatorName is the custom iSCSI Initiator Name.\nIf initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface\n\u003ctarget portal\u003e:\u003cvolume name\u003e will be created for the connection.\n+optional" } }, "description": "Represents an ISCSI disk.\nISCSI volumes can only be mounted as read/write once.\nISCSI volumes support ownership management and SELinux relabeling." @@ -2791,16 +2791,16 @@ "properties": { "key": { "type": "string", - "description": "The key to project." + "description": "key is the key to project." }, "path": { "type": "string", - "description": "The relative path of the file to map the key to.\nMay not be an absolute path.\nMay not contain the path element '..'.\nMay not start with the string '..'." + "description": "path is the relative path of the file to map the key to.\nMay not be an absolute path.\nMay not contain the path element '..'.\nMay not start with the string '..'." }, "mode": { "type": "integer", "format": "int32", - "title": "Optional: mode bits used to set permissions on this file.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values for mode bits.\nIf not specified, the volume defaultMode will be used.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional" + "title": "mode is Optional: mode bits used to set permissions on this file.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values for mode bits.\nIf not specified, the volume defaultMode will be used.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional" } }, "description": "Maps a string key to a path within a volume." @@ -2852,15 +2852,15 @@ "properties": { "server": { "type": "string", - "title": "Server is the hostname or IP address of the NFS server.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#nfs" + "title": "server is the hostname or IP address of the NFS server.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#nfs" }, "path": { "type": "string", - "title": "Path that is exported by the NFS server.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#nfs" + "title": "path that is exported by the NFS server.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#nfs" }, "readOnly": { "type": "boolean", - "title": "ReadOnly here will force\nthe NFS export to be mounted with read-only permissions.\nDefaults to false.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#nfs\n+optional" + "title": "readOnly here will force the NFS export to be mounted with read-only permissions.\nDefaults to false.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#nfs\n+optional" } }, "description": "Represents an NFS mount that lasts the lifetime of a pod.\nNFS volumes do not support ownership management or SELinux relabeling." @@ -2958,23 +2958,23 @@ "items": { "type": "string" }, - "title": "AccessModes contains the desired access modes the volume should have.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1\n+optional" + "title": "accessModes contains the desired access modes the volume should have.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1\n+optional" }, "selector": { "$ref": "#/definitions/k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector", - "title": "A label query over volumes to consider for binding.\n+optional" + "title": "selector is a label query over volumes to consider for binding.\n+optional" }, "resources": { "$ref": "#/definitions/k8s.io.api.core.v1.ResourceRequirements", - "title": "Resources represents the minimum resources the volume should have.\nIf RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements\nthat are lower than previous value but must still be higher than capacity recorded in the\nstatus field of the claim.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources\n+optional" + "title": "resources represents the minimum resources the volume should have.\nIf RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements\nthat are lower than previous value but must still be higher than capacity recorded in the\nstatus field of the claim.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources\n+optional" }, "volumeName": { "type": "string", - "title": "VolumeName is the binding reference to the PersistentVolume backing this claim.\n+optional" + "title": "volumeName is the binding reference to the PersistentVolume backing this claim.\n+optional" }, "storageClassName": { "type": "string", - "title": "Name of the StorageClass required by the claim.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1\n+optional" + "title": "storageClassName is the name of the StorageClass required by the claim.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1\n+optional" }, "volumeMode": { "type": "string", @@ -2982,11 +2982,11 @@ }, "dataSource": { "$ref": "#/definitions/k8s.io.api.core.v1.TypedLocalObjectReference", - "title": "This field can be used to specify either:\n* An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot)\n* An existing PVC (PersistentVolumeClaim)\nIf the provisioner or an external controller can support the specified data source,\nit will create a new volume based on the contents of the specified data source.\nIf the AnyVolumeDataSource feature gate is enabled, this field will always have\nthe same contents as the DataSourceRef field.\n+optional" + "title": "dataSource field can be used to specify either:\n* An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot)\n* An existing PVC (PersistentVolumeClaim)\nIf the provisioner or an external controller can support the specified data source,\nit will create a new volume based on the contents of the specified data source.\nIf the AnyVolumeDataSource feature gate is enabled, this field will always have\nthe same contents as the DataSourceRef field.\n+optional" }, "dataSourceRef": { "$ref": "#/definitions/k8s.io.api.core.v1.TypedLocalObjectReference", - "title": "Specifies the object from which to populate the volume with data, if a non-empty\nvolume is desired. This may be any local object from a non-empty API group (non\ncore object) or a PersistentVolumeClaim object.\nWhen this field is specified, volume binding will only succeed if the type of\nthe specified object matches some installed volume populator or dynamic\nprovisioner.\nThis field will replace the functionality of the DataSource field and as such\nif both fields are non-empty, they must have the same value. For backwards\ncompatibility, both fields (DataSource and DataSourceRef) will be set to the same\nvalue automatically if one of them is empty and the other is non-empty.\nThere are two important differences between DataSource and DataSourceRef:\n* While DataSource only allows two specific types of objects, DataSourceRef\n allows any non-core object, as well as PersistentVolumeClaim objects.\n* While DataSource ignores disallowed values (dropping them), DataSourceRef\n preserves all values, and generates an error if a disallowed value is\n specified.\n(Alpha) Using this field requires the AnyVolumeDataSource feature gate to be enabled.\n+optional" + "title": "dataSourceRef specifies the object from which to populate the volume with data, if a non-empty\nvolume is desired. This may be any local object from a non-empty API group (non\ncore object) or a PersistentVolumeClaim object.\nWhen this field is specified, volume binding will only succeed if the type of\nthe specified object matches some installed volume populator or dynamic\nprovisioner.\nThis field will replace the functionality of the DataSource field and as such\nif both fields are non-empty, they must have the same value. For backwards\ncompatibility, both fields (DataSource and DataSourceRef) will be set to the same\nvalue automatically if one of them is empty and the other is non-empty.\nThere are two important differences between DataSource and DataSourceRef:\n* While DataSource only allows two specific types of objects, DataSourceRef\n allows any non-core object, as well as PersistentVolumeClaim objects.\n* While DataSource ignores disallowed values (dropping them), DataSourceRef\n preserves all values, and generates an error if a disallowed value is\n specified.\n(Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled.\n+optional" } }, "title": "PersistentVolumeClaimSpec describes the common attributes of storage devices\nand allows a Source for provider-specific attributes" @@ -3010,11 +3010,11 @@ "properties": { "claimName": { "type": "string", - "title": "ClaimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims" + "title": "claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims" }, "readOnly": { "type": "boolean", - "title": "Will force the ReadOnly setting in VolumeMounts.\nDefault false.\n+optional" + "title": "readOnly Will force the ReadOnly setting in VolumeMounts.\nDefault false.\n+optional" } }, "description": "PersistentVolumeClaimVolumeSource references the user's PVC in the same namespace.\nThis volume finds the bound PV and mounts that volume for the pod. A\nPersistentVolumeClaimVolumeSource is, essentially, a wrapper around another\ntype of volume that is owned by someone else (the system)." @@ -3024,11 +3024,11 @@ "properties": { "pdID": { "type": "string", - "title": "ID that identifies Photon Controller persistent disk" + "title": "pdID is the ID that identifies Photon Controller persistent disk" }, "fsType": { "type": "string", - "description": "Filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified." + "description": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified." } }, "description": "Represents a Photon Controller persistent disk resource." @@ -3065,7 +3065,7 @@ "items": { "type": "string" }, - "title": "namespaces specifies a static list of namespace names that the term applies to.\nThe term is applied to the union of the namespaces listed in this field\nand the ones selected by namespaceSelector.\nnull or empty namespaces list and null namespaceSelector means \"this pod's namespace\"\n+optional" + "title": "namespaces specifies a static list of namespace names that the term applies to.\nThe term is applied to the union of the namespaces listed in this field\nand the ones selected by namespaceSelector.\nnull or empty namespaces list and null namespaceSelector means \"this pod's namespace\".\n+optional" }, "topologyKey": { "type": "string", @@ -3073,7 +3073,7 @@ }, "namespaceSelector": { "$ref": "#/definitions/k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector", - "title": "A label query over the set of namespaces that the term applies to.\nThe term is applied to the union of the namespaces selected by this field\nand the ones listed in the namespaces field.\nnull selector and null or empty namespaces list means \"this pod's namespace\".\nAn empty selector ({}) matches all namespaces.\nThis field is beta-level and is only honored when PodAffinityNamespaceSelector feature is enabled.\n+optional" + "title": "A label query over the set of namespaces that the term applies to.\nThe term is applied to the union of the namespaces selected by this field\nand the ones listed in the namespaces field.\nnull selector and null or empty namespaces list means \"this pod's namespace\".\nAn empty selector ({}) matches all namespaces.\n+optional" } }, "title": "Defines a set of pods (namely those matching the labelSelector\nrelative to the given namespace(s)) that this pod should be\nco-located (affinity) or not co-located (anti-affinity) with,\nwhere co-located is defined as running on a node whose value of\nthe label with key \u003ctopologyKey\u003e matches that of any node on which\na pod of the set of pods is running" @@ -3313,7 +3313,7 @@ "items": { "$ref": "#/definitions/k8s.io.api.core.v1.LocalObjectReference" }, - "title": "ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.\nIf specified, these secrets will be passed to individual puller implementations for them to use. For example,\nin the case of docker, only DockerConfig type secrets are honored.\nMore info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod\n+optional\n+patchMergeKey=name\n+patchStrategy=merge" + "title": "ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.\nIf specified, these secrets will be passed to individual puller implementations for them to use.\nMore info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod\n+optional\n+patchMergeKey=name\n+patchStrategy=merge" }, "hostname": { "type": "string", @@ -3367,7 +3367,7 @@ }, "runtimeClassName": { "type": "string", - "title": "RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used\nto run this pod. If no RuntimeClass resource matches the named class, the pod will not be run.\nIf unset or empty, the \"legacy\" RuntimeClass will be used, which is an implicit class with an\nempty definition that uses the default runtime handler.\nMore info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class\nThis is a beta feature as of Kubernetes v1.14.\n+optional" + "title": "RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used\nto run this pod. If no RuntimeClass resource matches the named class, the pod will not be run.\nIf unset or empty, the \"legacy\" RuntimeClass will be used, which is an implicit class with an\nempty definition that uses the default runtime handler.\nMore info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class\n+optional" }, "enableServiceLinks": { "type": "boolean", @@ -3375,14 +3375,14 @@ }, "preemptionPolicy": { "type": "string", - "title": "PreemptionPolicy is the Policy for preempting pods with lower priority.\nOne of Never, PreemptLowerPriority.\nDefaults to PreemptLowerPriority if unset.\nThis field is beta-level, gated by the NonPreemptingPriority feature-gate.\n+optional" + "title": "PreemptionPolicy is the Policy for preempting pods with lower priority.\nOne of Never, PreemptLowerPriority.\nDefaults to PreemptLowerPriority if unset.\n+optional" }, "overhead": { "type": "object", "additionalProperties": { "$ref": "#/definitions/k8s.io.apimachinery.pkg.api.resource.Quantity" }, - "title": "Overhead represents the resource overhead associated with running a pod for a given RuntimeClass.\nThis field will be autopopulated at admission time by the RuntimeClass admission controller. If\nthe RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests.\nThe RuntimeClass admission controller will reject Pod create requests which have the overhead already\nset. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value\ndefined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero.\nMore info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead/README.md\nThis field is beta-level as of Kubernetes v1.18, and is only honored by servers that enable the PodOverhead feature.\n+optional" + "title": "Overhead represents the resource overhead associated with running a pod for a given RuntimeClass.\nThis field will be autopopulated at admission time by the RuntimeClass admission controller. If\nthe RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests.\nThe RuntimeClass admission controller will reject Pod create requests which have the overhead already\nset. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value\ndefined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero.\nMore info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead/README.md\n+optional" }, "topologySpreadConstraints": { "type": "array", @@ -3397,7 +3397,7 @@ }, "os": { "$ref": "#/definitions/k8s.io.api.core.v1.PodOS", - "description": "Specifies the OS of the containers in the pod.\nSome pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset:\n-securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset:\n- spec.hostPID\n- spec.hostIPC\n- spec.securityContext.seLinuxOptions\n- spec.securityContext.seccompProfile\n- spec.securityContext.fsGroup\n- spec.securityContext.fsGroupChangePolicy\n- spec.securityContext.sysctls\n- spec.shareProcessNamespace\n- spec.securityContext.runAsUser\n- spec.securityContext.runAsGroup\n- spec.securityContext.supplementalGroups\n- spec.containers[*].securityContext.seLinuxOptions\n- spec.containers[*].securityContext.seccompProfile\n- spec.containers[*].securityContext.capabilities\n- spec.containers[*].securityContext.readOnlyRootFilesystem\n- spec.containers[*].securityContext.privileged\n- spec.containers[*].securityContext.allowPrivilegeEscalation\n- spec.containers[*].securityContext.procMount\n- spec.containers[*].securityContext.runAsUser\n- spec.containers[*].securityContext.runAsGroup\n+optional\nThis is an alpha field and requires the IdentifyPodOS feature" + "description": "Specifies the OS of the containers in the pod.\nSome pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset:\n-securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset:\n- spec.hostPID\n- spec.hostIPC\n- spec.securityContext.seLinuxOptions\n- spec.securityContext.seccompProfile\n- spec.securityContext.fsGroup\n- spec.securityContext.fsGroupChangePolicy\n- spec.securityContext.sysctls\n- spec.shareProcessNamespace\n- spec.securityContext.runAsUser\n- spec.securityContext.runAsGroup\n- spec.securityContext.supplementalGroups\n- spec.containers[*].securityContext.seLinuxOptions\n- spec.containers[*].securityContext.seccompProfile\n- spec.containers[*].securityContext.capabilities\n- spec.containers[*].securityContext.readOnlyRootFilesystem\n- spec.containers[*].securityContext.privileged\n- spec.containers[*].securityContext.allowPrivilegeEscalation\n- spec.containers[*].securityContext.procMount\n- spec.containers[*].securityContext.runAsUser\n- spec.containers[*].securityContext.runAsGroup\n+optional\nThis is a beta field and requires the IdentifyPodOS feature" } }, "description": "PodSpec is a description of a pod." @@ -3421,15 +3421,15 @@ "properties": { "volumeID": { "type": "string", - "title": "VolumeID uniquely identifies a Portworx volume" + "title": "volumeID uniquely identifies a Portworx volume" }, "fsType": { "type": "string", - "description": "FSType represents the filesystem type to mount\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\". Implicitly inferred to be \"ext4\" if unspecified." + "description": "fSType represents the filesystem type to mount\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\". Implicitly inferred to be \"ext4\" if unspecified." }, "readOnly": { "type": "boolean", - "title": "Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional" + "title": "readOnly defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional" } }, "description": "PortworxVolumeSource represents a Portworx volume resource." @@ -3506,7 +3506,7 @@ }, "grpc": { "$ref": "#/definitions/k8s.io.api.core.v1.GRPCAction", - "title": "GRPC specifies an action involving a GRPC port.\nThis is an alpha field and requires enabling GRPCContainerProbe feature gate.\n+featureGate=GRPCContainerProbe\n+optional" + "title": "GRPC specifies an action involving a GRPC port.\nThis is a beta field and requires enabling GRPCContainerProbe feature gate.\n+featureGate=GRPCContainerProbe\n+optional" } }, "description": "ProbeHandler defines a specific action that should be taken in a probe.\nOne and only one of the fields must be specified." @@ -3519,12 +3519,12 @@ "items": { "$ref": "#/definitions/k8s.io.api.core.v1.VolumeProjection" }, - "title": "list of volume projections\n+optional" + "title": "sources is the list of volume projections\n+optional" }, "defaultMode": { "type": "integer", "format": "int32", - "title": "Mode bits used to set permissions on created files by default.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values for mode bits.\nDirectories within the path are not affected by this setting.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional" + "title": "defaultMode are the mode bits used to set permissions on created files by default.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values for mode bits.\nDirectories within the path are not affected by this setting.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional" } }, "title": "Represents a projected volume source" @@ -3534,27 +3534,27 @@ "properties": { "registry": { "type": "string", - "title": "Registry represents a single or multiple Quobyte Registry services\nspecified as a string as host:port pair (multiple entries are separated with commas)\nwhich acts as the central registry for volumes" + "title": "registry represents a single or multiple Quobyte Registry services\nspecified as a string as host:port pair (multiple entries are separated with commas)\nwhich acts as the central registry for volumes" }, "volume": { "type": "string", - "description": "Volume is a string that references an already created Quobyte volume by name." + "description": "volume is a string that references an already created Quobyte volume by name." }, "readOnly": { "type": "boolean", - "title": "ReadOnly here will force the Quobyte volume to be mounted with read-only permissions.\nDefaults to false.\n+optional" + "title": "readOnly here will force the Quobyte volume to be mounted with read-only permissions.\nDefaults to false.\n+optional" }, "user": { "type": "string", - "title": "User to map volume access to\nDefaults to serivceaccount user\n+optional" + "title": "user to map volume access to\nDefaults to serivceaccount user\n+optional" }, "group": { "type": "string", - "title": "Group to map volume access to\nDefault is no group\n+optional" + "title": "group to map volume access to\nDefault is no group\n+optional" }, "tenant": { "type": "string", - "title": "Tenant owning the given Quobyte volume in the Backend\nUsed with dynamically provisioned Quobyte volumes, value is set by the plugin\n+optional" + "title": "tenant owning the given Quobyte volume in the Backend\nUsed with dynamically provisioned Quobyte volumes, value is set by the plugin\n+optional" } }, "description": "Represents a Quobyte mount that lasts the lifetime of a pod.\nQuobyte volumes do not support ownership management or SELinux relabeling." @@ -3567,35 +3567,35 @@ "items": { "type": "string" }, - "title": "A collection of Ceph monitors.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it" + "title": "monitors is a collection of Ceph monitors.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it" }, "image": { "type": "string", - "title": "The rados image name.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it" + "title": "image is the rados image name.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it" }, "fsType": { "type": "string", - "title": "Filesystem type of the volume that you want to mount.\nTip: Ensure that the filesystem type is supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#rbd\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional" + "title": "fsType is the filesystem type of the volume that you want to mount.\nTip: Ensure that the filesystem type is supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#rbd\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional" }, "pool": { "type": "string", - "title": "The rados pool name.\nDefault is rbd.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional" + "title": "pool is the rados pool name.\nDefault is rbd.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional" }, "user": { "type": "string", - "title": "The rados user name.\nDefault is admin.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional" + "title": "user is the rados user name.\nDefault is admin.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional" }, "keyring": { "type": "string", - "title": "Keyring is the path to key ring for RBDUser.\nDefault is /etc/ceph/keyring.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional" + "title": "keyring is the path to key ring for RBDUser.\nDefault is /etc/ceph/keyring.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional" }, "secretRef": { "$ref": "#/definitions/k8s.io.api.core.v1.LocalObjectReference", - "title": "SecretRef is name of the authentication secret for RBDUser. If provided\noverrides keyring.\nDefault is nil.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional" + "title": "secretRef is name of the authentication secret for RBDUser. If provided\noverrides keyring.\nDefault is nil.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional" }, "readOnly": { "type": "boolean", - "title": "ReadOnly here will force the ReadOnly setting in VolumeMounts.\nDefaults to false.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional" + "title": "readOnly here will force the ReadOnly setting in VolumeMounts.\nDefaults to false.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional" } }, "description": "Represents a Rados Block Device mount that lasts the lifetime of a pod.\nRBD volumes support ownership management and SELinux relabeling." @@ -3665,43 +3665,43 @@ "properties": { "gateway": { "type": "string", - "description": "The host address of the ScaleIO API Gateway." + "description": "gateway is the host address of the ScaleIO API Gateway." }, "system": { "type": "string", - "description": "The name of the storage system as configured in ScaleIO." + "description": "system is the name of the storage system as configured in ScaleIO." }, "secretRef": { "$ref": "#/definitions/k8s.io.api.core.v1.LocalObjectReference", - "description": "SecretRef references to the secret for ScaleIO user and other\nsensitive information. If this is not provided, Login operation will fail." + "description": "secretRef references to the secret for ScaleIO user and other\nsensitive information. If this is not provided, Login operation will fail." }, "sslEnabled": { "type": "boolean", - "title": "Flag to enable/disable SSL communication with Gateway, default false\n+optional" + "title": "sslEnabled Flag enable/disable SSL communication with Gateway, default false\n+optional" }, "protectionDomain": { "type": "string", - "title": "The name of the ScaleIO Protection Domain for the configured storage.\n+optional" + "title": "protectionDomain is the name of the ScaleIO Protection Domain for the configured storage.\n+optional" }, "storagePool": { "type": "string", - "title": "The ScaleIO Storage Pool associated with the protection domain.\n+optional" + "title": "storagePool is the ScaleIO Storage Pool associated with the protection domain.\n+optional" }, "storageMode": { "type": "string", - "title": "Indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned.\nDefault is ThinProvisioned.\n+optional" + "title": "storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned.\nDefault is ThinProvisioned.\n+optional" }, "volumeName": { "type": "string", - "description": "The name of a volume already created in the ScaleIO system\nthat is associated with this volume source." + "description": "volumeName is the name of a volume already created in the ScaleIO system\nthat is associated with this volume source." }, "fsType": { "type": "string", - "title": "Filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\".\nDefault is \"xfs\".\n+optional" + "title": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\".\nDefault is \"xfs\".\n+optional" }, "readOnly": { "type": "boolean", - "title": "Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional" + "title": "readOnly Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional" } }, "title": "ScaleIOVolumeSource represents a persistent ScaleIO volume" @@ -3764,11 +3764,11 @@ "items": { "$ref": "#/definitions/k8s.io.api.core.v1.KeyToPath" }, - "title": "If unspecified, each key-value pair in the Data field of the referenced\nSecret will be projected into the volume as a file whose name is the\nkey and content is the value. If specified, the listed keys will be\nprojected into the specified paths, and unlisted keys will not be\npresent. If a key is specified which is not present in the Secret,\nthe volume setup will error unless it is marked optional. Paths must be\nrelative and may not contain the '..' path or start with '..'.\n+optional" + "title": "items if unspecified, each key-value pair in the Data field of the referenced\nSecret will be projected into the volume as a file whose name is the\nkey and content is the value. If specified, the listed keys will be\nprojected into the specified paths, and unlisted keys will not be\npresent. If a key is specified which is not present in the Secret,\nthe volume setup will error unless it is marked optional. Paths must be\nrelative and may not contain the '..' path or start with '..'.\n+optional" }, "optional": { "type": "boolean", - "title": "Specify whether the Secret or its key must be defined\n+optional" + "title": "optional field specify whether the Secret or its key must be defined\n+optional" } }, "description": "Adapts a secret into a projected volume.\n\nThe contents of the target Secret's Data field will be presented in a\nprojected volume as files using the keys in the Data field as the file names.\nNote that this is identical to a secret volume source without the default\nmode." @@ -3778,23 +3778,23 @@ "properties": { "secretName": { "type": "string", - "title": "Name of the secret in the pod's namespace to use.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#secret\n+optional" + "title": "secretName is the name of the secret in the pod's namespace to use.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#secret\n+optional" }, "items": { "type": "array", "items": { "$ref": "#/definitions/k8s.io.api.core.v1.KeyToPath" }, - "title": "If unspecified, each key-value pair in the Data field of the referenced\nSecret will be projected into the volume as a file whose name is the\nkey and content is the value. If specified, the listed keys will be\nprojected into the specified paths, and unlisted keys will not be\npresent. If a key is specified which is not present in the Secret,\nthe volume setup will error unless it is marked optional. Paths must be\nrelative and may not contain the '..' path or start with '..'.\n+optional" + "title": "items If unspecified, each key-value pair in the Data field of the referenced\nSecret will be projected into the volume as a file whose name is the\nkey and content is the value. If specified, the listed keys will be\nprojected into the specified paths, and unlisted keys will not be\npresent. If a key is specified which is not present in the Secret,\nthe volume setup will error unless it is marked optional. Paths must be\nrelative and may not contain the '..' path or start with '..'.\n+optional" }, "defaultMode": { "type": "integer", "format": "int32", - "title": "Optional: mode bits used to set permissions on created files by default.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values\nfor mode bits. Defaults to 0644.\nDirectories within the path are not affected by this setting.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional" + "title": "defaultMode is Optional: mode bits used to set permissions on created files by default.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values\nfor mode bits. Defaults to 0644.\nDirectories within the path are not affected by this setting.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional" }, "optional": { "type": "boolean", - "title": "Specify whether the Secret or its keys must be defined\n+optional" + "title": "optional field specify whether the Secret or its keys must be defined\n+optional" } }, "description": "Adapts a Secret into a volume.\n\nThe contents of the target Secret's Data field will be presented in a volume\nas files using the keys in the Data field as the file names.\nSecret volumes support ownership management and SELinux relabeling." @@ -3856,16 +3856,16 @@ "properties": { "audience": { "type": "string", - "title": "Audience is the intended audience of the token. A recipient of a token\nmust identify itself with an identifier specified in the audience of the\ntoken, and otherwise should reject the token. The audience defaults to the\nidentifier of the apiserver.\n+optional" + "title": "audience is the intended audience of the token. A recipient of a token\nmust identify itself with an identifier specified in the audience of the\ntoken, and otherwise should reject the token. The audience defaults to the\nidentifier of the apiserver.\n+optional" }, "expirationSeconds": { "type": "string", "format": "int64", - "title": "ExpirationSeconds is the requested duration of validity of the service\naccount token. As the token approaches expiration, the kubelet volume\nplugin will proactively rotate the service account token. The kubelet will\nstart trying to rotate the token if the token is older than 80 percent of\nits time to live or if the token is older than 24 hours.Defaults to 1 hour\nand must be at least 10 minutes.\n+optional" + "title": "expirationSeconds is the requested duration of validity of the service\naccount token. As the token approaches expiration, the kubelet volume\nplugin will proactively rotate the service account token. The kubelet will\nstart trying to rotate the token if the token is older than 80 percent of\nits time to live or if the token is older than 24 hours.Defaults to 1 hour\nand must be at least 10 minutes.\n+optional" }, "path": { "type": "string", - "description": "Path is the path relative to the mount point of the file to project the\ntoken into." + "description": "path is the path relative to the mount point of the file to project the\ntoken into." } }, "description": "ServiceAccountTokenProjection represents a projected service account token\nvolume. This projection can be used to insert a service account token into\nthe pods runtime filesystem for use against APIs (Kubernetes API Server or\notherwise)." @@ -3875,23 +3875,23 @@ "properties": { "volumeName": { "type": "string", - "description": "VolumeName is the human-readable name of the StorageOS volume. Volume\nnames are only unique within a namespace." + "description": "volumeName is the human-readable name of the StorageOS volume. Volume\nnames are only unique within a namespace." }, "volumeNamespace": { "type": "string", - "title": "VolumeNamespace specifies the scope of the volume within StorageOS. If no\nnamespace is specified then the Pod's namespace will be used. This allows the\nKubernetes name scoping to be mirrored within StorageOS for tighter integration.\nSet VolumeName to any name to override the default behaviour.\nSet to \"default\" if you are not using namespaces within StorageOS.\nNamespaces that do not pre-exist within StorageOS will be created.\n+optional" + "title": "volumeNamespace specifies the scope of the volume within StorageOS. If no\nnamespace is specified then the Pod's namespace will be used. This allows the\nKubernetes name scoping to be mirrored within StorageOS for tighter integration.\nSet VolumeName to any name to override the default behaviour.\nSet to \"default\" if you are not using namespaces within StorageOS.\nNamespaces that do not pre-exist within StorageOS will be created.\n+optional" }, "fsType": { "type": "string", - "title": "Filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\n+optional" + "title": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\n+optional" }, "readOnly": { "type": "boolean", - "title": "Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional" + "title": "readOnly defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional" }, "secretRef": { "$ref": "#/definitions/k8s.io.api.core.v1.LocalObjectReference", - "title": "SecretRef specifies the secret to use for obtaining the StorageOS API\ncredentials. If not specified, default values will be attempted.\n+optional" + "title": "secretRef specifies the secret to use for obtaining the StorageOS API\ncredentials. If not specified, default values will be attempted.\n+optional" } }, "description": "Represents a StorageOS persistent volume resource." @@ -3957,11 +3957,11 @@ "maxSkew": { "type": "integer", "format": "int32", - "description": "MaxSkew describes the degree to which pods may be unevenly distributed.\nWhen `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference\nbetween the number of matching pods in the target topology and the global minimum.\nFor example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same\nlabelSelector spread as 1/1/0:\n+-------+-------+-------+\n| zone1 | zone2 | zone3 |\n+-------+-------+-------+\n| P | P | |\n+-------+-------+-------+\n- if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 1/1/1;\nscheduling it onto zone1(zone2) would make the ActualSkew(2-0) on zone1(zone2)\nviolate MaxSkew(1).\n- if MaxSkew is 2, incoming pod can be scheduled onto any zone.\nWhen `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence\nto topologies that satisfy it.\nIt's a required field. Default value is 1 and 0 is not allowed." + "description": "MaxSkew describes the degree to which pods may be unevenly distributed.\nWhen `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference\nbetween the number of matching pods in the target topology and the global minimum.\nThe global minimum is the minimum number of matching pods in an eligible domain\nor zero if the number of eligible domains is less than MinDomains.\nFor example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same\nlabelSelector spread as 2/2/1:\nIn this case, the global minimum is 1.\n+-------+-------+-------+\n| zone1 | zone2 | zone3 |\n+-------+-------+-------+\n| P P | P P | P |\n+-------+-------+-------+\n- if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2;\nscheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2)\nviolate MaxSkew(1).\n- if MaxSkew is 2, incoming pod can be scheduled onto any zone.\nWhen `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence\nto topologies that satisfy it.\nIt's a required field. Default value is 1 and 0 is not allowed." }, "topologyKey": { "type": "string", - "description": "TopologyKey is the key of node labels. Nodes that have a label with this key\nand identical values are considered to be in the same topology.\nWe consider each \u003ckey, value\u003e as a \"bucket\", and try to put balanced number\nof pods into each bucket.\nIt's a required field." + "description": "TopologyKey is the key of node labels. Nodes that have a label with this key\nand identical values are considered to be in the same topology.\nWe consider each \u003ckey, value\u003e as a \"bucket\", and try to put balanced number\nof pods into each bucket.\nWe define a domain as a particular instance of a topology.\nAlso, we define an eligible domain as a domain whose nodes match the node selector.\ne.g. If TopologyKey is \"kubernetes.io/hostname\", each Node is a domain of that topology.\nAnd, if TopologyKey is \"topology.kubernetes.io/zone\", each zone is a domain of that topology.\nIt's a required field." }, "whenUnsatisfiable": { "type": "string", @@ -3970,6 +3970,11 @@ "labelSelector": { "$ref": "#/definitions/k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector", "title": "LabelSelector is used to find matching pods.\nPods that match this label selector are counted to determine the number of pods\nin their corresponding topology domain.\n+optional" + }, + "minDomains": { + "type": "integer", + "format": "int32", + "description": "MinDomains indicates a minimum number of eligible domains.\nWhen the number of eligible domains with matching topology keys is less than minDomains,\nPod Topology Spread treats \"global minimum\" as 0, and then the calculation of Skew is performed.\nAnd when the number of eligible domains with matching topology keys equals or greater than minDomains,\nthis value has no effect on scheduling.\nAs a result, when the number of eligible domains is less than minDomains,\nscheduler won't schedule more than maxSkew Pods to those domains.\nIf value is nil, the constraint behaves as if MinDomains is equal to 1.\nValid values are integers greater than 0.\nWhen value is not nil, WhenUnsatisfiable must be DoNotSchedule.\n\nFor example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same\nlabelSelector spread as 2/2/2:\n+-------+-------+-------+\n| zone1 | zone2 | zone3 |\n+-------+-------+-------+\n| P P | P P | P P |\n+-------+-------+-------+\nThe number of domains is less than 5(MinDomains), so \"global minimum\" is treated as 0.\nIn this situation, new pod with the same labelSelector cannot be scheduled,\nbecause computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones,\nit will violate MaxSkew.\n\nThis is an alpha field and requires enabling MinDomainsInPodTopologySpread feature gate.\n+optional" } }, "description": "TopologySpreadConstraint specifies how to spread matching pods among the given topology." @@ -3997,11 +4002,11 @@ "properties": { "name": { "type": "string", - "title": "Volume's name.\nMust be a DNS_LABEL and unique within the pod.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" + "title": "name of the volume.\nMust be a DNS_LABEL and unique within the pod.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names" }, "volumeSource": { "$ref": "#/definitions/k8s.io.api.core.v1.VolumeSource", - "description": "VolumeSource represents the location and type of the mounted volume.\nIf not specified, the Volume is implied to be an EmptyDir.\nThis implied behavior is deprecated and will be removed in a future version." + "description": "volumeSource represents the location and type of the mounted volume.\nIf not specified, the Volume is implied to be an EmptyDir.\nThis implied behavior is deprecated and will be removed in a future version." } }, "description": "Volume represents a named volume in a pod that may be accessed by any container in the pod." @@ -4055,19 +4060,19 @@ "properties": { "secret": { "$ref": "#/definitions/k8s.io.api.core.v1.SecretProjection", - "title": "information about the secret data to project\n+optional" + "title": "secret information about the secret data to project\n+optional" }, "downwardAPI": { "$ref": "#/definitions/k8s.io.api.core.v1.DownwardAPIProjection", - "title": "information about the downwardAPI data to project\n+optional" + "title": "downwardAPI information about the downwardAPI data to project\n+optional" }, "configMap": { "$ref": "#/definitions/k8s.io.api.core.v1.ConfigMapProjection", - "title": "information about the configMap data to project\n+optional" + "title": "configMap information about the configMap data to project\n+optional" }, "serviceAccountToken": { "$ref": "#/definitions/k8s.io.api.core.v1.ServiceAccountTokenProjection", - "title": "information about the serviceAccountToken data to project\n+optional" + "title": "serviceAccountToken is information about the serviceAccountToken data to project\n+optional" } }, "title": "Projection that may be projected along with other supported volume types" @@ -4077,119 +4082,119 @@ "properties": { "hostPath": { "$ref": "#/definitions/k8s.io.api.core.v1.HostPathVolumeSource", - "title": "HostPath represents a pre-existing file or directory on the host\nmachine that is directly exposed to the container. This is generally\nused for system agents or other privileged things that are allowed\nto see the host machine. Most containers will NOT need this.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath\n---\nTODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not\nmount host directories as read/write.\n+optional" + "title": "hostPath represents a pre-existing file or directory on the host\nmachine that is directly exposed to the container. This is generally\nused for system agents or other privileged things that are allowed\nto see the host machine. Most containers will NOT need this.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath\n---\nTODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not\nmount host directories as read/write.\n+optional" }, "emptyDir": { "$ref": "#/definitions/k8s.io.api.core.v1.EmptyDirVolumeSource", - "title": "EmptyDir represents a temporary directory that shares a pod's lifetime.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir\n+optional" + "title": "emptyDir represents a temporary directory that shares a pod's lifetime.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir\n+optional" }, "gcePersistentDisk": { "$ref": "#/definitions/k8s.io.api.core.v1.GCEPersistentDiskVolumeSource", - "title": "GCEPersistentDisk represents a GCE Disk resource that is attached to a\nkubelet's host machine and then exposed to the pod.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk\n+optional" + "title": "gcePersistentDisk represents a GCE Disk resource that is attached to a\nkubelet's host machine and then exposed to the pod.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk\n+optional" }, "awsElasticBlockStore": { "$ref": "#/definitions/k8s.io.api.core.v1.AWSElasticBlockStoreVolumeSource", - "title": "AWSElasticBlockStore represents an AWS Disk resource that is attached to a\nkubelet's host machine and then exposed to the pod.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore\n+optional" + "title": "awsElasticBlockStore represents an AWS Disk resource that is attached to a\nkubelet's host machine and then exposed to the pod.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore\n+optional" }, "gitRepo": { "$ref": "#/definitions/k8s.io.api.core.v1.GitRepoVolumeSource", - "title": "GitRepo represents a git repository at a particular revision.\nDEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an\nEmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir\ninto the Pod's container.\n+optional" + "title": "gitRepo represents a git repository at a particular revision.\nDEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an\nEmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir\ninto the Pod's container.\n+optional" }, "secret": { "$ref": "#/definitions/k8s.io.api.core.v1.SecretVolumeSource", - "title": "Secret represents a secret that should populate this volume.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#secret\n+optional" + "title": "secret represents a secret that should populate this volume.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#secret\n+optional" }, "nfs": { "$ref": "#/definitions/k8s.io.api.core.v1.NFSVolumeSource", - "title": "NFS represents an NFS mount on the host that shares a pod's lifetime\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#nfs\n+optional" + "title": "nfs represents an NFS mount on the host that shares a pod's lifetime\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#nfs\n+optional" }, "iscsi": { "$ref": "#/definitions/k8s.io.api.core.v1.ISCSIVolumeSource", - "title": "ISCSI represents an ISCSI Disk resource that is attached to a\nkubelet's host machine and then exposed to the pod.\nMore info: https://examples.k8s.io/volumes/iscsi/README.md\n+optional" + "title": "iscsi represents an ISCSI Disk resource that is attached to a\nkubelet's host machine and then exposed to the pod.\nMore info: https://examples.k8s.io/volumes/iscsi/README.md\n+optional" }, "glusterfs": { "$ref": "#/definitions/k8s.io.api.core.v1.GlusterfsVolumeSource", - "title": "Glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime.\nMore info: https://examples.k8s.io/volumes/glusterfs/README.md\n+optional" + "title": "glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime.\nMore info: https://examples.k8s.io/volumes/glusterfs/README.md\n+optional" }, "persistentVolumeClaim": { "$ref": "#/definitions/k8s.io.api.core.v1.PersistentVolumeClaimVolumeSource", - "title": "PersistentVolumeClaimVolumeSource represents a reference to a\nPersistentVolumeClaim in the same namespace.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims\n+optional" + "title": "persistentVolumeClaimVolumeSource represents a reference to a\nPersistentVolumeClaim in the same namespace.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims\n+optional" }, "rbd": { "$ref": "#/definitions/k8s.io.api.core.v1.RBDVolumeSource", - "title": "RBD represents a Rados Block Device mount on the host that shares a pod's lifetime.\nMore info: https://examples.k8s.io/volumes/rbd/README.md\n+optional" + "title": "rbd represents a Rados Block Device mount on the host that shares a pod's lifetime.\nMore info: https://examples.k8s.io/volumes/rbd/README.md\n+optional" }, "flexVolume": { "$ref": "#/definitions/k8s.io.api.core.v1.FlexVolumeSource", - "title": "FlexVolume represents a generic volume resource that is\nprovisioned/attached using an exec based plugin.\n+optional" + "title": "flexVolume represents a generic volume resource that is\nprovisioned/attached using an exec based plugin.\n+optional" }, "cinder": { "$ref": "#/definitions/k8s.io.api.core.v1.CinderVolumeSource", - "title": "Cinder represents a cinder volume attached and mounted on kubelets host machine.\nMore info: https://examples.k8s.io/mysql-cinder-pd/README.md\n+optional" + "title": "cinder represents a cinder volume attached and mounted on kubelets host machine.\nMore info: https://examples.k8s.io/mysql-cinder-pd/README.md\n+optional" }, "cephfs": { "$ref": "#/definitions/k8s.io.api.core.v1.CephFSVolumeSource", - "title": "CephFS represents a Ceph FS mount on the host that shares a pod's lifetime\n+optional" + "title": "cephFS represents a Ceph FS mount on the host that shares a pod's lifetime\n+optional" }, "flocker": { "$ref": "#/definitions/k8s.io.api.core.v1.FlockerVolumeSource", - "title": "Flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running\n+optional" + "title": "flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running\n+optional" }, "downwardAPI": { "$ref": "#/definitions/k8s.io.api.core.v1.DownwardAPIVolumeSource", - "title": "DownwardAPI represents downward API about the pod that should populate this volume\n+optional" + "title": "downwardAPI represents downward API about the pod that should populate this volume\n+optional" }, "fc": { "$ref": "#/definitions/k8s.io.api.core.v1.FCVolumeSource", - "title": "FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.\n+optional" + "title": "fc represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.\n+optional" }, "azureFile": { "$ref": "#/definitions/k8s.io.api.core.v1.AzureFileVolumeSource", - "title": "AzureFile represents an Azure File Service mount on the host and bind mount to the pod.\n+optional" + "title": "azureFile represents an Azure File Service mount on the host and bind mount to the pod.\n+optional" }, "configMap": { "$ref": "#/definitions/k8s.io.api.core.v1.ConfigMapVolumeSource", - "title": "ConfigMap represents a configMap that should populate this volume\n+optional" + "title": "configMap represents a configMap that should populate this volume\n+optional" }, "vsphereVolume": { "$ref": "#/definitions/k8s.io.api.core.v1.VsphereVirtualDiskVolumeSource", - "title": "VsphereVolume represents a vSphere volume attached and mounted on kubelets host machine\n+optional" + "title": "vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine\n+optional" }, "quobyte": { "$ref": "#/definitions/k8s.io.api.core.v1.QuobyteVolumeSource", - "title": "Quobyte represents a Quobyte mount on the host that shares a pod's lifetime\n+optional" + "title": "quobyte represents a Quobyte mount on the host that shares a pod's lifetime\n+optional" }, "azureDisk": { "$ref": "#/definitions/k8s.io.api.core.v1.AzureDiskVolumeSource", - "title": "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.\n+optional" + "title": "azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.\n+optional" }, "photonPersistentDisk": { "$ref": "#/definitions/k8s.io.api.core.v1.PhotonPersistentDiskVolumeSource", - "title": "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine" + "title": "photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine" }, "projected": { "$ref": "#/definitions/k8s.io.api.core.v1.ProjectedVolumeSource", - "title": "Items for all in one resources secrets, configmaps, and downward API" + "title": "projected items for all in one resources secrets, configmaps, and downward API" }, "portworxVolume": { "$ref": "#/definitions/k8s.io.api.core.v1.PortworxVolumeSource", - "title": "PortworxVolume represents a portworx volume attached and mounted on kubelets host machine\n+optional" + "title": "portworxVolume represents a portworx volume attached and mounted on kubelets host machine\n+optional" }, "scaleIO": { "$ref": "#/definitions/k8s.io.api.core.v1.ScaleIOVolumeSource", - "title": "ScaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes.\n+optional" + "title": "scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes.\n+optional" }, "storageos": { "$ref": "#/definitions/k8s.io.api.core.v1.StorageOSVolumeSource", - "title": "StorageOS represents a StorageOS volume attached and mounted on Kubernetes nodes.\n+optional" + "title": "storageOS represents a StorageOS volume attached and mounted on Kubernetes nodes.\n+optional" }, "csi": { "$ref": "#/definitions/k8s.io.api.core.v1.CSIVolumeSource", - "title": "CSI (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature).\n+optional" + "title": "csi (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature).\n+optional" }, "ephemeral": { "$ref": "#/definitions/k8s.io.api.core.v1.EphemeralVolumeSource", - "description": "Ephemeral represents a volume that is handled by a cluster storage driver.\nThe volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts,\nand deleted when the pod is removed.\n\nUse this if:\na) the volume is only needed while the pod runs,\nb) features of normal volumes like restoring from snapshot or capacity\n tracking are needed,\nc) the storage driver is specified through a storage class, and\nd) the storage driver supports dynamic volume provisioning through\n a PersistentVolumeClaim (see EphemeralVolumeSource for more\n information on the connection between this volume type\n and PersistentVolumeClaim).\n\nUse PersistentVolumeClaim or one of the vendor-specific\nAPIs for volumes that persist for longer than the lifecycle\nof an individual pod.\n\nUse CSI for light-weight local ephemeral volumes if the CSI driver is meant to\nbe used that way - see the documentation of the driver for\nmore information.\n\nA pod can use both types of ephemeral volumes and\npersistent volumes at the same time.\n\n+optional" + "description": "ephemeral represents a volume that is handled by a cluster storage driver.\nThe volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts,\nand deleted when the pod is removed.\n\nUse this if:\na) the volume is only needed while the pod runs,\nb) features of normal volumes like restoring from snapshot or capacity\n tracking are needed,\nc) the storage driver is specified through a storage class, and\nd) the storage driver supports dynamic volume provisioning through\n a PersistentVolumeClaim (see EphemeralVolumeSource for more\n information on the connection between this volume type\n and PersistentVolumeClaim).\n\nUse PersistentVolumeClaim or one of the vendor-specific\nAPIs for volumes that persist for longer than the lifecycle\nof an individual pod.\n\nUse CSI for light-weight local ephemeral volumes if the CSI driver is meant to\nbe used that way - see the documentation of the driver for\nmore information.\n\nA pod can use both types of ephemeral volumes and\npersistent volumes at the same time.\n\n+optional" } }, "description": "Represents the source of a volume to mount.\nOnly one of its members may be specified." @@ -4199,19 +4204,19 @@ "properties": { "volumePath": { "type": "string", - "title": "Path that identifies vSphere volume vmdk" + "title": "volumePath is the path that identifies vSphere volume vmdk" }, "fsType": { "type": "string", - "title": "Filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\n+optional" + "title": "fsType is filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\n+optional" }, "storagePolicyName": { "type": "string", - "title": "Storage Policy Based Management (SPBM) profile name.\n+optional" + "title": "storagePolicyName is the storage Policy Based Management (SPBM) profile name.\n+optional" }, "storagePolicyID": { "type": "string", - "title": "Storage Policy Based Management (SPBM) profile ID associated with the StoragePolicyName.\n+optional" + "title": "storagePolicyID is the storage Policy Based Management (SPBM) profile ID associated with the StoragePolicyName.\n+optional" } }, "description": "Represents a vSphere volume resource." @@ -4331,7 +4336,7 @@ }, "time": { "$ref": "#/definitions/k8s.io.apimachinery.pkg.apis.meta.v1.Time", - "title": "Time is timestamp of when these fields were set. It should always be empty if Operation is 'Apply'\n+optional" + "title": "Time is the timestamp of when the ManagedFields entry was added. The\ntimestamp will also be updated if a field is added, the manager\nchanges any of the owned fields value or removes a field. The\ntimestamp does not update when a field is removed from the entry\nbecause another manager took it over.\n+optional" }, "fieldsType": { "type": "string", @@ -4357,7 +4362,7 @@ }, "generateName": { "type": "string", - "description": "GenerateName is an optional prefix, used by the server, to generate a unique\nname ONLY IF the Name field has not been provided.\nIf this field is used, the name returned to the client will be different\nthan the name passed. This value will also be combined with a unique suffix.\nThe provided value has the same validation rules as the Name field,\nand may be truncated by the length of the suffix required to make the value\nunique on the server.\n\nIf this field is specified and the generated name exists, the server will\nNOT return a 409 - instead, it will either return 201 Created or 500 with Reason\nServerTimeout indicating a unique name could not be found in the time allotted, and the client\nshould retry (optionally after the time indicated in the Retry-After header).\n\nApplied only if Name is not specified.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency\n+optional" + "description": "GenerateName is an optional prefix, used by the server, to generate a unique\nname ONLY IF the Name field has not been provided.\nIf this field is used, the name returned to the client will be different\nthan the name passed. This value will also be combined with a unique suffix.\nThe provided value has the same validation rules as the Name field,\nand may be truncated by the length of the suffix required to make the value\nunique on the server.\n\nIf this field is specified and the generated name exists, the server will return a 409.\n\nApplied only if Name is not specified.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency\n+optional" }, "namespace": { "type": "string", @@ -4365,7 +4370,7 @@ }, "selfLink": { "type": "string", - "description": "SelfLink is a URL representing this object.\nPopulated by the system.\nRead-only.\n\nDEPRECATED\nKubernetes will stop propagating this field in 1.20 release and the field is planned\nto be removed in 1.21 release.\n+optional" + "title": "Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.\n+optional" }, "uid": { "type": "string", @@ -4423,7 +4428,7 @@ }, "clusterName": { "type": "string", - "title": "The name of the cluster which the object belongs to.\nThis is used to distinguish resources with same name and namespace in different clusters.\nThis field is not set anywhere right now and apiserver is going to ignore it if set in create or update request.\n+optional" + "description": "Deprecated: ClusterName is a legacy field that was always cleared by\nthe system and never used; it will be removed completely in 1.25.\n\nThe name in the go struct is changed to help clients detect\naccidental use.\n\n+optional" }, "managedFields": { "type": "array", @@ -4460,7 +4465,7 @@ }, "blockOwnerDeletion": { "type": "boolean", - "title": "If true, AND if the owner has the \"foregroundDeletion\" finalizer, then\nthe owner cannot be deleted from the key-value store until this\nreference is removed.\nDefaults to false.\nTo set this field, a user needs \"delete\" permission of the owner,\notherwise 422 (Unprocessable Entity) will be returned.\n+optional" + "title": "If true, AND if the owner has the \"foregroundDeletion\" finalizer, then\nthe owner cannot be deleted from the key-value store until this\nreference is removed.\nSee https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion\nfor how the garbage collector interacts with this field and enforces the foreground deletion.\nDefaults to false.\nTo set this field, a user needs \"delete\" permission of the owner,\notherwise 422 (Unprocessable Entity) will be returned.\n+optional" } }, "title": "OwnerReference contains enough information to let you identify an owning\nobject. An owning object must be in the same namespace as the dependent, or\nbe cluster-scoped, so there is no namespace field.\n+structType=atomic" diff --git a/pkg/apis/rollouts/v1alpha1/generated.pb.go b/pkg/apis/rollouts/v1alpha1/generated.pb.go index 0dc12eaa6b..fc7ecb4fbb 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.pb.go +++ b/pkg/apis/rollouts/v1alpha1/generated.pb.go @@ -3055,478 +3055,479 @@ func init() { } var fileDescriptor_e0e705f843545fab = []byte{ - // 7521 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x6b, 0x8c, 0x24, 0x57, - 0x75, 0xb0, 0xab, 0x7b, 0x7a, 0xa6, 0xfb, 0xcc, 0xfb, 0xee, 0x2c, 0x3b, 0x1e, 0x7b, 0xb7, 0x4d, - 0x19, 0xf9, 0x33, 0xdf, 0x07, 0xb3, 0xe0, 0xc7, 0xf7, 0x19, 0x8c, 0xfc, 0xa5, 0x7b, 0x66, 0x1f, - 0xb3, 0x9e, 0x99, 0x9d, 0xbd, 0x3d, 0xbb, 0x0b, 0x06, 0x03, 0x35, 0xdd, 0x77, 0x7a, 0x6a, 0xb7, - 0xbb, 0xaa, 0xa9, 0xaa, 0x9e, 0xdd, 0x31, 0x16, 0xd8, 0x41, 0x76, 0x48, 0x04, 0xc2, 0x09, 0xa0, - 0x28, 0x8a, 0x88, 0x50, 0x64, 0x29, 0x0f, 0xf2, 0x0b, 0x25, 0xca, 0x1f, 0xa4, 0x44, 0xe1, 0x11, - 0xf2, 0x23, 0x11, 0x44, 0x49, 0x80, 0x48, 0x74, 0xe2, 0x26, 0x7f, 0x12, 0x25, 0x42, 0x91, 0x88, - 0x22, 0xf6, 0x57, 0x74, 0x9f, 0x75, 0xab, 0xba, 0x7a, 0xb6, 0x7b, 0xba, 0x66, 0xb1, 0x12, 0xfe, - 0x75, 0xdf, 0x73, 0xee, 0x39, 0xe7, 0x3e, 0xcf, 0xb9, 0xe7, 0x9e, 0x7b, 0x0a, 0xd6, 0xeb, 0x76, - 0xb0, 0xd7, 0xde, 0x59, 0xae, 0xba, 0xcd, 0xb3, 0x96, 0x57, 0x77, 0x5b, 0x9e, 0x7b, 0x83, 0xfd, - 0x78, 0xa7, 0xe7, 0x36, 0x1a, 0x6e, 0x3b, 0xf0, 0xcf, 0xb6, 0x6e, 0xd6, 0xcf, 0x5a, 0x2d, 0xdb, - 0x3f, 0xab, 0x4a, 0xf6, 0xdf, 0x6d, 0x35, 0x5a, 0x7b, 0xd6, 0xbb, 0xcf, 0xd6, 0x89, 0x43, 0x3c, - 0x2b, 0x20, 0xb5, 0xe5, 0x96, 0xe7, 0x06, 0x2e, 0x7a, 0x5f, 0x48, 0x6d, 0x59, 0x52, 0x63, 0x3f, - 0x3e, 0x22, 0xeb, 0x2e, 0xb7, 0x6e, 0xd6, 0x97, 0x29, 0xb5, 0x65, 0x55, 0x22, 0xa9, 0x2d, 0xbd, - 0x53, 0x93, 0xa5, 0xee, 0xd6, 0xdd, 0xb3, 0x8c, 0xe8, 0x4e, 0x7b, 0x97, 0xfd, 0x63, 0x7f, 0xd8, - 0x2f, 0xce, 0x6c, 0xe9, 0xe1, 0x9b, 0x4f, 0xf9, 0xcb, 0xb6, 0x4b, 0x65, 0x3b, 0xbb, 0x63, 0x05, - 0xd5, 0xbd, 0xb3, 0xfb, 0x3d, 0x12, 0x2d, 0x99, 0x1a, 0x52, 0xd5, 0xf5, 0x48, 0x12, 0xce, 0x13, - 0x21, 0x4e, 0xd3, 0xaa, 0xee, 0xd9, 0x0e, 0xf1, 0x0e, 0xc2, 0x56, 0x37, 0x49, 0x60, 0x25, 0xd5, - 0x3a, 0xdb, 0xaf, 0x96, 0xd7, 0x76, 0x02, 0xbb, 0x49, 0x7a, 0x2a, 0xfc, 0xdf, 0xbb, 0x55, 0xf0, - 0xab, 0x7b, 0xa4, 0x69, 0xf5, 0xd4, 0x7b, 0xbc, 0x5f, 0xbd, 0x76, 0x60, 0x37, 0xce, 0xda, 0x4e, - 0xe0, 0x07, 0x5e, 0xbc, 0x92, 0xf9, 0x8d, 0x2c, 0x14, 0x4a, 0xeb, 0xe5, 0x4a, 0x60, 0x05, 0x6d, - 0x1f, 0xbd, 0x6a, 0xc0, 0x54, 0xc3, 0xb5, 0x6a, 0x65, 0xab, 0x61, 0x39, 0x55, 0xe2, 0x2d, 0x1a, - 0x0f, 0x19, 0x8f, 0x4e, 0x3e, 0xb6, 0xbe, 0x3c, 0xca, 0x78, 0x2d, 0x97, 0x6e, 0xf9, 0x98, 0xf8, - 0x6e, 0xdb, 0xab, 0x12, 0x4c, 0x76, 0xcb, 0x0b, 0xdf, 0xee, 0x14, 0xef, 0xeb, 0x76, 0x8a, 0x53, - 0xeb, 0x1a, 0x27, 0x1c, 0xe1, 0x8b, 0xbe, 0x68, 0xc0, 0x7c, 0xd5, 0x72, 0x2c, 0xef, 0x60, 0xdb, - 0xf2, 0xea, 0x24, 0xb8, 0xe0, 0xb9, 0xed, 0xd6, 0x62, 0xe6, 0x18, 0xa4, 0xb9, 0x5f, 0x48, 0x33, - 0xbf, 0x12, 0x67, 0x87, 0x7b, 0x25, 0x60, 0x72, 0xf9, 0x81, 0xb5, 0xd3, 0x20, 0xba, 0x5c, 0xd9, - 0xe3, 0x94, 0xab, 0x12, 0x67, 0x87, 0x7b, 0x25, 0x30, 0x5f, 0xc9, 0xc2, 0x7c, 0x69, 0xbd, 0xbc, - 0xed, 0x59, 0xbb, 0xbb, 0x76, 0x15, 0xbb, 0xed, 0xc0, 0x76, 0xea, 0xe8, 0xed, 0x30, 0x61, 0x3b, - 0x75, 0x8f, 0xf8, 0x3e, 0x1b, 0xc8, 0x42, 0x79, 0x56, 0x10, 0x9d, 0x58, 0xe3, 0xc5, 0x58, 0xc2, - 0xd1, 0x93, 0x30, 0xe9, 0x13, 0x6f, 0xdf, 0xae, 0x92, 0x2d, 0xd7, 0x0b, 0x58, 0x4f, 0xe7, 0xca, - 0x27, 0x04, 0xfa, 0x64, 0x25, 0x04, 0x61, 0x1d, 0x8f, 0x56, 0xf3, 0x5c, 0x37, 0x10, 0x70, 0xd6, - 0x11, 0x85, 0xb0, 0x1a, 0x0e, 0x41, 0x58, 0xc7, 0x43, 0xaf, 0x19, 0x30, 0xe7, 0x07, 0x76, 0xf5, - 0xa6, 0xed, 0x10, 0xdf, 0x5f, 0x71, 0x9d, 0x5d, 0xbb, 0xbe, 0x98, 0x63, 0xbd, 0xb8, 0x39, 0x5a, - 0x2f, 0x56, 0x62, 0x54, 0xcb, 0x0b, 0xdd, 0x4e, 0x71, 0x2e, 0x5e, 0x8a, 0x7b, 0xb8, 0xa3, 0x55, - 0x98, 0xb3, 0x1c, 0xc7, 0x0d, 0xac, 0xc0, 0x76, 0x9d, 0x2d, 0x8f, 0xec, 0xda, 0xb7, 0x17, 0xc7, - 0x58, 0x73, 0x16, 0x45, 0x73, 0xe6, 0x4a, 0x31, 0x38, 0xee, 0xa9, 0x61, 0xae, 0xc2, 0x62, 0xa9, - 0xb9, 0x63, 0xf9, 0xbe, 0x55, 0x73, 0xbd, 0xd8, 0x68, 0x3c, 0x0a, 0xf9, 0xa6, 0xd5, 0x6a, 0xd9, - 0x4e, 0x9d, 0x0e, 0x47, 0xf6, 0xd1, 0x42, 0x79, 0xaa, 0xdb, 0x29, 0xe6, 0x37, 0x44, 0x19, 0x56, - 0x50, 0xf3, 0x07, 0x19, 0x98, 0x2c, 0x39, 0x56, 0xe3, 0xc0, 0xb7, 0x7d, 0xdc, 0x76, 0xd0, 0x47, - 0x21, 0x4f, 0x77, 0x97, 0x9a, 0x15, 0x58, 0x62, 0x45, 0xbe, 0x6b, 0x99, 0x2f, 0xf6, 0x65, 0x7d, - 0xb1, 0x87, 0xfd, 0x42, 0xb1, 0x97, 0xf7, 0xdf, 0xbd, 0x7c, 0x79, 0xe7, 0x06, 0xa9, 0x06, 0x1b, - 0x24, 0xb0, 0xca, 0x48, 0xb4, 0x02, 0xc2, 0x32, 0xac, 0xa8, 0x22, 0x17, 0xc6, 0xfc, 0x16, 0xa9, - 0x8a, 0x15, 0xb6, 0x31, 0xe2, 0x4c, 0x0e, 0x45, 0xaf, 0xb4, 0x48, 0xb5, 0x3c, 0x25, 0x58, 0x8f, - 0xd1, 0x7f, 0x98, 0x31, 0x42, 0xb7, 0x60, 0xdc, 0x67, 0x7b, 0x8e, 0x58, 0x3c, 0x97, 0xd3, 0x63, - 0xc9, 0xc8, 0x96, 0x67, 0x04, 0xd3, 0x71, 0xfe, 0x1f, 0x0b, 0x76, 0xe6, 0xdf, 0x1b, 0x70, 0x42, - 0xc3, 0x2e, 0x79, 0xf5, 0x76, 0x93, 0x38, 0x01, 0x7a, 0x08, 0xc6, 0x1c, 0xab, 0x49, 0xc4, 0x42, - 0x51, 0x22, 0x6f, 0x5a, 0x4d, 0x82, 0x19, 0x04, 0x3d, 0x0c, 0xb9, 0x7d, 0xab, 0xd1, 0x26, 0xac, - 0x93, 0x0a, 0xe5, 0x69, 0x81, 0x92, 0xbb, 0x46, 0x0b, 0x31, 0x87, 0xa1, 0x17, 0xa1, 0xc0, 0x7e, - 0x9c, 0xf7, 0xdc, 0x66, 0x4a, 0x4d, 0x13, 0x12, 0x5e, 0x93, 0x64, 0xcb, 0xd3, 0xdd, 0x4e, 0xb1, - 0xa0, 0xfe, 0xe2, 0x90, 0xa1, 0xf9, 0x0f, 0x06, 0xcc, 0x6a, 0x8d, 0x5b, 0xb7, 0xfd, 0x00, 0x7d, - 0xa8, 0x67, 0xf2, 0x2c, 0x0f, 0x36, 0x79, 0x68, 0x6d, 0x36, 0x75, 0xe6, 0x44, 0x4b, 0xf3, 0xb2, - 0x44, 0x9b, 0x38, 0x0e, 0xe4, 0xec, 0x80, 0x34, 0xfd, 0xc5, 0xcc, 0x43, 0xd9, 0x47, 0x27, 0x1f, - 0x5b, 0x4b, 0x6d, 0x18, 0xc3, 0xfe, 0x5d, 0xa3, 0xf4, 0x31, 0x67, 0x63, 0x7e, 0x75, 0x2c, 0xd2, - 0x42, 0x3a, 0xa3, 0x90, 0x0b, 0x13, 0x4d, 0x12, 0x78, 0x76, 0x95, 0xaf, 0xab, 0xc9, 0xc7, 0x56, - 0x47, 0x93, 0x62, 0x83, 0x11, 0x0b, 0x37, 0x4b, 0xfe, 0xdf, 0xc7, 0x92, 0x0b, 0xda, 0x83, 0x31, - 0xcb, 0xab, 0xcb, 0x36, 0x9f, 0x4f, 0x67, 0x7c, 0xc3, 0x39, 0x57, 0xf2, 0xea, 0x3e, 0x66, 0x1c, - 0xd0, 0x59, 0x28, 0x04, 0xc4, 0x6b, 0xda, 0x8e, 0x15, 0xf0, 0xdd, 0x35, 0x5f, 0x9e, 0x17, 0x68, - 0x85, 0x6d, 0x09, 0xc0, 0x21, 0x0e, 0x6a, 0xc0, 0x78, 0xcd, 0x3b, 0xc0, 0x6d, 0x67, 0x71, 0x2c, - 0x8d, 0xae, 0x58, 0x65, 0xb4, 0xc2, 0xc5, 0xc4, 0xff, 0x63, 0xc1, 0x03, 0xbd, 0x6e, 0xc0, 0x42, - 0x93, 0x58, 0x7e, 0xdb, 0x23, 0xb4, 0x09, 0x98, 0x04, 0xc4, 0xa1, 0xbb, 0xe1, 0x62, 0x8e, 0x31, - 0xc7, 0xa3, 0x8e, 0x43, 0x2f, 0xe5, 0xf2, 0x83, 0x42, 0x94, 0x85, 0x24, 0x28, 0x4e, 0x94, 0xc6, - 0xfc, 0xc1, 0x18, 0xcc, 0xf7, 0xec, 0x10, 0xe8, 0x09, 0xc8, 0xb5, 0xf6, 0x2c, 0x5f, 0x2e, 0xf9, - 0x33, 0x72, 0xbe, 0x6d, 0xd1, 0xc2, 0x3b, 0x9d, 0xe2, 0xb4, 0xac, 0xc2, 0x0a, 0x30, 0x47, 0xa6, - 0x3a, 0xb5, 0x49, 0x7c, 0xdf, 0xaa, 0xcb, 0x7d, 0x40, 0x9b, 0x26, 0xac, 0x18, 0x4b, 0x38, 0xfa, - 0x25, 0x03, 0xa6, 0xf9, 0x94, 0xc1, 0xc4, 0x6f, 0x37, 0x02, 0xba, 0xd7, 0xd1, 0x6e, 0xb9, 0x94, - 0xc6, 0xf4, 0xe4, 0x24, 0xcb, 0x27, 0x05, 0xf7, 0x69, 0xbd, 0xd4, 0xc7, 0x51, 0xbe, 0xe8, 0x3a, - 0x14, 0xfc, 0xc0, 0xf2, 0x02, 0x52, 0x2b, 0x05, 0x4c, 0xab, 0x4d, 0x3e, 0xf6, 0xbf, 0x07, 0xdb, - 0x04, 0xb6, 0xed, 0x26, 0xe1, 0x1b, 0x4e, 0x45, 0x12, 0xc0, 0x21, 0x2d, 0xf4, 0x22, 0x80, 0xd7, - 0x76, 0x2a, 0xed, 0x66, 0xd3, 0xf2, 0x0e, 0x84, 0x06, 0xbf, 0x38, 0x5a, 0xf3, 0xb0, 0xa2, 0x17, - 0xea, 0xac, 0xb0, 0x0c, 0x6b, 0xfc, 0xd0, 0xcb, 0x06, 0x4c, 0xf3, 0x99, 0x28, 0x25, 0x18, 0x4f, - 0x59, 0x82, 0x79, 0xda, 0xb5, 0xab, 0x3a, 0x0b, 0x1c, 0xe5, 0x68, 0xfe, 0x6d, 0x54, 0x9f, 0x54, - 0x02, 0x6a, 0x5d, 0xd7, 0x0f, 0xd0, 0x07, 0xe1, 0x7e, 0xbf, 0x5d, 0xad, 0x12, 0xdf, 0xdf, 0x6d, - 0x37, 0x70, 0xdb, 0xb9, 0x68, 0xfb, 0x81, 0xeb, 0x1d, 0xac, 0xdb, 0x4d, 0x3b, 0x60, 0x33, 0x2e, - 0x57, 0x3e, 0xdd, 0xed, 0x14, 0xef, 0xaf, 0xf4, 0x43, 0xc2, 0xfd, 0xeb, 0x23, 0x0b, 0x1e, 0x68, - 0x3b, 0xfd, 0xc9, 0x73, 0xeb, 0xad, 0xd8, 0xed, 0x14, 0x1f, 0xb8, 0xda, 0x1f, 0x0d, 0x1f, 0x46, - 0xc3, 0xfc, 0x17, 0x03, 0xe6, 0x64, 0xbb, 0xb6, 0x49, 0xb3, 0xd5, 0xa0, 0xbb, 0xcb, 0xf1, 0x1b, - 0x22, 0x41, 0xc4, 0x10, 0xc1, 0xe9, 0xa8, 0x13, 0x29, 0x7f, 0x3f, 0x6b, 0xc4, 0xfc, 0x67, 0x03, - 0x16, 0xe2, 0xc8, 0xf7, 0x40, 0x79, 0xfa, 0x51, 0xe5, 0xb9, 0x99, 0x6e, 0x6b, 0xfb, 0x68, 0xd0, - 0x57, 0xc7, 0x7a, 0xdb, 0xfa, 0xdf, 0x5d, 0x8d, 0x86, 0x5a, 0x31, 0xfb, 0xb3, 0xd4, 0x8a, 0x63, - 0x6f, 0x2a, 0xad, 0xf8, 0xbb, 0x63, 0x30, 0x55, 0x72, 0x02, 0xbb, 0xb4, 0xbb, 0x6b, 0x3b, 0x76, - 0x70, 0x80, 0x3e, 0x93, 0x81, 0xb3, 0x2d, 0x8f, 0xec, 0x12, 0xcf, 0x23, 0xb5, 0xd5, 0xb6, 0x67, - 0x3b, 0xf5, 0x4a, 0x75, 0x8f, 0xd4, 0xda, 0x0d, 0xdb, 0xa9, 0xaf, 0xd5, 0x1d, 0x57, 0x15, 0x9f, - 0xbb, 0x4d, 0xaa, 0x6d, 0xd6, 0x24, 0xbe, 0x28, 0x9a, 0xa3, 0x35, 0x69, 0x6b, 0x38, 0xa6, 0xe5, - 0xc7, 0xbb, 0x9d, 0xe2, 0xd9, 0x21, 0x2b, 0xe1, 0x61, 0x9b, 0x86, 0x3e, 0x9d, 0x81, 0x65, 0x8f, - 0x7c, 0xac, 0x6d, 0x0f, 0xde, 0x1b, 0x7c, 0xd7, 0x6a, 0x8c, 0xa8, 0x7e, 0x86, 0xe2, 0x59, 0x7e, - 0xac, 0xdb, 0x29, 0x0e, 0x59, 0x07, 0x0f, 0xd9, 0x2e, 0xf3, 0xeb, 0x19, 0x38, 0x59, 0x6a, 0xb5, - 0x36, 0x88, 0xbf, 0x17, 0x3b, 0xd4, 0x7e, 0xce, 0x80, 0x99, 0x7d, 0xdb, 0x0b, 0xda, 0x56, 0x43, - 0x3a, 0x01, 0xf8, 0x94, 0xa8, 0x8c, 0xb8, 0x9c, 0x39, 0xb7, 0x6b, 0x11, 0xd2, 0x65, 0xd4, 0xed, - 0x14, 0x67, 0xa2, 0x65, 0x38, 0xc6, 0x1e, 0xfd, 0xba, 0x01, 0x73, 0xa2, 0x68, 0xd3, 0xad, 0x11, - 0xdd, 0x73, 0x74, 0x35, 0x4d, 0x99, 0x14, 0x71, 0xee, 0x62, 0x88, 0x97, 0xe2, 0x1e, 0x21, 0xcc, - 0x7f, 0xcb, 0xc0, 0xa9, 0x3e, 0x34, 0xd0, 0xef, 0x18, 0xb0, 0xc0, 0xdd, 0x4d, 0x1a, 0x08, 0x93, - 0x5d, 0xd1, 0x9b, 0x1f, 0x48, 0x5b, 0x72, 0x4c, 0xd7, 0x02, 0x71, 0xaa, 0xa4, 0xbc, 0x48, 0xb7, - 0x8d, 0x95, 0x04, 0xd6, 0x38, 0x51, 0x20, 0x26, 0x29, 0x77, 0x40, 0xc5, 0x24, 0xcd, 0xdc, 0x13, - 0x49, 0x2b, 0x09, 0xac, 0x71, 0xa2, 0x40, 0xe6, 0xff, 0x87, 0x07, 0x0e, 0x21, 0x77, 0xf7, 0x13, - 0xbf, 0xf9, 0xbc, 0x9a, 0xf5, 0xd1, 0x39, 0x37, 0x80, 0xb3, 0xc0, 0x84, 0x71, 0xcf, 0x6d, 0x07, - 0x84, 0x6b, 0xb7, 0x42, 0x19, 0xa8, 0x9e, 0xc0, 0xac, 0x04, 0x0b, 0x88, 0xf9, 0x75, 0x03, 0xf2, - 0x43, 0xf8, 0x1f, 0x8a, 0x51, 0xff, 0x43, 0xa1, 0xc7, 0xf7, 0x10, 0xf4, 0xfa, 0x1e, 0x2e, 0x8c, - 0x36, 0x1a, 0x83, 0xf8, 0x1c, 0x7e, 0x6c, 0xc0, 0x7c, 0x8f, 0x8f, 0x02, 0xed, 0xc1, 0x42, 0xcb, - 0xad, 0x49, 0xfb, 0xe2, 0xa2, 0xe5, 0xef, 0x31, 0x98, 0x68, 0xde, 0x13, 0x74, 0x24, 0xb7, 0x12, - 0xe0, 0x77, 0x3a, 0xc5, 0x45, 0x45, 0x24, 0x86, 0x80, 0x13, 0x29, 0xa2, 0x16, 0xe4, 0x77, 0x6d, - 0xd2, 0xa8, 0x85, 0x53, 0x70, 0x44, 0x4b, 0xe2, 0xbc, 0xa0, 0xc6, 0xdd, 0x73, 0xf2, 0x1f, 0x56, - 0x5c, 0xcc, 0x2b, 0x30, 0x13, 0x75, 0xd6, 0x0e, 0x30, 0x78, 0xa7, 0x21, 0x6b, 0x79, 0x8e, 0x18, - 0xba, 0x49, 0x81, 0x90, 0x2d, 0xe1, 0x4d, 0x4c, 0xcb, 0xcd, 0x9f, 0x8e, 0xc1, 0x6c, 0xb9, 0xd1, - 0x26, 0x17, 0x3c, 0x42, 0xe4, 0xf9, 0xb4, 0x04, 0xb3, 0x2d, 0x8f, 0xec, 0xdb, 0xe4, 0x56, 0x85, - 0x34, 0x48, 0x35, 0x70, 0x3d, 0x41, 0xff, 0x94, 0xa8, 0x3e, 0xbb, 0x15, 0x05, 0xe3, 0x38, 0x3e, - 0x7a, 0x06, 0x66, 0xac, 0x6a, 0x60, 0xef, 0x13, 0x45, 0x81, 0x0b, 0xf0, 0x16, 0x41, 0x61, 0xa6, - 0x14, 0x81, 0xe2, 0x18, 0x36, 0xfa, 0x10, 0x2c, 0xfa, 0x55, 0xab, 0x41, 0xae, 0xb6, 0x04, 0xab, - 0x95, 0x3d, 0x52, 0xbd, 0xb9, 0xe5, 0xda, 0x4e, 0x20, 0xbc, 0x11, 0x0f, 0x09, 0x4a, 0x8b, 0x95, - 0x3e, 0x78, 0xb8, 0x2f, 0x05, 0xf4, 0x27, 0x06, 0x9c, 0x6e, 0x79, 0x64, 0xcb, 0x73, 0x9b, 0x2e, - 0x55, 0x33, 0x3d, 0x47, 0x74, 0x71, 0x54, 0xbd, 0x36, 0xa2, 0x3e, 0xe5, 0x25, 0xbd, 0x2e, 0xc2, - 0xb7, 0x76, 0x3b, 0xc5, 0xd3, 0x5b, 0x87, 0x09, 0x80, 0x0f, 0x97, 0x0f, 0xfd, 0x99, 0x01, 0x67, - 0x5a, 0xae, 0x1f, 0x1c, 0xd2, 0x84, 0xdc, 0xb1, 0x36, 0xc1, 0xec, 0x76, 0x8a, 0x67, 0xb6, 0x0e, - 0x95, 0x00, 0xdf, 0x45, 0x42, 0xb3, 0x3b, 0x09, 0xf3, 0xda, 0xdc, 0x13, 0xe7, 0xd7, 0xa7, 0x61, - 0x5a, 0x4e, 0x86, 0x50, 0xad, 0x17, 0x42, 0x7f, 0x43, 0x49, 0x07, 0xe2, 0x28, 0x2e, 0x9d, 0x77, - 0x6a, 0x2a, 0xf2, 0xda, 0xb1, 0x79, 0xb7, 0x15, 0x81, 0xe2, 0x18, 0x36, 0x5a, 0x83, 0x13, 0xa2, - 0x04, 0x93, 0x56, 0xc3, 0xae, 0x5a, 0x2b, 0x6e, 0x5b, 0x4c, 0xb9, 0x5c, 0xf9, 0x54, 0xb7, 0x53, - 0x3c, 0xb1, 0xd5, 0x0b, 0xc6, 0x49, 0x75, 0xd0, 0x3a, 0x2c, 0x58, 0xed, 0xc0, 0x55, 0xed, 0x3f, - 0xe7, 0x50, 0x4d, 0x51, 0x63, 0x53, 0x2b, 0xcf, 0x55, 0x4a, 0x29, 0x01, 0x8e, 0x13, 0x6b, 0xa1, - 0xad, 0x18, 0xb5, 0x0a, 0xa9, 0xba, 0x4e, 0x8d, 0x8f, 0x72, 0x2e, 0xb4, 0xc2, 0x4b, 0x09, 0x38, - 0x38, 0xb1, 0x26, 0x6a, 0xc0, 0x4c, 0xd3, 0xba, 0x7d, 0xd5, 0xb1, 0xf6, 0x2d, 0xbb, 0x41, 0x99, - 0x08, 0x1f, 0x46, 0xff, 0x83, 0x75, 0x3b, 0xb0, 0x1b, 0xcb, 0xfc, 0x3a, 0x6f, 0x79, 0xcd, 0x09, - 0x2e, 0x7b, 0x95, 0x80, 0x5a, 0x6b, 0xdc, 0x38, 0xda, 0x88, 0xd0, 0xc2, 0x31, 0xda, 0xe8, 0x32, - 0x9c, 0x64, 0xcb, 0x71, 0xd5, 0xbd, 0xe5, 0xac, 0x92, 0x86, 0x75, 0x20, 0x1b, 0x30, 0xc1, 0x1a, - 0x70, 0x7f, 0xb7, 0x53, 0x3c, 0x59, 0x49, 0x42, 0xc0, 0xc9, 0xf5, 0x90, 0x05, 0x0f, 0x44, 0x01, - 0x98, 0xec, 0xdb, 0xbe, 0xed, 0x3a, 0xdc, 0x13, 0x91, 0x0f, 0x3d, 0x11, 0x95, 0xfe, 0x68, 0xf8, - 0x30, 0x1a, 0xe8, 0x37, 0x0d, 0x58, 0x48, 0x5a, 0x86, 0x8b, 0x85, 0x34, 0x2e, 0x2b, 0x62, 0x4b, - 0x8b, 0xcf, 0x88, 0xc4, 0x4d, 0x21, 0x51, 0x08, 0xf4, 0x92, 0x01, 0x53, 0x96, 0x76, 0x8a, 0x5a, - 0x04, 0x26, 0xd5, 0xa5, 0x51, 0xcf, 0xf2, 0x21, 0xc5, 0xf2, 0x5c, 0xb7, 0x53, 0x8c, 0x9c, 0xd4, - 0x70, 0x84, 0x23, 0xfa, 0x2d, 0x03, 0x4e, 0x26, 0xae, 0xf1, 0xc5, 0xc9, 0xe3, 0xe8, 0x21, 0x36, - 0x49, 0x92, 0xf7, 0x9c, 0x64, 0x31, 0xd0, 0x6b, 0x86, 0x52, 0x65, 0x1b, 0xd2, 0x9b, 0x32, 0xc5, - 0x44, 0xbb, 0x32, 0xe2, 0xc1, 0x31, 0x34, 0x08, 0x24, 0xe1, 0xf2, 0x09, 0x4d, 0x33, 0xca, 0x42, - 0x1c, 0x67, 0x8f, 0x3e, 0x6b, 0x48, 0xd5, 0xa8, 0x24, 0x9a, 0x3e, 0x2e, 0x89, 0x50, 0xa8, 0x69, - 0x95, 0x40, 0x31, 0xe6, 0xe8, 0xc3, 0xb0, 0x64, 0xed, 0xb8, 0x5e, 0x90, 0xb8, 0xf8, 0x16, 0x67, - 0xd8, 0x32, 0x3a, 0xd3, 0xed, 0x14, 0x97, 0x4a, 0x7d, 0xb1, 0xf0, 0x21, 0x14, 0xcc, 0x3f, 0xc8, - 0xc1, 0x14, 0x37, 0xf2, 0x85, 0xea, 0xfa, 0x9a, 0x01, 0x0f, 0x56, 0xdb, 0x9e, 0x47, 0x9c, 0xa0, - 0x12, 0x90, 0x56, 0xaf, 0xe2, 0x32, 0x8e, 0x55, 0x71, 0x3d, 0xd4, 0xed, 0x14, 0x1f, 0x5c, 0x39, - 0x84, 0x3f, 0x3e, 0x54, 0x3a, 0xf4, 0x57, 0x06, 0x98, 0x02, 0xa1, 0x6c, 0x55, 0x6f, 0xd6, 0x3d, - 0xb7, 0xed, 0xd4, 0x7a, 0x1b, 0x91, 0x39, 0xd6, 0x46, 0x3c, 0xd2, 0xed, 0x14, 0xcd, 0x95, 0xbb, - 0x4a, 0x81, 0x07, 0x90, 0x14, 0x5d, 0x80, 0x79, 0x81, 0x75, 0xee, 0x76, 0x8b, 0x78, 0x36, 0x35, - 0xa7, 0xc5, 0x7d, 0x7a, 0x18, 0xa2, 0x10, 0x47, 0xc0, 0xbd, 0x75, 0x90, 0x0f, 0x13, 0xb7, 0x88, - 0x5d, 0xdf, 0x0b, 0xa4, 0xf9, 0x34, 0x62, 0x5c, 0x82, 0x38, 0xf0, 0x5f, 0xe7, 0x34, 0xcb, 0x93, - 0xdd, 0x4e, 0x71, 0x42, 0xfc, 0xc1, 0x92, 0x13, 0xda, 0x84, 0x19, 0x7e, 0x04, 0xdb, 0xb2, 0x9d, - 0xfa, 0x96, 0xeb, 0xf0, 0xdb, 0xfc, 0x42, 0xf9, 0x11, 0xa9, 0xf0, 0x2b, 0x11, 0xe8, 0x9d, 0x4e, - 0x71, 0x4a, 0xfe, 0xde, 0x3e, 0x68, 0x11, 0x1c, 0xab, 0x6d, 0x7e, 0x6b, 0x1c, 0x40, 0x4e, 0x57, - 0xd2, 0x42, 0xff, 0x07, 0x0a, 0x3e, 0x09, 0x38, 0x57, 0xe1, 0x3c, 0xe7, 0x77, 0x12, 0xb2, 0x10, - 0x87, 0x70, 0x74, 0x13, 0x72, 0x2d, 0xab, 0xed, 0x13, 0x31, 0xf8, 0x97, 0x52, 0x19, 0xfc, 0x2d, - 0x4a, 0x91, 0x9f, 0xb9, 0xd8, 0x4f, 0xcc, 0x79, 0xa0, 0x4f, 0x19, 0x00, 0x24, 0x3a, 0x60, 0x23, - 0xfb, 0x3e, 0x04, 0xcb, 0x70, 0x4c, 0x69, 0x1f, 0x94, 0x67, 0xba, 0x9d, 0x22, 0x68, 0x43, 0xaf, - 0xb1, 0x45, 0xb7, 0x20, 0x6f, 0xc9, 0x3d, 0x7f, 0xec, 0x38, 0xf6, 0x7c, 0x76, 0x14, 0x52, 0x93, - 0x56, 0x31, 0x43, 0x9f, 0x36, 0x60, 0xc6, 0x27, 0x81, 0x18, 0x2a, 0xba, 0xf3, 0x08, 0x83, 0x77, - 0xc4, 0x49, 0x57, 0x89, 0xd0, 0xe4, 0x3b, 0x68, 0xb4, 0x0c, 0xc7, 0xf8, 0x4a, 0x51, 0x2e, 0x12, - 0xab, 0x46, 0x3c, 0x76, 0xd2, 0x16, 0x96, 0xd4, 0xe8, 0xa2, 0x68, 0x34, 0x95, 0x28, 0x5a, 0x19, - 0x8e, 0xf1, 0x95, 0xa2, 0x6c, 0xd8, 0x9e, 0xe7, 0x0a, 0x51, 0xf2, 0x29, 0x89, 0xa2, 0xd1, 0x54, - 0xa2, 0x68, 0x65, 0x38, 0xc6, 0xd7, 0xfc, 0xeb, 0x29, 0x98, 0x91, 0x0b, 0x29, 0xb4, 0xec, 0xb9, - 0x63, 0xa7, 0x8f, 0x65, 0xbf, 0xa2, 0x03, 0x71, 0x14, 0x97, 0x56, 0xe6, 0x4b, 0x35, 0x6a, 0xd8, - 0xab, 0xca, 0x15, 0x1d, 0x88, 0xa3, 0xb8, 0xa8, 0x09, 0x39, 0x3f, 0x20, 0x2d, 0x79, 0x0f, 0x3a, - 0xe2, 0x35, 0x5d, 0xb8, 0x3f, 0x84, 0x37, 0x1d, 0xf4, 0x9f, 0x8f, 0x39, 0x17, 0xe6, 0x9b, 0x0c, - 0x22, 0xee, 0x4a, 0xb1, 0x38, 0xd2, 0x59, 0x9f, 0x51, 0x4f, 0x28, 0x1f, 0x8d, 0x68, 0x19, 0x8e, - 0xb1, 0x4f, 0x30, 0xf6, 0x73, 0xc7, 0x68, 0xec, 0x3f, 0x07, 0xf9, 0xa6, 0x75, 0xbb, 0xd2, 0xf6, - 0xea, 0x47, 0x3f, 0x54, 0x88, 0x10, 0x25, 0x4e, 0x05, 0x2b, 0x7a, 0xe8, 0x65, 0x43, 0xdb, 0x72, - 0x26, 0x18, 0xf1, 0xeb, 0xe9, 0x6e, 0x39, 0x4a, 0x57, 0xf6, 0xdd, 0x7c, 0x7a, 0x4c, 0xef, 0xfc, - 0x3d, 0x37, 0xbd, 0xa9, 0x19, 0xc9, 0x17, 0x88, 0x32, 0x23, 0x0b, 0xc7, 0x6a, 0x46, 0xae, 0x44, - 0x98, 0xe1, 0x18, 0x73, 0x26, 0x0f, 0x5f, 0x73, 0x4a, 0x1e, 0x38, 0x56, 0x79, 0x2a, 0x11, 0x66, - 0x38, 0xc6, 0xbc, 0xff, 0x79, 0x73, 0xf2, 0x78, 0xce, 0x9b, 0x53, 0x29, 0x9c, 0x37, 0x0f, 0x37, - 0xc5, 0xa7, 0x47, 0x35, 0xc5, 0xd1, 0x25, 0x40, 0xb5, 0x03, 0xc7, 0x6a, 0xda, 0x55, 0xb1, 0x59, - 0x32, 0xb5, 0x39, 0xc3, 0xfc, 0x11, 0x4b, 0x62, 0x23, 0x43, 0xab, 0x3d, 0x18, 0x38, 0xa1, 0x16, - 0x0a, 0x20, 0xdf, 0x92, 0x16, 0xd7, 0x6c, 0x1a, 0xb3, 0x5f, 0x5a, 0x60, 0xfc, 0xaa, 0x9c, 0x2e, - 0x3c, 0x59, 0x82, 0x15, 0x27, 0xf3, 0x3f, 0x0c, 0x98, 0x5b, 0x69, 0xb8, 0xed, 0xda, 0x75, 0x2b, - 0xa8, 0xee, 0xf1, 0x7b, 0x5d, 0xf4, 0x0c, 0xe4, 0x6d, 0x27, 0x20, 0xde, 0xbe, 0xd5, 0x10, 0x1a, - 0xc5, 0x94, 0x57, 0xdf, 0x6b, 0xa2, 0xfc, 0x4e, 0xa7, 0x38, 0xb3, 0xda, 0xf6, 0x58, 0xc0, 0x24, - 0xdf, 0x5f, 0xb0, 0xaa, 0x83, 0xbe, 0x6c, 0xc0, 0x3c, 0xbf, 0x19, 0x5e, 0xb5, 0x02, 0xeb, 0x4a, - 0x9b, 0x78, 0x36, 0x91, 0x77, 0xc3, 0x23, 0x6e, 0x2d, 0x71, 0x59, 0x25, 0x83, 0x83, 0xd0, 0xb4, - 0xde, 0x88, 0x73, 0xc6, 0xbd, 0xc2, 0x98, 0x9f, 0xcf, 0xc2, 0xfd, 0x7d, 0x69, 0xa1, 0x25, 0xc8, - 0xd8, 0x35, 0xd1, 0x74, 0x10, 0x74, 0x33, 0x6b, 0x35, 0x9c, 0xb1, 0x6b, 0x68, 0x99, 0x59, 0x89, - 0x1e, 0xf1, 0x7d, 0x79, 0x4d, 0x58, 0x50, 0x06, 0x9d, 0x28, 0xc5, 0x1a, 0x06, 0x2a, 0x42, 0xae, - 0x61, 0xed, 0x90, 0x86, 0x38, 0x01, 0x30, 0xbb, 0x73, 0x9d, 0x16, 0x60, 0x5e, 0x8e, 0x7e, 0xd1, - 0x00, 0xe0, 0x02, 0xd2, 0xf3, 0x83, 0xd0, 0x6b, 0x38, 0xdd, 0x6e, 0xa2, 0x94, 0xb9, 0x94, 0xe1, - 0x7f, 0xac, 0x71, 0x45, 0xdb, 0x30, 0x4e, 0x4d, 0x50, 0xb7, 0x76, 0x64, 0x35, 0xc6, 0xae, 0x45, - 0xb6, 0x18, 0x0d, 0x2c, 0x68, 0xd1, 0xbe, 0xf2, 0x48, 0xd0, 0xf6, 0x1c, 0xda, 0xb5, 0x4c, 0x71, - 0xe5, 0xb9, 0x14, 0x58, 0x95, 0x62, 0x0d, 0xc3, 0xfc, 0xe3, 0x0c, 0x2c, 0x24, 0x89, 0x4e, 0xf5, - 0xc3, 0x38, 0x97, 0x56, 0x1c, 0x66, 0xdf, 0x9f, 0x7e, 0xff, 0x88, 0x20, 0x07, 0x15, 0x0a, 0x20, - 0xc2, 0xb0, 0x04, 0x5f, 0xf4, 0x7e, 0xd5, 0x43, 0x99, 0x23, 0xf6, 0x90, 0xa2, 0x1c, 0xeb, 0xa5, - 0x87, 0x60, 0xcc, 0xa7, 0x23, 0x9f, 0x8d, 0x5e, 0x39, 0xb0, 0x31, 0x62, 0x10, 0x8a, 0xd1, 0x76, - 0xec, 0x40, 0x44, 0x31, 0x2b, 0x8c, 0xab, 0x8e, 0x1d, 0x60, 0x06, 0x31, 0xbf, 0x98, 0x81, 0xa5, - 0xfe, 0x8d, 0x42, 0x5f, 0x34, 0x00, 0x6a, 0xf4, 0x80, 0x41, 0xa7, 0xa4, 0x0c, 0x0a, 0xb1, 0x8e, - 0xab, 0x0f, 0x57, 0x25, 0xa7, 0x30, 0x42, 0x48, 0x15, 0xf9, 0x58, 0x13, 0x04, 0x3d, 0x26, 0xa7, - 0xfe, 0xa6, 0xd5, 0x94, 0x06, 0xa8, 0xaa, 0xb3, 0xa1, 0x20, 0x58, 0xc3, 0xa2, 0x27, 0x48, 0xc7, - 0x6a, 0x12, 0xbf, 0x65, 0xa9, 0x30, 0x75, 0x76, 0x82, 0xdc, 0x94, 0x85, 0x38, 0x84, 0x9b, 0x0d, - 0x78, 0x78, 0x00, 0x39, 0x53, 0x0a, 0x19, 0x36, 0xff, 0xdd, 0x80, 0x53, 0x2b, 0x8d, 0xb6, 0x1f, - 0x10, 0xef, 0x7f, 0x4c, 0xc0, 0xd5, 0x7f, 0x1a, 0xf0, 0x40, 0x9f, 0x36, 0xdf, 0x83, 0xb8, 0xab, - 0x17, 0xa2, 0x71, 0x57, 0x57, 0x47, 0x9d, 0xd2, 0x89, 0xed, 0xe8, 0x13, 0x7e, 0x15, 0xc0, 0x34, - 0xdd, 0xb5, 0x6a, 0x6e, 0x3d, 0x25, 0xbd, 0xf9, 0x30, 0xe4, 0x3e, 0x46, 0xf5, 0x4f, 0x7c, 0x8e, - 0x31, 0xa5, 0x84, 0x39, 0xcc, 0x7c, 0x1f, 0x88, 0x20, 0xa5, 0xd8, 0xe2, 0x31, 0x06, 0x59, 0x3c, - 0xe6, 0xdf, 0x65, 0x40, 0xf3, 0x3c, 0xdc, 0x83, 0x49, 0xe9, 0x44, 0x26, 0xe5, 0x88, 0xa7, 0x66, - 0xcd, 0x8f, 0xd2, 0xef, 0x35, 0xc2, 0x7e, 0xec, 0x35, 0xc2, 0x66, 0x6a, 0x1c, 0x0f, 0x7f, 0x8c, - 0xf0, 0x3d, 0x03, 0x1e, 0x08, 0x91, 0x7b, 0x9d, 0x82, 0x77, 0xdf, 0x61, 0x9e, 0x84, 0x49, 0x2b, - 0xac, 0x26, 0xe6, 0x80, 0x7a, 0x80, 0xa3, 0x51, 0xc4, 0x3a, 0x5e, 0x18, 0xfb, 0x9c, 0x3d, 0x62, - 0xec, 0xf3, 0xd8, 0xe1, 0xb1, 0xcf, 0xe6, 0x4f, 0x32, 0x70, 0xba, 0xb7, 0x65, 0x72, 0x6d, 0x0c, - 0x76, 0x67, 0xfe, 0x14, 0x4c, 0x05, 0xa2, 0x82, 0xb6, 0xd3, 0xab, 0xe7, 0x63, 0xdb, 0x1a, 0x0c, - 0x47, 0x30, 0x69, 0xcd, 0x2a, 0x5f, 0x95, 0x95, 0xaa, 0xdb, 0x92, 0x91, 0xf3, 0xaa, 0xe6, 0x8a, - 0x06, 0xc3, 0x11, 0x4c, 0x15, 0x93, 0x38, 0x76, 0xec, 0x31, 0x89, 0x15, 0x38, 0x29, 0xa3, 0xb0, - 0xce, 0xbb, 0xde, 0x8a, 0xdb, 0x6c, 0x35, 0x88, 0x88, 0x9d, 0xa7, 0xc2, 0x9e, 0x16, 0x55, 0x4e, - 0xe2, 0x24, 0x24, 0x9c, 0x5c, 0xd7, 0xfc, 0x5e, 0x16, 0x4e, 0x84, 0xdd, 0xbe, 0xe2, 0x3a, 0x35, - 0x9b, 0xc5, 0xb2, 0x3d, 0x0d, 0x63, 0xc1, 0x41, 0x4b, 0x76, 0xf6, 0xff, 0x92, 0xe2, 0x6c, 0x1f, - 0xb4, 0xe8, 0x68, 0x9f, 0x4a, 0xa8, 0xc2, 0xdc, 0xb2, 0xac, 0x12, 0x5a, 0x57, 0xab, 0x83, 0x8f, - 0xc0, 0x13, 0xd1, 0xd9, 0x7c, 0xa7, 0x53, 0x4c, 0x78, 0x3d, 0xb9, 0xac, 0x28, 0x45, 0xe7, 0x3c, - 0xba, 0x01, 0x33, 0x0d, 0xcb, 0x0f, 0xae, 0xb6, 0x6a, 0x56, 0x40, 0xb6, 0xed, 0x26, 0x11, 0x6b, - 0x6e, 0x98, 0x80, 0x74, 0x75, 0x8f, 0xbc, 0x1e, 0xa1, 0x84, 0x63, 0x94, 0xd1, 0x3e, 0x20, 0x5a, - 0xb2, 0xed, 0x59, 0x8e, 0xcf, 0x5b, 0x45, 0xf9, 0x0d, 0x1f, 0x00, 0xaf, 0x8e, 0x65, 0xeb, 0x3d, - 0xd4, 0x70, 0x02, 0x07, 0xf4, 0x08, 0x8c, 0x7b, 0xc4, 0xf2, 0xc5, 0x60, 0x16, 0xc2, 0xf5, 0x8f, - 0x59, 0x29, 0x16, 0x50, 0x7d, 0x41, 0x8d, 0xdf, 0x65, 0x41, 0xfd, 0xd0, 0x80, 0x99, 0x70, 0x98, - 0xee, 0x81, 0x92, 0x6c, 0x46, 0x95, 0xe4, 0xc5, 0xb4, 0xb6, 0xc4, 0x3e, 0x7a, 0xf1, 0xcf, 0xc7, - 0xf5, 0xf6, 0xb1, 0x80, 0xe4, 0x8f, 0x43, 0x41, 0xae, 0x6a, 0x69, 0x7d, 0x8e, 0x78, 0xba, 0x8d, - 0xd8, 0x25, 0xda, 0x43, 0x1a, 0xc1, 0x04, 0x87, 0xfc, 0xa8, 0x5a, 0xae, 0x09, 0x95, 0x2b, 0xa6, - 0xbd, 0x52, 0xcb, 0x52, 0x15, 0x27, 0xa9, 0x65, 0x59, 0x07, 0x5d, 0x85, 0x53, 0x2d, 0xcf, 0x65, - 0x8f, 0x2b, 0x57, 0x89, 0x55, 0x6b, 0xd8, 0x0e, 0x91, 0x2e, 0x04, 0x1e, 0xc6, 0xf0, 0x40, 0xb7, - 0x53, 0x3c, 0xb5, 0x95, 0x8c, 0x82, 0xfb, 0xd5, 0x8d, 0x3e, 0x08, 0x1a, 0x1b, 0xe0, 0x41, 0xd0, - 0x2f, 0x2b, 0x47, 0x1d, 0xf1, 0xc5, 0xb3, 0x9c, 0x0f, 0xa6, 0x35, 0x94, 0x09, 0xdb, 0x7a, 0x38, - 0xa5, 0x4a, 0x82, 0x29, 0x56, 0xec, 0xfb, 0x7b, 0x83, 0xc6, 0x8f, 0xe8, 0x0d, 0x0a, 0xe3, 0xba, - 0x27, 0x7e, 0x96, 0x71, 0xdd, 0xf9, 0x37, 0x55, 0x5c, 0xf7, 0x2b, 0x39, 0x98, 0x8b, 0x5b, 0x20, - 0xc7, 0xff, 0xd8, 0xe9, 0xd7, 0x0c, 0x98, 0x93, 0xab, 0x87, 0xf3, 0x24, 0xd2, 0xcf, 0xbf, 0x9e, - 0xd2, 0xa2, 0xe5, 0xb6, 0x94, 0x7a, 0x8e, 0xbb, 0x1d, 0xe3, 0x86, 0x7b, 0xf8, 0xa3, 0xe7, 0x61, - 0x52, 0xb9, 0xc3, 0x8f, 0xf4, 0xf2, 0x69, 0x96, 0x59, 0x51, 0x21, 0x09, 0xac, 0xd3, 0x43, 0xaf, - 0x18, 0x00, 0x55, 0xa9, 0xe6, 0xe4, 0xea, 0xba, 0x92, 0xd6, 0xea, 0x52, 0x0a, 0x34, 0x34, 0x96, - 0x55, 0x91, 0x8f, 0x35, 0xc6, 0xe8, 0xf3, 0xcc, 0x11, 0xae, 0xac, 0x3b, 0xba, 0x9e, 0xb2, 0xa3, - 0x87, 0xe2, 0x1e, 0x62, 0x98, 0x86, 0xa6, 0x94, 0x06, 0xf2, 0x71, 0x44, 0x08, 0xf3, 0x69, 0x50, - 0xc1, 0x93, 0x74, 0xdb, 0x62, 0xe1, 0x93, 0x5b, 0x56, 0xb0, 0x27, 0xa6, 0xa0, 0xda, 0xb6, 0xce, - 0x4b, 0x00, 0x0e, 0x71, 0xcc, 0x8f, 0xc2, 0xcc, 0x05, 0xcf, 0x6a, 0xed, 0xd9, 0xcc, 0xe1, 0x4c, - 0xcf, 0x49, 0x6f, 0x87, 0x09, 0xab, 0x56, 0x4b, 0x7a, 0xcc, 0x5e, 0xe2, 0xc5, 0x58, 0xc2, 0x07, - 0x3b, 0x12, 0x7d, 0xcb, 0x00, 0x14, 0x5e, 0xda, 0xd9, 0x4e, 0x7d, 0x83, 0x9e, 0xf6, 0xe9, 0xf9, - 0x68, 0x8f, 0x95, 0x26, 0x9d, 0x8f, 0x2e, 0x2a, 0x08, 0xd6, 0xb0, 0xd0, 0x8b, 0x30, 0xc9, 0xff, - 0x5d, 0x53, 0x87, 0xfd, 0x91, 0x9f, 0xc2, 0x72, 0x85, 0xc2, 0x64, 0xe2, 0xb3, 0xf0, 0x62, 0xc8, - 0x01, 0xeb, 0xec, 0x68, 0x57, 0xad, 0x39, 0xbb, 0x8d, 0xf6, 0xed, 0xda, 0x4e, 0xd8, 0x55, 0x2d, - 0xcf, 0xdd, 0xb5, 0x1b, 0x24, 0xde, 0x55, 0x5b, 0xbc, 0x18, 0x4b, 0xf8, 0x60, 0x5d, 0xf5, 0x0d, - 0x03, 0x16, 0xd6, 0xfc, 0xc0, 0x76, 0x57, 0x89, 0x1f, 0x50, 0xb5, 0x42, 0x37, 0x9f, 0x76, 0x63, - 0x90, 0x38, 0xe8, 0x55, 0x98, 0x13, 0x17, 0x88, 0xed, 0x1d, 0x9f, 0x04, 0x9a, 0x1d, 0xaf, 0xd6, - 0xf1, 0x4a, 0x0c, 0x8e, 0x7b, 0x6a, 0x50, 0x2a, 0xe2, 0x26, 0x31, 0xa4, 0x92, 0x8d, 0x52, 0xa9, - 0xc4, 0xe0, 0xb8, 0xa7, 0x86, 0xf9, 0x9d, 0x2c, 0x9c, 0x60, 0xcd, 0x88, 0xbd, 0x61, 0xf8, 0x6c, - 0xbf, 0x37, 0x0c, 0x23, 0x2e, 0x65, 0xc6, 0xeb, 0x08, 0x2f, 0x18, 0x7e, 0xd5, 0x80, 0xd9, 0x5a, - 0xb4, 0xa7, 0xd3, 0x71, 0xcf, 0x24, 0x8d, 0x21, 0x8f, 0x97, 0x8a, 0x15, 0xe2, 0x38, 0x7f, 0xf4, - 0x05, 0x03, 0x66, 0xa3, 0x62, 0xca, 0xdd, 0xfd, 0x18, 0x3a, 0x49, 0x05, 0x38, 0x47, 0xcb, 0x7d, - 0x1c, 0x17, 0xc1, 0xfc, 0x1b, 0x43, 0x0c, 0xe9, 0x71, 0x04, 0xe8, 0xa3, 0x5b, 0x50, 0x08, 0x1a, - 0x3e, 0x2f, 0x14, 0xad, 0x1d, 0xf1, 0x44, 0xb8, 0xbd, 0x5e, 0xe1, 0x77, 0xf7, 0xa1, 0xd1, 0x26, - 0x4a, 0xa8, 0xf1, 0x29, 0x79, 0x99, 0x5f, 0x31, 0xa0, 0x70, 0xc9, 0x95, 0xcb, 0xf9, 0xc3, 0x29, - 0xf8, 0x5b, 0x94, 0x59, 0xa6, 0xae, 0xea, 0x42, 0x4b, 0xff, 0x99, 0x88, 0xb7, 0xe5, 0x41, 0x8d, - 0xf6, 0x32, 0xcb, 0x97, 0x43, 0x49, 0x5d, 0x72, 0x77, 0xfa, 0x3a, 0xf3, 0x7e, 0x3b, 0x07, 0xd3, - 0xcf, 0x5a, 0x07, 0xc4, 0x09, 0xac, 0xe1, 0xf7, 0xea, 0x27, 0x61, 0xd2, 0x6a, 0xb1, 0x78, 0x5d, - 0xcd, 0xd4, 0x0e, 0x1d, 0x18, 0x21, 0x08, 0xeb, 0x78, 0xe1, 0xbe, 0xc2, 0xd3, 0x77, 0x24, 0xed, - 0x08, 0x2b, 0x31, 0x38, 0xee, 0xa9, 0x81, 0x2e, 0x01, 0x12, 0x8f, 0x11, 0x4b, 0xd5, 0xaa, 0xdb, - 0x76, 0xf8, 0xce, 0xc2, 0x7d, 0x1b, 0xea, 0xcc, 0xb7, 0xd1, 0x83, 0x81, 0x13, 0x6a, 0xa1, 0x0f, - 0xc1, 0x62, 0x95, 0x51, 0x16, 0x27, 0x00, 0x9d, 0x22, 0x3f, 0x05, 0xaa, 0x58, 0xf9, 0x95, 0x3e, - 0x78, 0xb8, 0x2f, 0x05, 0x2a, 0xa9, 0x1f, 0xb8, 0x9e, 0x55, 0x27, 0x3a, 0xdd, 0xf1, 0xa8, 0xa4, - 0x95, 0x1e, 0x0c, 0x9c, 0x50, 0x0b, 0x7d, 0x12, 0x0a, 0xc1, 0x9e, 0x47, 0xfc, 0x3d, 0xb7, 0x51, - 0x13, 0x77, 0xf7, 0x23, 0x3a, 0xbc, 0xc4, 0xe8, 0x6f, 0x4b, 0xaa, 0xda, 0xf4, 0x96, 0x45, 0x38, - 0xe4, 0x89, 0x3c, 0x18, 0xf7, 0xab, 0x6e, 0x8b, 0xf8, 0xc2, 0x72, 0xbe, 0x94, 0x0a, 0x77, 0xe6, - 0xc0, 0xd1, 0x5c, 0x6d, 0x8c, 0x03, 0x16, 0x9c, 0xcc, 0x6f, 0x66, 0x60, 0x4a, 0x47, 0x1c, 0x60, - 0x8b, 0xf8, 0x94, 0x01, 0x53, 0x55, 0xd7, 0x09, 0x3c, 0xb7, 0xc1, 0xdd, 0x48, 0xe9, 0x28, 0x76, - 0x4a, 0x6a, 0x95, 0x04, 0x96, 0xdd, 0xd0, 0x3c, 0x52, 0x1a, 0x1b, 0x1c, 0x61, 0x8a, 0x3e, 0x63, - 0xc0, 0x6c, 0x18, 0xea, 0x15, 0xfa, 0xb3, 0x52, 0x15, 0x44, 0xed, 0xb8, 0xe7, 0xa2, 0x9c, 0x70, - 0x9c, 0xb5, 0xb9, 0x03, 0x73, 0xf1, 0xd1, 0xa6, 0x5d, 0xd9, 0xb2, 0xc4, 0x5a, 0xcf, 0x86, 0x5d, - 0xb9, 0x65, 0xf9, 0x3e, 0x66, 0x10, 0xf4, 0x0e, 0xc8, 0x37, 0x2d, 0xaf, 0x6e, 0x3b, 0x56, 0x83, - 0xf5, 0x62, 0x56, 0xdb, 0x90, 0x44, 0x39, 0x56, 0x18, 0xe6, 0xbb, 0x60, 0x6a, 0xc3, 0x72, 0xea, - 0xa4, 0xc6, 0xb7, 0xc3, 0x01, 0x5e, 0x6a, 0xfd, 0x68, 0x0c, 0x26, 0xb5, 0x23, 0xd2, 0xf1, 0x1f, - 0x77, 0x22, 0x19, 0x15, 0xb2, 0x29, 0x66, 0x54, 0x78, 0x0e, 0x60, 0xd7, 0x76, 0x6c, 0x7f, 0xef, - 0x88, 0xb9, 0x1a, 0xd8, 0x4d, 0xe9, 0x79, 0x45, 0x01, 0x6b, 0xd4, 0xc2, 0xeb, 0xa8, 0xdc, 0x21, - 0x19, 0x6c, 0x5e, 0x31, 0x34, 0x75, 0x33, 0x9e, 0xc6, 0xf5, 0xbb, 0x36, 0x30, 0xcb, 0x52, 0xfd, - 0x9c, 0x73, 0x02, 0xef, 0xe0, 0x50, 0xad, 0xb4, 0x0d, 0x79, 0x8f, 0xf8, 0xed, 0x26, 0x3d, 0xb8, - 0x4d, 0x0c, 0xdd, 0x0d, 0x2c, 0x74, 0x01, 0x8b, 0xfa, 0x58, 0x51, 0x5a, 0x7a, 0x1a, 0xa6, 0x23, - 0x22, 0xa0, 0x39, 0xc8, 0xde, 0x24, 0x07, 0x7c, 0x9e, 0x60, 0xfa, 0x13, 0x2d, 0x44, 0x2e, 0xed, - 0x44, 0xb7, 0xbc, 0x37, 0xf3, 0x94, 0x61, 0xba, 0x90, 0x78, 0x0e, 0x3f, 0xca, 0x9d, 0x0a, 0x1d, - 0x8b, 0x86, 0x96, 0xac, 0x41, 0x8d, 0x05, 0x0f, 0x50, 0xe1, 0x30, 0xf3, 0x27, 0xe3, 0x20, 0x6e, - 0x94, 0x07, 0xd8, 0xae, 0xf4, 0x8b, 0xa4, 0xcc, 0x11, 0x2e, 0x92, 0x2e, 0xc1, 0x94, 0xed, 0xd8, - 0x81, 0x6d, 0x35, 0x98, 0x8f, 0x45, 0xa8, 0x53, 0x19, 0xc1, 0x3b, 0xb5, 0xa6, 0xc1, 0x12, 0xe8, - 0x44, 0xea, 0xa2, 0x2b, 0x90, 0x63, 0xfa, 0x46, 0x4c, 0xe0, 0xe1, 0xaf, 0xbd, 0x59, 0xc4, 0x03, - 0x7f, 0xd6, 0xc3, 0x29, 0xb1, 0x33, 0x00, 0xcf, 0x56, 0xa1, 0x4e, 0xc1, 0x62, 0x1e, 0x87, 0x67, - 0x80, 0x18, 0x1c, 0xf7, 0xd4, 0xa0, 0x54, 0x76, 0x2d, 0xbb, 0xd1, 0xf6, 0x48, 0x48, 0x65, 0x3c, - 0x4a, 0xe5, 0x7c, 0x0c, 0x8e, 0x7b, 0x6a, 0xa0, 0x5d, 0x98, 0x12, 0x65, 0x3c, 0xec, 0x68, 0xe2, - 0x88, 0xad, 0x64, 0xe1, 0x65, 0xe7, 0x35, 0x4a, 0x38, 0x42, 0x17, 0xb5, 0x61, 0xde, 0x76, 0xaa, - 0xae, 0x53, 0x6d, 0xb4, 0x7d, 0x7b, 0x9f, 0x84, 0x6f, 0x6a, 0x8e, 0xc2, 0xec, 0x64, 0xb7, 0x53, - 0x9c, 0x5f, 0x8b, 0x93, 0xc3, 0xbd, 0x1c, 0xd0, 0xcb, 0x06, 0x9c, 0xac, 0xba, 0x8e, 0xcf, 0x9e, - 0x7f, 0xef, 0x93, 0x73, 0x9e, 0xe7, 0x7a, 0x9c, 0x77, 0xe1, 0x88, 0xbc, 0x99, 0x6b, 0x6f, 0x25, - 0x89, 0x24, 0x4e, 0xe6, 0x84, 0x5e, 0x80, 0x7c, 0xcb, 0x73, 0xf7, 0xed, 0x1a, 0xf1, 0x44, 0x08, - 0xdb, 0x7a, 0x1a, 0xe9, 0x28, 0xb6, 0x04, 0xcd, 0x70, 0xeb, 0x91, 0x25, 0x58, 0xf1, 0x33, 0x5f, - 0x2f, 0xc0, 0x4c, 0x14, 0x1d, 0x7d, 0x02, 0xa0, 0xe5, 0xb9, 0x4d, 0x12, 0xec, 0x11, 0xf5, 0x36, - 0x62, 0x73, 0xd4, 0xac, 0x07, 0x92, 0x9e, 0x0c, 0x22, 0xa1, 0xdb, 0x45, 0x58, 0x8a, 0x35, 0x8e, - 0xc8, 0x83, 0x89, 0x9b, 0x5c, 0xed, 0x0a, 0x2b, 0xe4, 0xd9, 0x54, 0x6c, 0x26, 0xc1, 0x99, 0x05, - 0xf5, 0x8b, 0x22, 0x2c, 0x19, 0xa1, 0x1d, 0xc8, 0xde, 0x22, 0x3b, 0xe9, 0xbc, 0x24, 0xbe, 0x4e, - 0xc4, 0x69, 0xa6, 0x3c, 0xd1, 0xed, 0x14, 0xb3, 0xd7, 0xc9, 0x0e, 0xa6, 0xc4, 0x69, 0xbb, 0x6a, - 0xfc, 0x3a, 0x5c, 0x6c, 0x15, 0x23, 0xb6, 0x2b, 0x72, 0xb7, 0xce, 0xdb, 0x25, 0x8a, 0xb0, 0x64, - 0x84, 0x5e, 0x80, 0xc2, 0x2d, 0x6b, 0x9f, 0xec, 0x7a, 0xae, 0x13, 0x88, 0xc8, 0xa5, 0x11, 0xc3, - 0xe5, 0xaf, 0x4b, 0x72, 0x82, 0x2f, 0x53, 0xef, 0xaa, 0x10, 0x87, 0xec, 0xd0, 0x3e, 0xe4, 0x1d, - 0x72, 0x0b, 0x93, 0x86, 0x5d, 0x4d, 0x27, 0x3c, 0x7d, 0x53, 0x50, 0x13, 0x9c, 0x99, 0xde, 0x93, - 0x65, 0x58, 0xf1, 0xa2, 0x63, 0x79, 0xc3, 0xdd, 0x11, 0x1b, 0xd5, 0x88, 0x63, 0xa9, 0x4e, 0xa6, - 0x7c, 0x2c, 0x2f, 0xb9, 0x3b, 0x98, 0x12, 0xa7, 0x6b, 0xa4, 0xaa, 0xc2, 0x66, 0xc4, 0x36, 0xb5, - 0x99, 0x6e, 0xb8, 0x10, 0x5f, 0x23, 0x61, 0x29, 0xd6, 0x38, 0xd2, 0xbe, 0xad, 0x0b, 0x9f, 0xa1, - 0xd8, 0xa8, 0x46, 0xec, 0xdb, 0xa8, 0x07, 0x92, 0xf7, 0xad, 0x2c, 0xc3, 0x8a, 0x17, 0xe5, 0x6b, - 0x0b, 0x07, 0x5c, 0x3a, 0x5b, 0x55, 0xd4, 0x9d, 0xc7, 0xf9, 0xca, 0x32, 0xac, 0x78, 0x99, 0x5f, - 0x19, 0x87, 0x29, 0x3d, 0xed, 0xd7, 0x00, 0x36, 0x82, 0xb2, 0x8b, 0x33, 0xc3, 0xd8, 0xc5, 0xf4, - 0x20, 0xa4, 0x5d, 0x35, 0x48, 0x5f, 0xc8, 0x5a, 0x6a, 0x66, 0x61, 0x78, 0x10, 0xd2, 0x0a, 0x7d, - 0x1c, 0x61, 0x3a, 0x44, 0xf4, 0x01, 0x35, 0xae, 0xb8, 0xf9, 0x91, 0x8b, 0x1a, 0x57, 0x11, 0x83, - 0xe2, 0x31, 0x80, 0x30, 0xfd, 0x95, 0xb8, 0x82, 0x52, 0x56, 0x9b, 0x96, 0x96, 0x4b, 0xc3, 0x42, - 0x8f, 0xc0, 0x38, 0x55, 0xd0, 0xa4, 0x26, 0x1e, 0xcc, 0xaa, 0xd3, 0xe6, 0x79, 0x56, 0x8a, 0x05, - 0x14, 0x3d, 0x45, 0x6d, 0xa9, 0x50, 0xad, 0x8a, 0x77, 0xb0, 0x0b, 0xa1, 0x2d, 0x15, 0xc2, 0x70, - 0x04, 0x93, 0x8a, 0x4e, 0xa8, 0x16, 0x64, 0x33, 0x58, 0x13, 0x9d, 0xa9, 0x46, 0xcc, 0x61, 0xcc, - 0xfb, 0x11, 0xd3, 0x9a, 0x6c, 0xe6, 0xe5, 0x34, 0xef, 0x47, 0x0c, 0x8e, 0x7b, 0x6a, 0xd0, 0xc6, - 0x88, 0xdb, 0xb3, 0x49, 0x1e, 0x64, 0xd9, 0xe7, 0xde, 0xeb, 0x55, 0xfd, 0x44, 0x30, 0xc5, 0x86, - 0xfe, 0xfd, 0xe9, 0xa5, 0xb0, 0x1b, 0xfc, 0x48, 0x30, 0x9a, 0xf1, 0xfe, 0x51, 0x98, 0x89, 0xee, - 0x95, 0xa9, 0xbb, 0xc9, 0xff, 0x22, 0x0b, 0x27, 0x36, 0xeb, 0xb6, 0x73, 0x3b, 0xe6, 0x5f, 0x4e, - 0x4a, 0x2d, 0x6b, 0x0c, 0x9b, 0x5a, 0x36, 0x7c, 0x79, 0x23, 0x72, 0xf7, 0x26, 0xbf, 0xbc, 0x91, - 0x89, 0x7d, 0xa3, 0xb8, 0xe8, 0x87, 0x06, 0x3c, 0x68, 0xd5, 0xb8, 0xf5, 0x6a, 0x35, 0x44, 0x69, - 0xc8, 0x54, 0xae, 0x68, 0x7f, 0x44, 0x5d, 0xd4, 0xdb, 0xf8, 0xe5, 0xd2, 0x21, 0x5c, 0xf9, 0x88, - 0xbf, 0x4d, 0xb4, 0xe0, 0xc1, 0xc3, 0x50, 0xf1, 0xa1, 0xe2, 0x2f, 0x5d, 0x86, 0xb7, 0xde, 0x95, - 0xd1, 0x50, 0xb3, 0xe5, 0x53, 0x06, 0x14, 0xb8, 0xfb, 0x14, 0x93, 0x5d, 0xba, 0x55, 0x58, 0x2d, - 0xfb, 0x1a, 0xf1, 0x7c, 0x99, 0xf3, 0x4a, 0x3b, 0xe0, 0x95, 0xb6, 0xd6, 0x04, 0x04, 0x6b, 0x58, - 0x74, 0x33, 0xbe, 0x69, 0x3b, 0x35, 0x31, 0x4c, 0x6a, 0x33, 0x7e, 0xd6, 0x76, 0x6a, 0x98, 0x41, - 0xd4, 0x76, 0x9d, 0xed, 0xeb, 0xd6, 0x78, 0xdd, 0x80, 0x19, 0xf6, 0xdc, 0x30, 0x3c, 0x7a, 0x3c, - 0xa9, 0x42, 0x4b, 0xb8, 0x18, 0xa7, 0xa3, 0xa1, 0x25, 0x77, 0x3a, 0xc5, 0x49, 0xfe, 0x40, 0x31, - 0x1a, 0x69, 0xf2, 0x41, 0xe1, 0xaf, 0x60, 0x01, 0x30, 0x99, 0xa1, 0x8f, 0xd3, 0xca, 0x9f, 0x57, - 0x91, 0x44, 0x70, 0x48, 0xcf, 0x7c, 0x11, 0xa6, 0xf4, 0x77, 0x03, 0xe8, 0x49, 0x98, 0x6c, 0xd9, - 0x4e, 0x3d, 0xfa, 0xbe, 0x4c, 0xf9, 0x74, 0xb7, 0x42, 0x10, 0xd6, 0xf1, 0x58, 0x35, 0x37, 0xac, - 0x16, 0x73, 0x05, 0x6f, 0xb9, 0x7a, 0xb5, 0xf0, 0x8f, 0xf9, 0x87, 0x59, 0x38, 0x91, 0xf0, 0x3e, - 0x05, 0xbd, 0x62, 0xc0, 0x38, 0x0b, 0x96, 0x97, 0xc1, 0x23, 0xcf, 0xa7, 0xfe, 0x06, 0x66, 0x99, - 0xc5, 0xe4, 0x8b, 0x79, 0xac, 0xb6, 0x4f, 0x5e, 0x88, 0x05, 0x73, 0xf4, 0x1b, 0x06, 0x4c, 0x5a, - 0xda, 0x52, 0xe3, 0xf1, 0x34, 0x3b, 0xe9, 0x0b, 0xd3, 0xb3, 0xb2, 0xb4, 0x38, 0xc0, 0x70, 0x21, - 0xe9, 0xb2, 0x2c, 0xbd, 0x07, 0x26, 0xb5, 0x26, 0x0c, 0xb3, 0x42, 0x96, 0x9e, 0x81, 0xb9, 0x91, - 0x56, 0xd8, 0x07, 0x60, 0xd8, 0x14, 0x6e, 0x54, 0x61, 0xdd, 0xd2, 0xdf, 0x00, 0xab, 0x1e, 0x17, - 0x8f, 0x80, 0x05, 0xd4, 0xdc, 0x81, 0xb9, 0xf8, 0xe1, 0x2a, 0xf5, 0xeb, 0xe3, 0x77, 0xc1, 0x90, - 0x49, 0xd7, 0xcc, 0xbf, 0xcc, 0xc0, 0x84, 0x78, 0xe4, 0x76, 0x0f, 0x42, 0x68, 0x6f, 0x46, 0x2e, - 0x75, 0xd6, 0x52, 0x79, 0x9b, 0xd7, 0x37, 0x7e, 0xd6, 0x8f, 0xc5, 0xcf, 0x3e, 0x9b, 0x0e, 0xbb, - 0xc3, 0x83, 0x67, 0x5f, 0x1f, 0x83, 0xd9, 0xd8, 0xa3, 0x41, 0x6a, 0xaa, 0xf4, 0xc4, 0x8c, 0x5d, - 0x4d, 0xf5, 0x5d, 0xa2, 0x0a, 0xef, 0x3e, 0x3c, 0x7c, 0xcc, 0x8f, 0xe4, 0xb6, 0xbc, 0x92, 0x5a, - 0x5a, 0xec, 0x9f, 0xa7, 0xb9, 0x1c, 0x36, 0x1c, 0xea, 0x9f, 0x0c, 0xb8, 0xbf, 0xef, 0xdb, 0x52, - 0x96, 0x9a, 0xc4, 0x8b, 0x42, 0xc5, 0x82, 0x4c, 0xf9, 0x05, 0xbd, 0xba, 0x61, 0x89, 0x67, 0x93, - 0x88, 0xb3, 0x47, 0x4f, 0xc0, 0x14, 0x53, 0xad, 0x74, 0x4f, 0x09, 0x48, 0x4b, 0x38, 0x88, 0x99, - 0xab, 0xb0, 0xa2, 0x95, 0xe3, 0x08, 0x96, 0xf9, 0x65, 0x03, 0x16, 0xfb, 0x25, 0xaa, 0x18, 0xe0, - 0x60, 0xf8, 0xff, 0x62, 0x31, 0xbe, 0xc5, 0x9e, 0x18, 0xdf, 0xd8, 0xd1, 0x50, 0x86, 0xf3, 0x6a, - 0xa7, 0xb2, 0xec, 0x5d, 0x42, 0x58, 0x3f, 0x6b, 0xc0, 0xa9, 0x3e, 0xab, 0xa9, 0x27, 0xd6, 0xdb, - 0x38, 0x72, 0xac, 0x77, 0x66, 0xd0, 0x58, 0x6f, 0xf3, 0xbb, 0x59, 0x98, 0x13, 0xf2, 0x84, 0xf6, - 0xd5, 0x53, 0x91, 0x48, 0xe9, 0xb7, 0xc5, 0x22, 0xa5, 0x17, 0xe2, 0xf8, 0x3f, 0x0f, 0x93, 0x7e, - 0x73, 0x85, 0x49, 0xff, 0x34, 0x03, 0x27, 0x13, 0xf3, 0x67, 0xa0, 0x4f, 0x27, 0xa8, 0x86, 0xeb, - 0x29, 0x27, 0xea, 0x18, 0x50, 0x39, 0x8c, 0x1a, 0x5b, 0xfc, 0x05, 0x3d, 0xa6, 0x97, 0x6f, 0xf5, - 0xbb, 0xc7, 0x90, 0x72, 0x64, 0xc8, 0xf0, 0x5e, 0xf3, 0x57, 0xb2, 0xf0, 0xe8, 0xa0, 0x84, 0xde, - 0xa4, 0xcf, 0x3f, 0xfc, 0xc8, 0xf3, 0x8f, 0x7b, 0xa4, 0xb6, 0x8f, 0xe5, 0x25, 0xc8, 0x57, 0xb2, - 0x4a, 0xed, 0xf5, 0xce, 0xcf, 0x81, 0x6e, 0x13, 0x27, 0xa8, 0x69, 0x27, 0xb3, 0x6a, 0x86, 0x5b, - 0xe1, 0x44, 0x85, 0x17, 0xdf, 0xe9, 0x14, 0xe7, 0x45, 0xa6, 0xbd, 0x0a, 0x09, 0x44, 0x21, 0x96, - 0x95, 0xd0, 0xa3, 0x90, 0xf7, 0x38, 0x54, 0x06, 0xbc, 0x8b, 0x2b, 0x59, 0x5e, 0x86, 0x15, 0x14, - 0x7d, 0x52, 0xb3, 0x85, 0xc7, 0x8e, 0x2b, 0x59, 0xc1, 0x61, 0x37, 0xcd, 0xcf, 0x43, 0xde, 0x97, - 0xf9, 0x31, 0xf9, 0x75, 0xc0, 0xe3, 0x03, 0xbe, 0xa3, 0xa0, 0x47, 0x27, 0x99, 0x2c, 0x93, 0xb7, - 0x4f, 0xa5, 0xd2, 0x54, 0x24, 0x91, 0xa9, 0x4e, 0x2d, 0xdc, 0xc7, 0x08, 0x09, 0x27, 0x96, 0xef, - 0x19, 0x30, 0x29, 0x46, 0xeb, 0x1e, 0x3c, 0xed, 0xb8, 0x11, 0x7d, 0xda, 0x71, 0x2e, 0x95, 0xbd, - 0xa3, 0xcf, 0xbb, 0x8e, 0x1b, 0x30, 0xa5, 0xa7, 0x50, 0x42, 0xcf, 0x69, 0x7b, 0x9f, 0x31, 0x4a, - 0x52, 0x12, 0xb9, 0x3b, 0x86, 0xfb, 0xa2, 0xf9, 0xa5, 0xbc, 0xea, 0x45, 0xe6, 0x87, 0xd0, 0xe7, - 0xa0, 0x71, 0xe8, 0x1c, 0xd4, 0xa7, 0x40, 0x26, 0xfd, 0x29, 0x70, 0x05, 0xf2, 0x72, 0x83, 0x12, - 0x6a, 0xfc, 0x61, 0x3d, 0xca, 0x8e, 0xda, 0x02, 0x94, 0x98, 0x36, 0x71, 0xd9, 0x51, 0x4b, 0x8d, - 0xa1, 0xda, 0x38, 0x15, 0x19, 0xf4, 0x02, 0x4c, 0xde, 0x72, 0xbd, 0x9b, 0x0d, 0xd7, 0x62, 0x99, - 0x6f, 0x21, 0x8d, 0x8b, 0x1d, 0xe5, 0xf0, 0xe2, 0x11, 0xc7, 0xd7, 0x43, 0xfa, 0x58, 0x67, 0x86, - 0x4a, 0x30, 0xdb, 0xb4, 0x1d, 0x4c, 0xac, 0x9a, 0x7a, 0xc1, 0x31, 0xc6, 0x53, 0x73, 0x4a, 0x23, - 0x77, 0x23, 0x0a, 0xc6, 0x71, 0x7c, 0xf4, 0x71, 0xc8, 0xfb, 0x22, 0x21, 0x51, 0x3a, 0x57, 0x70, - 0xea, 0xcc, 0xc8, 0x89, 0x86, 0x7d, 0x27, 0x4b, 0xb0, 0x62, 0x88, 0xd6, 0x61, 0xc1, 0x13, 0x29, - 0x3f, 0x22, 0xdf, 0xcd, 0xe0, 0xeb, 0x93, 0x65, 0x80, 0xc4, 0x09, 0x70, 0x9c, 0x58, 0x8b, 0x5a, - 0x31, 0x2c, 0x17, 0x18, 0xbf, 0x13, 0xd0, 0xdc, 0xe8, 0x6c, 0xc2, 0xd7, 0xb0, 0x80, 0x1e, 0xf6, - 0x22, 0x28, 0x3f, 0xc2, 0x8b, 0xa0, 0x0a, 0x9c, 0x8c, 0x83, 0x58, 0x62, 0x12, 0x96, 0x0b, 0x45, - 0xd3, 0x1e, 0x5b, 0x49, 0x48, 0x38, 0xb9, 0x2e, 0xba, 0x0e, 0x05, 0x8f, 0xb0, 0xf3, 0x45, 0x49, - 0x5e, 0xfa, 0x0f, 0x1d, 0xde, 0x84, 0x25, 0x01, 0x1c, 0xd2, 0xa2, 0xe3, 0x6e, 0x45, 0xb3, 0x53, - 0x5e, 0x49, 0xf1, 0xcb, 0x5f, 0x62, 0xec, 0xfb, 0x24, 0x0c, 0x32, 0xdf, 0x98, 0x81, 0xe9, 0x88, - 0x6f, 0x01, 0x3d, 0x0c, 0x39, 0x96, 0xa9, 0x85, 0x6d, 0x0f, 0xf9, 0x70, 0x0b, 0xe3, 0x9d, 0xc3, - 0x61, 0xe8, 0x73, 0x06, 0xcc, 0xb6, 0x22, 0x5e, 0x58, 0xb9, 0x73, 0x8e, 0x78, 0xcf, 0x17, 0x75, - 0xed, 0x6a, 0x79, 0x9d, 0xa3, 0xcc, 0x70, 0x9c, 0x3b, 0x5d, 0x80, 0x22, 0x46, 0xb0, 0x41, 0x3c, - 0x86, 0x2d, 0x6c, 0x1c, 0x45, 0x62, 0x25, 0x0a, 0xc6, 0x71, 0x7c, 0x3a, 0xc2, 0xac, 0x75, 0xa3, - 0x7c, 0x12, 0xa8, 0x24, 0x09, 0xe0, 0x90, 0x16, 0x7a, 0x06, 0x66, 0x44, 0x52, 0xc2, 0x2d, 0xb7, - 0x76, 0xd1, 0xf2, 0xf7, 0x84, 0x71, 0xaf, 0x0e, 0x23, 0x2b, 0x11, 0x28, 0x8e, 0x61, 0xb3, 0xb6, - 0x85, 0x99, 0x1f, 0x19, 0x81, 0xf1, 0x68, 0xda, 0xeb, 0x95, 0x28, 0x18, 0xc7, 0xf1, 0xd1, 0x3b, - 0xb4, 0x7d, 0x9f, 0xdf, 0xd3, 0xa9, 0xdd, 0x20, 0x61, 0xef, 0x2f, 0xc1, 0x6c, 0x9b, 0x9d, 0x85, - 0x6a, 0x12, 0x28, 0xd6, 0xa3, 0x62, 0x78, 0x35, 0x0a, 0xc6, 0x71, 0x7c, 0xf4, 0x34, 0x4c, 0x7b, - 0x74, 0x77, 0x53, 0x04, 0xf8, 0xe5, 0x9d, 0xba, 0x9b, 0xc1, 0x3a, 0x10, 0x47, 0x71, 0xd1, 0x05, - 0x98, 0x0f, 0x73, 0x78, 0x49, 0x02, 0xfc, 0x36, 0x4f, 0xa5, 0xa7, 0x29, 0xc5, 0x11, 0x70, 0x6f, - 0x1d, 0xf4, 0x0b, 0x30, 0xa7, 0xf5, 0xc4, 0x9a, 0x53, 0x23, 0xb7, 0x45, 0x9e, 0x25, 0xf6, 0x85, - 0x82, 0x95, 0x18, 0x0c, 0xf7, 0x60, 0xa3, 0xf7, 0xc2, 0x4c, 0xd5, 0x6d, 0x34, 0xd8, 0x1e, 0xc7, - 0x53, 0x2e, 0xf3, 0x84, 0x4a, 0x3c, 0xf5, 0x54, 0x04, 0x82, 0x63, 0x98, 0xe8, 0x12, 0x20, 0x77, - 0xc7, 0x27, 0xde, 0x3e, 0xa9, 0x5d, 0xe0, 0x1f, 0x19, 0xa5, 0x2a, 0x7e, 0x3a, 0x1a, 0xa1, 0x7c, - 0xb9, 0x07, 0x03, 0x27, 0xd4, 0x62, 0xd9, 0x6d, 0xb4, 0x87, 0x55, 0x33, 0x69, 0x7c, 0x1e, 0x27, - 0x7e, 0x72, 0xbf, 0xeb, 0xab, 0x2a, 0x0f, 0xc6, 0x79, 0xc0, 0x78, 0x3a, 0x99, 0x95, 0xf4, 0xec, - 0xab, 0xa1, 0x8e, 0xe0, 0xa5, 0x58, 0x70, 0x42, 0x9f, 0x80, 0xc2, 0x8e, 0x4c, 0xc5, 0xbd, 0x38, - 0x97, 0x86, 0x5e, 0x8c, 0x65, 0x95, 0x0f, 0x4f, 0xa6, 0x0a, 0x80, 0x43, 0x96, 0xe8, 0x11, 0x98, - 0xbc, 0xb8, 0x55, 0x52, 0xb3, 0x70, 0x9e, 0x8d, 0xfe, 0x18, 0xad, 0x82, 0x75, 0x00, 0x5d, 0x61, - 0xca, 0x5e, 0x42, 0x6c, 0x88, 0x43, 0x7d, 0xdb, 0x6b, 0xfe, 0x50, 0x6c, 0x76, 0x1d, 0x89, 0x2b, - 0x8b, 0x27, 0x62, 0xd8, 0xa2, 0x1c, 0x2b, 0x0c, 0xf4, 0x3c, 0x4c, 0x0a, 0x7d, 0xc1, 0xf6, 0xa6, - 0x85, 0xa3, 0x3d, 0xda, 0xc3, 0x21, 0x09, 0xac, 0xd3, 0x63, 0xb7, 0x4c, 0x2c, 0x43, 0x31, 0x39, - 0xdf, 0x6e, 0x34, 0x16, 0x4f, 0xb2, 0x7d, 0x33, 0xbc, 0x65, 0x0a, 0x41, 0x58, 0xc7, 0x43, 0x8f, - 0xcb, 0xc8, 0x89, 0xb7, 0x44, 0xae, 0xdd, 0x54, 0xe4, 0x84, 0xb2, 0x72, 0xfb, 0x04, 0x14, 0x9f, - 0xba, 0x4b, 0xc8, 0xc2, 0x0e, 0x2c, 0x49, 0x13, 0xab, 0x77, 0x91, 0x2c, 0x2e, 0x46, 0xbc, 0x04, - 0x4b, 0xd7, 0xfb, 0x62, 0xe2, 0x43, 0xa8, 0xa0, 0x1d, 0xc8, 0x5a, 0x8d, 0x9d, 0xc5, 0xfb, 0xd3, - 0xb0, 0x15, 0xd5, 0x47, 0x83, 0x79, 0x10, 0x50, 0x69, 0xbd, 0x8c, 0x29, 0x71, 0xf3, 0xe5, 0x8c, - 0xf2, 0xca, 0xab, 0x8c, 0x93, 0x2f, 0xea, 0xb3, 0xda, 0x48, 0xe3, 0xa3, 0x98, 0x3d, 0xf9, 0xea, - 0xb9, 0x42, 0x4a, 0x9c, 0xd3, 0x2d, 0xb5, 0x8e, 0x53, 0x49, 0x27, 0x12, 0xcd, 0xa6, 0xc9, 0x4f, - 0x73, 0xd1, 0x55, 0x6c, 0x76, 0x27, 0x94, 0x13, 0x2a, 0x16, 0x0a, 0xe0, 0x41, 0xce, 0xf6, 0x03, - 0xdb, 0x4d, 0xf1, 0x81, 0x59, 0x2c, 0x0d, 0x25, 0x0b, 0x9c, 0x65, 0x00, 0xcc, 0x59, 0x51, 0x9e, - 0x4e, 0xdd, 0x76, 0x6e, 0x8b, 0xe6, 0x5f, 0x49, 0xfd, 0x8e, 0x9f, 0xf3, 0x64, 0x00, 0xcc, 0x59, - 0xa1, 0x1b, 0x7c, 0xa6, 0xa5, 0xf3, 0x01, 0xd4, 0xf8, 0x77, 0x8d, 0xa3, 0x33, 0x8e, 0xf2, 0xf2, - 0x9b, 0xb6, 0xb0, 0x61, 0x46, 0xe4, 0x55, 0xd9, 0x58, 0x4b, 0xe2, 0x55, 0xd9, 0x58, 0xc3, 0x94, - 0x09, 0x7a, 0xd5, 0x00, 0xb0, 0xd4, 0x07, 0x7e, 0xd3, 0xf9, 0xb8, 0x43, 0xbf, 0x0f, 0x06, 0xf3, - 0x58, 0xb7, 0x10, 0x8a, 0x35, 0xce, 0xe8, 0x05, 0x98, 0xb0, 0xf8, 0xa7, 0x69, 0x44, 0x18, 0x61, - 0x3a, 0xdf, 0x5b, 0x8a, 0x49, 0xc0, 0xe2, 0x27, 0x05, 0x08, 0x4b, 0x86, 0x94, 0x77, 0xe0, 0x59, - 0x64, 0xd7, 0xbe, 0x29, 0xe2, 0x09, 0x2b, 0x23, 0x67, 0x98, 0xa6, 0xc4, 0x92, 0x78, 0x0b, 0x10, - 0x96, 0x0c, 0xf9, 0x37, 0x35, 0x2d, 0xc7, 0x52, 0x8f, 0x43, 0xd2, 0x79, 0x42, 0xa4, 0x3f, 0x37, - 0xd1, 0xbe, 0xa9, 0xa9, 0x33, 0xc2, 0x51, 0xbe, 0xe6, 0x8f, 0xb3, 0x00, 0xec, 0x27, 0x7f, 0x37, - 0xdc, 0x64, 0xb9, 0xe6, 0xf6, 0xdc, 0x9a, 0x58, 0xda, 0x29, 0x3e, 0xff, 0x05, 0x91, 0x58, 0x6e, - 0xcf, 0xad, 0x61, 0xc1, 0x04, 0xd5, 0x61, 0xac, 0x65, 0x05, 0x7b, 0xe9, 0xbf, 0x35, 0xce, 0xf3, - 0x97, 0x3b, 0xc1, 0x1e, 0x66, 0x0c, 0xd0, 0x4b, 0x06, 0x4c, 0xf0, 0xd7, 0xc6, 0xd2, 0xd5, 0x3c, - 0xf2, 0x7d, 0xaa, 0xec, 0xb3, 0x65, 0xfe, 0xa4, 0x59, 0x04, 0x2b, 0x28, 0xd5, 0x28, 0x4a, 0xb1, - 0x64, 0xbb, 0xf4, 0x8a, 0x01, 0x53, 0x3a, 0x6a, 0x42, 0x98, 0xc1, 0x47, 0xf4, 0x30, 0x83, 0x34, - 0xfb, 0x43, 0x8f, 0x58, 0xf8, 0x57, 0x03, 0xb4, 0x2f, 0x91, 0x86, 0x41, 0x86, 0xc6, 0xc0, 0x41, - 0x86, 0x99, 0x21, 0x83, 0x0c, 0xb3, 0x43, 0x05, 0x19, 0x8e, 0x0d, 0x1f, 0x64, 0x98, 0xeb, 0x1f, - 0x64, 0x68, 0xbe, 0x66, 0xc0, 0x7c, 0xcf, 0x7e, 0x18, 0xff, 0xe2, 0xbb, 0x31, 0xe0, 0x17, 0xdf, - 0x57, 0x61, 0x4e, 0xe4, 0x42, 0xae, 0xb4, 0x1a, 0x76, 0xe2, 0x3b, 0xf0, 0xed, 0x18, 0x1c, 0xf7, - 0xd4, 0x30, 0xff, 0xd4, 0x80, 0x49, 0xed, 0xd9, 0x1a, 0x6d, 0x07, 0x7b, 0xde, 0x27, 0xc4, 0x08, - 0xd3, 0x40, 0x33, 0xd7, 0x3e, 0x87, 0xf1, 0x5b, 0xa6, 0xba, 0x96, 0x77, 0x33, 0xbc, 0x65, 0xa2, - 0xa5, 0x58, 0x40, 0x79, 0x46, 0x45, 0xc2, 0xbf, 0xe6, 0x9f, 0xd5, 0x33, 0x2a, 0x92, 0x16, 0x66, - 0x10, 0xc6, 0x8e, 0xda, 0x91, 0x22, 0xfe, 0x54, 0xcb, 0x3a, 0x6d, 0x79, 0x01, 0xe6, 0x30, 0x74, - 0x1a, 0xb2, 0xc4, 0xa9, 0x89, 0x43, 0xaf, 0xfa, 0xd2, 0xd3, 0x39, 0xa7, 0x86, 0x69, 0xb9, 0x79, - 0x19, 0xa6, 0x2a, 0xa4, 0xea, 0x91, 0xe0, 0x59, 0x72, 0x30, 0xf0, 0xa7, 0xa3, 0xe8, 0x6c, 0x8f, - 0x7d, 0x3a, 0x8a, 0x56, 0xa7, 0xe5, 0xe6, 0xef, 0x1b, 0x10, 0x4b, 0x8d, 0xae, 0x79, 0x9c, 0x8d, - 0x7e, 0x1e, 0xe7, 0x88, 0x6f, 0x34, 0x73, 0xa8, 0x6f, 0xf4, 0x12, 0xa0, 0x26, 0x5d, 0x0a, 0x91, - 0x0f, 0x01, 0x08, 0x7f, 0x43, 0xf8, 0x48, 0xb6, 0x07, 0x03, 0x27, 0xd4, 0x32, 0x7f, 0x8f, 0x0b, - 0xab, 0x27, 0x4b, 0xbf, 0x7b, 0x07, 0xb4, 0x21, 0xc7, 0x48, 0x09, 0xa7, 0xcb, 0xd6, 0x68, 0x8b, - 0xbb, 0x37, 0xe7, 0x43, 0x38, 0x90, 0x62, 0xc9, 0x33, 0x6e, 0xe6, 0x77, 0xb9, 0xac, 0x5a, 0x36, - 0xf5, 0x01, 0x64, 0x6d, 0x46, 0x65, 0xbd, 0x98, 0xd6, 0x5e, 0x99, 0x2c, 0x23, 0x5a, 0x06, 0x68, - 0x11, 0xaf, 0x4a, 0x9c, 0x40, 0x86, 0x45, 0xe7, 0xc4, 0x33, 0x12, 0x55, 0x8a, 0x35, 0x0c, 0xf3, - 0x25, 0x03, 0xe6, 0x2a, 0x81, 0x5d, 0xbd, 0x69, 0x3b, 0xfc, 0x59, 0xd4, 0xae, 0x5d, 0xa7, 0xa7, - 0x14, 0x22, 0xbe, 0x8a, 0xc4, 0xdd, 0x60, 0x6a, 0x2b, 0x96, 0x1f, 0x43, 0x92, 0x70, 0x54, 0x82, - 0x59, 0xe9, 0x6d, 0x97, 0xbe, 0x4b, 0xfe, 0x9c, 0x53, 0xf9, 0x4a, 0x56, 0xa3, 0x60, 0x1c, 0xc7, - 0x37, 0x3f, 0x09, 0x93, 0xda, 0xfe, 0xca, 0xb6, 0xa2, 0xdb, 0x56, 0x35, 0x88, 0x2f, 0xe1, 0x73, - 0xb4, 0x10, 0x73, 0x18, 0x73, 0xb1, 0xf2, 0xb8, 0xd9, 0xd8, 0x12, 0x16, 0xd1, 0xb2, 0x02, 0x4a, - 0x89, 0x79, 0xa4, 0x4e, 0x6e, 0xcb, 0x0c, 0x9f, 0x92, 0x18, 0xa6, 0x85, 0x98, 0xc3, 0xcc, 0x6b, - 0x90, 0x97, 0x8f, 0xee, 0xd9, 0xcb, 0x55, 0xe9, 0xfe, 0xd3, 0x5f, 0xae, 0xba, 0x5e, 0x80, 0x19, - 0x84, 0xae, 0x13, 0xdf, 0xb1, 0x2f, 0xba, 0x7e, 0x20, 0x33, 0x05, 0x70, 0x27, 0xff, 0xe6, 0x1a, - 0x2b, 0xc3, 0x0a, 0x6a, 0xce, 0xc3, 0xac, 0xf2, 0xde, 0x8b, 0xd0, 0xc4, 0x6f, 0x66, 0x61, 0x2a, - 0xf2, 0x8d, 0xdd, 0xbb, 0x4f, 0xa0, 0xc1, 0xd7, 0x65, 0x82, 0x17, 0x3e, 0x3b, 0xa4, 0x17, 0x5e, - 0xbf, 0xf6, 0x18, 0x3b, 0xde, 0x6b, 0x8f, 0x5c, 0x3a, 0xd7, 0x1e, 0x01, 0x4c, 0xf8, 0x42, 0xf5, - 0x8c, 0xa7, 0xe1, 0x1e, 0x89, 0x8d, 0x18, 0xb7, 0x3a, 0xa5, 0x06, 0x93, 0xac, 0xcc, 0xaf, 0xe5, - 0x60, 0x26, 0x9a, 0x6e, 0x68, 0x80, 0x91, 0x7c, 0x47, 0xcf, 0x48, 0x0e, 0xe9, 0x85, 0xcc, 0x8e, - 0xea, 0x85, 0x1c, 0x1b, 0xd5, 0x0b, 0x99, 0x3b, 0x82, 0x17, 0xb2, 0xd7, 0x87, 0x38, 0x3e, 0xb0, - 0x0f, 0xf1, 0x7d, 0x2a, 0x84, 0x66, 0x22, 0x72, 0xe7, 0x1c, 0x86, 0xd0, 0xa0, 0xe8, 0x30, 0xac, - 0xb8, 0xb5, 0xc4, 0x50, 0xa4, 0xfc, 0x5d, 0xbc, 0x2d, 0x5e, 0x62, 0xc4, 0xcb, 0xf0, 0x17, 0x1d, - 0x6f, 0x19, 0x22, 0xda, 0xe5, 0x49, 0x98, 0x14, 0xf3, 0x89, 0x59, 0x3f, 0x10, 0xb5, 0x9c, 0x2a, - 0x21, 0x08, 0xeb, 0x78, 0xec, 0x33, 0x90, 0xd1, 0xef, 0x5e, 0x32, 0xa7, 0xae, 0xfe, 0x19, 0xc8, - 0xd8, 0x77, 0x32, 0xe3, 0xf8, 0xe6, 0xc7, 0xe1, 0x64, 0xe2, 0x19, 0x8b, 0x39, 0x9d, 0x98, 0x62, - 0x26, 0x35, 0x81, 0xa0, 0x89, 0x11, 0xcb, 0x46, 0xbb, 0x74, 0xbd, 0x2f, 0x26, 0x3e, 0x84, 0x8a, - 0xf9, 0xd5, 0x2c, 0xcc, 0x44, 0xbf, 0x21, 0x84, 0x6e, 0x29, 0x8f, 0x4c, 0x2a, 0xce, 0x20, 0x4e, - 0x56, 0x4b, 0x61, 0xd3, 0xd7, 0xbd, 0x7a, 0x8b, 0xcd, 0xaf, 0x1d, 0x95, 0x4f, 0xe7, 0xf8, 0x18, - 0x0b, 0xbf, 0xa6, 0x60, 0xc7, 0x3e, 0x13, 0x14, 0x3e, 0x60, 0x10, 0x07, 0xa9, 0xd4, 0xb9, 0x87, - 0x4f, 0x12, 0x14, 0x2b, 0xac, 0xb1, 0xa5, 0xba, 0x65, 0x9f, 0x78, 0xf6, 0xae, 0xad, 0xbe, 0x7f, - 0xc8, 0x76, 0xee, 0x6b, 0xa2, 0x0c, 0x2b, 0xa8, 0xf9, 0x52, 0x06, 0xc2, 0xaf, 0xbd, 0xb2, 0x0f, - 0x6d, 0xf8, 0x9a, 0xd1, 0x2a, 0x86, 0xed, 0xd2, 0xa8, 0x5f, 0xb3, 0x09, 0x29, 0x8a, 0xf0, 0x46, - 0xad, 0x04, 0x47, 0x38, 0xfe, 0x0c, 0xbe, 0xf2, 0x6a, 0xc1, 0x6c, 0xec, 0x59, 0x67, 0xea, 0x31, - 0xe4, 0x5f, 0xca, 0x42, 0x41, 0x3d, 0x8c, 0x45, 0xef, 0x89, 0x78, 0x10, 0x0a, 0xe5, 0xb7, 0x6a, - 0x39, 0xe5, 0xf7, 0xdc, 0xda, 0x9d, 0x4e, 0x71, 0x56, 0x21, 0xc7, 0xbc, 0x01, 0xa7, 0x21, 0xdb, - 0xf6, 0x1a, 0xf1, 0x23, 0xc2, 0x55, 0xbc, 0x8e, 0x69, 0x39, 0xba, 0x1d, 0x3f, 0xc2, 0x6f, 0xa4, - 0xf4, 0x98, 0x97, 0xdb, 0xd2, 0xfd, 0x8f, 0xee, 0x54, 0x4b, 0xee, 0xb8, 0xb5, 0x83, 0x78, 0x0e, - 0xfa, 0xb2, 0x5b, 0x3b, 0xc0, 0x0c, 0x82, 0x9e, 0x81, 0x99, 0xc0, 0x6e, 0x12, 0xb7, 0x1d, 0xe8, - 0xdf, 0xd2, 0xcc, 0x86, 0xd7, 0x85, 0xdb, 0x11, 0x28, 0x8e, 0x61, 0x53, 0x2d, 0x7b, 0xc3, 0x77, - 0x1d, 0x96, 0x58, 0x6e, 0x3c, 0x7a, 0xb7, 0x70, 0xa9, 0x72, 0x79, 0x93, 0x79, 0x32, 0x14, 0x06, - 0xc5, 0xb6, 0xd9, 0x2b, 0x38, 0x8f, 0x88, 0xdb, 0xfa, 0xb9, 0x30, 0x47, 0x02, 0x2f, 0xc7, 0x0a, - 0xc3, 0xbc, 0x0a, 0xb3, 0xb1, 0xa6, 0xca, 0xc3, 0x98, 0x91, 0x7c, 0x18, 0x1b, 0x2c, 0xe1, 0xfb, - 0x1f, 0x19, 0x30, 0xdf, 0xb3, 0x78, 0x07, 0x7d, 0xdc, 0x10, 0x57, 0x23, 0x99, 0xa3, 0xab, 0x91, - 0xec, 0x70, 0x6a, 0xa4, 0xbc, 0xfc, 0xed, 0x37, 0xce, 0xdc, 0xf7, 0x9d, 0x37, 0xce, 0xdc, 0xf7, - 0xfd, 0x37, 0xce, 0xdc, 0xf7, 0x52, 0xf7, 0x8c, 0xf1, 0xed, 0xee, 0x19, 0xe3, 0x3b, 0xdd, 0x33, - 0xc6, 0xf7, 0xbb, 0x67, 0x8c, 0x7f, 0xec, 0x9e, 0x31, 0x5e, 0xfb, 0xd1, 0x99, 0xfb, 0x9e, 0xcb, - 0xcb, 0x69, 0xf2, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xd0, 0x87, 0xc1, 0x24, 0x34, 0x92, 0x00, - 0x00, + // 7541 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x5d, 0x6c, 0x23, 0xd7, + 0x75, 0xb0, 0x87, 0x14, 0x25, 0xf2, 0xe8, 0xff, 0xae, 0x36, 0x2b, 0xcb, 0xde, 0xa5, 0x33, 0x0e, + 0xfc, 0x39, 0x5f, 0x13, 0x29, 0xf1, 0x4f, 0xeb, 0xc4, 0x86, 0x5b, 0x52, 0xda, 0xf5, 0x6a, 0x2d, + 0x69, 0xb5, 0x97, 0xda, 0xdd, 0xc4, 0x89, 0x93, 0x8c, 0xc8, 0x2b, 0x6a, 0x56, 0xe4, 0x0c, 0x33, + 0x33, 0xd4, 0xae, 0x1c, 0x23, 0xb1, 0x1b, 0xd8, 0x4d, 0x8b, 0x04, 0x71, 0x9b, 0x04, 0x45, 0x51, + 0xa4, 0x08, 0x0a, 0x03, 0xfd, 0x49, 0x9f, 0x82, 0x16, 0x7d, 0x09, 0xd0, 0xa2, 0xf9, 0x69, 0xfa, + 0xd0, 0x22, 0x29, 0xda, 0x26, 0x29, 0x10, 0xb6, 0x56, 0xfa, 0xd2, 0xa2, 0x45, 0x50, 0x20, 0x45, + 0x91, 0x7d, 0x2a, 0xee, 0xef, 0xdc, 0x19, 0x0e, 0xb5, 0xa4, 0x38, 0xda, 0x18, 0x6d, 0xde, 0xc8, + 0x7b, 0xce, 0x3d, 0xe7, 0xdc, 0xdf, 0x73, 0xee, 0xb9, 0xe7, 0x9e, 0x81, 0xb5, 0xba, 0x1d, 0xec, + 0xb6, 0xb7, 0x17, 0xab, 0x6e, 0x73, 0xc9, 0xf2, 0xea, 0x6e, 0xcb, 0x73, 0x6f, 0xb0, 0x1f, 0xef, + 0xf4, 0xdc, 0x46, 0xc3, 0x6d, 0x07, 0xfe, 0x52, 0x6b, 0xaf, 0xbe, 0x64, 0xb5, 0x6c, 0x7f, 0x49, + 0x95, 0xec, 0xbf, 0xdb, 0x6a, 0xb4, 0x76, 0xad, 0x77, 0x2f, 0xd5, 0x89, 0x43, 0x3c, 0x2b, 0x20, + 0xb5, 0xc5, 0x96, 0xe7, 0x06, 0x2e, 0x7a, 0x2a, 0xa4, 0xb6, 0x28, 0xa9, 0xb1, 0x1f, 0x1f, 0x96, + 0x75, 0x17, 0x5b, 0x7b, 0xf5, 0x45, 0x4a, 0x6d, 0x51, 0x95, 0x48, 0x6a, 0x0b, 0xef, 0xd4, 0x64, + 0xa9, 0xbb, 0x75, 0x77, 0x89, 0x11, 0xdd, 0x6e, 0xef, 0xb0, 0x7f, 0xec, 0x0f, 0xfb, 0xc5, 0x99, + 0x2d, 0x3c, 0xb8, 0xf7, 0x84, 0xbf, 0x68, 0xbb, 0x54, 0xb6, 0xa5, 0x6d, 0x2b, 0xa8, 0xee, 0x2e, + 0xed, 0x77, 0x49, 0xb4, 0x60, 0x6a, 0x48, 0x55, 0xd7, 0x23, 0x49, 0x38, 0x8f, 0x85, 0x38, 0x4d, + 0xab, 0xba, 0x6b, 0x3b, 0xc4, 0x3b, 0x08, 0x5b, 0xdd, 0x24, 0x81, 0x95, 0x54, 0x6b, 0xa9, 0x57, + 0x2d, 0xaf, 0xed, 0x04, 0x76, 0x93, 0x74, 0x55, 0xf8, 0xf9, 0x3b, 0x55, 0xf0, 0xab, 0xbb, 0xa4, + 0x69, 0x75, 0xd5, 0x7b, 0xb4, 0x57, 0xbd, 0x76, 0x60, 0x37, 0x96, 0x6c, 0x27, 0xf0, 0x03, 0x2f, + 0x5e, 0xc9, 0xfc, 0x7a, 0x16, 0x0a, 0xa5, 0xb5, 0x72, 0x25, 0xb0, 0x82, 0xb6, 0x8f, 0x5e, 0x35, + 0x60, 0xa2, 0xe1, 0x5a, 0xb5, 0xb2, 0xd5, 0xb0, 0x9c, 0x2a, 0xf1, 0xe6, 0x8d, 0x07, 0x8c, 0x87, + 0xc7, 0x1f, 0x59, 0x5b, 0x1c, 0x66, 0xbc, 0x16, 0x4b, 0x37, 0x7d, 0x4c, 0x7c, 0xb7, 0xed, 0x55, + 0x09, 0x26, 0x3b, 0xe5, 0xb9, 0x6f, 0x75, 0x8a, 0xf7, 0x1c, 0x76, 0x8a, 0x13, 0x6b, 0x1a, 0x27, + 0x1c, 0xe1, 0x8b, 0xbe, 0x60, 0xc0, 0x6c, 0xd5, 0x72, 0x2c, 0xef, 0x60, 0xcb, 0xf2, 0xea, 0x24, + 0x78, 0xc6, 0x73, 0xdb, 0xad, 0xf9, 0xcc, 0x09, 0x48, 0x73, 0xaf, 0x90, 0x66, 0x76, 0x39, 0xce, + 0x0e, 0x77, 0x4b, 0xc0, 0xe4, 0xf2, 0x03, 0x6b, 0xbb, 0x41, 0x74, 0xb9, 0xb2, 0x27, 0x29, 0x57, + 0x25, 0xce, 0x0e, 0x77, 0x4b, 0x60, 0xbe, 0x92, 0x85, 0xd9, 0xd2, 0x5a, 0x79, 0xcb, 0xb3, 0x76, + 0x76, 0xec, 0x2a, 0x76, 0xdb, 0x81, 0xed, 0xd4, 0xd1, 0xdb, 0x61, 0xcc, 0x76, 0xea, 0x1e, 0xf1, + 0x7d, 0x36, 0x90, 0x85, 0xf2, 0xb4, 0x20, 0x3a, 0xb6, 0xca, 0x8b, 0xb1, 0x84, 0xa3, 0xc7, 0x61, + 0xdc, 0x27, 0xde, 0xbe, 0x5d, 0x25, 0x9b, 0xae, 0x17, 0xb0, 0x9e, 0xce, 0x95, 0x4f, 0x09, 0xf4, + 0xf1, 0x4a, 0x08, 0xc2, 0x3a, 0x1e, 0xad, 0xe6, 0xb9, 0x6e, 0x20, 0xe0, 0xac, 0x23, 0x0a, 0x61, + 0x35, 0x1c, 0x82, 0xb0, 0x8e, 0x87, 0x5e, 0x33, 0x60, 0xc6, 0x0f, 0xec, 0xea, 0x9e, 0xed, 0x10, + 0xdf, 0x5f, 0x76, 0x9d, 0x1d, 0xbb, 0x3e, 0x9f, 0x63, 0xbd, 0xb8, 0x31, 0x5c, 0x2f, 0x56, 0x62, + 0x54, 0xcb, 0x73, 0x87, 0x9d, 0xe2, 0x4c, 0xbc, 0x14, 0x77, 0x71, 0x47, 0x2b, 0x30, 0x63, 0x39, + 0x8e, 0x1b, 0x58, 0x81, 0xed, 0x3a, 0x9b, 0x1e, 0xd9, 0xb1, 0x6f, 0xcd, 0x8f, 0xb0, 0xe6, 0xcc, + 0x8b, 0xe6, 0xcc, 0x94, 0x62, 0x70, 0xdc, 0x55, 0xc3, 0x5c, 0x81, 0xf9, 0x52, 0x73, 0xdb, 0xf2, + 0x7d, 0xab, 0xe6, 0x7a, 0xb1, 0xd1, 0x78, 0x18, 0xf2, 0x4d, 0xab, 0xd5, 0xb2, 0x9d, 0x3a, 0x1d, + 0x8e, 0xec, 0xc3, 0x85, 0xf2, 0xc4, 0x61, 0xa7, 0x98, 0x5f, 0x17, 0x65, 0x58, 0x41, 0xcd, 0xef, + 0x67, 0x60, 0xbc, 0xe4, 0x58, 0x8d, 0x03, 0xdf, 0xf6, 0x71, 0xdb, 0x41, 0x1f, 0x81, 0x3c, 0xdd, + 0x5d, 0x6a, 0x56, 0x60, 0x89, 0x15, 0xf9, 0xae, 0x45, 0xbe, 0xd8, 0x17, 0xf5, 0xc5, 0x1e, 0xf6, + 0x0b, 0xc5, 0x5e, 0xdc, 0x7f, 0xf7, 0xe2, 0xe5, 0xed, 0x1b, 0xa4, 0x1a, 0xac, 0x93, 0xc0, 0x2a, + 0x23, 0xd1, 0x0a, 0x08, 0xcb, 0xb0, 0xa2, 0x8a, 0x5c, 0x18, 0xf1, 0x5b, 0xa4, 0x2a, 0x56, 0xd8, + 0xfa, 0x90, 0x33, 0x39, 0x14, 0xbd, 0xd2, 0x22, 0xd5, 0xf2, 0x84, 0x60, 0x3d, 0x42, 0xff, 0x61, + 0xc6, 0x08, 0xdd, 0x84, 0x51, 0x9f, 0xed, 0x39, 0x62, 0xf1, 0x5c, 0x4e, 0x8f, 0x25, 0x23, 0x5b, + 0x9e, 0x12, 0x4c, 0x47, 0xf9, 0x7f, 0x2c, 0xd8, 0x99, 0xff, 0x68, 0xc0, 0x29, 0x0d, 0xbb, 0xe4, + 0xd5, 0xdb, 0x4d, 0xe2, 0x04, 0xe8, 0x01, 0x18, 0x71, 0xac, 0x26, 0x11, 0x0b, 0x45, 0x89, 0xbc, + 0x61, 0x35, 0x09, 0x66, 0x10, 0xf4, 0x20, 0xe4, 0xf6, 0xad, 0x46, 0x9b, 0xb0, 0x4e, 0x2a, 0x94, + 0x27, 0x05, 0x4a, 0xee, 0x1a, 0x2d, 0xc4, 0x1c, 0x86, 0x5e, 0x84, 0x02, 0xfb, 0x71, 0xc1, 0x73, + 0x9b, 0x29, 0x35, 0x4d, 0x48, 0x78, 0x4d, 0x92, 0x2d, 0x4f, 0x1e, 0x76, 0x8a, 0x05, 0xf5, 0x17, + 0x87, 0x0c, 0xcd, 0x7f, 0x32, 0x60, 0x5a, 0x6b, 0xdc, 0x9a, 0xed, 0x07, 0xe8, 0x83, 0x5d, 0x93, + 0x67, 0xb1, 0xbf, 0xc9, 0x43, 0x6b, 0xb3, 0xa9, 0x33, 0x23, 0x5a, 0x9a, 0x97, 0x25, 0xda, 0xc4, + 0x71, 0x20, 0x67, 0x07, 0xa4, 0xe9, 0xcf, 0x67, 0x1e, 0xc8, 0x3e, 0x3c, 0xfe, 0xc8, 0x6a, 0x6a, + 0xc3, 0x18, 0xf6, 0xef, 0x2a, 0xa5, 0x8f, 0x39, 0x1b, 0xf3, 0x2b, 0x23, 0x91, 0x16, 0xd2, 0x19, + 0x85, 0x5c, 0x18, 0x6b, 0x92, 0xc0, 0xb3, 0xab, 0x7c, 0x5d, 0x8d, 0x3f, 0xb2, 0x32, 0x9c, 0x14, + 0xeb, 0x8c, 0x58, 0xb8, 0x59, 0xf2, 0xff, 0x3e, 0x96, 0x5c, 0xd0, 0x2e, 0x8c, 0x58, 0x5e, 0x5d, + 0xb6, 0xf9, 0x42, 0x3a, 0xe3, 0x1b, 0xce, 0xb9, 0x92, 0x57, 0xf7, 0x31, 0xe3, 0x80, 0x96, 0xa0, + 0x10, 0x10, 0xaf, 0x69, 0x3b, 0x56, 0xc0, 0x77, 0xd7, 0x7c, 0x79, 0x56, 0xa0, 0x15, 0xb6, 0x24, + 0x00, 0x87, 0x38, 0xa8, 0x01, 0xa3, 0x35, 0xef, 0x00, 0xb7, 0x9d, 0xf9, 0x91, 0x34, 0xba, 0x62, + 0x85, 0xd1, 0x0a, 0x17, 0x13, 0xff, 0x8f, 0x05, 0x0f, 0xf4, 0xba, 0x01, 0x73, 0x4d, 0x62, 0xf9, + 0x6d, 0x8f, 0xd0, 0x26, 0x60, 0x12, 0x10, 0x87, 0xee, 0x86, 0xf3, 0x39, 0xc6, 0x1c, 0x0f, 0x3b, + 0x0e, 0xdd, 0x94, 0xcb, 0xf7, 0x0b, 0x51, 0xe6, 0x92, 0xa0, 0x38, 0x51, 0x1a, 0xf3, 0xfb, 0x23, + 0x30, 0xdb, 0xb5, 0x43, 0xa0, 0xc7, 0x20, 0xd7, 0xda, 0xb5, 0x7c, 0xb9, 0xe4, 0xcf, 0xc9, 0xf9, + 0xb6, 0x49, 0x0b, 0x6f, 0x77, 0x8a, 0x93, 0xb2, 0x0a, 0x2b, 0xc0, 0x1c, 0x99, 0xea, 0xd4, 0x26, + 0xf1, 0x7d, 0xab, 0x2e, 0xf7, 0x01, 0x6d, 0x9a, 0xb0, 0x62, 0x2c, 0xe1, 0xe8, 0x57, 0x0c, 0x98, + 0xe4, 0x53, 0x06, 0x13, 0xbf, 0xdd, 0x08, 0xe8, 0x5e, 0x47, 0xbb, 0xe5, 0x52, 0x1a, 0xd3, 0x93, + 0x93, 0x2c, 0x9f, 0x16, 0xdc, 0x27, 0xf5, 0x52, 0x1f, 0x47, 0xf9, 0xa2, 0xeb, 0x50, 0xf0, 0x03, + 0xcb, 0x0b, 0x48, 0xad, 0x14, 0x30, 0xad, 0x36, 0xfe, 0xc8, 0xff, 0xef, 0x6f, 0x13, 0xd8, 0xb2, + 0x9b, 0x84, 0x6f, 0x38, 0x15, 0x49, 0x00, 0x87, 0xb4, 0xd0, 0x8b, 0x00, 0x5e, 0xdb, 0xa9, 0xb4, + 0x9b, 0x4d, 0xcb, 0x3b, 0x10, 0x1a, 0xfc, 0xe2, 0x70, 0xcd, 0xc3, 0x8a, 0x5e, 0xa8, 0xb3, 0xc2, + 0x32, 0xac, 0xf1, 0x43, 0x2f, 0x1b, 0x30, 0xc9, 0x67, 0xa2, 0x94, 0x60, 0x34, 0x65, 0x09, 0x66, + 0x69, 0xd7, 0xae, 0xe8, 0x2c, 0x70, 0x94, 0xa3, 0xf9, 0xf7, 0x51, 0x7d, 0x52, 0x09, 0xa8, 0x75, + 0x5d, 0x3f, 0x40, 0x1f, 0x80, 0x7b, 0xfd, 0x76, 0xb5, 0x4a, 0x7c, 0x7f, 0xa7, 0xdd, 0xc0, 0x6d, + 0xe7, 0xa2, 0xed, 0x07, 0xae, 0x77, 0xb0, 0x66, 0x37, 0xed, 0x80, 0xcd, 0xb8, 0x5c, 0xf9, 0xec, + 0x61, 0xa7, 0x78, 0x6f, 0xa5, 0x17, 0x12, 0xee, 0x5d, 0x1f, 0x59, 0x70, 0x5f, 0xdb, 0xe9, 0x4d, + 0x9e, 0x5b, 0x6f, 0xc5, 0xc3, 0x4e, 0xf1, 0xbe, 0xab, 0xbd, 0xd1, 0xf0, 0x51, 0x34, 0xcc, 0x7f, + 0x33, 0x60, 0x46, 0xb6, 0x6b, 0x8b, 0x34, 0x5b, 0x0d, 0xba, 0xbb, 0x9c, 0xbc, 0x21, 0x12, 0x44, + 0x0c, 0x11, 0x9c, 0x8e, 0x3a, 0x91, 0xf2, 0xf7, 0xb2, 0x46, 0xcc, 0x7f, 0x35, 0x60, 0x2e, 0x8e, + 0x7c, 0x17, 0x94, 0xa7, 0x1f, 0x55, 0x9e, 0x1b, 0xe9, 0xb6, 0xb6, 0x87, 0x06, 0x7d, 0x75, 0xa4, + 0xbb, 0xad, 0xff, 0xdb, 0xd5, 0x68, 0xa8, 0x15, 0xb3, 0x3f, 0x4d, 0xad, 0x38, 0xf2, 0xa6, 0xd2, + 0x8a, 0xbf, 0x3f, 0x02, 0x13, 0x25, 0x27, 0xb0, 0x4b, 0x3b, 0x3b, 0xb6, 0x63, 0x07, 0x07, 0xe8, + 0xd3, 0x19, 0x58, 0x6a, 0x79, 0x64, 0x87, 0x78, 0x1e, 0xa9, 0xad, 0xb4, 0x3d, 0xdb, 0xa9, 0x57, + 0xaa, 0xbb, 0xa4, 0xd6, 0x6e, 0xd8, 0x4e, 0x7d, 0xb5, 0xee, 0xb8, 0xaa, 0xf8, 0xfc, 0x2d, 0x52, + 0x6d, 0xb3, 0x26, 0xf1, 0x45, 0xd1, 0x1c, 0xae, 0x49, 0x9b, 0x83, 0x31, 0x2d, 0x3f, 0x7a, 0xd8, + 0x29, 0x2e, 0x0d, 0x58, 0x09, 0x0f, 0xda, 0x34, 0xf4, 0xa9, 0x0c, 0x2c, 0x7a, 0xe4, 0xa3, 0x6d, + 0xbb, 0xff, 0xde, 0xe0, 0xbb, 0x56, 0x63, 0x48, 0xf5, 0x33, 0x10, 0xcf, 0xf2, 0x23, 0x87, 0x9d, + 0xe2, 0x80, 0x75, 0xf0, 0x80, 0xed, 0x32, 0xbf, 0x96, 0x81, 0xd3, 0xa5, 0x56, 0x6b, 0x9d, 0xf8, + 0xbb, 0xb1, 0x43, 0xed, 0x67, 0x0d, 0x98, 0xda, 0xb7, 0xbd, 0xa0, 0x6d, 0x35, 0xa4, 0x13, 0x80, + 0x4f, 0x89, 0xca, 0x90, 0xcb, 0x99, 0x73, 0xbb, 0x16, 0x21, 0x5d, 0x46, 0x87, 0x9d, 0xe2, 0x54, + 0xb4, 0x0c, 0xc7, 0xd8, 0xa3, 0xdf, 0x34, 0x60, 0x46, 0x14, 0x6d, 0xb8, 0x35, 0xa2, 0x7b, 0x8e, + 0xae, 0xa6, 0x29, 0x93, 0x22, 0xce, 0x5d, 0x0c, 0xf1, 0x52, 0xdc, 0x25, 0x84, 0xf9, 0x1f, 0x19, + 0x38, 0xd3, 0x83, 0x06, 0xfa, 0x3d, 0x03, 0xe6, 0xb8, 0xbb, 0x49, 0x03, 0x61, 0xb2, 0x23, 0x7a, + 0xf3, 0xfd, 0x69, 0x4b, 0x8e, 0xe9, 0x5a, 0x20, 0x4e, 0x95, 0x94, 0xe7, 0xe9, 0xb6, 0xb1, 0x9c, + 0xc0, 0x1a, 0x27, 0x0a, 0xc4, 0x24, 0xe5, 0x0e, 0xa8, 0x98, 0xa4, 0x99, 0xbb, 0x22, 0x69, 0x25, + 0x81, 0x35, 0x4e, 0x14, 0xc8, 0xfc, 0x45, 0xb8, 0xef, 0x08, 0x72, 0x77, 0x3e, 0xf1, 0x9b, 0xcf, + 0xab, 0x59, 0x1f, 0x9d, 0x73, 0x7d, 0x38, 0x0b, 0x4c, 0x18, 0xf5, 0xdc, 0x76, 0x40, 0xb8, 0x76, + 0x2b, 0x94, 0x81, 0xea, 0x09, 0xcc, 0x4a, 0xb0, 0x80, 0x98, 0x5f, 0x33, 0x20, 0x3f, 0x80, 0xff, + 0xa1, 0x18, 0xf5, 0x3f, 0x14, 0xba, 0x7c, 0x0f, 0x41, 0xb7, 0xef, 0xe1, 0x99, 0xe1, 0x46, 0xa3, + 0x1f, 0x9f, 0xc3, 0x8f, 0x0c, 0x98, 0xed, 0xf2, 0x51, 0xa0, 0x5d, 0x98, 0x6b, 0xb9, 0x35, 0x69, + 0x5f, 0x5c, 0xb4, 0xfc, 0x5d, 0x06, 0x13, 0xcd, 0x7b, 0x8c, 0x8e, 0xe4, 0x66, 0x02, 0xfc, 0x76, + 0xa7, 0x38, 0xaf, 0x88, 0xc4, 0x10, 0x70, 0x22, 0x45, 0xd4, 0x82, 0xfc, 0x8e, 0x4d, 0x1a, 0xb5, + 0x70, 0x0a, 0x0e, 0x69, 0x49, 0x5c, 0x10, 0xd4, 0xb8, 0x7b, 0x4e, 0xfe, 0xc3, 0x8a, 0x8b, 0x79, + 0x05, 0xa6, 0xa2, 0xce, 0xda, 0x3e, 0x06, 0xef, 0x2c, 0x64, 0x2d, 0xcf, 0x11, 0x43, 0x37, 0x2e, + 0x10, 0xb2, 0x25, 0xbc, 0x81, 0x69, 0xb9, 0xf9, 0x93, 0x11, 0x98, 0x2e, 0x37, 0xda, 0xe4, 0x19, + 0x8f, 0x10, 0x79, 0x3e, 0x2d, 0xc1, 0x74, 0xcb, 0x23, 0xfb, 0x36, 0xb9, 0x59, 0x21, 0x0d, 0x52, + 0x0d, 0x5c, 0x4f, 0xd0, 0x3f, 0x23, 0xaa, 0x4f, 0x6f, 0x46, 0xc1, 0x38, 0x8e, 0x8f, 0x9e, 0x86, + 0x29, 0xab, 0x1a, 0xd8, 0xfb, 0x44, 0x51, 0xe0, 0x02, 0xbc, 0x45, 0x50, 0x98, 0x2a, 0x45, 0xa0, + 0x38, 0x86, 0x8d, 0x3e, 0x08, 0xf3, 0x7e, 0xd5, 0x6a, 0x90, 0xab, 0x2d, 0xc1, 0x6a, 0x79, 0x97, + 0x54, 0xf7, 0x36, 0x5d, 0xdb, 0x09, 0x84, 0x37, 0xe2, 0x01, 0x41, 0x69, 0xbe, 0xd2, 0x03, 0x0f, + 0xf7, 0xa4, 0x80, 0xfe, 0xcc, 0x80, 0xb3, 0x2d, 0x8f, 0x6c, 0x7a, 0x6e, 0xd3, 0xa5, 0x6a, 0xa6, + 0xeb, 0x88, 0x2e, 0x8e, 0xaa, 0xd7, 0x86, 0xd4, 0xa7, 0xbc, 0xa4, 0xdb, 0x45, 0xf8, 0xd6, 0xc3, + 0x4e, 0xf1, 0xec, 0xe6, 0x51, 0x02, 0xe0, 0xa3, 0xe5, 0x43, 0x7f, 0x61, 0xc0, 0xb9, 0x96, 0xeb, + 0x07, 0x47, 0x34, 0x21, 0x77, 0xa2, 0x4d, 0x30, 0x0f, 0x3b, 0xc5, 0x73, 0x9b, 0x47, 0x4a, 0x80, + 0xef, 0x20, 0xa1, 0x79, 0x38, 0x0e, 0xb3, 0xda, 0xdc, 0x13, 0xe7, 0xd7, 0x27, 0x61, 0x52, 0x4e, + 0x86, 0x50, 0xad, 0x17, 0x42, 0x7f, 0x43, 0x49, 0x07, 0xe2, 0x28, 0x2e, 0x9d, 0x77, 0x6a, 0x2a, + 0xf2, 0xda, 0xb1, 0x79, 0xb7, 0x19, 0x81, 0xe2, 0x18, 0x36, 0x5a, 0x85, 0x53, 0xa2, 0x04, 0x93, + 0x56, 0xc3, 0xae, 0x5a, 0xcb, 0x6e, 0x5b, 0x4c, 0xb9, 0x5c, 0xf9, 0xcc, 0x61, 0xa7, 0x78, 0x6a, + 0xb3, 0x1b, 0x8c, 0x93, 0xea, 0xa0, 0x35, 0x98, 0xb3, 0xda, 0x81, 0xab, 0xda, 0x7f, 0xde, 0xa1, + 0x9a, 0xa2, 0xc6, 0xa6, 0x56, 0x9e, 0xab, 0x94, 0x52, 0x02, 0x1c, 0x27, 0xd6, 0x42, 0x9b, 0x31, + 0x6a, 0x15, 0x52, 0x75, 0x9d, 0x1a, 0x1f, 0xe5, 0x5c, 0x68, 0x85, 0x97, 0x12, 0x70, 0x70, 0x62, + 0x4d, 0xd4, 0x80, 0xa9, 0xa6, 0x75, 0xeb, 0xaa, 0x63, 0xed, 0x5b, 0x76, 0x83, 0x32, 0x11, 0x3e, + 0x8c, 0xde, 0x07, 0xeb, 0x76, 0x60, 0x37, 0x16, 0xf9, 0x75, 0xde, 0xe2, 0xaa, 0x13, 0x5c, 0xf6, + 0x2a, 0x01, 0xb5, 0xd6, 0xb8, 0x71, 0xb4, 0x1e, 0xa1, 0x85, 0x63, 0xb4, 0xd1, 0x65, 0x38, 0xcd, + 0x96, 0xe3, 0x8a, 0x7b, 0xd3, 0x59, 0x21, 0x0d, 0xeb, 0x40, 0x36, 0x60, 0x8c, 0x35, 0xe0, 0xde, + 0xc3, 0x4e, 0xf1, 0x74, 0x25, 0x09, 0x01, 0x27, 0xd7, 0x43, 0x16, 0xdc, 0x17, 0x05, 0x60, 0xb2, + 0x6f, 0xfb, 0xb6, 0xeb, 0x70, 0x4f, 0x44, 0x3e, 0xf4, 0x44, 0x54, 0x7a, 0xa3, 0xe1, 0xa3, 0x68, + 0xa0, 0xdf, 0x36, 0x60, 0x2e, 0x69, 0x19, 0xce, 0x17, 0xd2, 0xb8, 0xac, 0x88, 0x2d, 0x2d, 0x3e, + 0x23, 0x12, 0x37, 0x85, 0x44, 0x21, 0xd0, 0x4b, 0x06, 0x4c, 0x58, 0xda, 0x29, 0x6a, 0x1e, 0x98, + 0x54, 0x97, 0x86, 0x3d, 0xcb, 0x87, 0x14, 0xcb, 0x33, 0x87, 0x9d, 0x62, 0xe4, 0xa4, 0x86, 0x23, + 0x1c, 0xd1, 0xef, 0x18, 0x70, 0x3a, 0x71, 0x8d, 0xcf, 0x8f, 0x9f, 0x44, 0x0f, 0xb1, 0x49, 0x92, + 0xbc, 0xe7, 0x24, 0x8b, 0x81, 0x5e, 0x33, 0x94, 0x2a, 0x5b, 0x97, 0xde, 0x94, 0x09, 0x26, 0xda, + 0x95, 0x21, 0x0f, 0x8e, 0xa1, 0x41, 0x20, 0x09, 0x97, 0x4f, 0x69, 0x9a, 0x51, 0x16, 0xe2, 0x38, + 0x7b, 0xf4, 0x19, 0x43, 0xaa, 0x46, 0x25, 0xd1, 0xe4, 0x49, 0x49, 0x84, 0x42, 0x4d, 0xab, 0x04, + 0x8a, 0x31, 0x47, 0x1f, 0x82, 0x05, 0x6b, 0xdb, 0xf5, 0x82, 0xc4, 0xc5, 0x37, 0x3f, 0xc5, 0x96, + 0xd1, 0xb9, 0xc3, 0x4e, 0x71, 0xa1, 0xd4, 0x13, 0x0b, 0x1f, 0x41, 0xc1, 0xfc, 0xa3, 0x1c, 0x4c, + 0x70, 0x23, 0x5f, 0xa8, 0xae, 0xaf, 0x1a, 0x70, 0x7f, 0xb5, 0xed, 0x79, 0xc4, 0x09, 0x2a, 0x01, + 0x69, 0x75, 0x2b, 0x2e, 0xe3, 0x44, 0x15, 0xd7, 0x03, 0x87, 0x9d, 0xe2, 0xfd, 0xcb, 0x47, 0xf0, + 0xc7, 0x47, 0x4a, 0x87, 0xfe, 0xc6, 0x00, 0x53, 0x20, 0x94, 0xad, 0xea, 0x5e, 0xdd, 0x73, 0xdb, + 0x4e, 0xad, 0xbb, 0x11, 0x99, 0x13, 0x6d, 0xc4, 0x43, 0x87, 0x9d, 0xa2, 0xb9, 0x7c, 0x47, 0x29, + 0x70, 0x1f, 0x92, 0xa2, 0x67, 0x60, 0x56, 0x60, 0x9d, 0xbf, 0xd5, 0x22, 0x9e, 0x4d, 0xcd, 0x69, + 0x71, 0x9f, 0x1e, 0x86, 0x28, 0xc4, 0x11, 0x70, 0x77, 0x1d, 0xe4, 0xc3, 0xd8, 0x4d, 0x62, 0xd7, + 0x77, 0x03, 0x69, 0x3e, 0x0d, 0x19, 0x97, 0x20, 0x0e, 0xfc, 0xd7, 0x39, 0xcd, 0xf2, 0xf8, 0x61, + 0xa7, 0x38, 0x26, 0xfe, 0x60, 0xc9, 0x09, 0x6d, 0xc0, 0x14, 0x3f, 0x82, 0x6d, 0xda, 0x4e, 0x7d, + 0xd3, 0x75, 0xf8, 0x6d, 0x7e, 0xa1, 0xfc, 0x90, 0x54, 0xf8, 0x95, 0x08, 0xf4, 0x76, 0xa7, 0x38, + 0x21, 0x7f, 0x6f, 0x1d, 0xb4, 0x08, 0x8e, 0xd5, 0x36, 0xbf, 0x39, 0x0a, 0x20, 0xa7, 0x2b, 0x69, + 0xa1, 0x9f, 0x83, 0x82, 0x4f, 0x02, 0xce, 0x55, 0x38, 0xcf, 0xf9, 0x9d, 0x84, 0x2c, 0xc4, 0x21, + 0x1c, 0xed, 0x41, 0xae, 0x65, 0xb5, 0x7d, 0x22, 0x06, 0xff, 0x52, 0x2a, 0x83, 0xbf, 0x49, 0x29, + 0xf2, 0x33, 0x17, 0xfb, 0x89, 0x39, 0x0f, 0xf4, 0x49, 0x03, 0x80, 0x44, 0x07, 0x6c, 0x68, 0xdf, + 0x87, 0x60, 0x19, 0x8e, 0x29, 0xed, 0x83, 0xf2, 0xd4, 0x61, 0xa7, 0x08, 0xda, 0xd0, 0x6b, 0x6c, + 0xd1, 0x4d, 0xc8, 0x5b, 0x72, 0xcf, 0x1f, 0x39, 0x89, 0x3d, 0x9f, 0x1d, 0x85, 0xd4, 0xa4, 0x55, + 0xcc, 0xd0, 0xa7, 0x0c, 0x98, 0xf2, 0x49, 0x20, 0x86, 0x8a, 0xee, 0x3c, 0xc2, 0xe0, 0x1d, 0x72, + 0xd2, 0x55, 0x22, 0x34, 0xf9, 0x0e, 0x1a, 0x2d, 0xc3, 0x31, 0xbe, 0x52, 0x94, 0x8b, 0xc4, 0xaa, + 0x11, 0x8f, 0x9d, 0xb4, 0x85, 0x25, 0x35, 0xbc, 0x28, 0x1a, 0x4d, 0x25, 0x8a, 0x56, 0x86, 0x63, + 0x7c, 0xa5, 0x28, 0xeb, 0xb6, 0xe7, 0xb9, 0x42, 0x94, 0x7c, 0x4a, 0xa2, 0x68, 0x34, 0x95, 0x28, + 0x5a, 0x19, 0x8e, 0xf1, 0x35, 0xff, 0x76, 0x02, 0xa6, 0xe4, 0x42, 0x0a, 0x2d, 0x7b, 0xee, 0xd8, + 0xe9, 0x61, 0xd9, 0x2f, 0xeb, 0x40, 0x1c, 0xc5, 0xa5, 0x95, 0xf9, 0x52, 0x8d, 0x1a, 0xf6, 0xaa, + 0x72, 0x45, 0x07, 0xe2, 0x28, 0x2e, 0x6a, 0x42, 0xce, 0x0f, 0x48, 0x4b, 0xde, 0x83, 0x0e, 0x79, + 0x4d, 0x17, 0xee, 0x0f, 0xe1, 0x4d, 0x07, 0xfd, 0xe7, 0x63, 0xce, 0x85, 0xf9, 0x26, 0x83, 0x88, + 0xbb, 0x52, 0x2c, 0x8e, 0x74, 0xd6, 0x67, 0xd4, 0x13, 0xca, 0x47, 0x23, 0x5a, 0x86, 0x63, 0xec, + 0x13, 0x8c, 0xfd, 0xdc, 0x09, 0x1a, 0xfb, 0xcf, 0x41, 0xbe, 0x69, 0xdd, 0xaa, 0xb4, 0xbd, 0xfa, + 0xf1, 0x0f, 0x15, 0x22, 0x44, 0x89, 0x53, 0xc1, 0x8a, 0x1e, 0x7a, 0xd9, 0xd0, 0xb6, 0x9c, 0x31, + 0x46, 0xfc, 0x7a, 0xba, 0x5b, 0x8e, 0xd2, 0x95, 0x3d, 0x37, 0x9f, 0x2e, 0xd3, 0x3b, 0x7f, 0xd7, + 0x4d, 0x6f, 0x6a, 0x46, 0xf2, 0x05, 0xa2, 0xcc, 0xc8, 0xc2, 0x89, 0x9a, 0x91, 0xcb, 0x11, 0x66, + 0x38, 0xc6, 0x9c, 0xc9, 0xc3, 0xd7, 0x9c, 0x92, 0x07, 0x4e, 0x54, 0x9e, 0x4a, 0x84, 0x19, 0x8e, + 0x31, 0xef, 0x7d, 0xde, 0x1c, 0x3f, 0x99, 0xf3, 0xe6, 0x44, 0x0a, 0xe7, 0xcd, 0xa3, 0x4d, 0xf1, + 0xc9, 0x61, 0x4d, 0x71, 0x74, 0x09, 0x50, 0xed, 0xc0, 0xb1, 0x9a, 0x76, 0x55, 0x6c, 0x96, 0x4c, + 0x6d, 0x4e, 0x31, 0x7f, 0xc4, 0x82, 0xd8, 0xc8, 0xd0, 0x4a, 0x17, 0x06, 0x4e, 0xa8, 0x85, 0x02, + 0xc8, 0xb7, 0xa4, 0xc5, 0x35, 0x9d, 0xc6, 0xec, 0x97, 0x16, 0x18, 0xbf, 0x2a, 0xa7, 0x0b, 0x4f, + 0x96, 0x60, 0xc5, 0xc9, 0xfc, 0x2f, 0x03, 0x66, 0x96, 0x1b, 0x6e, 0xbb, 0x76, 0xdd, 0x0a, 0xaa, + 0xbb, 0xfc, 0x5e, 0x17, 0x3d, 0x0d, 0x79, 0xdb, 0x09, 0x88, 0xb7, 0x6f, 0x35, 0x84, 0x46, 0x31, + 0xe5, 0xd5, 0xf7, 0xaa, 0x28, 0xbf, 0xdd, 0x29, 0x4e, 0xad, 0xb4, 0x3d, 0x16, 0x30, 0xc9, 0xf7, + 0x17, 0xac, 0xea, 0xa0, 0x2f, 0x19, 0x30, 0xcb, 0x6f, 0x86, 0x57, 0xac, 0xc0, 0xba, 0xd2, 0x26, + 0x9e, 0x4d, 0xe4, 0xdd, 0xf0, 0x90, 0x5b, 0x4b, 0x5c, 0x56, 0xc9, 0xe0, 0x20, 0x34, 0xad, 0xd7, + 0xe3, 0x9c, 0x71, 0xb7, 0x30, 0xe6, 0xe7, 0xb2, 0x70, 0x6f, 0x4f, 0x5a, 0x68, 0x01, 0x32, 0x76, + 0x4d, 0x34, 0x1d, 0x04, 0xdd, 0xcc, 0x6a, 0x0d, 0x67, 0xec, 0x1a, 0x5a, 0x64, 0x56, 0xa2, 0x47, + 0x7c, 0x5f, 0x5e, 0x13, 0x16, 0x94, 0x41, 0x27, 0x4a, 0xb1, 0x86, 0x81, 0x8a, 0x90, 0x6b, 0x58, + 0xdb, 0xa4, 0x21, 0x4e, 0x00, 0xcc, 0xee, 0x5c, 0xa3, 0x05, 0x98, 0x97, 0xa3, 0x5f, 0x36, 0x00, + 0xb8, 0x80, 0xf4, 0xfc, 0x20, 0xf4, 0x1a, 0x4e, 0xb7, 0x9b, 0x28, 0x65, 0x2e, 0x65, 0xf8, 0x1f, + 0x6b, 0x5c, 0xd1, 0x16, 0x8c, 0x52, 0x13, 0xd4, 0xad, 0x1d, 0x5b, 0x8d, 0xb1, 0x6b, 0x91, 0x4d, + 0x46, 0x03, 0x0b, 0x5a, 0xb4, 0xaf, 0x3c, 0x12, 0xb4, 0x3d, 0x87, 0x76, 0x2d, 0x53, 0x5c, 0x79, + 0x2e, 0x05, 0x56, 0xa5, 0x58, 0xc3, 0x30, 0xff, 0x34, 0x03, 0x73, 0x49, 0xa2, 0x53, 0xfd, 0x30, + 0xca, 0xa5, 0x15, 0x87, 0xd9, 0xf7, 0xa5, 0xdf, 0x3f, 0x22, 0xc8, 0x41, 0x85, 0x02, 0x88, 0x30, + 0x2c, 0xc1, 0x17, 0xbd, 0x4f, 0xf5, 0x50, 0xe6, 0x98, 0x3d, 0xa4, 0x28, 0xc7, 0x7a, 0xe9, 0x01, + 0x18, 0xf1, 0xe9, 0xc8, 0x67, 0xa3, 0x57, 0x0e, 0x6c, 0x8c, 0x18, 0x84, 0x62, 0xb4, 0x1d, 0x3b, + 0x10, 0x51, 0xcc, 0x0a, 0xe3, 0xaa, 0x63, 0x07, 0x98, 0x41, 0xcc, 0x2f, 0x64, 0x60, 0xa1, 0x77, + 0xa3, 0xd0, 0x17, 0x0c, 0x80, 0x1a, 0x3d, 0x60, 0xd0, 0x29, 0x29, 0x83, 0x42, 0xac, 0x93, 0xea, + 0xc3, 0x15, 0xc9, 0x29, 0x8c, 0x10, 0x52, 0x45, 0x3e, 0xd6, 0x04, 0x41, 0x8f, 0xc8, 0xa9, 0xbf, + 0x61, 0x35, 0xa5, 0x01, 0xaa, 0xea, 0xac, 0x2b, 0x08, 0xd6, 0xb0, 0xe8, 0x09, 0xd2, 0xb1, 0x9a, + 0xc4, 0x6f, 0x59, 0x2a, 0x4c, 0x9d, 0x9d, 0x20, 0x37, 0x64, 0x21, 0x0e, 0xe1, 0x66, 0x03, 0x1e, + 0xec, 0x43, 0xce, 0x94, 0x42, 0x86, 0xcd, 0xff, 0x34, 0xe0, 0xcc, 0x72, 0xa3, 0xed, 0x07, 0xc4, + 0xfb, 0x3f, 0x13, 0x70, 0xf5, 0xdf, 0x06, 0xdc, 0xd7, 0xa3, 0xcd, 0x77, 0x21, 0xee, 0xea, 0x85, + 0x68, 0xdc, 0xd5, 0xd5, 0x61, 0xa7, 0x74, 0x62, 0x3b, 0x7a, 0x84, 0x5f, 0x05, 0x30, 0x49, 0x77, + 0xad, 0x9a, 0x5b, 0x4f, 0x49, 0x6f, 0x3e, 0x08, 0xb9, 0x8f, 0x52, 0xfd, 0x13, 0x9f, 0x63, 0x4c, + 0x29, 0x61, 0x0e, 0x33, 0x9f, 0x02, 0x11, 0xa4, 0x14, 0x5b, 0x3c, 0x46, 0x3f, 0x8b, 0xc7, 0xfc, + 0x87, 0x0c, 0x68, 0x9e, 0x87, 0xbb, 0x30, 0x29, 0x9d, 0xc8, 0xa4, 0x1c, 0xf2, 0xd4, 0xac, 0xf9, + 0x51, 0x7a, 0xbd, 0x46, 0xd8, 0x8f, 0xbd, 0x46, 0xd8, 0x48, 0x8d, 0xe3, 0xd1, 0x8f, 0x11, 0xbe, + 0x6b, 0xc0, 0x7d, 0x21, 0x72, 0xb7, 0x53, 0xf0, 0xce, 0x3b, 0xcc, 0xe3, 0x30, 0x6e, 0x85, 0xd5, + 0xc4, 0x1c, 0x50, 0x0f, 0x70, 0x34, 0x8a, 0x58, 0xc7, 0x0b, 0x63, 0x9f, 0xb3, 0xc7, 0x8c, 0x7d, + 0x1e, 0x39, 0x3a, 0xf6, 0xd9, 0xfc, 0x71, 0x06, 0xce, 0x76, 0xb7, 0x4c, 0xae, 0x8d, 0xfe, 0xee, + 0xcc, 0x9f, 0x80, 0x89, 0x40, 0x54, 0xd0, 0x76, 0x7a, 0xf5, 0x7c, 0x6c, 0x4b, 0x83, 0xe1, 0x08, + 0x26, 0xad, 0x59, 0xe5, 0xab, 0xb2, 0x52, 0x75, 0x5b, 0x32, 0x72, 0x5e, 0xd5, 0x5c, 0xd6, 0x60, + 0x38, 0x82, 0xa9, 0x62, 0x12, 0x47, 0x4e, 0x3c, 0x26, 0xb1, 0x02, 0xa7, 0x65, 0x14, 0xd6, 0x05, + 0xd7, 0x5b, 0x76, 0x9b, 0xad, 0x06, 0x11, 0xb1, 0xf3, 0x54, 0xd8, 0xb3, 0xa2, 0xca, 0x69, 0x9c, + 0x84, 0x84, 0x93, 0xeb, 0x9a, 0xdf, 0xcd, 0xc2, 0xa9, 0xb0, 0xdb, 0x97, 0x5d, 0xa7, 0x66, 0xb3, + 0x58, 0xb6, 0x27, 0x61, 0x24, 0x38, 0x68, 0xc9, 0xce, 0xfe, 0x7f, 0x52, 0x9c, 0xad, 0x83, 0x16, + 0x1d, 0xed, 0x33, 0x09, 0x55, 0x98, 0x5b, 0x96, 0x55, 0x42, 0x6b, 0x6a, 0x75, 0xf0, 0x11, 0x78, + 0x2c, 0x3a, 0x9b, 0x6f, 0x77, 0x8a, 0x09, 0xaf, 0x27, 0x17, 0x15, 0xa5, 0xe8, 0x9c, 0x47, 0x37, + 0x60, 0xaa, 0x61, 0xf9, 0xc1, 0xd5, 0x56, 0xcd, 0x0a, 0xc8, 0x96, 0xdd, 0x24, 0x62, 0xcd, 0x0d, + 0x12, 0x90, 0xae, 0xee, 0x91, 0xd7, 0x22, 0x94, 0x70, 0x8c, 0x32, 0xda, 0x07, 0x44, 0x4b, 0xb6, + 0x3c, 0xcb, 0xf1, 0x79, 0xab, 0x28, 0xbf, 0xc1, 0x03, 0xe0, 0xd5, 0xb1, 0x6c, 0xad, 0x8b, 0x1a, + 0x4e, 0xe0, 0x80, 0x1e, 0x82, 0x51, 0x8f, 0x58, 0xbe, 0x18, 0xcc, 0x42, 0xb8, 0xfe, 0x31, 0x2b, + 0xc5, 0x02, 0xaa, 0x2f, 0xa8, 0xd1, 0x3b, 0x2c, 0xa8, 0x1f, 0x18, 0x30, 0x15, 0x0e, 0xd3, 0x5d, + 0x50, 0x92, 0xcd, 0xa8, 0x92, 0xbc, 0x98, 0xd6, 0x96, 0xd8, 0x43, 0x2f, 0xfe, 0xe5, 0xa8, 0xde, + 0x3e, 0x16, 0x90, 0xfc, 0x31, 0x28, 0xc8, 0x55, 0x2d, 0xad, 0xcf, 0x21, 0x4f, 0xb7, 0x11, 0xbb, + 0x44, 0x7b, 0x48, 0x23, 0x98, 0xe0, 0x90, 0x1f, 0x55, 0xcb, 0x35, 0xa1, 0x72, 0xc5, 0xb4, 0x57, + 0x6a, 0x59, 0xaa, 0xe2, 0x24, 0xb5, 0x2c, 0xeb, 0xa0, 0xab, 0x70, 0xa6, 0xe5, 0xb9, 0xec, 0x71, + 0xe5, 0x0a, 0xb1, 0x6a, 0x0d, 0xdb, 0x21, 0xd2, 0x85, 0xc0, 0xc3, 0x18, 0xee, 0x3b, 0xec, 0x14, + 0xcf, 0x6c, 0x26, 0xa3, 0xe0, 0x5e, 0x75, 0xa3, 0x0f, 0x82, 0x46, 0xfa, 0x78, 0x10, 0xf4, 0xab, + 0xca, 0x51, 0x47, 0x7c, 0xf1, 0x2c, 0xe7, 0x03, 0x69, 0x0d, 0x65, 0xc2, 0xb6, 0x1e, 0x4e, 0xa9, + 0x92, 0x60, 0x8a, 0x15, 0xfb, 0xde, 0xde, 0xa0, 0xd1, 0x63, 0x7a, 0x83, 0xc2, 0xb8, 0xee, 0xb1, + 0x9f, 0x66, 0x5c, 0x77, 0xfe, 0x4d, 0x15, 0xd7, 0xfd, 0x4a, 0x0e, 0x66, 0xe2, 0x16, 0xc8, 0xc9, + 0x3f, 0x76, 0xfa, 0x0d, 0x03, 0x66, 0xe4, 0xea, 0xe1, 0x3c, 0x89, 0xf4, 0xf3, 0xaf, 0xa5, 0xb4, + 0x68, 0xb9, 0x2d, 0xa5, 0x9e, 0xe3, 0x6e, 0xc5, 0xb8, 0xe1, 0x2e, 0xfe, 0xe8, 0x79, 0x18, 0x57, + 0xee, 0xf0, 0x63, 0xbd, 0x7c, 0x9a, 0x66, 0x56, 0x54, 0x48, 0x02, 0xeb, 0xf4, 0xd0, 0x2b, 0x06, + 0x40, 0x55, 0xaa, 0x39, 0xb9, 0xba, 0xae, 0xa4, 0xb5, 0xba, 0x94, 0x02, 0x0d, 0x8d, 0x65, 0x55, + 0xe4, 0x63, 0x8d, 0x31, 0xfa, 0x1c, 0x73, 0x84, 0x2b, 0xeb, 0x8e, 0xae, 0xa7, 0xec, 0xf0, 0xa1, + 0xb8, 0x47, 0x18, 0xa6, 0xa1, 0x29, 0xa5, 0x81, 0x7c, 0x1c, 0x11, 0xc2, 0x7c, 0x12, 0x54, 0xf0, + 0x24, 0xdd, 0xb6, 0x58, 0xf8, 0xe4, 0xa6, 0x15, 0xec, 0x8a, 0x29, 0xa8, 0xb6, 0xad, 0x0b, 0x12, + 0x80, 0x43, 0x1c, 0xf3, 0x23, 0x30, 0xf5, 0x8c, 0x67, 0xb5, 0x76, 0x6d, 0xe6, 0x70, 0xa6, 0xe7, + 0xa4, 0xb7, 0xc3, 0x98, 0x55, 0xab, 0x25, 0x3d, 0x66, 0x2f, 0xf1, 0x62, 0x2c, 0xe1, 0xfd, 0x1d, + 0x89, 0xbe, 0x69, 0x00, 0x0a, 0x2f, 0xed, 0x6c, 0xa7, 0xbe, 0x4e, 0x4f, 0xfb, 0xf4, 0x7c, 0xb4, + 0xcb, 0x4a, 0x93, 0xce, 0x47, 0x17, 0x15, 0x04, 0x6b, 0x58, 0xe8, 0x45, 0x18, 0xe7, 0xff, 0xae, + 0xa9, 0xc3, 0xfe, 0xd0, 0x4f, 0x61, 0xb9, 0x42, 0x61, 0x32, 0xf1, 0x59, 0x78, 0x31, 0xe4, 0x80, + 0x75, 0x76, 0xb4, 0xab, 0x56, 0x9d, 0x9d, 0x46, 0xfb, 0x56, 0x6d, 0x3b, 0xec, 0xaa, 0x96, 0xe7, + 0xee, 0xd8, 0x0d, 0x12, 0xef, 0xaa, 0x4d, 0x5e, 0x8c, 0x25, 0xbc, 0xbf, 0xae, 0xfa, 0xba, 0x01, + 0x73, 0xab, 0x7e, 0x60, 0xbb, 0x2b, 0xc4, 0x0f, 0xa8, 0x5a, 0xa1, 0x9b, 0x4f, 0xbb, 0xd1, 0x4f, + 0x1c, 0xf4, 0x0a, 0xcc, 0x88, 0x0b, 0xc4, 0xf6, 0xb6, 0x4f, 0x02, 0xcd, 0x8e, 0x57, 0xeb, 0x78, + 0x39, 0x06, 0xc7, 0x5d, 0x35, 0x28, 0x15, 0x71, 0x93, 0x18, 0x52, 0xc9, 0x46, 0xa9, 0x54, 0x62, + 0x70, 0xdc, 0x55, 0xc3, 0xfc, 0x76, 0x16, 0x4e, 0xb1, 0x66, 0xc4, 0xde, 0x30, 0x7c, 0xa6, 0xd7, + 0x1b, 0x86, 0x21, 0x97, 0x32, 0xe3, 0x75, 0x8c, 0x17, 0x0c, 0xbf, 0x6e, 0xc0, 0x74, 0x2d, 0xda, + 0xd3, 0xe9, 0xb8, 0x67, 0x92, 0xc6, 0x90, 0xc7, 0x4b, 0xc5, 0x0a, 0x71, 0x9c, 0x3f, 0xfa, 0xbc, + 0x01, 0xd3, 0x51, 0x31, 0xe5, 0xee, 0x7e, 0x02, 0x9d, 0xa4, 0x02, 0x9c, 0xa3, 0xe5, 0x3e, 0x8e, + 0x8b, 0x60, 0xfe, 0x9d, 0x21, 0x86, 0xf4, 0x24, 0x02, 0xf4, 0xd1, 0x4d, 0x28, 0x04, 0x0d, 0x9f, + 0x17, 0x8a, 0xd6, 0x0e, 0x79, 0x22, 0xdc, 0x5a, 0xab, 0xf0, 0xbb, 0xfb, 0xd0, 0x68, 0x13, 0x25, + 0xd4, 0xf8, 0x94, 0xbc, 0xcc, 0x2f, 0x1b, 0x50, 0xb8, 0xe4, 0xca, 0xe5, 0xfc, 0xa1, 0x14, 0xfc, + 0x2d, 0xca, 0x2c, 0x53, 0x57, 0x75, 0xa1, 0xa5, 0xff, 0x74, 0xc4, 0xdb, 0x72, 0xbf, 0x46, 0x7b, + 0x91, 0xe5, 0xcb, 0xa1, 0xa4, 0x2e, 0xb9, 0xdb, 0x3d, 0x9d, 0x79, 0xbf, 0x9b, 0x83, 0xc9, 0x67, + 0xad, 0x03, 0xe2, 0x04, 0xd6, 0xe0, 0x7b, 0xf5, 0xe3, 0x30, 0x6e, 0xb5, 0x58, 0xbc, 0xae, 0x66, + 0x6a, 0x87, 0x0e, 0x8c, 0x10, 0x84, 0x75, 0xbc, 0x70, 0x5f, 0xe1, 0xe9, 0x3b, 0x92, 0x76, 0x84, + 0xe5, 0x18, 0x1c, 0x77, 0xd5, 0x40, 0x97, 0x00, 0x89, 0xc7, 0x88, 0xa5, 0x6a, 0xd5, 0x6d, 0x3b, + 0x7c, 0x67, 0xe1, 0xbe, 0x0d, 0x75, 0xe6, 0x5b, 0xef, 0xc2, 0xc0, 0x09, 0xb5, 0xd0, 0x07, 0x61, + 0xbe, 0xca, 0x28, 0x8b, 0x13, 0x80, 0x4e, 0x91, 0x9f, 0x02, 0x55, 0xac, 0xfc, 0x72, 0x0f, 0x3c, + 0xdc, 0x93, 0x02, 0x95, 0xd4, 0x0f, 0x5c, 0xcf, 0xaa, 0x13, 0x9d, 0xee, 0x68, 0x54, 0xd2, 0x4a, + 0x17, 0x06, 0x4e, 0xa8, 0x85, 0x3e, 0x01, 0x85, 0x60, 0xd7, 0x23, 0xfe, 0xae, 0xdb, 0xa8, 0x89, + 0xbb, 0xfb, 0x21, 0x1d, 0x5e, 0x62, 0xf4, 0xb7, 0x24, 0x55, 0x6d, 0x7a, 0xcb, 0x22, 0x1c, 0xf2, + 0x44, 0x1e, 0x8c, 0xfa, 0x55, 0xb7, 0x45, 0x7c, 0x61, 0x39, 0x5f, 0x4a, 0x85, 0x3b, 0x73, 0xe0, + 0x68, 0xae, 0x36, 0xc6, 0x01, 0x0b, 0x4e, 0xe6, 0x37, 0x32, 0x30, 0xa1, 0x23, 0xf6, 0xb1, 0x45, + 0x7c, 0xd2, 0x80, 0x89, 0xaa, 0xeb, 0x04, 0x9e, 0xdb, 0xe0, 0x6e, 0xa4, 0x74, 0x14, 0x3b, 0x25, + 0xb5, 0x42, 0x02, 0xcb, 0x6e, 0x68, 0x1e, 0x29, 0x8d, 0x0d, 0x8e, 0x30, 0x45, 0x9f, 0x36, 0x60, + 0x3a, 0x0c, 0xf5, 0x0a, 0xfd, 0x59, 0xa9, 0x0a, 0xa2, 0x76, 0xdc, 0xf3, 0x51, 0x4e, 0x38, 0xce, + 0xda, 0xdc, 0x86, 0x99, 0xf8, 0x68, 0xd3, 0xae, 0x6c, 0x59, 0x62, 0xad, 0x67, 0xc3, 0xae, 0xdc, + 0xb4, 0x7c, 0x1f, 0x33, 0x08, 0x7a, 0x07, 0xe4, 0x9b, 0x96, 0x57, 0xb7, 0x1d, 0xab, 0xc1, 0x7a, + 0x31, 0xab, 0x6d, 0x48, 0xa2, 0x1c, 0x2b, 0x0c, 0xf3, 0x5d, 0x30, 0xb1, 0x6e, 0x39, 0x75, 0x52, + 0xe3, 0xdb, 0x61, 0x1f, 0x2f, 0xb5, 0x7e, 0x38, 0x02, 0xe3, 0xda, 0x11, 0xe9, 0xe4, 0x8f, 0x3b, + 0x91, 0x8c, 0x0a, 0xd9, 0x14, 0x33, 0x2a, 0x3c, 0x07, 0xb0, 0x63, 0x3b, 0xb6, 0xbf, 0x7b, 0xcc, + 0x5c, 0x0d, 0xec, 0xa6, 0xf4, 0x82, 0xa2, 0x80, 0x35, 0x6a, 0xe1, 0x75, 0x54, 0xee, 0x88, 0x0c, + 0x36, 0xaf, 0x18, 0x9a, 0xba, 0x19, 0x4d, 0xe3, 0xfa, 0x5d, 0x1b, 0x98, 0x45, 0xa9, 0x7e, 0xce, + 0x3b, 0x81, 0x77, 0x70, 0xa4, 0x56, 0xda, 0x82, 0xbc, 0x47, 0xfc, 0x76, 0x93, 0x1e, 0xdc, 0xc6, + 0x06, 0xee, 0x06, 0x16, 0xba, 0x80, 0x45, 0x7d, 0xac, 0x28, 0x2d, 0x3c, 0x09, 0x93, 0x11, 0x11, + 0xd0, 0x0c, 0x64, 0xf7, 0xc8, 0x01, 0x9f, 0x27, 0x98, 0xfe, 0x44, 0x73, 0x91, 0x4b, 0x3b, 0xd1, + 0x2d, 0xef, 0xcd, 0x3c, 0x61, 0x98, 0x2e, 0x24, 0x9e, 0xc3, 0x8f, 0x73, 0xa7, 0x42, 0xc7, 0xa2, + 0xa1, 0x25, 0x6b, 0x50, 0x63, 0xc1, 0x03, 0x54, 0x38, 0xcc, 0xfc, 0xf1, 0x28, 0x88, 0x1b, 0xe5, + 0x3e, 0xb6, 0x2b, 0xfd, 0x22, 0x29, 0x73, 0x8c, 0x8b, 0xa4, 0x4b, 0x30, 0x61, 0x3b, 0x76, 0x60, + 0x5b, 0x0d, 0xe6, 0x63, 0x11, 0xea, 0x54, 0x46, 0xf0, 0x4e, 0xac, 0x6a, 0xb0, 0x04, 0x3a, 0x91, + 0xba, 0xe8, 0x0a, 0xe4, 0x98, 0xbe, 0x11, 0x13, 0x78, 0xf0, 0x6b, 0x6f, 0x16, 0xf1, 0xc0, 0x9f, + 0xf5, 0x70, 0x4a, 0xec, 0x0c, 0xc0, 0xb3, 0x55, 0xa8, 0x53, 0xb0, 0x98, 0xc7, 0xe1, 0x19, 0x20, + 0x06, 0xc7, 0x5d, 0x35, 0x28, 0x95, 0x1d, 0xcb, 0x6e, 0xb4, 0x3d, 0x12, 0x52, 0x19, 0x8d, 0x52, + 0xb9, 0x10, 0x83, 0xe3, 0xae, 0x1a, 0x68, 0x07, 0x26, 0x44, 0x19, 0x0f, 0x3b, 0x1a, 0x3b, 0x66, + 0x2b, 0x59, 0x78, 0xd9, 0x05, 0x8d, 0x12, 0x8e, 0xd0, 0x45, 0x6d, 0x98, 0xb5, 0x9d, 0xaa, 0xeb, + 0x54, 0x1b, 0x6d, 0xdf, 0xde, 0x27, 0xe1, 0x9b, 0x9a, 0xe3, 0x30, 0x3b, 0x7d, 0xd8, 0x29, 0xce, + 0xae, 0xc6, 0xc9, 0xe1, 0x6e, 0x0e, 0xe8, 0x65, 0x03, 0x4e, 0x57, 0x5d, 0xc7, 0x67, 0xcf, 0xbf, + 0xf7, 0xc9, 0x79, 0xcf, 0x73, 0x3d, 0xce, 0xbb, 0x70, 0x4c, 0xde, 0xcc, 0xb5, 0xb7, 0x9c, 0x44, + 0x12, 0x27, 0x73, 0x42, 0x2f, 0x40, 0xbe, 0xe5, 0xb9, 0xfb, 0x76, 0x8d, 0x78, 0x22, 0x84, 0x6d, + 0x2d, 0x8d, 0x74, 0x14, 0x9b, 0x82, 0x66, 0xb8, 0xf5, 0xc8, 0x12, 0xac, 0xf8, 0x99, 0xaf, 0x17, + 0x60, 0x2a, 0x8a, 0x8e, 0x3e, 0x0e, 0xd0, 0xf2, 0xdc, 0x26, 0x09, 0x76, 0x89, 0x7a, 0x1b, 0xb1, + 0x31, 0x6c, 0xd6, 0x03, 0x49, 0x4f, 0x06, 0x91, 0xd0, 0xed, 0x22, 0x2c, 0xc5, 0x1a, 0x47, 0xe4, + 0xc1, 0xd8, 0x1e, 0x57, 0xbb, 0xc2, 0x0a, 0x79, 0x36, 0x15, 0x9b, 0x49, 0x70, 0x66, 0x41, 0xfd, + 0xa2, 0x08, 0x4b, 0x46, 0x68, 0x1b, 0xb2, 0x37, 0xc9, 0x76, 0x3a, 0x2f, 0x89, 0xaf, 0x13, 0x71, + 0x9a, 0x29, 0x8f, 0x1d, 0x76, 0x8a, 0xd9, 0xeb, 0x64, 0x1b, 0x53, 0xe2, 0xb4, 0x5d, 0x35, 0x7e, + 0x1d, 0x2e, 0xb6, 0x8a, 0x21, 0xdb, 0x15, 0xb9, 0x5b, 0xe7, 0xed, 0x12, 0x45, 0x58, 0x32, 0x42, + 0x2f, 0x40, 0xe1, 0xa6, 0xb5, 0x4f, 0x76, 0x3c, 0xd7, 0x09, 0x44, 0xe4, 0xd2, 0x90, 0xe1, 0xf2, + 0xd7, 0x25, 0x39, 0xc1, 0x97, 0xa9, 0x77, 0x55, 0x88, 0x43, 0x76, 0x68, 0x1f, 0xf2, 0x0e, 0xb9, + 0x89, 0x49, 0xc3, 0xae, 0xa6, 0x13, 0x9e, 0xbe, 0x21, 0xa8, 0x09, 0xce, 0x4c, 0xef, 0xc9, 0x32, + 0xac, 0x78, 0xd1, 0xb1, 0xbc, 0xe1, 0x6e, 0x8b, 0x8d, 0x6a, 0xc8, 0xb1, 0x54, 0x27, 0x53, 0x3e, + 0x96, 0x97, 0xdc, 0x6d, 0x4c, 0x89, 0xd3, 0x35, 0x52, 0x55, 0x61, 0x33, 0x62, 0x9b, 0xda, 0x48, + 0x37, 0x5c, 0x88, 0xaf, 0x91, 0xb0, 0x14, 0x6b, 0x1c, 0x69, 0xdf, 0xd6, 0x85, 0xcf, 0x50, 0x6c, + 0x54, 0x43, 0xf6, 0x6d, 0xd4, 0x03, 0xc9, 0xfb, 0x56, 0x96, 0x61, 0xc5, 0x8b, 0xf2, 0xb5, 0x85, + 0x03, 0x2e, 0x9d, 0xad, 0x2a, 0xea, 0xce, 0xe3, 0x7c, 0x65, 0x19, 0x56, 0xbc, 0xcc, 0x2f, 0x8f, + 0xc2, 0x84, 0x9e, 0xf6, 0xab, 0x0f, 0x1b, 0x41, 0xd9, 0xc5, 0x99, 0x41, 0xec, 0x62, 0x7a, 0x10, + 0xd2, 0xae, 0x1a, 0xa4, 0x2f, 0x64, 0x35, 0x35, 0xb3, 0x30, 0x3c, 0x08, 0x69, 0x85, 0x3e, 0x8e, + 0x30, 0x1d, 0x20, 0xfa, 0x80, 0x1a, 0x57, 0xdc, 0xfc, 0xc8, 0x45, 0x8d, 0xab, 0x88, 0x41, 0xf1, + 0x08, 0x40, 0x98, 0xfe, 0x4a, 0x5c, 0x41, 0x29, 0xab, 0x4d, 0x4b, 0xcb, 0xa5, 0x61, 0xa1, 0x87, + 0x60, 0x94, 0x2a, 0x68, 0x52, 0x13, 0x0f, 0x66, 0xd5, 0x69, 0xf3, 0x02, 0x2b, 0xc5, 0x02, 0x8a, + 0x9e, 0xa0, 0xb6, 0x54, 0xa8, 0x56, 0xc5, 0x3b, 0xd8, 0xb9, 0xd0, 0x96, 0x0a, 0x61, 0x38, 0x82, + 0x49, 0x45, 0x27, 0x54, 0x0b, 0xb2, 0x19, 0xac, 0x89, 0xce, 0x54, 0x23, 0xe6, 0x30, 0xe6, 0xfd, + 0x88, 0x69, 0x4d, 0x36, 0xf3, 0x72, 0x9a, 0xf7, 0x23, 0x06, 0xc7, 0x5d, 0x35, 0x68, 0x63, 0xc4, + 0xed, 0xd9, 0x38, 0x0f, 0xb2, 0xec, 0x71, 0xef, 0xf5, 0xaa, 0x7e, 0x22, 0x98, 0x60, 0x43, 0xff, + 0xbe, 0xf4, 0x52, 0xd8, 0xf5, 0x7f, 0x24, 0x18, 0xce, 0x78, 0xff, 0x08, 0x4c, 0x45, 0xf7, 0xca, + 0xd4, 0xdd, 0xe4, 0x7f, 0x95, 0x85, 0x53, 0x1b, 0x75, 0xdb, 0xb9, 0x15, 0xf3, 0x2f, 0x27, 0xa5, + 0x96, 0x35, 0x06, 0x4d, 0x2d, 0x1b, 0xbe, 0xbc, 0x11, 0xb9, 0x7b, 0x93, 0x5f, 0xde, 0xc8, 0xc4, + 0xbe, 0x51, 0x5c, 0xf4, 0x03, 0x03, 0xee, 0xb7, 0x6a, 0xdc, 0x7a, 0xb5, 0x1a, 0xa2, 0x34, 0x64, + 0x2a, 0x57, 0xb4, 0x3f, 0xa4, 0x2e, 0xea, 0x6e, 0xfc, 0x62, 0xe9, 0x08, 0xae, 0x7c, 0xc4, 0xdf, + 0x26, 0x5a, 0x70, 0xff, 0x51, 0xa8, 0xf8, 0x48, 0xf1, 0x17, 0x2e, 0xc3, 0x5b, 0xef, 0xc8, 0x68, + 0xa0, 0xd9, 0xf2, 0x49, 0x03, 0x0a, 0xdc, 0x7d, 0x8a, 0xc9, 0x0e, 0xdd, 0x2a, 0xac, 0x96, 0x7d, + 0x8d, 0x78, 0xbe, 0xcc, 0x79, 0xa5, 0x1d, 0xf0, 0x4a, 0x9b, 0xab, 0x02, 0x82, 0x35, 0x2c, 0xba, + 0x19, 0xef, 0xd9, 0x4e, 0x4d, 0x0c, 0x93, 0xda, 0x8c, 0x9f, 0xb5, 0x9d, 0x1a, 0x66, 0x10, 0xb5, + 0x5d, 0x67, 0x7b, 0xba, 0x35, 0x5e, 0x37, 0x60, 0x8a, 0x3d, 0x37, 0x0c, 0x8f, 0x1e, 0x8f, 0xab, + 0xd0, 0x12, 0x2e, 0xc6, 0xd9, 0x68, 0x68, 0xc9, 0xed, 0x4e, 0x71, 0x9c, 0x3f, 0x50, 0x8c, 0x46, + 0x9a, 0x7c, 0x40, 0xf8, 0x2b, 0x58, 0x00, 0x4c, 0x66, 0xe0, 0xe3, 0xb4, 0xf2, 0xe7, 0x55, 0x24, + 0x11, 0x1c, 0xd2, 0x33, 0x5f, 0x84, 0x09, 0xfd, 0xdd, 0x00, 0x7a, 0x1c, 0xc6, 0x5b, 0xb6, 0x53, + 0x8f, 0xbe, 0x2f, 0x53, 0x3e, 0xdd, 0xcd, 0x10, 0x84, 0x75, 0x3c, 0x56, 0xcd, 0x0d, 0xab, 0xc5, + 0x5c, 0xc1, 0x9b, 0xae, 0x5e, 0x2d, 0xfc, 0x63, 0xfe, 0x71, 0x16, 0x4e, 0x25, 0xbc, 0x4f, 0x41, + 0xaf, 0x18, 0x30, 0xca, 0x82, 0xe5, 0x65, 0xf0, 0xc8, 0xf3, 0xa9, 0xbf, 0x81, 0x59, 0x64, 0x31, + 0xf9, 0x62, 0x1e, 0xab, 0xed, 0x93, 0x17, 0x62, 0xc1, 0x1c, 0xfd, 0x96, 0x01, 0xe3, 0x96, 0xb6, + 0xd4, 0x78, 0x3c, 0xcd, 0x76, 0xfa, 0xc2, 0x74, 0xad, 0x2c, 0x2d, 0x0e, 0x30, 0x5c, 0x48, 0xba, + 0x2c, 0x0b, 0xef, 0x81, 0x71, 0xad, 0x09, 0x83, 0xac, 0x90, 0x85, 0xa7, 0x61, 0x66, 0xa8, 0x15, + 0xf6, 0x7e, 0x18, 0x34, 0x85, 0x1b, 0x55, 0x58, 0x37, 0xf5, 0x37, 0xc0, 0xaa, 0xc7, 0xc5, 0x23, + 0x60, 0x01, 0x35, 0xb7, 0x61, 0x26, 0x7e, 0xb8, 0x4a, 0xfd, 0xfa, 0xf8, 0x5d, 0x30, 0x60, 0xd2, + 0x35, 0xf3, 0xaf, 0x33, 0x30, 0x26, 0x1e, 0xb9, 0xdd, 0x85, 0x10, 0xda, 0xbd, 0xc8, 0xa5, 0xce, + 0x6a, 0x2a, 0x6f, 0xf3, 0x7a, 0xc6, 0xcf, 0xfa, 0xb1, 0xf8, 0xd9, 0x67, 0xd3, 0x61, 0x77, 0x74, + 0xf0, 0xec, 0xeb, 0x23, 0x30, 0x1d, 0x7b, 0x34, 0x48, 0x4d, 0x95, 0xae, 0x98, 0xb1, 0xab, 0xa9, + 0xbe, 0x4b, 0x54, 0xe1, 0xdd, 0x47, 0x87, 0x8f, 0xf9, 0x91, 0xdc, 0x96, 0x57, 0x52, 0x4b, 0x8b, + 0xfd, 0xb3, 0x34, 0x97, 0x83, 0x86, 0x43, 0xfd, 0x8b, 0x01, 0xf7, 0xf6, 0x7c, 0x5b, 0xca, 0x52, + 0x93, 0x78, 0x51, 0xa8, 0x58, 0x90, 0x29, 0xbf, 0xa0, 0x57, 0x37, 0x2c, 0xf1, 0x6c, 0x12, 0x71, + 0xf6, 0xe8, 0x31, 0x98, 0x60, 0xaa, 0x95, 0xee, 0x29, 0x01, 0x69, 0x09, 0x07, 0x31, 0x73, 0x15, + 0x56, 0xb4, 0x72, 0x1c, 0xc1, 0x32, 0xbf, 0x64, 0xc0, 0x7c, 0xaf, 0x44, 0x15, 0x7d, 0x1c, 0x0c, + 0x7f, 0x21, 0x16, 0xe3, 0x5b, 0xec, 0x8a, 0xf1, 0x8d, 0x1d, 0x0d, 0x65, 0x38, 0xaf, 0x76, 0x2a, + 0xcb, 0xde, 0x21, 0x84, 0xf5, 0x33, 0x06, 0x9c, 0xe9, 0xb1, 0x9a, 0xba, 0x62, 0xbd, 0x8d, 0x63, + 0xc7, 0x7a, 0x67, 0xfa, 0x8d, 0xf5, 0x36, 0xbf, 0x93, 0x85, 0x19, 0x21, 0x4f, 0x68, 0x5f, 0x3d, + 0x11, 0x89, 0x94, 0x7e, 0x5b, 0x2c, 0x52, 0x7a, 0x2e, 0x8e, 0xff, 0xb3, 0x30, 0xe9, 0x37, 0x57, + 0x98, 0xf4, 0x4f, 0x32, 0x70, 0x3a, 0x31, 0x7f, 0x06, 0xfa, 0x54, 0x82, 0x6a, 0xb8, 0x9e, 0x72, + 0xa2, 0x8e, 0x3e, 0x95, 0xc3, 0xb0, 0xb1, 0xc5, 0x9f, 0xd7, 0x63, 0x7a, 0xf9, 0x56, 0xbf, 0x73, + 0x02, 0x29, 0x47, 0x06, 0x0c, 0xef, 0x35, 0x7f, 0x2d, 0x0b, 0x0f, 0xf7, 0x4b, 0xe8, 0x4d, 0xfa, + 0xfc, 0xc3, 0x8f, 0x3c, 0xff, 0xb8, 0x4b, 0x6a, 0xfb, 0x44, 0x5e, 0x82, 0x7c, 0x39, 0xab, 0xd4, + 0x5e, 0xf7, 0xfc, 0xec, 0xeb, 0x36, 0x71, 0x8c, 0x9a, 0x76, 0x32, 0xab, 0x66, 0xb8, 0x15, 0x8e, + 0x55, 0x78, 0xf1, 0xed, 0x4e, 0x71, 0x56, 0x64, 0xda, 0xab, 0x90, 0x40, 0x14, 0x62, 0x59, 0x09, + 0x3d, 0x0c, 0x79, 0x8f, 0x43, 0x65, 0xc0, 0xbb, 0xb8, 0x92, 0xe5, 0x65, 0x58, 0x41, 0xd1, 0x27, + 0x34, 0x5b, 0x78, 0xe4, 0xa4, 0x92, 0x15, 0x1c, 0x75, 0xd3, 0xfc, 0x3c, 0xe4, 0x7d, 0x99, 0x1f, + 0x93, 0x5f, 0x07, 0x3c, 0xda, 0xe7, 0x3b, 0x0a, 0x7a, 0x74, 0x92, 0xc9, 0x32, 0x79, 0xfb, 0x54, + 0x2a, 0x4d, 0x45, 0x12, 0x99, 0xea, 0xd4, 0xc2, 0x7d, 0x8c, 0x90, 0x70, 0x62, 0xf9, 0xae, 0x01, + 0xe3, 0x62, 0xb4, 0xee, 0xc2, 0xd3, 0x8e, 0x1b, 0xd1, 0xa7, 0x1d, 0xe7, 0x53, 0xd9, 0x3b, 0x7a, + 0xbc, 0xeb, 0xb8, 0x01, 0x13, 0x7a, 0x0a, 0x25, 0xf4, 0x9c, 0xb6, 0xf7, 0x19, 0xc3, 0x24, 0x25, + 0x91, 0xbb, 0x63, 0xb8, 0x2f, 0x9a, 0x5f, 0xcc, 0xab, 0x5e, 0x64, 0x7e, 0x08, 0x7d, 0x0e, 0x1a, + 0x47, 0xce, 0x41, 0x7d, 0x0a, 0x64, 0xd2, 0x9f, 0x02, 0x57, 0x20, 0x2f, 0x37, 0x28, 0xa1, 0xc6, + 0x1f, 0xd4, 0xa3, 0xec, 0xa8, 0x2d, 0x40, 0x89, 0x69, 0x13, 0x97, 0x1d, 0xb5, 0xd4, 0x18, 0xaa, + 0x8d, 0x53, 0x91, 0x41, 0x2f, 0xc0, 0xf8, 0x4d, 0xd7, 0xdb, 0x6b, 0xb8, 0x16, 0xcb, 0x7c, 0x0b, + 0x69, 0x5c, 0xec, 0x28, 0x87, 0x17, 0x8f, 0x38, 0xbe, 0x1e, 0xd2, 0xc7, 0x3a, 0x33, 0x54, 0x82, + 0xe9, 0xa6, 0xed, 0x60, 0x62, 0xd5, 0xd4, 0x0b, 0x8e, 0x11, 0x9e, 0x9a, 0x53, 0x1a, 0xb9, 0xeb, + 0x51, 0x30, 0x8e, 0xe3, 0xa3, 0x8f, 0x41, 0xde, 0x17, 0x09, 0x89, 0xd2, 0xb9, 0x82, 0x53, 0x67, + 0x46, 0x4e, 0x34, 0xec, 0x3b, 0x59, 0x82, 0x15, 0x43, 0xb4, 0x06, 0x73, 0x9e, 0x48, 0xf9, 0x11, + 0xf9, 0x6e, 0x06, 0x5f, 0x9f, 0x2c, 0x03, 0x24, 0x4e, 0x80, 0xe3, 0xc4, 0x5a, 0xd4, 0x8a, 0x61, + 0xb9, 0xc0, 0xf8, 0x9d, 0x80, 0xe6, 0x46, 0x67, 0x13, 0xbe, 0x86, 0x05, 0xf4, 0xa8, 0x17, 0x41, + 0xf9, 0x21, 0x5e, 0x04, 0x55, 0xe0, 0x74, 0x1c, 0xc4, 0x12, 0x93, 0xb0, 0x5c, 0x28, 0x9a, 0xf6, + 0xd8, 0x4c, 0x42, 0xc2, 0xc9, 0x75, 0xd1, 0x75, 0x28, 0x78, 0x84, 0x9d, 0x2f, 0x4a, 0xf2, 0xd2, + 0x7f, 0xe0, 0xf0, 0x26, 0x2c, 0x09, 0xe0, 0x90, 0x16, 0x1d, 0x77, 0x2b, 0x9a, 0x9d, 0xf2, 0x4a, + 0x8a, 0x5f, 0xfe, 0x12, 0x63, 0xdf, 0x23, 0x61, 0x90, 0xf9, 0xc6, 0x14, 0x4c, 0x46, 0x7c, 0x0b, + 0xe8, 0x41, 0xc8, 0xb1, 0x4c, 0x2d, 0x6c, 0x7b, 0xc8, 0x87, 0x5b, 0x18, 0xef, 0x1c, 0x0e, 0x43, + 0x9f, 0x35, 0x60, 0xba, 0x15, 0xf1, 0xc2, 0xca, 0x9d, 0x73, 0xc8, 0x7b, 0xbe, 0xa8, 0x6b, 0x57, + 0xcb, 0xeb, 0x1c, 0x65, 0x86, 0xe3, 0xdc, 0xe9, 0x02, 0x14, 0x31, 0x82, 0x0d, 0xe2, 0x31, 0x6c, + 0x61, 0xe3, 0x28, 0x12, 0xcb, 0x51, 0x30, 0x8e, 0xe3, 0xd3, 0x11, 0x66, 0xad, 0x1b, 0xe6, 0x93, + 0x40, 0x25, 0x49, 0x00, 0x87, 0xb4, 0xd0, 0xd3, 0x30, 0x25, 0x92, 0x12, 0x6e, 0xba, 0xb5, 0x8b, + 0x96, 0xbf, 0x2b, 0x8c, 0x7b, 0x75, 0x18, 0x59, 0x8e, 0x40, 0x71, 0x0c, 0x9b, 0xb5, 0x2d, 0xcc, + 0xfc, 0xc8, 0x08, 0x8c, 0x46, 0xd3, 0x5e, 0x2f, 0x47, 0xc1, 0x38, 0x8e, 0x8f, 0xde, 0xa1, 0xed, + 0xfb, 0xfc, 0x9e, 0x4e, 0xed, 0x06, 0x09, 0x7b, 0x7f, 0x09, 0xa6, 0xdb, 0xec, 0x2c, 0x54, 0x93, + 0x40, 0xb1, 0x1e, 0x15, 0xc3, 0xab, 0x51, 0x30, 0x8e, 0xe3, 0xa3, 0x27, 0x61, 0xd2, 0xa3, 0xbb, + 0x9b, 0x22, 0xc0, 0x2f, 0xef, 0xd4, 0xdd, 0x0c, 0xd6, 0x81, 0x38, 0x8a, 0x8b, 0x9e, 0x81, 0xd9, + 0x30, 0x87, 0x97, 0x24, 0xc0, 0x6f, 0xf3, 0x54, 0x7a, 0x9a, 0x52, 0x1c, 0x01, 0x77, 0xd7, 0x41, + 0xbf, 0x04, 0x33, 0x5a, 0x4f, 0xac, 0x3a, 0x35, 0x72, 0x4b, 0xe4, 0x59, 0x62, 0x5f, 0x28, 0x58, + 0x8e, 0xc1, 0x70, 0x17, 0x36, 0x7a, 0x2f, 0x4c, 0x55, 0xdd, 0x46, 0x83, 0xed, 0x71, 0x3c, 0xe5, + 0x32, 0x4f, 0xa8, 0xc4, 0x53, 0x4f, 0x45, 0x20, 0x38, 0x86, 0x89, 0x2e, 0x01, 0x72, 0xb7, 0x7d, + 0xe2, 0xed, 0x93, 0xda, 0x33, 0xfc, 0x23, 0xa3, 0x54, 0xc5, 0x4f, 0x46, 0x23, 0x94, 0x2f, 0x77, + 0x61, 0xe0, 0x84, 0x5a, 0x2c, 0xbb, 0x8d, 0xf6, 0xb0, 0x6a, 0x2a, 0x8d, 0xcf, 0xe3, 0xc4, 0x4f, + 0xee, 0x77, 0x7c, 0x55, 0xe5, 0xc1, 0x28, 0x0f, 0x18, 0x4f, 0x27, 0xb3, 0x92, 0x9e, 0x7d, 0x35, + 0xd4, 0x11, 0xbc, 0x14, 0x0b, 0x4e, 0xe8, 0xe3, 0x50, 0xd8, 0x96, 0xa9, 0xb8, 0xe7, 0x67, 0xd2, + 0xd0, 0x8b, 0xb1, 0xac, 0xf2, 0xe1, 0xc9, 0x54, 0x01, 0x70, 0xc8, 0x12, 0x3d, 0x04, 0xe3, 0x17, + 0x37, 0x4b, 0x6a, 0x16, 0xce, 0xb2, 0xd1, 0x1f, 0xa1, 0x55, 0xb0, 0x0e, 0xa0, 0x2b, 0x4c, 0xd9, + 0x4b, 0x88, 0x0d, 0x71, 0xa8, 0x6f, 0xbb, 0xcd, 0x1f, 0x8a, 0xcd, 0xae, 0x23, 0x71, 0x65, 0xfe, + 0x54, 0x0c, 0x5b, 0x94, 0x63, 0x85, 0x81, 0x9e, 0x87, 0x71, 0xa1, 0x2f, 0xd8, 0xde, 0x34, 0x77, + 0xbc, 0x47, 0x7b, 0x38, 0x24, 0x81, 0x75, 0x7a, 0xec, 0x96, 0x89, 0x65, 0x28, 0x26, 0x17, 0xda, + 0x8d, 0xc6, 0xfc, 0x69, 0xb6, 0x6f, 0x86, 0xb7, 0x4c, 0x21, 0x08, 0xeb, 0x78, 0xe8, 0x51, 0x19, + 0x39, 0xf1, 0x96, 0xc8, 0xb5, 0x9b, 0x8a, 0x9c, 0x50, 0x56, 0x6e, 0x8f, 0x80, 0xe2, 0x33, 0x77, + 0x08, 0x59, 0xd8, 0x86, 0x05, 0x69, 0x62, 0x75, 0x2f, 0x92, 0xf9, 0xf9, 0x88, 0x97, 0x60, 0xe1, + 0x7a, 0x4f, 0x4c, 0x7c, 0x04, 0x15, 0xb4, 0x0d, 0x59, 0xab, 0xb1, 0x3d, 0x7f, 0x6f, 0x1a, 0xb6, + 0xa2, 0xfa, 0x68, 0x30, 0x0f, 0x02, 0x2a, 0xad, 0x95, 0x31, 0x25, 0x6e, 0xbe, 0x9c, 0x51, 0x5e, + 0x79, 0x95, 0x71, 0xf2, 0x45, 0x7d, 0x56, 0x1b, 0x69, 0x7c, 0x14, 0xb3, 0x2b, 0x5f, 0x3d, 0x57, + 0x48, 0x89, 0x73, 0xba, 0xa5, 0xd6, 0x71, 0x2a, 0xe9, 0x44, 0xa2, 0xd9, 0x34, 0xf9, 0x69, 0x2e, + 0xba, 0x8a, 0xcd, 0xc3, 0x31, 0xe5, 0x84, 0x8a, 0x85, 0x02, 0x78, 0x90, 0xb3, 0xfd, 0xc0, 0x76, + 0x53, 0x7c, 0x60, 0x16, 0x4b, 0x43, 0xc9, 0x02, 0x67, 0x19, 0x00, 0x73, 0x56, 0x94, 0xa7, 0x53, + 0xb7, 0x9d, 0x5b, 0xa2, 0xf9, 0x57, 0x52, 0xbf, 0xe3, 0xe7, 0x3c, 0x19, 0x00, 0x73, 0x56, 0xe8, + 0x06, 0x9f, 0x69, 0xe9, 0x7c, 0x00, 0x35, 0xfe, 0x5d, 0xe3, 0xe8, 0x8c, 0xa3, 0xbc, 0xfc, 0xa6, + 0x2d, 0x6c, 0x98, 0x21, 0x79, 0x55, 0xd6, 0x57, 0x93, 0x78, 0x55, 0xd6, 0x57, 0x31, 0x65, 0x82, + 0x5e, 0x35, 0x00, 0x2c, 0xf5, 0x81, 0xdf, 0x74, 0x3e, 0xee, 0xd0, 0xeb, 0x83, 0xc1, 0x3c, 0xd6, + 0x2d, 0x84, 0x62, 0x8d, 0x33, 0x7a, 0x01, 0xc6, 0x2c, 0xfe, 0x69, 0x1a, 0x11, 0x46, 0x98, 0xce, + 0xf7, 0x96, 0x62, 0x12, 0xb0, 0xf8, 0x49, 0x01, 0xc2, 0x92, 0x21, 0xe5, 0x1d, 0x78, 0x16, 0xd9, + 0xb1, 0xf7, 0x44, 0x3c, 0x61, 0x65, 0xe8, 0x0c, 0xd3, 0x94, 0x58, 0x12, 0x6f, 0x01, 0xc2, 0x92, + 0x21, 0xff, 0xa6, 0xa6, 0xe5, 0x58, 0xea, 0x71, 0x48, 0x3a, 0x4f, 0x88, 0xf4, 0xe7, 0x26, 0xda, + 0x37, 0x35, 0x75, 0x46, 0x38, 0xca, 0xd7, 0xfc, 0x51, 0x16, 0x80, 0xfd, 0xe4, 0xef, 0x86, 0x9b, + 0x2c, 0xd7, 0xdc, 0xae, 0x5b, 0x13, 0x4b, 0x3b, 0xc5, 0xe7, 0xbf, 0x20, 0x12, 0xcb, 0xed, 0xba, + 0x35, 0x2c, 0x98, 0xa0, 0x3a, 0x8c, 0xb4, 0xac, 0x60, 0x37, 0xfd, 0xb7, 0xc6, 0x79, 0xfe, 0x72, + 0x27, 0xd8, 0xc5, 0x8c, 0x01, 0x7a, 0xc9, 0x80, 0x31, 0xfe, 0xda, 0x58, 0xba, 0x9a, 0x87, 0xbe, + 0x4f, 0x95, 0x7d, 0xb6, 0xc8, 0x9f, 0x34, 0x8b, 0x60, 0x05, 0xa5, 0x1a, 0x45, 0x29, 0x96, 0x6c, + 0x17, 0x5e, 0x31, 0x60, 0x42, 0x47, 0x4d, 0x08, 0x33, 0xf8, 0xb0, 0x1e, 0x66, 0x90, 0x66, 0x7f, + 0xe8, 0x11, 0x0b, 0xff, 0x6e, 0x80, 0xf6, 0x25, 0xd2, 0x30, 0xc8, 0xd0, 0xe8, 0x3b, 0xc8, 0x30, + 0x33, 0x60, 0x90, 0x61, 0x76, 0xa0, 0x20, 0xc3, 0x91, 0xc1, 0x83, 0x0c, 0x73, 0xbd, 0x83, 0x0c, + 0xcd, 0xd7, 0x0c, 0x98, 0xed, 0xda, 0x0f, 0xe3, 0x5f, 0x7c, 0x37, 0xfa, 0xfc, 0xe2, 0xfb, 0x0a, + 0xcc, 0x88, 0x5c, 0xc8, 0x95, 0x56, 0xc3, 0x4e, 0x7c, 0x07, 0xbe, 0x15, 0x83, 0xe3, 0xae, 0x1a, + 0xe6, 0x9f, 0x1b, 0x30, 0xae, 0x3d, 0x5b, 0xa3, 0xed, 0x60, 0xcf, 0xfb, 0x84, 0x18, 0x61, 0x1a, + 0x68, 0xe6, 0xda, 0xe7, 0x30, 0x7e, 0xcb, 0x54, 0xd7, 0xf2, 0x6e, 0x86, 0xb7, 0x4c, 0xb4, 0x14, + 0x0b, 0x28, 0xcf, 0xa8, 0x48, 0xf8, 0xd7, 0xfc, 0xb3, 0x7a, 0x46, 0x45, 0xd2, 0xc2, 0x0c, 0xc2, + 0xd8, 0x51, 0x3b, 0x52, 0xc4, 0x9f, 0x6a, 0x59, 0xa7, 0x2d, 0x2f, 0xc0, 0x1c, 0x86, 0xce, 0x42, + 0x96, 0x38, 0x35, 0x71, 0xe8, 0x55, 0x5f, 0x7a, 0x3a, 0xef, 0xd4, 0x30, 0x2d, 0x37, 0x2f, 0xc3, + 0x44, 0x85, 0x54, 0x3d, 0x12, 0x3c, 0x4b, 0x0e, 0xfa, 0xfe, 0x74, 0x14, 0x9d, 0xed, 0xb1, 0x4f, + 0x47, 0xd1, 0xea, 0xb4, 0xdc, 0xfc, 0x43, 0x03, 0x62, 0xa9, 0xd1, 0x35, 0x8f, 0xb3, 0xd1, 0xcb, + 0xe3, 0x1c, 0xf1, 0x8d, 0x66, 0x8e, 0xf4, 0x8d, 0x5e, 0x02, 0xd4, 0xa4, 0x4b, 0x21, 0xf2, 0x21, + 0x00, 0xe1, 0x6f, 0x08, 0x1f, 0xc9, 0x76, 0x61, 0xe0, 0x84, 0x5a, 0xe6, 0x1f, 0x70, 0x61, 0xf5, + 0x64, 0xe9, 0x77, 0xee, 0x80, 0x36, 0xe4, 0x18, 0x29, 0xe1, 0x74, 0xd9, 0x1c, 0x6e, 0x71, 0x77, + 0xe7, 0x7c, 0x08, 0x07, 0x52, 0x2c, 0x79, 0xc6, 0xcd, 0xfc, 0x0e, 0x97, 0x55, 0xcb, 0xa6, 0xde, + 0x87, 0xac, 0xcd, 0xa8, 0xac, 0x17, 0xd3, 0xda, 0x2b, 0x93, 0x65, 0x44, 0x8b, 0x00, 0x2d, 0xe2, + 0x55, 0x89, 0x13, 0xc8, 0xb0, 0xe8, 0x9c, 0x78, 0x46, 0xa2, 0x4a, 0xb1, 0x86, 0x61, 0xbe, 0x64, + 0xc0, 0x4c, 0x25, 0xb0, 0xab, 0x7b, 0xb6, 0xc3, 0x9f, 0x45, 0xed, 0xd8, 0x75, 0x7a, 0x4a, 0x21, + 0xe2, 0xab, 0x48, 0xdc, 0x0d, 0xa6, 0xb6, 0x62, 0xf9, 0x31, 0x24, 0x09, 0x47, 0x25, 0x98, 0x96, + 0xde, 0x76, 0xe9, 0xbb, 0xe4, 0xcf, 0x39, 0x95, 0xaf, 0x64, 0x25, 0x0a, 0xc6, 0x71, 0x7c, 0xf3, + 0x13, 0x30, 0xae, 0xed, 0xaf, 0x6c, 0x2b, 0xba, 0x65, 0x55, 0x83, 0xf8, 0x12, 0x3e, 0x4f, 0x0b, + 0x31, 0x87, 0x31, 0x17, 0x2b, 0x8f, 0x9b, 0x8d, 0x2d, 0x61, 0x11, 0x2d, 0x2b, 0xa0, 0x94, 0x98, + 0x47, 0xea, 0xe4, 0x96, 0xcc, 0xf0, 0x29, 0x89, 0x61, 0x5a, 0x88, 0x39, 0xcc, 0xbc, 0x06, 0x79, + 0xf9, 0xe8, 0x9e, 0xbd, 0x5c, 0x95, 0xee, 0x3f, 0xfd, 0xe5, 0xaa, 0xeb, 0x05, 0x98, 0x41, 0xe8, + 0x3a, 0xf1, 0x1d, 0xfb, 0xa2, 0xeb, 0x07, 0x32, 0x53, 0x00, 0x77, 0xf2, 0x6f, 0xac, 0xb2, 0x32, + 0xac, 0xa0, 0xe6, 0x2c, 0x4c, 0x2b, 0xef, 0xbd, 0x08, 0x4d, 0xfc, 0x46, 0x16, 0x26, 0x22, 0xdf, + 0xd8, 0xbd, 0xf3, 0x04, 0xea, 0x7f, 0x5d, 0x26, 0x78, 0xe1, 0xb3, 0x03, 0x7a, 0xe1, 0xf5, 0x6b, + 0x8f, 0x91, 0x93, 0xbd, 0xf6, 0xc8, 0xa5, 0x73, 0xed, 0x11, 0xc0, 0x98, 0x2f, 0x54, 0xcf, 0x68, + 0x1a, 0xee, 0x91, 0xd8, 0x88, 0x71, 0xab, 0x53, 0x6a, 0x30, 0xc9, 0xca, 0xfc, 0x6a, 0x0e, 0xa6, + 0xa2, 0xe9, 0x86, 0xfa, 0x18, 0xc9, 0x77, 0x74, 0x8d, 0xe4, 0x80, 0x5e, 0xc8, 0xec, 0xb0, 0x5e, + 0xc8, 0x91, 0x61, 0xbd, 0x90, 0xb9, 0x63, 0x78, 0x21, 0xbb, 0x7d, 0x88, 0xa3, 0x7d, 0xfb, 0x10, + 0x9f, 0x52, 0x21, 0x34, 0x63, 0x91, 0x3b, 0xe7, 0x30, 0x84, 0x06, 0x45, 0x87, 0x61, 0xd9, 0xad, + 0x25, 0x86, 0x22, 0xe5, 0xef, 0xe0, 0x6d, 0xf1, 0x12, 0x23, 0x5e, 0x06, 0xbf, 0xe8, 0x78, 0xcb, + 0x00, 0xd1, 0x2e, 0x8f, 0xc3, 0xb8, 0x98, 0x4f, 0xcc, 0xfa, 0x81, 0xa8, 0xe5, 0x54, 0x09, 0x41, + 0x58, 0xc7, 0x63, 0x9f, 0x81, 0x8c, 0x7e, 0xf7, 0x92, 0x39, 0x75, 0xf5, 0xcf, 0x40, 0xc6, 0xbe, + 0x93, 0x19, 0xc7, 0x37, 0x3f, 0x06, 0xa7, 0x13, 0xcf, 0x58, 0xcc, 0xe9, 0xc4, 0x14, 0x33, 0xa9, + 0x09, 0x04, 0x4d, 0x8c, 0x58, 0x36, 0xda, 0x85, 0xeb, 0x3d, 0x31, 0xf1, 0x11, 0x54, 0xcc, 0xaf, + 0x64, 0x61, 0x2a, 0xfa, 0x0d, 0x21, 0x74, 0x53, 0x79, 0x64, 0x52, 0x71, 0x06, 0x71, 0xb2, 0x5a, + 0x0a, 0x9b, 0x9e, 0xee, 0xd5, 0x9b, 0x6c, 0x7e, 0x6d, 0xab, 0x7c, 0x3a, 0x27, 0xc7, 0x58, 0xf8, + 0x35, 0x05, 0x3b, 0xf6, 0x99, 0xa0, 0xf0, 0x01, 0x83, 0x38, 0x48, 0xa5, 0xce, 0x3d, 0x7c, 0x92, + 0xa0, 0x58, 0x61, 0x8d, 0x2d, 0xd5, 0x2d, 0xfb, 0xc4, 0xb3, 0x77, 0x6c, 0xf5, 0xfd, 0x43, 0xb6, + 0x73, 0x5f, 0x13, 0x65, 0x58, 0x41, 0xcd, 0x97, 0x32, 0x10, 0x7e, 0xed, 0x95, 0x7d, 0x68, 0xc3, + 0xd7, 0x8c, 0x56, 0x31, 0x6c, 0x97, 0x86, 0xfd, 0x9a, 0x4d, 0x48, 0x51, 0x84, 0x37, 0x6a, 0x25, + 0x38, 0xc2, 0xf1, 0xa7, 0xf0, 0x95, 0x57, 0x0b, 0xa6, 0x63, 0xcf, 0x3a, 0x53, 0x8f, 0x21, 0xff, + 0x62, 0x16, 0x0a, 0xea, 0x61, 0x2c, 0x7a, 0x4f, 0xc4, 0x83, 0x50, 0x28, 0xbf, 0x55, 0xcb, 0x29, + 0xbf, 0xeb, 0xd6, 0x6e, 0x77, 0x8a, 0xd3, 0x0a, 0x39, 0xe6, 0x0d, 0x38, 0x0b, 0xd9, 0xb6, 0xd7, + 0x88, 0x1f, 0x11, 0xae, 0xe2, 0x35, 0x4c, 0xcb, 0xd1, 0xad, 0xf8, 0x11, 0x7e, 0x3d, 0xa5, 0xc7, + 0xbc, 0xdc, 0x96, 0xee, 0x7d, 0x74, 0xa7, 0x5a, 0x72, 0xdb, 0xad, 0x1d, 0xc4, 0x73, 0xd0, 0x97, + 0xdd, 0xda, 0x01, 0x66, 0x10, 0xf4, 0x34, 0x4c, 0x05, 0x76, 0x93, 0xb8, 0xed, 0x40, 0xff, 0x96, + 0x66, 0x36, 0xbc, 0x2e, 0xdc, 0x8a, 0x40, 0x71, 0x0c, 0x9b, 0x6a, 0xd9, 0x1b, 0xbe, 0xeb, 0xb0, + 0xc4, 0x72, 0xa3, 0xd1, 0xbb, 0x85, 0x4b, 0x95, 0xcb, 0x1b, 0xcc, 0x93, 0xa1, 0x30, 0x28, 0xb6, + 0xcd, 0x5e, 0xc1, 0x79, 0x44, 0xdc, 0xd6, 0xcf, 0x84, 0x39, 0x12, 0x78, 0x39, 0x56, 0x18, 0xe6, + 0x55, 0x98, 0x8e, 0x35, 0x55, 0x1e, 0xc6, 0x8c, 0xe4, 0xc3, 0x58, 0x7f, 0x09, 0xdf, 0xff, 0xc4, + 0x80, 0xd9, 0xae, 0xc5, 0xdb, 0xef, 0xe3, 0x86, 0xb8, 0x1a, 0xc9, 0x1c, 0x5f, 0x8d, 0x64, 0x07, + 0x53, 0x23, 0xe5, 0xed, 0x6f, 0xbd, 0x71, 0xee, 0x9e, 0x6f, 0xbf, 0x71, 0xee, 0x9e, 0xef, 0xbd, + 0x71, 0xee, 0x9e, 0x97, 0x0e, 0xcf, 0x19, 0xdf, 0x3a, 0x3c, 0x67, 0x7c, 0xfb, 0xf0, 0x9c, 0xf1, + 0xbd, 0xc3, 0x73, 0xc6, 0x3f, 0x1f, 0x9e, 0x33, 0x5e, 0xfb, 0xe1, 0xb9, 0x7b, 0x9e, 0x7b, 0x2a, + 0x9c, 0x5a, 0x4b, 0x72, 0x6a, 0xb1, 0x1f, 0xef, 0x94, 0x13, 0x69, 0xa9, 0xb5, 0x57, 0x5f, 0xa2, + 0x53, 0x6b, 0x49, 0x95, 0xc8, 0xa9, 0xf5, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xcd, 0x19, 0xc7, + 0x30, 0x68, 0x92, 0x00, 0x00, } func (m *ALBStatus) Marshal() (dAtA []byte, err error) { diff --git a/pkg/apis/rollouts/v1alpha1/generated.proto b/pkg/apis/rollouts/v1alpha1/generated.proto index 7194886619..480ccd1eec 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.proto +++ b/pkg/apis/rollouts/v1alpha1/generated.proto @@ -29,7 +29,7 @@ import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; import "k8s.io/apimachinery/pkg/util/intstr/generated.proto"; // Package-wide variables from generator "generated". -option go_package = "v1alpha1"; +option go_package = "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1"; message ALBStatus { optional AwsResourceRef loadBalancer = 1; diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index b4c63e2ced..fef1aaafe4 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -61,6 +61,10 @@ func (c *Clientset) Discovery() discovery.DiscoveryInterface { func NewForConfig(c *rest.Config) (*Clientset, error) { configShallowCopy := *c + if configShallowCopy.UserAgent == "" { + configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent() + } + // share the transport between all clients httpClient, err := rest.HTTPClientFor(&configShallowCopy) if err != nil { diff --git a/ui/src/models/rollout/generated/api.ts b/ui/src/models/rollout/generated/api.ts index dcfeec0a3e..1ff2433d07 100644 --- a/ui/src/models/rollout/generated/api.ts +++ b/ui/src/models/rollout/generated/api.ts @@ -1966,7 +1966,7 @@ export interface K8sIoApiCoreV1AzureFileVolumeSource { */ export interface K8sIoApiCoreV1CSIVolumeSource { /** - * Driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster. + * driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster. * @type {string} * @memberof K8sIoApiCoreV1CSIVolumeSource */ @@ -2756,7 +2756,7 @@ export interface K8sIoApiCoreV1FCVolumeSource { */ export interface K8sIoApiCoreV1FlexVolumeSource { /** - * Driver is the name of the driver to use for this volume. + * driver is the name of the driver to use for this volume. * @type {string} * @memberof K8sIoApiCoreV1FlexVolumeSource */ @@ -3006,19 +3006,19 @@ export interface K8sIoApiCoreV1HostPathVolumeSource { */ export interface K8sIoApiCoreV1ISCSIVolumeSource { /** - * iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260). + * targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260). * @type {string} * @memberof K8sIoApiCoreV1ISCSIVolumeSource */ targetPortal?: string; /** - * Target iSCSI Qualified Name. + * iqn is the target iSCSI Qualified Name. * @type {string} * @memberof K8sIoApiCoreV1ISCSIVolumeSource */ iqn?: string; /** - * iSCSI Target Lun number. + * lun represents iSCSI Target Lun number. * @type {number} * @memberof K8sIoApiCoreV1ISCSIVolumeSource */ @@ -3079,13 +3079,13 @@ export interface K8sIoApiCoreV1ISCSIVolumeSource { */ export interface K8sIoApiCoreV1KeyToPath { /** - * The key to project. + * key is the key to project. * @type {string} * @memberof K8sIoApiCoreV1KeyToPath */ key?: string; /** - * The relative path of the file to map the key to. May not be an absolute path. May not contain the path element '..'. May not start with the string '..'. + * path is the relative path of the file to map the key to. May not be an absolute path. May not contain the path element '..'. May not start with the string '..'. * @type {string} * @memberof K8sIoApiCoreV1KeyToPath */ @@ -3380,7 +3380,7 @@ export interface K8sIoApiCoreV1PhotonPersistentDiskVolumeSource { */ pdID?: string; /** - * Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. + * fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. * @type {string} * @memberof K8sIoApiCoreV1PhotonPersistentDiskVolumeSource */ @@ -3847,7 +3847,7 @@ export interface K8sIoApiCoreV1PortworxVolumeSource { */ volumeID?: string; /** - * FSType represents the filesystem type to mount Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\". Implicitly inferred to be \"ext4\" if unspecified. + * fSType represents the filesystem type to mount Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\". Implicitly inferred to be \"ext4\" if unspecified. * @type {string} * @memberof K8sIoApiCoreV1PortworxVolumeSource */ @@ -3990,7 +3990,7 @@ export interface K8sIoApiCoreV1QuobyteVolumeSource { */ registry?: string; /** - * Volume is a string that references an already created Quobyte volume by name. + * volume is a string that references an already created Quobyte volume by name. * @type {string} * @memberof K8sIoApiCoreV1QuobyteVolumeSource */ @@ -4157,13 +4157,13 @@ export interface K8sIoApiCoreV1SELinuxOptions { */ export interface K8sIoApiCoreV1ScaleIOVolumeSource { /** - * The host address of the ScaleIO API Gateway. + * gateway is the host address of the ScaleIO API Gateway. * @type {string} * @memberof K8sIoApiCoreV1ScaleIOVolumeSource */ gateway?: string; /** - * The name of the storage system as configured in ScaleIO. + * system is the name of the storage system as configured in ScaleIO. * @type {string} * @memberof K8sIoApiCoreV1ScaleIOVolumeSource */ @@ -4199,7 +4199,7 @@ export interface K8sIoApiCoreV1ScaleIOVolumeSource { */ storageMode?: string; /** - * The name of a volume already created in the ScaleIO system that is associated with this volume source. + * volumeName is the name of a volume already created in the ScaleIO system that is associated with this volume source. * @type {string} * @memberof K8sIoApiCoreV1ScaleIOVolumeSource */ @@ -4428,7 +4428,7 @@ export interface K8sIoApiCoreV1ServiceAccountTokenProjection { */ expirationSeconds?: string; /** - * Path is the path relative to the mount point of the file to project the token into. + * path is the path relative to the mount point of the file to project the token into. * @type {string} * @memberof K8sIoApiCoreV1ServiceAccountTokenProjection */ @@ -4441,7 +4441,7 @@ export interface K8sIoApiCoreV1ServiceAccountTokenProjection { */ export interface K8sIoApiCoreV1StorageOSVolumeSource { /** - * VolumeName is the human-readable name of the StorageOS volume. Volume names are only unique within a namespace. + * volumeName is the human-readable name of the StorageOS volume. Volume names are only unique within a namespace. * @type {string} * @memberof K8sIoApiCoreV1StorageOSVolumeSource */ @@ -4553,13 +4553,13 @@ export interface K8sIoApiCoreV1Toleration { */ export interface K8sIoApiCoreV1TopologySpreadConstraint { /** - * MaxSkew describes the degree to which pods may be unevenly distributed. When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference between the number of matching pods in the target topology and the global minimum. For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same labelSelector spread as 1/1/0: +-------+-------+-------+ | zone1 | zone2 | zone3 | +-------+-------+-------+ | P | P | | +-------+-------+-------+ - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 1/1/1; scheduling it onto zone1(zone2) would make the ActualSkew(2-0) on zone1(zone2) violate MaxSkew(1). - if MaxSkew is 2, incoming pod can be scheduled onto any zone. When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence to topologies that satisfy it. It's a required field. Default value is 1 and 0 is not allowed. + * MaxSkew describes the degree to which pods may be unevenly distributed. When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference between the number of matching pods in the target topology and the global minimum. The global minimum is the minimum number of matching pods in an eligible domain or zero if the number of eligible domains is less than MinDomains. For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same labelSelector spread as 2/2/1: In this case, the global minimum is 1. +-------+-------+-------+ | zone1 | zone2 | zone3 | +-------+-------+-------+ | P P | P P | P | +-------+-------+-------+ - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) violate MaxSkew(1). - if MaxSkew is 2, incoming pod can be scheduled onto any zone. When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence to topologies that satisfy it. It's a required field. Default value is 1 and 0 is not allowed. * @type {number} * @memberof K8sIoApiCoreV1TopologySpreadConstraint */ maxSkew?: number; /** - * TopologyKey is the key of node labels. Nodes that have a label with this key and identical values are considered to be in the same topology. We consider each as a \"bucket\", and try to put balanced number of pods into each bucket. It's a required field. + * TopologyKey is the key of node labels. Nodes that have a label with this key and identical values are considered to be in the same topology. We consider each as a \"bucket\", and try to put balanced number of pods into each bucket. We define a domain as a particular instance of a topology. Also, we define an eligible domain as a domain whose nodes match the node selector. e.g. If TopologyKey is \"kubernetes.io/hostname\", each Node is a domain of that topology. And, if TopologyKey is \"topology.kubernetes.io/zone\", each zone is a domain of that topology. It's a required field. * @type {string} * @memberof K8sIoApiCoreV1TopologySpreadConstraint */ @@ -4576,6 +4576,12 @@ export interface K8sIoApiCoreV1TopologySpreadConstraint { * @memberof K8sIoApiCoreV1TopologySpreadConstraint */ labelSelector?: K8sIoApimachineryPkgApisMetaV1LabelSelector; + /** + * MinDomains indicates a minimum number of eligible domains. When the number of eligible domains with matching topology keys is less than minDomains, Pod Topology Spread treats \"global minimum\" as 0, and then the calculation of Skew is performed. And when the number of eligible domains with matching topology keys equals or greater than minDomains, this value has no effect on scheduling. As a result, when the number of eligible domains is less than minDomains, scheduler won't schedule more than maxSkew Pods to those domains. If value is nil, the constraint behaves as if MinDomains is equal to 1. Valid values are integers greater than 0. When value is not nil, WhenUnsatisfiable must be DoNotSchedule. For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same labelSelector spread as 2/2/2: +-------+-------+-------+ | zone1 | zone2 | zone3 | +-------+-------+-------+ | P P | P P | P P | +-------+-------+-------+ The number of domains is less than 5(MinDomains), so \"global minimum\" is treated as 0. In this situation, new pod with the same labelSelector cannot be scheduled, because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, it will violate MaxSkew. This is an alpha field and requires enabling MinDomainsInPodTopologySpread feature gate. +optional + * @type {number} + * @memberof K8sIoApiCoreV1TopologySpreadConstraint + */ + minDomains?: number; } /** * @@ -5108,7 +5114,7 @@ export interface K8sIoApimachineryPkgApisMetaV1ObjectMeta { */ name?: string; /** - * GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the Name field has not been provided. If this field is used, the name returned to the client will be different than the name passed. This value will also be combined with a unique suffix. The provided value has the same validation rules as the Name field, and may be truncated by the length of the suffix required to make the value unique on the server. If this field is specified and the generated name exists, the server will NOT return a 409 - instead, it will either return 201 Created or 500 with Reason ServerTimeout indicating a unique name could not be found in the time allotted, and the client should retry (optionally after the time indicated in the Retry-After header). Applied only if Name is not specified. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency +optional + * GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the Name field has not been provided. If this field is used, the name returned to the client will be different than the name passed. This value will also be combined with a unique suffix. The provided value has the same validation rules as the Name field, and may be truncated by the length of the suffix required to make the value unique on the server. If this field is specified and the generated name exists, the server will return a 409. Applied only if Name is not specified. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency +optional * @type {string} * @memberof K8sIoApimachineryPkgApisMetaV1ObjectMeta */ @@ -5120,7 +5126,7 @@ export interface K8sIoApimachineryPkgApisMetaV1ObjectMeta { */ namespace?: string; /** - * SelfLink is a URL representing this object. Populated by the system. Read-only. DEPRECATED Kubernetes will stop propagating this field in 1.20 release and the field is planned to be removed in 1.21 release. +optional + * * @type {string} * @memberof K8sIoApimachineryPkgApisMetaV1ObjectMeta */ @@ -5186,7 +5192,7 @@ export interface K8sIoApimachineryPkgApisMetaV1ObjectMeta { */ finalizers?: Array; /** - * + * Deprecated: ClusterName is a legacy field that was always cleared by the system and never used; it will be removed completely in 1.25. The name in the go struct is changed to help clients detect accidental use. +optional * @type {string} * @memberof K8sIoApimachineryPkgApisMetaV1ObjectMeta */ From 0e2fdaee6442059549e55059e101f595e80b4739 Mon Sep 17 00:00:00 2001 From: Martin Adler <1208749+EagleIJoe@users.noreply.github.com> Date: Fri, 22 Jul 2022 23:06:54 +0200 Subject: [PATCH 154/175] fixes #2141 Added list and watch to clusterrole (#2145) Signed-off-by: Martin Adler <1208749+EagleIJoe@users.noreply.github.com> --- manifests/dashboard-install.yaml | 2 ++ manifests/dashboard-install/dashboard-clusterrole.yaml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/manifests/dashboard-install.yaml b/manifests/dashboard-install.yaml index d31c27b37e..009f5dff73 100644 --- a/manifests/dashboard-install.yaml +++ b/manifests/dashboard-install.yaml @@ -57,6 +57,8 @@ rules: verbs: - get - update + - list + - watch - apiGroups: - apps resources: diff --git a/manifests/dashboard-install/dashboard-clusterrole.yaml b/manifests/dashboard-install/dashboard-clusterrole.yaml index dd541479a0..2499752457 100644 --- a/manifests/dashboard-install/dashboard-clusterrole.yaml +++ b/manifests/dashboard-install/dashboard-clusterrole.yaml @@ -47,6 +47,8 @@ rules: verbs: - get - update + - list + - watch - apiGroups: - apps resources: From 1bffed59b8032a23e8edc173a88fe598265b06d3 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Fri, 22 Jul 2022 18:09:39 -0500 Subject: [PATCH 155/175] fix: Update ro.Status.ALB when first creating rollout object (#1986) * fix: make sure we update rollout.Status.ALB when first create Rollout object This fixes the case when we first create a rollout the status.ALB field does not get updated with valid information form the elb. Signed-off-by: zachaller * Refactor check for if we should verify alb. This creates a new rolloututil function ShouldVerifyWeight that verifies that we should call aws because the rollout is in the middle of some update. The reason I feel this should move into the ingress implmentation function VerifyWeight is becuase in the future other ingresses might also need to verify weights and adding ingress specific status checks in trafficrouting.go like a leak details where it should be up to the ingress provider to determin if it should be careful of rate limiting do to say it being a cloud provider call. Signed-off-by: zachaller * lint Signed-off-by: zachaller * Fix tests Signed-off-by: zachaller * Add new test for ShouldVerifyWeight Signed-off-by: zachaller * Fix logic Signed-off-by: zachaller * Add test for where we do not need to verify weight and its already set Signed-off-by: zachaller * fix up review comments Signed-off-by: zachaller * fix tests Signed-off-by: zachaller * fix bad merge Signed-off-by: zachaller * Fix test Signed-off-by: zachaller * Fix test Signed-off-by: zachaller * Clearer function name Signed-off-by: zachaller * Clean up if logic Signed-off-by: zachaller --- rollout/service_test.go | 13 +++++++-- rollout/trafficrouting.go | 40 +++++++++++++------------- rollout/trafficrouting/alb/alb.go | 19 ++++++++++-- rollout/trafficrouting/alb/alb_test.go | 31 ++++++++++++++++++++ rollout/trafficrouting_test.go | 13 +++++---- utils/rollout/rolloututil.go | 15 ++++++++++ utils/rollout/rolloututil_test.go | 18 ++++++++++++ 7 files changed, 119 insertions(+), 30 deletions(-) diff --git a/rollout/service_test.go b/rollout/service_test.go index 3e0affc53f..aa4f1d020b 100644 --- a/rollout/service_test.go +++ b/rollout/service_test.go @@ -459,7 +459,10 @@ func TestCanaryAWSVerifyTargetGroupsNotYetReady(t *testing.T) { } fakeELB.On("DescribeTargetHealth", mock.Anything, mock.Anything).Return(&thOut, nil) - r1 := newCanaryRollout("foo", 3, nil, nil, nil, intstr.FromString("25%"), intstr.FromString("25%")) + r1 := newCanaryRollout("foo", 3, nil, []v1alpha1.CanaryStep{{ + SetWeight: pointer.Int32Ptr(10), + }}, pointer.Int32Ptr(0), intstr.FromString("25%"), intstr.FromString("25%")) + r1.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{ ALB: &v1alpha1.ALBTrafficRouting{ Ingress: "ingress", @@ -553,7 +556,9 @@ func TestCanaryAWSVerifyTargetGroupsReady(t *testing.T) { } fakeELB.On("DescribeTargetHealth", mock.Anything, mock.Anything).Return(&thOut, nil) - r1 := newCanaryRollout("foo", 3, nil, nil, nil, intstr.FromString("25%"), intstr.FromString("25%")) + r1 := newCanaryRollout("foo", 3, nil, []v1alpha1.CanaryStep{{ + SetWeight: pointer.Int32Ptr(10), + }}, pointer.Int32Ptr(0), intstr.FromString("25%"), intstr.FromString("25%")) r1.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{ ALB: &v1alpha1.ALBTrafficRouting{ Ingress: "ingress", @@ -610,7 +615,9 @@ func TestCanaryAWSVerifyTargetGroupsSkip(t *testing.T) { f := newFixture(t) defer f.Close() - r1 := newCanaryRollout("foo", 3, nil, nil, nil, intstr.FromString("25%"), intstr.FromString("25%")) + r1 := newCanaryRollout("foo", 3, nil, []v1alpha1.CanaryStep{{ + SetWeight: pointer.Int32Ptr(10), + }}, pointer.Int32Ptr(0), intstr.FromString("25%"), intstr.FromString("25%")) r1.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{ ALB: &v1alpha1.ALBTrafficRouting{ Ingress: "ingress", diff --git a/rollout/trafficrouting.go b/rollout/trafficrouting.go index 8c3598e9ce..ebc22b9704 100644 --- a/rollout/trafficrouting.go +++ b/rollout/trafficrouting.go @@ -3,6 +3,7 @@ package rollout import ( "fmt" "reflect" + "strconv" "strings" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" @@ -232,27 +233,26 @@ func (c *rolloutContext) reconcileTrafficRouting() error { c.newStatus.Canary.Weights = newWeights } - // If we are in the middle of an update at a setWeight step, also perform weight verification. - // Note that we don't do this every reconciliation because weight verification typically involves - // API calls to the cloud provider which could incur rate limiting - shouldVerifyWeight := c.rollout.Status.StableRS != "" && - !rolloututil.IsFullyPromoted(c.rollout) && - currentStep != nil && currentStep.SetWeight != nil + weightVerified, err := reconciler.VerifyWeight(desiredWeight, weightDestinations...) + c.newStatus.Canary.Weights.Verified = weightVerified + if err != nil { + c.recorder.Warnf(c.rollout, record.EventOptions{EventReason: conditions.WeightVerifyErrorReason}, conditions.WeightVerifyErrorMessage, err) + return nil // return nil instead of error since we want to continue with normal reconciliation + } - if shouldVerifyWeight { - weightVerified, err := reconciler.VerifyWeight(desiredWeight, weightDestinations...) - c.newStatus.Canary.Weights.Verified = weightVerified - if err != nil { - c.recorder.Warnf(c.rollout, record.EventOptions{EventReason: conditions.WeightVerifyErrorReason}, conditions.WeightVerifyErrorMessage, err) - return nil // return nil instead of error since we want to continue with normal reconciliation - } - if weightVerified != nil { - if *weightVerified { - c.log.Infof("Desired weight (stepIdx: %d) %d verified", *index, desiredWeight) - } else { - c.log.Infof("Desired weight (stepIdx: %d) %d not yet verified", *index, desiredWeight) - c.enqueueRolloutAfter(c.rollout, defaults.GetRolloutVerifyRetryInterval()) - } + var indexString string + if index != nil { + indexString = strconv.FormatInt(int64(*index), 10) + } else { + indexString = "n/a" + } + + if weightVerified != nil { + if *weightVerified { + c.log.Infof("Desired weight (stepIdx: %s) %d verified", indexString, desiredWeight) + } else { + c.log.Infof("Desired weight (stepIdx: %s) %d not yet verified", indexString, desiredWeight) + c.enqueueRolloutAfter(c.rollout, defaults.GetRolloutVerifyRetryInterval()) } } } diff --git a/rollout/trafficrouting/alb/alb.go b/rollout/trafficrouting/alb/alb.go index 55fd0b83be..62d1a465d4 100644 --- a/rollout/trafficrouting/alb/alb.go +++ b/rollout/trafficrouting/alb/alb.go @@ -5,6 +5,8 @@ import ( "fmt" "strconv" + rolloututil "github.com/argoproj/argo-rollouts/utils/rollout" + "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" @@ -117,7 +119,8 @@ func (r *Reconciler) SetHeaderRoute(headerRouting *v1alpha1.SetHeaderRoute) erro return nil } -func (r *Reconciler) shouldVerifyWeight() bool { +// Gets the controller configuration flag for verifying alb weights +func (r *Reconciler) getShouldVerifyWeightCfg() bool { if r.cfg.VerifyWeight != nil { return *r.cfg.VerifyWeight } @@ -125,13 +128,25 @@ func (r *Reconciler) shouldVerifyWeight() bool { } func (r *Reconciler) VerifyWeight(desiredWeight int32, additionalDestinations ...v1alpha1.WeightDestination) (*bool, error) { - if !r.shouldVerifyWeight() { + if !r.getShouldVerifyWeightCfg() { r.cfg.Status.ALB = nil return nil, nil } + + if !rolloututil.ShouldVerifyWeight(r.cfg.Rollout) { + // If we should not verify weight but the ALB status has not been set yet due to a Rollout resource just being + // installed in the cluster we want to actually run the rest of the function, so we do not return if + // r.cfg.Rollout.Status.ALB is nil. However, if we should not verify, and we have already updated the status once + // we return early to avoid calling AWS apis. + if r.cfg.Rollout.Status.ALB != nil { + return nil, nil + } + } + if r.cfg.Status.ALB == nil { r.cfg.Status.ALB = &v1alpha1.ALBStatus{} } + ctx := context.TODO() rollout := r.cfg.Rollout ingressName := rollout.Spec.Strategy.Canary.TrafficRouting.ALB.Ingress diff --git a/rollout/trafficrouting/alb/alb_test.go b/rollout/trafficrouting/alb/alb_test.go index e455926836..7e26f6f16e 100644 --- a/rollout/trafficrouting/alb/alb_test.go +++ b/rollout/trafficrouting/alb/alb_test.go @@ -463,6 +463,10 @@ func (f *fakeAWSClient) getAlbStatus() *v1alpha1.ALBStatus { func TestVerifyWeight(t *testing.T) { newFakeReconciler := func(status *v1alpha1.RolloutStatus) (*Reconciler, *fakeAWSClient) { ro := fakeRollout(STABLE_SVC, CANARY_SVC, nil, "ingress", 443) + ro.Status.StableRS = "a45fe23" + ro.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{ + SetWeight: pointer.Int32Ptr(10), + }} i := ingress("ingress", STABLE_SVC, CANARY_SVC, STABLE_SVC, 443, 5, ro.Name, false) i.Status.LoadBalancer = corev1.LoadBalancerStatus{ Ingress: []corev1.LoadBalancerIngress{ @@ -503,6 +507,29 @@ func TestVerifyWeight(t *testing.T) { assert.False(t, *weightVerified) } + // VeryifyWeight not needed + { + var status v1alpha1.RolloutStatus + r, _ := newFakeReconciler(&status) + status.StableRS = "" + r.cfg.Rollout.Status.StableRS = "" + weightVerified, err := r.VerifyWeight(10) + assert.NoError(t, err) + assert.False(t, *weightVerified) + } + + // VeryifyWeight that we do not need to verify weight and status.ALB is already set + { + var status v1alpha1.RolloutStatus + r, _ := newFakeReconciler(&status) + r.cfg.Rollout.Status.ALB = &v1alpha1.ALBStatus{} + r.cfg.Rollout.Status.CurrentStepIndex = nil + r.cfg.Rollout.Spec.Strategy.Canary.Steps = nil + weightVerified, err := r.VerifyWeight(10) + assert.NoError(t, err) + assert.Nil(t, weightVerified) + } + // LoadBalancer found, not at weight { var status v1alpha1.RolloutStatus @@ -642,6 +669,10 @@ func TestVerifyWeightWithAdditionalDestinations(t *testing.T) { } newFakeReconciler := func(status *v1alpha1.RolloutStatus) (*Reconciler, *fakeAWSClient) { ro := fakeRollout(STABLE_SVC, CANARY_SVC, nil, "ingress", 443) + ro.Status.StableRS = "a45fe23" + ro.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{ + SetWeight: pointer.Int32Ptr(10), + }} i := ingress("ingress", STABLE_SVC, CANARY_SVC, STABLE_SVC, 443, 0, ro.Name, false) i.Annotations["alb.ingress.kubernetes.io/actions.stable-svc"] = fmt.Sprintf(actionTemplateWithExperiments, CANARY_SVC, 443, 10, weightDestinations[0].ServiceName, 443, weightDestinations[0].Weight, weightDestinations[1].ServiceName, 443, weightDestinations[1].Weight, STABLE_SVC, 443, 85) diff --git a/rollout/trafficrouting_test.go b/rollout/trafficrouting_test.go index ac7d9b6516..abb0cc09f6 100644 --- a/rollout/trafficrouting_test.go +++ b/rollout/trafficrouting_test.go @@ -177,7 +177,7 @@ func TestRolloutUseDesiredWeight(t *testing.T) { return nil }) f.fakeTrafficRouting.On("SetHeaderRoute", mock.Anything, mock.Anything).Return(nil) - f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(true, nil) + f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) f.run(getKey(r2, t)) } @@ -226,7 +226,7 @@ func TestRolloutUseDesiredWeight100(t *testing.T) { return nil }) f.fakeTrafficRouting.On("SetHeaderRoute", mock.Anything, mock.Anything).Return(nil) - f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(true, nil) + f.fakeTrafficRouting.On("VerifyWeight", mock.Anything).Return(pointer.BoolPtr(true), nil) f.run(getKey(r2, t)) } @@ -723,7 +723,9 @@ func TestCanaryWithTrafficRoutingAddScaleDownDelay(t *testing.T) { f := newFixture(t) defer f.Close() - r1 := newCanaryRollout("foo", 1, nil, nil, pointer.Int32Ptr(1), intstr.FromInt(1), intstr.FromInt(1)) + r1 := newCanaryRollout("foo", 1, nil, []v1alpha1.CanaryStep{{ + SetWeight: pointer.Int32Ptr(10), + }}, pointer.Int32Ptr(0), intstr.FromInt(1), intstr.FromInt(1)) r1.Spec.Strategy.Canary.CanaryService = "canary" r1.Spec.Strategy.Canary.StableService = "stable" r1.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{ @@ -735,7 +737,6 @@ func TestCanaryWithTrafficRoutingAddScaleDownDelay(t *testing.T) { rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] r2 = updateCanaryRolloutStatus(r2, rs2PodHash, 2, 1, 2, false) r2.Status.ObservedGeneration = strconv.Itoa(int(r2.Generation)) - r2.Status.CurrentStepIndex = nil availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) _, r2.Status.Canary.Weights = calculateWeightStatus(r2, rs2PodHash, rs2PodHash, 0) @@ -763,7 +764,9 @@ func TestCanaryWithTrafficRoutingScaleDownLimit(t *testing.T) { inTheFuture := timeutil.MetaNow().Add(10 * time.Second).UTC().Format(time.RFC3339) - r1 := newCanaryRollout("foo", 1, nil, nil, pointer.Int32Ptr(1), intstr.FromInt(1), intstr.FromInt(1)) + r1 := newCanaryRollout("foo", 1, nil, []v1alpha1.CanaryStep{{ + SetWeight: pointer.Int32Ptr(10), + }}, pointer.Int32Ptr(1), intstr.FromInt(1), intstr.FromInt(1)) rs1 := newReplicaSetWithStatus(r1, 1, 1) rs1.Annotations[v1alpha1.DefaultReplicaSetScaleDownDeadlineAnnotationKey] = inTheFuture r1.Spec.Strategy.Canary.ScaleDownDelayRevisionLimit = pointer.Int32Ptr(1) diff --git a/utils/rollout/rolloututil.go b/utils/rollout/rolloututil.go index c9243c3215..0b7df7ff38 100644 --- a/utils/rollout/rolloututil.go +++ b/utils/rollout/rolloututil.go @@ -4,6 +4,8 @@ import ( "fmt" "strconv" + replicasetutil "github.com/argoproj/argo-rollouts/utils/replicaset" + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/utils/annotations" "github.com/argoproj/argo-rollouts/utils/conditions" @@ -179,3 +181,16 @@ func CanaryStepString(c v1alpha1.CanaryStep) string { } return "invalid" } + +// ShouldVerifyWeight We use this to test if we should verify weights because weight verification could involve +// API calls to the cloud provider which could incur rate limiting +func ShouldVerifyWeight(ro *v1alpha1.Rollout) bool { + currentStep, _ := replicasetutil.GetCurrentCanaryStep(ro) + // If we are in the middle of an update at a setWeight step, also perform weight verification. + // Note that we don't do this every reconciliation because weight verification typically involves + // API calls to the cloud provider which could incur rate limitingq + shouldVerifyWeight := ro.Status.StableRS != "" && + !IsFullyPromoted(ro) && + currentStep != nil && currentStep.SetWeight != nil + return shouldVerifyWeight +} diff --git a/utils/rollout/rolloututil_test.go b/utils/rollout/rolloututil_test.go index efb76af9a3..572bd1cb51 100644 --- a/utils/rollout/rolloututil_test.go +++ b/utils/rollout/rolloututil_test.go @@ -414,3 +414,21 @@ func TestIsUnpausing(t *testing.T) { assert.Equal(t, v1alpha1.RolloutPhaseProgressing, status) assert.Equal(t, "waiting for rollout to unpause", message) } + +func TestShouldVerifyWeight(t *testing.T) { + ro := newCanaryRollout() + ro.Status.StableRS = "34feab23f" + ro.Status.CurrentStepIndex = pointer.Int32Ptr(0) + ro.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{ + SetWeight: pointer.Int32Ptr(20), + }} + assert.Equal(t, true, ShouldVerifyWeight(ro)) + + ro.Status.StableRS = "" + assert.Equal(t, false, ShouldVerifyWeight(ro)) + + ro.Status.StableRS = "34feab23f" + ro.Status.CurrentStepIndex = nil + ro.Spec.Strategy.Canary.Steps = nil + assert.Equal(t, false, ShouldVerifyWeight(ro)) +} From bb54a0795d87b01c4b0f7d902036e4f069cd82c7 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Fri, 22 Jul 2022 18:40:57 -0500 Subject: [PATCH 156/175] fix: remove metrics when objects are removed from cluster to prevent build up (#2115) * fix: remove metrics on resource removal Signed-off-by: zachaller * Add test Signed-off-by: zachaller * More tests Signed-off-by: zachaller * back off deps updates Signed-off-by: zachaller * Fix dep change Signed-off-by: zachaller * upgrade prom deps for new features Signed-off-by: zachaller * fix deps Signed-off-by: zachaller --- analysis/controller.go | 11 ++++- controller/metrics/analysis_test.go | 8 ++-- controller/metrics/client_test.go | 4 +- controller/metrics/experiment_test.go | 6 ++- controller/metrics/metrics.go | 47 ++++++++++++++++++++ controller/metrics/metrics_test.go | 36 ++++++++++++--- controller/metrics/rollout_test.go | 6 +-- experiments/controller.go | 5 +++ go.mod | 18 ++++---- go.sum | 30 +++++-------- metricproviders/prometheus/mock_test.go | 4 +- rollout/controller.go | 1 + test/e2e/analysis_test.go | 1 + test/fixtures/e2e_suite.go | 4 +- test/fixtures/when.go | 30 +++++++++---- utils/defaults/defaults.go | 14 ++++++ utils/defaults/defaults_test.go | 4 ++ utils/unstructured/unstructured.go | 18 ++++++++ utils/unstructured/unstructured_test.go | 58 +++++++++++++++++++++++-- 19 files changed, 247 insertions(+), 58 deletions(-) diff --git a/analysis/controller.go b/analysis/controller.go index 2be67de829..285cd1ff13 100644 --- a/analysis/controller.go +++ b/analysis/controller.go @@ -3,6 +3,8 @@ package analysis import ( "time" + unstructuredutil "github.com/argoproj/argo-rollouts/utils/unstructured" + log "github.com/sirupsen/logrus" batchv1 "k8s.io/api/batch/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" @@ -117,7 +119,14 @@ func NewController(cfg ControllerConfig) *Controller { UpdateFunc: func(old, new interface{}) { controller.enqueueAnalysis(new) }, - DeleteFunc: controller.enqueueAnalysis, + DeleteFunc: func(obj interface{}) { + controller.enqueueAnalysis(obj) + if ar := unstructuredutil.ObjectToAnalysisRun(obj); ar != nil { + logCtx := logutil.WithAnalysisRun(ar) + logCtx.Info("analysis run deleted") + controller.metricsServer.Remove(ar.Namespace, ar.Name, logutil.AnalysisRunKey) + } + }, }) return controller } diff --git a/controller/metrics/analysis_test.go b/controller/metrics/analysis_test.go index 992be05c9f..61ca87a80f 100644 --- a/controller/metrics/analysis_test.go +++ b/controller/metrics/analysis_test.go @@ -5,6 +5,8 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/ghodss/yaml" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -162,7 +164,7 @@ func testAnalysisRunDescribe(t *testing.T, fakeAnalysisRun string, expectedRespo registry.MustRegister(NewAnalysisRunCollector(serverCfg.AnalysisRunLister, serverCfg.AnalysisTemplateLister, serverCfg.ClusterAnalysisTemplateLister)) mux := http.NewServeMux() mux.Handle(MetricsPath, promhttp.HandlerFor(registry, promhttp.HandlerOpts{})) - testHttpResponse(t, mux, expectedResponse) + testHttpResponse(t, mux, expectedResponse, assert.Contains) } func TestIncAnalysisRunReconcile(t *testing.T) { @@ -184,7 +186,7 @@ analysis_run_reconcile_count{name="ar-test",namespace="ar-namespace"} 1` }, } metricsServ.IncAnalysisRunReconcile(ar, time.Millisecond) - testHttpResponse(t, metricsServ.Handler, expectedResponse) + testHttpResponse(t, metricsServ.Handler, expectedResponse, assert.Contains) } func TestAnalysisTemplateDescribe(t *testing.T) { @@ -206,5 +208,5 @@ analysis_template_metric_info{metric="web-metric-2",name="http-benchmark-test",n registry.MustRegister(NewAnalysisRunCollector(serverCfg.AnalysisRunLister, serverCfg.AnalysisTemplateLister, serverCfg.ClusterAnalysisTemplateLister)) mux := http.NewServeMux() mux.Handle(MetricsPath, promhttp.HandlerFor(registry, promhttp.HandlerOpts{})) - testHttpResponse(t, mux, expectedResponse) + testHttpResponse(t, mux, expectedResponse, assert.Contains) } diff --git a/controller/metrics/client_test.go b/controller/metrics/client_test.go index 9aedd570d1..0ebf470a68 100644 --- a/controller/metrics/client_test.go +++ b/controller/metrics/client_test.go @@ -3,6 +3,8 @@ package metrics import ( "testing" + "github.com/stretchr/testify/assert" + "github.com/argoproj/pkg/kubeclientmetrics" ) @@ -24,5 +26,5 @@ func TestIncKubernetesRequest(t *testing.T) { Verb: kubeclientmetrics.Unknown, StatusCode: 200, }) - testHttpResponse(t, metricsServ.Handler, expectedKubernetesRequest) + testHttpResponse(t, metricsServ.Handler, expectedKubernetesRequest, assert.Contains) } diff --git a/controller/metrics/experiment_test.go b/controller/metrics/experiment_test.go index fa4482bf87..da050e9377 100644 --- a/controller/metrics/experiment_test.go +++ b/controller/metrics/experiment_test.go @@ -5,6 +5,8 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/ghodss/yaml" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -133,7 +135,7 @@ func testExperimentDescribe(t *testing.T, fakeExperiment string, expectedRespons registry.MustRegister(NewExperimentCollector(config.ExperimentLister)) mux := http.NewServeMux() mux.Handle(MetricsPath, promhttp.HandlerFor(registry, promhttp.HandlerOpts{})) - testHttpResponse(t, mux, expectedResponse) + testHttpResponse(t, mux, expectedResponse, assert.Contains) } func TestIncExperimentReconcile(t *testing.T) { @@ -156,5 +158,5 @@ experiment_reconcile_count{name="ex-test",namespace="ex-namespace"} 1` }, } metricsServ.IncExperimentReconcile(ex, time.Millisecond) - testHttpResponse(t, metricsServ.Handler, expectedResponse) + testHttpResponse(t, metricsServ.Handler, expectedResponse, assert.Contains) } diff --git a/controller/metrics/metrics.go b/controller/metrics/metrics.go index b5940bc61f..3c3bbfe246 100644 --- a/controller/metrics/metrics.go +++ b/controller/metrics/metrics.go @@ -4,6 +4,8 @@ import ( "net/http" "time" + "github.com/argoproj/argo-rollouts/utils/defaults" + "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" registry "k8s.io/component-base/metrics/legacyregistry" @@ -136,6 +138,51 @@ func (m *MetricsServer) IncError(namespace, name string, kind string) { } } +// Remove removes the metrics server from the registry +func (m *MetricsServer) Remove(namespace string, name string, kind string) { + go func(namespace string, name string, kind string) { + // wait for the metrics to be collected, prometheus scrape interval is 60 seconds by default + time.Sleep(defaults.GetMetricCleanupDelaySeconds()) + switch kind { + case log.RolloutKey: + m.reconcileRolloutHistogram.Delete(map[string]string{"namespace": namespace, "name": name}) + m.errorRolloutCounter.Delete(map[string]string{"namespace": namespace, "name": name}) + + m.successNotificationCounter.DeletePartialMatch(map[string]string{"namespace": namespace, "name": name}) + m.errorNotificationCounter.DeletePartialMatch(map[string]string{"namespace": namespace, "name": name}) + m.sendNotificationRunHistogram.DeletePartialMatch(map[string]string{"namespace": namespace, "name": name}) + + MetricRolloutReconcile.Delete(map[string]string{"namespace": namespace, "name": name}) + + MetricRolloutReconcileError.Delete(map[string]string{"namespace": namespace, "name": name}) + + MetricRolloutEventsTotal.DeletePartialMatch(map[string]string{"namespace": namespace, "name": name}) + case log.AnalysisRunKey: + m.reconcileAnalysisRunHistogram.Delete(map[string]string{"namespace": namespace, "name": name}) + m.errorAnalysisRunCounter.Delete(map[string]string{"namespace": namespace, "name": name}) + + m.successNotificationCounter.DeletePartialMatch(map[string]string{"namespace": namespace, "name": name}) + m.errorNotificationCounter.DeletePartialMatch(map[string]string{"namespace": namespace, "name": name}) + m.sendNotificationRunHistogram.DeletePartialMatch(map[string]string{"namespace": namespace, "name": name}) + + MetricAnalysisRunReconcile.Delete(map[string]string{"namespace": namespace, "name": name}) + MetricAnalysisRunReconcileError.Delete(map[string]string{"namespace": namespace, "name": name}) + + case log.ExperimentKey: + m.reconcileExperimentHistogram.Delete(map[string]string{"namespace": namespace, "name": name}) + m.errorExperimentCounter.Delete(map[string]string{"namespace": namespace, "name": name}) + + m.successNotificationCounter.DeletePartialMatch(map[string]string{"namespace": namespace, "name": name}) + m.errorNotificationCounter.DeletePartialMatch(map[string]string{"namespace": namespace, "name": name}) + m.sendNotificationRunHistogram.DeletePartialMatch(map[string]string{"namespace": namespace, "name": name}) + + MetricExperimentReconcile.Delete(map[string]string{"namespace": namespace, "name": name}) + MetricExperimentReconcileError.Delete(map[string]string{"namespace": namespace, "name": name}) + } + }(namespace, name, kind) + +} + func boolFloat64(b bool) float64 { if b { return 1 diff --git a/controller/metrics/metrics_test.go b/controller/metrics/metrics_test.go index 098d576702..22d671cee1 100644 --- a/controller/metrics/metrics_test.go +++ b/controller/metrics/metrics_test.go @@ -7,7 +7,9 @@ import ( "net/http/httptest" "strings" "testing" + "time" + "github.com/argoproj/argo-rollouts/utils/defaults" "github.com/stretchr/testify/assert" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/tools/cache" @@ -52,7 +54,7 @@ func newFakeServerConfig(objs ...runtime.Object) ServerConfig { } } -func testHttpResponse(t *testing.T, handler http.Handler, expectedResponse string) { +func testHttpResponse(t *testing.T, handler http.Handler, expectedResponse string, testFunc func(t assert.TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) bool) { t.Helper() req, err := http.NewRequest("GET", "/metrics", nil) assert.NoError(t, err) @@ -62,7 +64,7 @@ func testHttpResponse(t *testing.T, handler http.Handler, expectedResponse strin body := rr.Body.String() log.Println(body) for _, line := range strings.Split(expectedResponse, "\n") { - assert.Contains(t, body, line) + testFunc(t, body, line) } } @@ -77,6 +79,7 @@ func TestIncError(t *testing.T) { analysis_run_reconcile_error{name="name",namespace="ns"} 1 # HELP experiment_reconcile_error Error occurring during the experiment # TYPE experiment_reconcile_error counter +experiment_reconcile_error{name="name",namespace="ns"} 1 # HELP rollout_reconcile_error Error occurring during the rollout # TYPE rollout_reconcile_error counter rollout_reconcile_error{name="name",namespace="ns"} 1` @@ -86,19 +89,42 @@ rollout_reconcile_error{name="name",namespace="ns"} 1` metricsServ.IncError("ns", "name", logutil.AnalysisRunKey) metricsServ.IncError("ns", "name", logutil.ExperimentKey) metricsServ.IncError("ns", "name", logutil.RolloutKey) - testHttpResponse(t, metricsServ.Handler, expectedResponse) + testHttpResponse(t, metricsServ.Handler, expectedResponse, assert.Contains) } func TestVersionInfo(t *testing.T) { expectedResponse := `# HELP argo_rollouts_controller_info Running Argo-rollouts version # TYPE argo_rollouts_controller_info gauge` metricsServ := NewMetricsServer(newFakeServerConfig(), true) - testHttpResponse(t, metricsServ.Handler, expectedResponse) + testHttpResponse(t, metricsServ.Handler, expectedResponse, assert.Contains) } func TestSecondaryMetricsServer(t *testing.T) { expectedResponse := `` metricsServ := NewMetricsServer(newFakeServerConfig(), false) - testHttpResponse(t, metricsServ.Handler, expectedResponse) + testHttpResponse(t, metricsServ.Handler, expectedResponse, assert.Contains) +} + +func TestRemove(t *testing.T) { + defaults.SetMetricCleanupDelaySeconds(1) + + expectedResponse := `analysis_run_reconcile_error{name="name1",namespace="ns"} 1 +experiment_reconcile_error{name="name1",namespace="ns"} 1 +rollout_reconcile_error{name="name1",namespace="ns"} 1` + + metricsServ := NewMetricsServer(newFakeServerConfig(), true) + + metricsServ.IncError("ns", "name1", logutil.RolloutKey) + metricsServ.IncError("ns", "name1", logutil.AnalysisRunKey) + metricsServ.IncError("ns", "name1", logutil.ExperimentKey) + testHttpResponse(t, metricsServ.Handler, expectedResponse, assert.Contains) + + metricsServ.Remove("ns", "name1", logutil.AnalysisRunKey) + metricsServ.Remove("ns", "name1", logutil.ExperimentKey) + metricsServ.Remove("ns", "name1", logutil.RolloutKey) + + //Sleep for 2x the cleanup delay to allow metrics to be removed + time.Sleep(defaults.GetMetricCleanupDelaySeconds() * 2) + testHttpResponse(t, metricsServ.Handler, expectedResponse, assert.NotContains) } diff --git a/controller/metrics/rollout_test.go b/controller/metrics/rollout_test.go index 1ff2495d14..b10af8b184 100644 --- a/controller/metrics/rollout_test.go +++ b/controller/metrics/rollout_test.go @@ -163,7 +163,7 @@ func testRolloutDescribe(t *testing.T, fakeRollout string, cond *v1alpha1.Rollou registry.MustRegister(NewRolloutCollector(config.RolloutLister)) mux := http.NewServeMux() mux.Handle(MetricsPath, promhttp.HandlerFor(registry, promhttp.HandlerOpts{})) - testHttpResponse(t, mux, expectedResponse) + testHttpResponse(t, mux, expectedResponse, assert.Contains) } func TestIncRolloutReconcile(t *testing.T) { @@ -188,7 +188,7 @@ rollout_reconcile_count{name="ro-test",namespace="ro-namespace"} 1 }, } metricsServ.IncRolloutReconcile(ro, time.Millisecond) - testHttpResponse(t, metricsServ.Handler, expectedResponse) + testHttpResponse(t, metricsServ.Handler, expectedResponse, assert.Contains) } func TestGetStrategyAndTrafficRouter(t *testing.T) { @@ -310,5 +310,5 @@ rollout_events_total{name="ro-test-2",namespace="ro-namespace",reason="BazEvent" MetricRolloutEventsTotal.WithLabelValues("ro-namespace", "ro-test-1", corev1.EventTypeNormal, "BarEvent").Inc() MetricRolloutEventsTotal.WithLabelValues("ro-namespace", "ro-test-2", corev1.EventTypeWarning, "BazEvent").Inc() MetricRolloutEventsTotal.WithLabelValues("ro-namespace", "ro-test-2", corev1.EventTypeWarning, "BazEvent").Inc() - testHttpResponse(t, metricsServ.Handler, expectedResponse) + testHttpResponse(t, metricsServ.Handler, expectedResponse, assert.Contains) } diff --git a/experiments/controller.go b/experiments/controller.go index 76d3841cc2..2b26005971 100644 --- a/experiments/controller.go +++ b/experiments/controller.go @@ -174,6 +174,11 @@ func NewController(cfg ControllerConfig) *Controller { controllerutil.Enqueue(obj, cfg.RolloutWorkQueue) } controllerutil.EnqueueParentObject(obj, register.RolloutKind, enqueueRollout) + if ex := unstructuredutil.ObjectToExperiment(obj); ex != nil { + logCtx := logutil.WithExperiment(ex) + logCtx.Info("experiment deleted") + controller.metricsServer.Remove(ex.Namespace, ex.Name, logutil.ExperimentKey) + } }, }) diff --git a/go.mod b/go.mod index 11388b57a3..92c90cf9f9 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 github.com/newrelic/newrelic-client-go v0.86.5 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.12.2 + github.com/prometheus/client_golang v1.12.2-0.20220620141757-4ad265f1b4ee github.com/prometheus/client_model v0.2.0 github.com/prometheus/common v0.36.0 github.com/servicemeshinterface/smi-sdk-go v0.5.0 @@ -145,15 +145,15 @@ require ( github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fastjson v1.6.3 // indirect - github.com/whilp/git-urls v1.0.0 // indirect - github.com/xlab/treeprint v1.1.0 // indirect - go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd // indirect - golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect + github.com/whilp/git-urls v0.0.0-20191001220047-6db9661140c0 // indirect + github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect + go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect + golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9 // indirect golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect - golang.org/x/net v0.0.0-20220708220712-1185a9018129 // indirect - golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 // indirect - golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e // indirect - golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect + golang.org/x/net v0.0.0-20220607020251-c690dde0001d // indirect + golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb // indirect + golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d // indirect + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect golang.org/x/tools v0.1.10 // indirect diff --git a/go.sum b/go.sum index 895aa0e1fe..47b4e85ccf 100644 --- a/go.sum +++ b/go.sum @@ -893,8 +893,8 @@ github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3O github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34= -github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.2-0.20220620141757-4ad265f1b4ee h1:8dyWwbEbKRZ13K6VEueQsOH2Ywu58j9YM/mn3bp50ww= +github.com/prometheus/client_golang v1.12.2-0.20220620141757-4ad265f1b4ee/go.mod h1:nDOYPpTKRWyFSHGWY5QbDUvjSMBusROfFzxhmDKUNWo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -907,6 +907,7 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= github.com/prometheus/common v0.36.0 h1:78hJTing+BLYLjhXE+Z2BubeEymH5Lr0/Mt8FKkxxYo= github.com/prometheus/common v0.36.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -1043,16 +1044,14 @@ github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYp github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/whilp/git-urls v0.0.0-20191001220047-6db9661140c0 h1:qqllXPzXh+So+mmANlX/gCJrgo+1kQyshMoQ+NASzm0= github.com/whilp/git-urls v0.0.0-20191001220047-6db9661140c0/go.mod h1:2rx5KE5FLD0HRfkkpyn8JwbVLBdhgeiOb2D2D9LLKM4= -github.com/whilp/git-urls v1.0.0 h1:95f6UMWN5FKW71ECsXRUd3FVYiXdrE7aX4NZKcPmIjU= -github.com/whilp/git-urls v1.0.0/go.mod h1:J16SAmobsqc3Qcy98brfl5f5+e0clUvg1krgwk/qCfE= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= -github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= -github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1092,9 +1091,8 @@ go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= -go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd h1:Uo/x0Ir5vQJ+683GXB9Ug+4fcjsbp7z7Ul8UaZbhsRM= -go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= @@ -1126,9 +1124,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9 h1:NUzdAbFtCJSXU20AOXgeqaUwg8Ypg4MPYmL+d+rsB5c= golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1243,10 +1240,8 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220513224357-95641704303c/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220708220712-1185a9018129 h1:vucSRfWwTsoXro7P+3Cjlr6flUMtzCwzlvkxEQtHHB0= -golang.org/x/net v0.0.0-20220708220712-1185a9018129/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1269,9 +1264,8 @@ golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb h1:8tDJ3aechhddbdPAxpycgXHJRMLpk/Ab+aa4OgdN5/g= golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 h1:VnGaRqoLmqZH/3TMLJwYCEWkR4j1nuIU1U9TvbqsDUw= -golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1399,15 +1393,13 @@ golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d h1:Zu/JngovGLVi6t2J3nmAf3AoTDwuzw85YZ3b9o4yU7s= golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e h1:NHvCuwuS43lGnYhten69ZWqi2QOj/CiDNcKbVqwVoew= -golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM= -golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/metricproviders/prometheus/mock_test.go b/metricproviders/prometheus/mock_test.go index ae833b8074..e16a42902d 100644 --- a/metricproviders/prometheus/mock_test.go +++ b/metricproviders/prometheus/mock_test.go @@ -19,7 +19,7 @@ func (m mockAPI) WalReplay(ctx context.Context) (v1.WalReplayStatus, error) { } // Query performs a query for the given time. -func (m mockAPI) Query(ctx context.Context, query string, ts time.Time) (model.Value, v1.Warnings, error) { +func (m mockAPI) Query(ctx context.Context, query string, ts time.Time, opt ...v1.Option) (model.Value, v1.Warnings, error) { if m.err != nil { return nil, m.warnings, m.err } @@ -48,7 +48,7 @@ func (m mockAPI) LabelValues(ctx context.Context, label string, matches []string panic("Not used") } -func (m mockAPI) QueryRange(ctx context.Context, query string, r v1.Range) (model.Value, v1.Warnings, error) { +func (m mockAPI) QueryRange(ctx context.Context, query string, r v1.Range, opt ...v1.Option) (model.Value, v1.Warnings, error) { panic("Not used") } diff --git a/rollout/controller.go b/rollout/controller.go index 827c7a7a20..84d0b8e4ca 100644 --- a/rollout/controller.go +++ b/rollout/controller.go @@ -245,6 +245,7 @@ func NewController(cfg ControllerConfig) *Controller { if ro := unstructuredutil.ObjectToRollout(obj); ro != nil { logCtx := logutil.WithRollout(ro) logCtx.Info("rollout deleted") + controller.metricsServer.Remove(ro.Namespace, ro.Name, logutil.RolloutKey) // Rollout is deleted, queue up the referenced Service and/or DestinationRules so // that the rollouts-pod-template-hash can be cleared from each for _, s := range serviceutil.GetRolloutServiceKeys(ro) { diff --git a/test/e2e/analysis_test.go b/test/e2e/analysis_test.go index c5ee4f8e55..13b6d19b60 100644 --- a/test/e2e/analysis_test.go +++ b/test/e2e/analysis_test.go @@ -1,3 +1,4 @@ +//go:build e2e // +build e2e package e2e diff --git a/test/fixtures/e2e_suite.go b/test/fixtures/e2e_suite.go index f9ab48c1ee..6eb059b446 100644 --- a/test/fixtures/e2e_suite.go +++ b/test/fixtures/e2e_suite.go @@ -140,8 +140,8 @@ func (s *E2ESuite) SetupSuite() { restConfig, err := config.ClientConfig() s.CheckError(err) s.Common.kubernetesHost = restConfig.Host - restConfig.Burst = defaults.DefaultBurst - restConfig.QPS = defaults.DefaultQPS + restConfig.Burst = defaults.DefaultBurst * 2 + restConfig.QPS = defaults.DefaultQPS * 2 s.namespace, _, err = config.Namespace() s.CheckError(err) s.kubeClient, err = kubernetes.NewForConfig(restConfig) diff --git a/test/fixtures/when.go b/test/fixtures/when.go index ea6d855e43..40998dc73f 100644 --- a/test/fixtures/when.go +++ b/test/fixtures/when.go @@ -452,10 +452,17 @@ func (w *When) DeleteRollout() *When { func (w *When) WaitForExperimentCondition(name string, test func(ex *rov1.Experiment) bool, condition string, timeout time.Duration) *When { start := time.Now() w.log.Infof("Waiting for Experiment %s condition: %s", name, condition) - opts := metav1.ListOptions{FieldSelector: fields.ParseSelectorOrDie(fmt.Sprintf("metadata.name=%s", name)).String()} - watch, err := w.rolloutClient.ArgoprojV1alpha1().Experiments(w.namespace).Watch(w.Context, opts) + exIf := w.dynamicClient.Resource(rov1.ExperimentGVR).Namespace(w.namespace) + ex, err := exIf.Get(w.Context, name, metav1.GetOptions{}) w.CheckError(err) - defer watch.Stop() + retryWatcher, err := watchutil.NewRetryWatcher(ex.GetResourceVersion(), &cache.ListWatch{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + opts := metav1.ListOptions{FieldSelector: fields.ParseSelectorOrDie(fmt.Sprintf("metadata.name=%s", name)).String()} + return w.rolloutClient.ArgoprojV1alpha1().Experiments(w.namespace).Watch(w.Context, opts) + }, + }) + w.CheckError(err) + defer retryWatcher.Stop() timeoutCh := make(chan bool, 1) go func() { time.Sleep(timeout) @@ -463,7 +470,7 @@ func (w *When) WaitForExperimentCondition(name string, test func(ex *rov1.Experi }() for { select { - case event := <-watch.ResultChan(): + case event := <-retryWatcher.ResultChan(): ex, ok := event.Object.(*rov1.Experiment) if ok { if test(ex) { @@ -482,10 +489,17 @@ func (w *When) WaitForExperimentCondition(name string, test func(ex *rov1.Experi func (w *When) WaitForAnalysisRunCondition(name string, test func(ar *rov1.AnalysisRun) bool, condition string, timeout time.Duration) *When { start := time.Now() w.log.Infof("Waiting for AnalysisRun %s condition: %s", name, condition) - opts := metav1.ListOptions{FieldSelector: fields.ParseSelectorOrDie(fmt.Sprintf("metadata.name=%s", name)).String()} - watch, err := w.rolloutClient.ArgoprojV1alpha1().AnalysisRuns(w.namespace).Watch(w.Context, opts) + arIf := w.dynamicClient.Resource(rov1.AnalysisRunGVR).Namespace(w.namespace) + ar, err := arIf.Get(w.Context, name, metav1.GetOptions{}) w.CheckError(err) - defer watch.Stop() + retryWatcher, err := watchutil.NewRetryWatcher(ar.GetResourceVersion(), &cache.ListWatch{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + opts := metav1.ListOptions{FieldSelector: fields.ParseSelectorOrDie(fmt.Sprintf("metadata.name=%s", name)).String()} + return w.rolloutClient.ArgoprojV1alpha1().AnalysisRuns(w.namespace).Watch(w.Context, opts) + }, + }) + w.CheckError(err) + defer retryWatcher.Stop() timeoutCh := make(chan bool, 1) go func() { time.Sleep(timeout) @@ -493,7 +507,7 @@ func (w *When) WaitForAnalysisRunCondition(name string, test func(ar *rov1.Analy }() for { select { - case event := <-watch.ResultChan(): + case event := <-retryWatcher.ResultChan(): ar, ok := event.Object.(*rov1.AnalysisRun) if ok { if test(ar) { diff --git a/utils/defaults/defaults.go b/utils/defaults/defaults.go index 79e208671f..c38a044c25 100644 --- a/utils/defaults/defaults.go +++ b/utils/defaults/defaults.go @@ -42,6 +42,9 @@ const ( DefaultBurst int = 80 // DefaultAwsLoadBalancerPageSize is the default page size used when calling aws to get load balancers by DNS name DefaultAwsLoadBalancerPageSize = int32(300) + // DefaultMetricCleanupDelay is the default time to delay metrics removal upon object removal, gives time for metrics + // to be collected + DefaultMetricCleanupDelay = int32(65) ) const ( @@ -62,6 +65,7 @@ var ( smiAPIVersion = DefaultSMITrafficSplitVersion targetGroupBindingAPIVersion = DefaultTargetGroupBindingAPIVersion appmeshCRDVersion = DefaultAppMeshCRDVersion + defaultMetricCleanupDelay = DefaultMetricCleanupDelay ) const ( @@ -296,3 +300,13 @@ func GetTargetGroupBindingAPIVersion() string { func GetRolloutVerifyRetryInterval() time.Duration { return rolloutVerifyRetryInterval } + +// GetMetricCleanupDelaySeconds returns the duration to delay the cleanup of metrics +func GetMetricCleanupDelaySeconds() time.Duration { + return time.Duration(defaultMetricCleanupDelay) * time.Second +} + +// SetMetricCleanupDelaySeconds sets the metric cleanup delay in seconds +func SetMetricCleanupDelaySeconds(seconds int32) { + defaultMetricCleanupDelay = seconds +} diff --git a/utils/defaults/defaults_test.go b/utils/defaults/defaults_test.go index f5a429f202..d099cc0343 100644 --- a/utils/defaults/defaults_test.go +++ b/utils/defaults/defaults_test.go @@ -402,4 +402,8 @@ func TestSetDefaults(t *testing.T) { SetAppMeshCRDVersion("v1beta3") assert.Equal(t, "v1beta3", GetAppMeshCRDVersion()) SetAppMeshCRDVersion(DefaultAmbassadorVersion) + + assert.Equal(t, DefaultMetricCleanupDelay, int32(GetMetricCleanupDelaySeconds().Seconds())) + SetMetricCleanupDelaySeconds(24) + assert.Equal(t, time.Duration(24)*time.Second, GetMetricCleanupDelaySeconds()) } diff --git a/utils/unstructured/unstructured.go b/utils/unstructured/unstructured.go index e92fb00e81..12e1034755 100644 --- a/utils/unstructured/unstructured.go +++ b/utils/unstructured/unstructured.go @@ -67,6 +67,24 @@ func ObjectToAnalysisRun(obj interface{}) *v1alpha1.AnalysisRun { return ar } +func ObjectToExperiment(obj interface{}) *v1alpha1.Experiment { + un, ok := obj.(*unstructured.Unstructured) + if ok { + var ex v1alpha1.Experiment + err := runtime.DefaultUnstructuredConverter.FromUnstructured(un.Object, &ex) + if err != nil { + log.Warnf("Failed to convert Experiment from Unstructured object: %v", err) + return nil + } + return &ex + } + ex, ok := obj.(*v1alpha1.Experiment) + if !ok { + log.Warn("Object is neither a rollout or unstructured") + } + return ex +} + var diffSeparator = regexp.MustCompile(`\n---`) // SplitYAML splits a YAML file into unstructured objects. Returns list of all unstructured objects diff --git a/utils/unstructured/unstructured_test.go b/utils/unstructured/unstructured_test.go index 5472646130..1dd9562c2c 100644 --- a/utils/unstructured/unstructured_test.go +++ b/utils/unstructured/unstructured_test.go @@ -155,11 +155,63 @@ spec: obj, err := StrToUnstructured(arYAML) assert.NotNil(t, obj) assert.NoError(t, err) - ar := ObjectToRollout(obj) + ar := ObjectToAnalysisRun(obj) assert.NotNil(t, ar) - ar2 := ObjectToRollout(ar) + ar2 := ObjectToAnalysisRun(ar) assert.Equal(t, ar, ar2) var invalid struct{} - ar3 := ObjectToRollout(&invalid) + ar3 := ObjectToAnalysisRun(&invalid) assert.Nil(t, ar3) } + +func TestObjectToExpirment(t *testing.T) { + exYAML := ` +apiVersion: argoproj.io/v1alpha1 +kind: Experiment +metadata: + name: experiment-with-analysis +spec: + templates: + - name: purple + selector: + matchLabels: + app: rollouts-demo + template: + metadata: + labels: + app: rollouts-demo + spec: + containers: + - name: rollouts-demo + image: argoproj/rollouts-demo:purple + imagePullPolicy: Always + - name: orange + selector: + matchLabels: + app: rollouts-demo + template: + metadata: + labels: + app: rollouts-demo + spec: + containers: + - name: rollouts-demo + image: argoproj/rollouts-demo:orange + imagePullPolicy: Always + analyses: + - name: random-fail + templateName: random-fail + - name: pass + templateName: pass +` + obj, err := StrToUnstructured(exYAML) + assert.NotNil(t, obj) + assert.NoError(t, err) + ex := ObjectToExperiment(obj) + assert.NotNil(t, ex) + ex2 := ObjectToExperiment(ex) + assert.Equal(t, ex, ex2) + var invalid struct{} + ex3 := ObjectToExperiment(&invalid) + assert.Nil(t, ex3) +} From df528693d2bb6ba4af9810f68dcb0c6168e4ca38 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Fri, 22 Jul 2022 18:43:34 -0500 Subject: [PATCH 157/175] chore: use controler-gen for cluster analysis template scope (#2148) Signed-off-by: zachaller --- hack/gen-crd-spec/main.go | 6 ------ pkg/apis/rollouts/v1alpha1/analysis_types.go | 2 +- pkg/apis/rollouts/v1alpha1/generated.proto | 2 +- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/hack/gen-crd-spec/main.go b/hack/gen-crd-spec/main.go index 22b893c663..607f8ddd53 100644 --- a/hack/gen-crd-spec/main.go +++ b/hack/gen-crd-spec/main.go @@ -113,12 +113,6 @@ func NewCustomResourceDefinition() []*extensionsobj.CustomResourceDefinition { removeK8S118Fields(obj) createMetadataValidation(obj) crd := toCRD(obj) - - if crd.Name == "clusteranalysistemplates.argoproj.io" { - crd.Spec.Scope = "Cluster" - } else { - crd.Spec.Scope = "Namespaced" - } crds = append(crds, crd) } diff --git a/pkg/apis/rollouts/v1alpha1/analysis_types.go b/pkg/apis/rollouts/v1alpha1/analysis_types.go index c22fef2572..7d5931e458 100644 --- a/pkg/apis/rollouts/v1alpha1/analysis_types.go +++ b/pkg/apis/rollouts/v1alpha1/analysis_types.go @@ -13,7 +13,7 @@ import ( // +genclient // +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// +kubebuilder:resource:path=clusteranalysistemplates,shortName=cat +// +kubebuilder:resource:path=clusteranalysistemplates,shortName=cat,scope=Cluster // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time since resource was created" type ClusterAnalysisTemplate struct { metav1.TypeMeta `json:",inline"` diff --git a/pkg/apis/rollouts/v1alpha1/generated.proto b/pkg/apis/rollouts/v1alpha1/generated.proto index 480ccd1eec..2bdc40c2ec 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.proto +++ b/pkg/apis/rollouts/v1alpha1/generated.proto @@ -549,7 +549,7 @@ message CloudWatchMetricStatMetricDimension { // +genclient // +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// +kubebuilder:resource:path=clusteranalysistemplates,shortName=cat +// +kubebuilder:resource:path=clusteranalysistemplates,shortName=cat,scope=Cluster // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time since resource was created" message ClusterAnalysisTemplate { optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; From 709a709897c365bea1df1f1d2fcb826fb1e02f91 Mon Sep 17 00:00:00 2001 From: Rohit Agrawal Date: Mon, 25 Jul 2022 19:08:52 -0700 Subject: [PATCH 158/175] fix(analysis): Fix Analysis Terminal Decision For Dry-Run Metrics (#2131) Signed-off-by: Rohit Agrawal --- analysis/analysis_test.go | 8 ++++---- utils/analysis/helpers.go | 4 +++- utils/analysis/helpers_test.go | 14 ++++++++++++++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/analysis/analysis_test.go b/analysis/analysis_test.go index d4763f3e4b..30e3b7adb9 100644 --- a/analysis/analysis_test.go +++ b/analysis/analysis_test.go @@ -1500,7 +1500,7 @@ func TestAssessRunStatusErrorMessageAnalysisPhaseFail(t *testing.T) { func TestAssessRunStatusErrorMessageAnalysisPhaseFailInDryRunMode(t *testing.T) { status, message, dryRunSummary := StartAssessRunStatusErrorMessageAnalysisPhaseFail(t, true) - assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, status) + assert.Equal(t, v1alpha1.AnalysisPhaseRunning, status) assert.Equal(t, "", message) expectedDryRunSummary := v1alpha1.RunSummary{ Count: 2, @@ -1545,7 +1545,7 @@ func TestAssessRunStatusErrorMessageFromProvider(t *testing.T) { func TestAssessRunStatusErrorMessageFromProviderInDryRunMode(t *testing.T) { providerMessage := "Provider Error" status, message, dryRunSummary := StartAssessRunStatusErrorMessageFromProvider(t, providerMessage, true) - assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, status) + assert.Equal(t, v1alpha1.AnalysisPhaseRunning, status) assert.Equal(t, "", message) expectedDryRunSummary := v1alpha1.RunSummary{ Count: 2, @@ -1587,7 +1587,7 @@ func TestAssessRunStatusMultipleFailures(t *testing.T) { func TestAssessRunStatusMultipleFailuresInDryRunMode(t *testing.T) { status, message, dryRunSummary := StartAssessRunStatusMultipleFailures(t, true) - assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, status) + assert.Equal(t, v1alpha1.AnalysisPhaseRunning, status) assert.Equal(t, "", message) expectedDryRunSummary := v1alpha1.RunSummary{ Count: 2, @@ -1623,7 +1623,7 @@ func TestAssessRunStatusWorstMessageInReconcileAnalysisRun(t *testing.T) { func TestAssessRunStatusWorstMessageInReconcileAnalysisRunInDryRunMode(t *testing.T) { newRun := StartAssessRunStatusWorstMessageInReconcileAnalysisRun(t, true) - assert.Equal(t, v1alpha1.AnalysisPhaseSuccessful, newRun.Status.Phase) + assert.Equal(t, v1alpha1.AnalysisPhaseRunning, newRun.Status.Phase) assert.Equal(t, "", newRun.Status.Message) expectedDryRunSummary := v1alpha1.RunSummary{ Count: 2, diff --git a/utils/analysis/helpers.go b/utils/analysis/helpers.go index 64506ebae0..77583136af 100644 --- a/utils/analysis/helpers.go +++ b/utils/analysis/helpers.go @@ -87,7 +87,9 @@ func IsTerminating(run *v1alpha1.AnalysisRun) bool { for _, res := range run.Status.MetricResults { switch res.Phase { case v1alpha1.AnalysisPhaseFailed, v1alpha1.AnalysisPhaseError, v1alpha1.AnalysisPhaseInconclusive: - return true + // If this metric is running in the dryRun mode then we don't care about the failures and hence the terminal + // decision shouldn't be affected. + return !res.DryRun } } return false diff --git a/utils/analysis/helpers_test.go b/utils/analysis/helpers_test.go index c7bd003c18..f9baf89f14 100644 --- a/utils/analysis/helpers_test.go +++ b/utils/analysis/helpers_test.go @@ -62,20 +62,34 @@ func TestIsFastFailTerminating(t *testing.T) { Name: "success-rate", Phase: v1alpha1.AnalysisPhaseRunning, }, + { + Name: "dry-run-metric", + Phase: v1alpha1.AnalysisPhaseRunning, + DryRun: true, + }, }, }, } + // Verify that when the metric is not failing or in the error state then we don't terminate. successRate := run.Status.MetricResults[1] assert.False(t, IsTerminating(run)) + // Metric failing in the dryRun mode shouldn't impact the terminal decision. + dryRunMetricResult := run.Status.MetricResults[2] + dryRunMetricResult.Phase = v1alpha1.AnalysisPhaseError + run.Status.MetricResults[2] = dryRunMetricResult + assert.False(t, IsTerminating(run)) + // Verify that a wet run metric failure/error results in terminal decision. successRate.Phase = v1alpha1.AnalysisPhaseError run.Status.MetricResults[1] = successRate assert.True(t, IsTerminating(run)) successRate.Phase = v1alpha1.AnalysisPhaseFailed run.Status.MetricResults[1] = successRate assert.True(t, IsTerminating(run)) + // Verify that an inconclusive wet run metric results in terminal decision. successRate.Phase = v1alpha1.AnalysisPhaseInconclusive run.Status.MetricResults[1] = successRate assert.True(t, IsTerminating(run)) + // Verify that we don't terminate when there are no metric results or when the status is empty. run.Status.MetricResults = nil assert.False(t, IsTerminating(run)) run.Status = v1alpha1.AnalysisRunStatus{} From 03b0813832da48ee9ca079404df6a149a9f87c64 Mon Sep 17 00:00:00 2001 From: Leonardo Luz Almeida Date: Tue, 26 Jul 2022 18:24:21 -0400 Subject: [PATCH 159/175] docs: update release doc with brew formula details (#2165) Signed-off-by: Leonardo Luz Almeida --- docs/releasing.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/releasing.md b/docs/releasing.md index 4e5b527302..a72f1308e6 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -19,14 +19,15 @@ 1. Update Brew formula: + * Fork the repo https://github.com/argoproj/homebrew-tap + * Run the following commands to update the brew formula: ```bash - git clone git@github.com:argoproj/homebrew-tap.git cd homebrew-tap - git pull ./update.sh kubectl-argo-rollouts $VERSION git commit -am "Update kubectl-argo-rollouts to $VERSION" - git push ``` + * Create a PR with the modified files pointing to upstream/master + * Once the PR is approved by a maintainer, it can be merged. ### Verify From 9c87d0d189cb685794c067b12a4a06faac38fb37 Mon Sep 17 00:00:00 2001 From: Mike Ball Date: Wed, 27 Jul 2022 09:22:10 -0400 Subject: [PATCH 160/175] fix(docs) Graphite metrics provider linked in docs sidebar. Fixes #2102. (#2094) * Graphite metrics provider linked in docs sidebar This fixes an issue wherein the Graphite metrics provider has no sidebar link in the docs hosted at https://argoproj.github.io/argo-rollouts/. As a bonus, this also removes various trailing whitespace from analysis docs. Signed-off-by: Mike Ball * build trigger Signed-off-by: Mike Ball --- docs/analysis/cloudwatch.md | 2 +- docs/analysis/kayenta.md | 6 +++--- docs/analysis/newrelic.md | 2 +- docs/analysis/prometheus.md | 6 +++--- docs/analysis/wavefront.md | 1 - docs/analysis/web.md | 6 +++--- docs/index.md | 10 +++++----- mkdocs.yml | 1 + 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/analysis/cloudwatch.md b/docs/analysis/cloudwatch.md index 145fad6f8b..7bccbc2072 100644 --- a/docs/analysis/cloudwatch.md +++ b/docs/analysis/cloudwatch.md @@ -11,7 +11,7 @@ You can use CloudWatch Metrics if you have used to EKS or not. This analysis is ### EKS -If you create new cluster on EKS, you can attach [cluster IAM role](https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role.html) or attach [IAM roles for service accounts](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html). +If you create new cluster on EKS, you can attach [cluster IAM role](https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role.html) or attach [IAM roles for service accounts](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html). If you have already cluster on EKS, you can attach [IAM roles for service accounts](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html). ### not EKS diff --git a/docs/analysis/kayenta.md b/docs/analysis/kayenta.md index 907ed9196d..06cc91b02a 100644 --- a/docs/analysis/kayenta.md +++ b/docs/analysis/kayenta.md @@ -1,6 +1,6 @@ ## Kayenta (e.g. Mann-Whitney Analysis) -Analysis can also be done as part of an [Experiment](../features/experiment.md). +Analysis can also be done as part of an [Experiment](../features/experiment.md). This example starts both a canary and baseline ReplicaSet. The ReplicaSets run for 1 hour, then scale down to zero. Call out to Kayenta to perform Mann-Whintney analysis against the two pods. Demonstrates ability to start a @@ -23,7 +23,7 @@ This example demonstrates: app: guestbook spec: strategy: - canary: + canary: steps: - experiment: duration: 1h @@ -45,7 +45,7 @@ This example demonstrates: === "AnalysisTemplate" - ```yaml + ```yaml apiVersion: argoproj.io/v1alpha1 kind: AnalysisTemplate metadata: diff --git a/docs/analysis/newrelic.md b/docs/analysis/newrelic.md index de1153505d..b71b661f84 100644 --- a/docs/analysis/newrelic.md +++ b/docs/analysis/newrelic.md @@ -3,7 +3,7 @@ !!! important Available since v0.10.0 -A [New Relic](https://newrelic.com/) query using [NRQL](https://docs.newrelic.com/docs/query-your-data/nrql-new-relic-query-language/get-started/introduction-nrql-new-relics-query-language) can be used to obtain measurements for analysis. +A [New Relic](https://newrelic.com/) query using [NRQL](https://docs.newrelic.com/docs/query-your-data/nrql-new-relic-query-language/get-started/introduction-nrql-new-relics-query-language) can be used to obtain measurements for analysis. ```yaml apiVersion: argoproj.io/v1alpha1 diff --git a/docs/analysis/prometheus.md b/docs/analysis/prometheus.md index 56736f0257..a698626d10 100644 --- a/docs/analysis/prometheus.md +++ b/docs/analysis/prometheus.md @@ -23,7 +23,7 @@ spec: query: | sum(irate( istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code!~"5.*"}[5m] - )) / + )) / sum(irate( istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}"}[5m] )) @@ -36,5 +36,5 @@ See the [Analysis Overview page](../../features/analysis) for more details on th # Additional Metadata -Any additional metadata from the Prometheus controller, like the resolved queries after substituting the template's -arguments, etc. will appear under the `Metadata` map in the `MetricsResult` object of `AnalysisRun`. \ No newline at end of file +Any additional metadata from the Prometheus controller, like the resolved queries after substituting the template's +arguments, etc. will appear under the `Metadata` map in the `MetricsResult` object of `AnalysisRun`. diff --git a/docs/analysis/wavefront.md b/docs/analysis/wavefront.md index 7eb58863e2..f7c8f57d91 100644 --- a/docs/analysis/wavefront.md +++ b/docs/analysis/wavefront.md @@ -39,4 +39,3 @@ data: example1.wavefront.com: example2.wavefront.com: ``` - diff --git a/docs/analysis/web.md b/docs/analysis/web.md index e3e133cec0..285403ffe7 100644 --- a/docs/analysis/web.md +++ b/docs/analysis/web.md @@ -17,7 +17,7 @@ of the as the result variable. headers: - key: Authorization value: "Bearer {{ args.api-token }}" - jsonPath: "{$.data.ok}" + jsonPath: "{$.data.ok}" ``` In the following example, given the payload, the measurement will be Successful if the `data.ok` field was `true`, and the `data.successPercent` @@ -42,7 +42,7 @@ was greater than `0.90` headers: - key: Authorization value: "Bearer {{ args.api-token }}" - jsonPath: "{$.data}" + jsonPath: "{$.data}" ``` NOTE: if the result is a string, two convenience functions `asInt` and `asFloat` are provided @@ -67,7 +67,7 @@ It is possible to use a POST or PUT requests, by specifying the `method` and `bo - key: Content-Type # if body is a json, it is recommended to set the Content-Type value: "application/json" body: "{\"key\": \"string value\"}" - jsonPath: "{$.data.ok}" + jsonPath: "{$.data.ok}" ``` !!! tip In order to send in JSON, you have to encode it yourself, and send the correct Content-Type as well. diff --git a/docs/index.md b/docs/index.md index 2614a51e08..1ac7a815ba 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,7 +1,7 @@ # Argo Rollouts - Kubernetes Progressive Delivery Controller ## What is Argo Rollouts? -Argo Rollouts is a [Kubernetes controller](https://kubernetes.io/docs/concepts/architecture/controller/) and set of [CRDs](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) which provide advanced deployment capabilities such as blue-green, canary, canary analysis, experimentation, and progressive delivery features to Kubernetes. +Argo Rollouts is a [Kubernetes controller](https://kubernetes.io/docs/concepts/architecture/controller/) and set of [CRDs](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) which provide advanced deployment capabilities such as blue-green, canary, canary analysis, experimentation, and progressive delivery features to Kubernetes. Argo Rollouts (optionally) integrates with [ingress controllers](https://kubernetes.io/docs/concepts/services-networking/ingress/) and service meshes, leveraging their traffic shaping abilities to gradually shift traffic to the new version during an update. Additionally, Rollouts can query and interpret metrics from various providers to verify key KPIs and drive automated promotion or rollback during an update. @@ -39,12 +39,12 @@ kubectl create namespace argo-rollouts kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml ``` -Follow the full [getting started guide](getting-started.md) to walk through creating and then updating a rollout object. +Follow the full [getting started guide](getting-started.md) to walk through creating and then updating a rollout object. ## How does it work? -Similar to the [deployment object](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/), the Argo Rollouts controller will manage the creation, scaling, and deletion of [ReplicaSets](https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/). These ReplicaSets are defined by the `spec.template` field inside the Rollout resource, which uses the same pod template as the deployment object. +Similar to the [deployment object](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/), the Argo Rollouts controller will manage the creation, scaling, and deletion of [ReplicaSets](https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/). These ReplicaSets are defined by the `spec.template` field inside the Rollout resource, which uses the same pod template as the deployment object. -When the `spec.template` is changed, that signals to the Argo Rollouts controller that a new ReplicaSet will be introduced. The controller will use the strategy set within the `spec.strategy` field in order to determine how the rollout will progress from the old ReplicaSet to the new ReplicaSet. Once that new ReplicaSet is scaled up (and optionally passes an [Analysis](features/analysis/)), the controller will mark it as "stable". +When the `spec.template` is changed, that signals to the Argo Rollouts controller that a new ReplicaSet will be introduced. The controller will use the strategy set within the `spec.strategy` field in order to determine how the rollout will progress from the old ReplicaSet to the new ReplicaSet. Once that new ReplicaSet is scaled up (and optionally passes an [Analysis](features/analysis/)), the controller will mark it as "stable". If another change occurs in the `spec.template` during a transition from a stable ReplicaSet to a new ReplicaSet (i.e. you change the application version in the middle of a rollout), then the previously new ReplicaSet will be scaled down, and the controller will try to progress the ReplicasSet that reflects the updated `spec.template` field. There is more information on the behaviors of each strategy in the [spec](features/specification/) section. @@ -60,7 +60,7 @@ If another change occurs in the `spec.template` during a transition from a stabl - A user wants to use the normal Rolling Update strategy from the deployment. If a user uses the canary strategy with no steps, the rollout will use the max surge and max unavailable values to roll to the new version. ([example](https://github.com/argoproj/argo-rollouts/blob/master/examples/rollout-rolling-update.yaml)) -## Examples +## Examples You can see more examples of Rollouts at: diff --git a/mkdocs.yml b/mkdocs.yml index fbe3dcca09..a84ef3a807 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -55,6 +55,7 @@ nav: - Web: analysis/web.md - Kayenta: analysis/kayenta.md - CloudWatch: analysis/cloudwatch.md + - Graphite: analysis/graphite.md - InfluxDB: analysis/influxdb.md - Experiments: features/experiment.md - Notifications: From 0b022eead59ed89744f4eebd7558be67363a543e Mon Sep 17 00:00:00 2001 From: cskh Date: Wed, 27 Jul 2022 10:13:38 -0400 Subject: [PATCH 161/175] feat: emit rollout delete event (#1893) Signed-off-by: Hui Kang Co-authored-by: Hui Kang --- rollout/controller.go | 1 + utils/conditions/conditions.go | 3 +++ 2 files changed, 4 insertions(+) diff --git a/rollout/controller.go b/rollout/controller.go index 84d0b8e4ca..eaece46ce7 100644 --- a/rollout/controller.go +++ b/rollout/controller.go @@ -254,6 +254,7 @@ func NewController(cfg ControllerConfig) *Controller { for _, key := range istioutil.GetRolloutDesinationRuleKeys(ro) { controller.IstioController.EnqueueDestinationRule(key) } + controller.recorder.Eventf(ro, record.EventOptions{EventReason: conditions.RolloutDeletedReason}, conditions.RolloutDeletedMessage, ro.Name, ro.Namespace) } }, }) diff --git a/utils/conditions/conditions.go b/utils/conditions/conditions.go index 03341742f5..99b6d59ddf 100644 --- a/utils/conditions/conditions.go +++ b/utils/conditions/conditions.go @@ -129,6 +129,9 @@ const ( // within the given deadline (progressDeadlineSeconds). RolloutTimeOutMessage = "Rollout %q has timed out progressing." + RolloutDeletedReason = "RolloutDeleted" + RolloutDeletedMessage = "Rollout %s/%s is deleted." + ScalingReplicaSetReason = "ScalingReplicaSet" ScalingReplicaSetMessage = "Scaled %s ReplicaSet %s (revision %d) from %d to %d" From 3329626785c8030221496ad8b46f7feaa62a1b5d Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Wed, 27 Jul 2022 13:14:14 -0500 Subject: [PATCH 162/175] chore: Upgrade golang (#2160) * Upgrade golang Signed-off-by: zachaller * upgrade golang to 1.18 for e2e Signed-off-by: zachaller * Fix deps Signed-off-by: zachaller * Update build action Signed-off-by: zachaller * Upgrade push action Signed-off-by: zachaller * Update docker file Signed-off-by: zachaller * Bump golang lint to match Signed-off-by: zachaller * fix go.mod Signed-off-by: zachaller --- .github/workflows/docker-publish.yml | 6 ++-- .github/workflows/e2e.yaml | 2 +- .github/workflows/gh-pages.yaml | 2 +- .github/workflows/go.yml | 4 +-- .github/workflows/release.yaml | 2 +- Dockerfile | 6 ++-- go.mod | 2 +- go.sum | 33 --------------------- hack/installers/install-codegen-go-tools.sh | 2 +- metricproviders/mocks/Provider.go | 17 ++++++++++- rollout/mocks/TrafficRoutingReconciler.go | 17 ++++++++++- utils/aws/mocks/ELBv2APIClient.go | 17 ++++++++++- 12 files changed, 61 insertions(+), 49 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index a7c8e55a75..0299f089a0 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -21,7 +21,7 @@ jobs: uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2 with: config-inline: | [worker.oci] @@ -79,14 +79,14 @@ jobs: echo "::set-output name=platform-matrix::$PLATFORM_MATRIX" - name: Build and push (controller-image) - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v3 with: platforms: ${{ steps.platform-matrix.outputs.platform-matrix }} push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.controller-meta.outputs.tags }} - name: Build and push (plugin-image) - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v3 with: target: kubectl-argo-rollouts platforms: ${{ steps.platform-matrix.outputs.platform-matrix }} diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index f65aeac991..8f933b5bbd 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -37,7 +37,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.17 + go-version: 1.18 - uses: actions/checkout@v2 - name: Setup k3s run: | diff --git a/.github/workflows/gh-pages.yaml b/.github/workflows/gh-pages.yaml index 00dd5adaac..3b054e9d82 100644 --- a/.github/workflows/gh-pages.yaml +++ b/.github/workflows/gh-pages.yaml @@ -21,7 +21,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.17 + go-version: 1.18 - name: build run: | pip install mkdocs mkdocs_material diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 19925d9628..ff2d356420 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -9,7 +9,7 @@ on: - "master" env: # Golang version to use across CI steps - GOLANG_VERSION: '1.17' + GOLANG_VERSION: '1.18' concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -38,7 +38,7 @@ jobs: - name: Run golangci-lint uses: golangci/golangci-lint-action@v3 with: - version: v1.45.2 + version: v1.47.2 args: --timeout 5m build: name: Build diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 5a2336a5f7..a5f37f1f8e 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -106,7 +106,7 @@ jobs: - name: Setup Golang uses: actions/setup-go@v2 with: - go-version: 1.17 + go-version: 1.18 - name: Generate release artifacts run: | diff --git a/Dockerfile b/Dockerfile index 9865e51415..19553e355e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ # Initial stage which pulls prepares build dependencies and CLI tooling we need for our final image # Also used as the image in CI jobs so needs all dependencies #################################################################################################### -FROM --platform=$BUILDPLATFORM golang:1.17 as builder +FROM --platform=$BUILDPLATFORM golang:1.18 as builder RUN apt-get update && apt-get install -y \ wget \ @@ -12,7 +12,7 @@ RUN apt-get update && apt-get install -y \ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* # Install golangci-lint -RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.44.0 && \ +RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.47.2 && \ golangci-lint linters COPY .golangci.yml ${GOPATH}/src/dummy/.golangci.yml @@ -40,7 +40,7 @@ RUN NODE_ENV='production' yarn build #################################################################################################### # Rollout Controller Build stage which performs the actual build of argo-rollouts binaries #################################################################################################### -FROM --platform=$BUILDPLATFORM golang:1.17 as argo-rollouts-build +FROM --platform=$BUILDPLATFORM golang:1.18 as argo-rollouts-build WORKDIR /go/src/github.com/argoproj/argo-rollouts diff --git a/go.mod b/go.mod index 92c90cf9f9..ca2591fc13 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/argoproj/argo-rollouts -go 1.17 +go 1.18 require ( github.com/antonmedv/expr v1.9.0 diff --git a/go.sum b/go.sum index 47b4e85ccf..a2f53996ca 100644 --- a/go.sum +++ b/go.sum @@ -30,7 +30,6 @@ cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Ud cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.102.0 h1:DAq3r8y4mDgyB/ZPJ9v/5VJNqjgJAxTn6ZYLlUywOu8= cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= @@ -203,7 +202,6 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= @@ -277,7 +275,6 @@ github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14y github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= -github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= github.com/deepmap/oapi-codegen v1.11.0 h1:f/X2NdIkaBKsSdpeuwLnY/vDI0AtPUrmB5LMgc7YD+A= github.com/deepmap/oapi-codegen v1.11.0/go.mod h1:k+ujhoQGxmQYBZBbxhOZNZf4j08qv5mC+OH+fFTnKxM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -295,10 +292,7 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20220417044921-416226498f94 h1:VIy7cdK7ufs7ctpTFkXJHm1uP3dJSnCGSPysEICB1so= -github.com/elazarl/goproxy v0.0.0-20220417044921-416226498f94/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= -github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw= github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= @@ -351,7 +345,6 @@ github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5 github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM= -github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= github.com/getkin/kin-openapi v0.94.0/go.mod h1:LWZfzOd7PRy8GJ1dJ6mCU6tNdSfOwRac1BUPam4aw6Q= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= @@ -362,7 +355,6 @@ github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= -github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= @@ -431,7 +423,6 @@ github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5 github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= @@ -530,7 +521,6 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= @@ -597,7 +587,6 @@ github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHh github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-retryablehttp v0.5.1/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= @@ -633,14 +622,12 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb-client-go/v2 v2.9.1 h1:5kbH226fmmiV0MMTs7a8L7/ECCKdJWBi1QZNNv4/TkI= github.com/influxdata/influxdb-client-go/v2 v2.9.1/go.mod h1:x7Jo5UHHl+w8wu8UnGiNobDDHygojXwJX4mx7rXGKMk= -github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf h1:7JTmneyiNEwVBOHSjoMxiWAqB992atOeepeFYegn5RU= github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= github.com/ishidawataru/sctp v0.0.0-20190723014705-7c296d48a2b5/go.mod h1:DM4VvS+hD/kDi1U1QsX2fnZowwBhqD0Dk3bRPKF/Oc8= @@ -698,9 +685,7 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= github.com/labstack/echo/v4 v4.7.2/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= -github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= @@ -735,14 +720,11 @@ github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7 github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/matryer/moq v0.2.7/go.mod h1:kITsx543GOENm48TUAQyJ9+SAvFSr7iGQXPoth/VUBk= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.10/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= @@ -750,7 +732,6 @@ github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZb github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= @@ -842,18 +823,14 @@ github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9k github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= -github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= -github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= @@ -907,7 +884,6 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= github.com/prometheus/common v0.36.0 h1:78hJTing+BLYLjhXE+Z2BubeEymH5Lr0/Mt8FKkxxYo= github.com/prometheus/common v0.36.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -927,7 +903,6 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= @@ -1037,7 +1012,6 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fastjson v1.6.3 h1:tAKFnnwmeMGPbwJ7IwxcTPCNr3uIzoIj3/Fh90ra4xc= github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= -github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= @@ -1115,10 +1089,8 @@ golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= @@ -1225,7 +1197,6 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -1301,7 +1272,6 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1338,7 +1308,6 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1386,7 +1355,6 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1800,7 +1768,6 @@ k8s.io/gengo v0.0.0-20211129171323-c02415ce4185 h1:TT1WdmqqXareKxZ/oNXEUSwKlLiHz k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= diff --git a/hack/installers/install-codegen-go-tools.sh b/hack/installers/install-codegen-go-tools.sh index 435838126c..8a08efd826 100755 --- a/hack/installers/install-codegen-go-tools.sh +++ b/hack/installers/install-codegen-go-tools.sh @@ -54,4 +54,4 @@ go install github.com/go-swagger/go-swagger/cmd/swagger@v0.28.0 go install golang.org/x/tools/cmd/goimports@v0.1.8 # mockery is used for generating mock -go install github.com/vektra/mockery/v2@v2.6.0 +go install github.com/vektra/mockery/v2@v2.14.0 diff --git a/metricproviders/mocks/Provider.go b/metricproviders/mocks/Provider.go index 7e483078ae..1b54e4281c 100644 --- a/metricproviders/mocks/Provider.go +++ b/metricproviders/mocks/Provider.go @@ -1,4 +1,4 @@ -// Code generated by mockery v0.0.0-dev. DO NOT EDIT. +// Code generated by mockery v2.14.0. DO NOT EDIT. package mocks @@ -97,3 +97,18 @@ func (_m *Provider) Type() string { return r0 } + +type mockConstructorTestingTNewProvider interface { + mock.TestingT + Cleanup(func()) +} + +// NewProvider creates a new instance of Provider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewProvider(t mockConstructorTestingTNewProvider) *Provider { + mock := &Provider{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/rollout/mocks/TrafficRoutingReconciler.go b/rollout/mocks/TrafficRoutingReconciler.go index 278fbbd37c..3a5b1fa67f 100644 --- a/rollout/mocks/TrafficRoutingReconciler.go +++ b/rollout/mocks/TrafficRoutingReconciler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v0.0.0-dev. DO NOT EDIT. +// Code generated by mockery v2.14.0. DO NOT EDIT. package mocks @@ -140,3 +140,18 @@ func (_m *TrafficRoutingReconciler) VerifyWeight(desiredWeight int32, additional return r0, r1 } + +type mockConstructorTestingTNewTrafficRoutingReconciler interface { + mock.TestingT + Cleanup(func()) +} + +// NewTrafficRoutingReconciler creates a new instance of TrafficRoutingReconciler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewTrafficRoutingReconciler(t mockConstructorTestingTNewTrafficRoutingReconciler) *TrafficRoutingReconciler { + mock := &TrafficRoutingReconciler{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/utils/aws/mocks/ELBv2APIClient.go b/utils/aws/mocks/ELBv2APIClient.go index 7f621b0563..cfc8872f3b 100644 --- a/utils/aws/mocks/ELBv2APIClient.go +++ b/utils/aws/mocks/ELBv2APIClient.go @@ -1,4 +1,4 @@ -// Code generated by mockery v0.0.0-dev. DO NOT EDIT. +// Code generated by mockery v2.14.0. DO NOT EDIT. package mocks @@ -193,3 +193,18 @@ func (_m *ELBv2APIClient) DescribeTargetHealth(ctx context.Context, params *elas return r0, r1 } + +type mockConstructorTestingTNewELBv2APIClient interface { + mock.TestingT + Cleanup(func()) +} + +// NewELBv2APIClient creates a new instance of ELBv2APIClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewELBv2APIClient(t mockConstructorTestingTNewELBv2APIClient) *ELBv2APIClient { + mock := &ELBv2APIClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} From 0ec5ac18a307ae579787b974e17f3e4c0bf41cff Mon Sep 17 00:00:00 2001 From: RaviHari Date: Fri, 29 Jul 2022 21:22:52 +0530 Subject: [PATCH 163/175] fix: Failed to process: Object 'Kind' is missing in Errors with rollouts notification (#2150) * fix: update rolloutobject with gvk before writing to rollout informer Signed-off-by: Ravi Hari * fix: controller schema linting Signed-off-by: Ravi Hari * docs: comment the details on the change Signed-off-by: Ravi Hari * docs: comment the details on the change Signed-off-by: Ravi Hari --- rollout/controller.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/rollout/controller.go b/rollout/controller.go index eaece46ce7..e314adf4af 100644 --- a/rollout/controller.go +++ b/rollout/controller.go @@ -8,6 +8,9 @@ import ( "strconv" "time" + "k8s.io/apimachinery/pkg/runtime/schema" + + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts" smiclientset "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/clientset/versioned" log "github.com/sirupsen/logrus" appsv1 "k8s.io/api/apps/v1" @@ -421,6 +424,19 @@ func (c *Controller) writeBackToInformer(ro *v1alpha1.Rollout) { return } un := unstructured.Unstructured{Object: obj} + // With code-gen tools the argoclientset is generated and the update method here is removing typemetafields + // which the notification controller expects when it converts rolloutobject to toUnstructured and if not present + // and that throws an error "Failed to process: Object 'Kind' is missing in ..." + // Fixing this here as the informer is shared by notification controller by updating typemetafileds. + // TODO: Need to revisit this in the future and maybe we should have a dedicated informer for notification + gvk := un.GetObjectKind().GroupVersionKind() + if len(gvk.Version) == 0 || len(gvk.Group) == 0 || len(gvk.Kind) == 0 { + un.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{ + Group: v1alpha1.SchemeGroupVersion.Group, + Kind: rollouts.RolloutKind, + Version: v1alpha1.SchemeGroupVersion.Version, + }) + } err = c.rolloutsInformer.GetStore().Update(&un) if err != nil { logCtx.Errorf("failed to update informer store: %v", err) From 53f410589356264d7698ecb50eba2f768ecce5bf Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Wed, 17 Aug 2022 09:59:27 -0500 Subject: [PATCH 164/175] fix: rootPath support so that it uses the embedded files system (#2198) * fix: rootPath support so that it uses the embeded files system Signed-off-by: zachaller * Catch edge cases and make sure we always server index.html on not found Signed-off-by: zachaller * turn path.Clean into var Signed-off-by: zachaller Signed-off-by: zachaller --- server/server.go | 138 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 95 insertions(+), 43 deletions(-) diff --git a/server/server.go b/server/server.go index a7bb7f298e..df19f4cfc4 100644 --- a/server/server.go +++ b/server/server.go @@ -1,13 +1,13 @@ package server import ( - "bufio" "context" "embed" "fmt" + "io/fs" "net" "net/http" - "os" + "path" "regexp" "strings" "time" @@ -81,45 +81,11 @@ func NewServer(o ServerOptions) *ArgoRolloutsServer { return &ArgoRolloutsServer{Options: o} } -type spaFileSystem struct { - root http.FileSystem -} - -func (fs *spaFileSystem) Open(name string) (http.File, error) { - f, err := fs.root.Open(name) - if os.IsNotExist(err) { - return fs.root.Open("index.html") - } - return f, err -} +var re = regexp.MustCompile(``) -//This function helps in changing base href to point to rootpath as basepath, we are making modification in only server/static/index.html file -func withRootPath(rootpath string) { - inputFile, inputError := os.Open("./server/static/index.html") - if inputError != nil { - log.Error("An error occurred on opening the inputfile\n" + - "Does the file exist?\n" + - "Have you got access to it?\n") - panic(inputError) // exit on error - } - defer inputFile.Close() - inputReader := bufio.NewReader(inputFile) - inputString, _ := inputReader.ReadString('\n') - re := regexp.MustCompile(``) - var temp = re.ReplaceAllString(inputString, "") // href="/root/" - - outputFile, _ := os.OpenFile("./server/static/index.html", os.O_TRUNC|os.O_WRONLY, 0666) - defer outputFile.Close() - outputWriter := bufio.NewWriter(outputFile) - outputWriter.WriteString(temp) - outputWriter.Flush() - - //To make ui/dist/index.html file consistent with server/static/index.html - outputFileDist, _ := os.OpenFile("./ui/dist/app/index.html", os.O_TRUNC|os.O_WRONLY, 0666) - defer outputFileDist.Close() - outputWriterDist := bufio.NewWriter(outputFileDist) - outputWriterDist.WriteString(temp) - outputWriterDist.Flush() +func withRootPath(fileContent []byte, rootpath string) []byte { + var temp = re.ReplaceAllString(string(fileContent), ``) + return []byte(temp) } func (s *ArgoRolloutsServer) newHTTPServer(ctx context.Context, port int) *http.Server { @@ -153,15 +119,101 @@ func (s *ArgoRolloutsServer) newHTTPServer(ctx context.Context, port int) *http. var handler http.Handler = gwmux - withRootPath(s.Options.RootPath) - mux.Handle("/api/", handler) - mux.Handle("/"+s.Options.RootPath+"/", http.StripPrefix("/"+s.Options.RootPath+"/", http.FileServer(http.Dir("./server/static")))) + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + requestedURI := path.Clean(r.RequestURI) + rootPath := path.Clean("/" + s.Options.RootPath) + //If the rootPath is not in the prefix 404 + if !strings.HasPrefix(requestedURI, rootPath) { + http.NotFound(w, r) + return + } + //If the rootPath is the requestedURI, serve index.html + if requestedURI == rootPath { + fileBytes, openErr := s.readIndexHtml() + if openErr != nil { + log.Errorf("Error opening file index.html: %v", openErr) + w.WriteHeader(http.StatusInternalServerError) + return + } + w.Write(fileBytes) + return + } + + embedPath := path.Join("static", strings.TrimPrefix(requestedURI, rootPath)) + file, openErr := static.Open(embedPath) + if openErr != nil { + fErr := openErr.(*fs.PathError) + //If the file is not found, serve index.html + if fErr.Err == fs.ErrNotExist { + fileBytes, openErr := s.readIndexHtml() + if openErr != nil { + log.Errorf("Error opening file index.html: %v", openErr) + w.WriteHeader(http.StatusInternalServerError) + return + } + w.Write(fileBytes) + return + } else { + log.Errorf("Error opening file %s: %v", embedPath, openErr) + w.WriteHeader(http.StatusInternalServerError) + return + } + } + defer file.Close() + + stat, statErr := file.Stat() + if statErr != nil { + log.Errorf("Failed to stat file or dir %s: %v", embedPath, err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + fileBytes := make([]byte, stat.Size()) + _, err = file.Read(fileBytes) + if err != nil { + log.Errorf("Failed to read file %s: %v", embedPath, err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.Write(fileBytes) + }) return &httpS } +func (s *ArgoRolloutsServer) readIndexHtml() ([]byte, error) { + file, err := static.Open("static/index.html") + if err != nil { + log.Errorf("Failed to open file %s: %v", "static/index.html", err) + return nil, err + } + defer func() { + if file != nil { + if err := file.Close(); err != nil { + log.Errorf("Error closing file: %v", err) + } + } + }() + + stat, err := file.Stat() + if err != nil { + log.Errorf("Failed to stat file or dir %s: %v", "static/index.html", err) + return nil, err + } + + fileBytes := make([]byte, stat.Size()) + _, err = file.Read(fileBytes) + if err != nil { + log.Errorf("Failed to read file %s: %v", "static/index.html", err) + return nil, err + } + + return withRootPath(fileBytes, s.Options.RootPath), nil +} + func (s *ArgoRolloutsServer) newGRPCServer() *grpc.Server { grpcS := grpc.NewServer() var rolloutsServer rollout.RolloutServiceServer = NewServer(s.Options) From 5c39cbc86948e00a04856646778b5415b563cb7e Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Wed, 24 Aug 2022 16:16:43 -0500 Subject: [PATCH 165/175] fix: change completed condition so it only triggers on pod hash changes also adds an event for when it does changes. (#2203) * feat: add healthy event/condition and fix completed event/condition Signed-off-by: zachaller * fix unit tests Signed-off-by: zachaller * rename vars to make more sense and remove healthy event becase it will never be consistent Signed-off-by: zachaller * fix unit tests Signed-off-by: zachaller * possible fix for e2e Signed-off-by: zachaller * fix e2e Signed-off-by: zachaller * unit test for complete function Signed-off-by: zachaller * small cleanup and changes to not check generation Signed-off-by: zachaller * fix unit test and proper behavior Signed-off-by: zachaller * Fix e2e Signed-off-by: zachaller * rename and fix one unit test Signed-off-by: zachaller * fix unit tests Signed-off-by: zachaller * fix unit test Signed-off-by: zachaller * add seperate test for TestRolloutComplete Signed-off-by: zachaller * renames Signed-off-by: zachaller * fix e2e Signed-off-by: zachaller * Set Completed to false Signed-off-by: zachaller * Add event Signed-off-by: zachaller * fix e2e Signed-off-by: zachaller * refactor Signed-off-by: zachaller * Fix all but one unit test Signed-off-by: zachaller * fix last unit test Signed-off-by: zachaller * lint Signed-off-by: zachaller * cleanup Signed-off-by: zachaller * Rename Signed-off-by: zachaller * More renames Signed-off-by: zachaller * small comment change Signed-off-by: zachaller Signed-off-by: zachaller --- pkg/apis/rollouts/v1alpha1/types.go | 7 +- rollout/analysis_test.go | 81 +++++++++++++----- rollout/bluegreen_test.go | 127 +++++++++++++++++----------- rollout/canary_test.go | 38 ++++++--- rollout/controller_test.go | 76 ++++++++++++++--- rollout/experiment_test.go | 14 +-- rollout/service_test.go | 32 ++++--- rollout/sync.go | 47 +++++++--- rollout/trafficrouting_test.go | 2 + test/e2e/functional_test.go | 27 +++--- utils/conditions/conditions.go | 22 ++++- utils/conditions/rollouts_test.go | 28 +++++- 12 files changed, 358 insertions(+), 143 deletions(-) diff --git a/pkg/apis/rollouts/v1alpha1/types.go b/pkg/apis/rollouts/v1alpha1/types.go index d83a23d639..de417edb16 100644 --- a/pkg/apis/rollouts/v1alpha1/types.go +++ b/pkg/apis/rollouts/v1alpha1/types.go @@ -979,8 +979,13 @@ const ( RolloutReplicaFailure RolloutConditionType = "ReplicaFailure" // RolloutPaused means that rollout is in a paused state. It is still progressing at this point. RolloutPaused RolloutConditionType = "Paused" - // RolloutCompleted means that rollout is in a completed state. It is still progressing at this point. + // RolloutCompleted indicates that the rollout completed its update to the desired revision and is not in the middle + // of any update. Note that a Completed rollout could also be considered Progressing or Degraded, if its Pods become + // unavailable sometime after the update completes. RolloutCompleted RolloutConditionType = "Completed" + // RolloutHealthy means that rollout is in a completed state and is healthy. Which means that all the pods have been updated + // and are passing their health checks and are ready to serve traffic. + RolloutHealthy RolloutConditionType = "Healthy" ) // RolloutCondition describes the state of a rollout at a certain point. diff --git a/rollout/analysis_test.go b/rollout/analysis_test.go index ed21a4c848..46fe961fec 100644 --- a/rollout/analysis_test.go +++ b/rollout/analysis_test.go @@ -153,6 +153,8 @@ func TestCreateBackgroundAnalysisRun(t *testing.T) { conditions.SetRolloutCondition(&r2.Status, progressingCondition) availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) + completeCond, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completeCond) f.rolloutLister = append(f.rolloutLister, r2) f.analysisTemplateLister = append(f.analysisTemplateLister, at) @@ -212,6 +214,8 @@ func TestCreateBackgroundAnalysisRunWithTemplates(t *testing.T) { conditions.SetRolloutCondition(&r2.Status, progressingCondition) availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) + completeCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completeCondition) f.rolloutLister = append(f.rolloutLister, r2) f.analysisTemplateLister = append(f.analysisTemplateLister, at) @@ -272,6 +276,8 @@ func TestCreateBackgroundAnalysisRunWithClusterTemplates(t *testing.T) { conditions.SetRolloutCondition(&r2.Status, progressingCondition) availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) f.rolloutLister = append(f.rolloutLister, r2) f.clusterAnalysisTemplateLister = append(f.clusterAnalysisTemplateLister, cat) @@ -381,6 +387,8 @@ func TestCreateBackgroundAnalysisRunWithClusterTemplatesAndTemplate(t *testing.T conditions.SetRolloutCondition(&r2.Status, progressingCondition) availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) f.rolloutLister = append(f.rolloutLister, r2) f.clusterAnalysisTemplateLister = append(f.clusterAnalysisTemplateLister, cat) @@ -446,6 +454,8 @@ func TestCreateAnalysisRunWithCollision(t *testing.T) { conditions.SetRolloutCondition(&r2.Status, progressingCondition) availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) ar.Status.Phase = v1alpha1.AnalysisPhaseFailed @@ -514,6 +524,8 @@ func TestCreateAnalysisRunWithCollisionAndSemanticEquality(t *testing.T) { conditions.SetRolloutCondition(&r2.Status, progressingCondition) availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) f.rolloutLister = append(f.rolloutLister, r2) f.analysisRunLister = append(f.analysisRunLister, ar) @@ -573,6 +585,8 @@ func TestCreateAnalysisRunOnAnalysisStep(t *testing.T) { conditions.SetRolloutCondition(&r2.Status, progressingCondition) availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) f.rolloutLister = append(f.rolloutLister, r2) f.analysisTemplateLister = append(f.analysisTemplateLister, at) @@ -768,6 +782,8 @@ func TestDoNothingWithAnalysisRunsWhileBackgroundAnalysisRunRunning(t *testing.T conditions.SetRolloutCondition(&r2.Status, progressingCondition) availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) r2.Status.Canary.CurrentBackgroundAnalysisRunStatus = &v1alpha1.RolloutAnalysisRunStatus{ Name: ar.Name, Status: v1alpha1.AnalysisPhaseRunning, @@ -816,6 +832,8 @@ func TestDoNothingWhileStepBasedAnalysisRunRunning(t *testing.T) { conditions.SetRolloutCondition(&r2.Status, progressingCondition) availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) r2.Status.Canary.CurrentStepAnalysisRunStatus = &v1alpha1.RolloutAnalysisRunStatus{ Name: ar.Name, Status: v1alpha1.AnalysisPhaseRunning, @@ -866,6 +884,8 @@ func TestCancelOlderAnalysisRuns(t *testing.T) { conditions.SetRolloutCondition(&r2.Status, progressingCondition) availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) r2.Status.Canary.CurrentStepAnalysisRunStatus = &v1alpha1.RolloutAnalysisRunStatus{ Name: ar.Name, Status: "", @@ -933,6 +953,8 @@ func TestDeleteAnalysisRunsWithNoMatchingRS(t *testing.T) { conditions.SetRolloutCondition(&r2.Status, progressingCondition) availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) r2.Status.Canary.CurrentStepAnalysisRunStatus = &v1alpha1.RolloutAnalysisRunStatus{ Name: ar.Name, } @@ -1059,7 +1081,7 @@ func TestIncrementStepAfterSuccessfulAnalysisRun(t *testing.T) { "conditions": %s } }` - condition := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs2, false, "") + condition := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs2, false, "", false) assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, condition)), patch) } @@ -1128,7 +1150,7 @@ func TestPausedOnInconclusiveBackgroundAnalysisRun(t *testing.T) { "message": "%s" } }` - condition := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "") + condition := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "", false) assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, condition, v1alpha1.PauseReasonInconclusiveAnalysis, now, v1alpha1.PauseReasonInconclusiveAnalysis)), patch) } @@ -1192,7 +1214,7 @@ func TestPausedStepAfterInconclusiveAnalysisRun(t *testing.T) { "message": "%s" } }` - condition := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "") + condition := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "", false) assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, condition, v1alpha1.PauseReasonInconclusiveAnalysis, now, v1alpha1.PauseReasonInconclusiveAnalysis)), patch) } @@ -1258,7 +1280,7 @@ func TestErrorConditionAfterErrorAnalysisRunStep(t *testing.T) { }` now := timeutil.MetaNow().UTC().Format(time.RFC3339) errmsg := fmt.Sprintf(conditions.RolloutAbortedMessage, 2) + ": " + ar.Status.Message - condition := generateConditionsPatch(true, conditions.RolloutAbortedReason, r2, false, errmsg) + condition := generateConditionsPatch(true, conditions.RolloutAbortedReason, r2, false, errmsg, false) expectedPatch = fmt.Sprintf(expectedPatch, condition, now, errmsg) assert.Equal(t, calculatePatch(r2, expectedPatch), patch) } @@ -1333,7 +1355,7 @@ func TestErrorConditionAfterErrorAnalysisRunBackground(t *testing.T) { } }` errmsg := fmt.Sprintf(conditions.RolloutAbortedMessage, 2) - condition := generateConditionsPatch(true, conditions.RolloutAbortedReason, r2, false, "") + condition := generateConditionsPatch(true, conditions.RolloutAbortedReason, r2, false, "", false) now := timeutil.Now().UTC().Format(time.RFC3339) assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, condition, now, errmsg)), patch) @@ -1386,7 +1408,7 @@ func TestCancelAnalysisRunsWhenAborted(t *testing.T) { assert.True(t, f.verifyPatchedAnalysisRun(cancelOldAr, olderAr)) assert.True(t, f.verifyPatchedAnalysisRun(cancelCurrentAr, ar)) patch := f.getPatchedRollout(patchIndex) - newConditions := generateConditionsPatch(true, conditions.RolloutAbortedReason, r2, false, "") + newConditions := generateConditionsPatch(true, conditions.RolloutAbortedReason, r2, false, "", false) expectedPatch := `{ "status": { "conditions": %s, @@ -1488,6 +1510,9 @@ func TestDoNotCreateBackgroundAnalysisRunAfterInconclusiveRun(t *testing.T) { availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) + f.rolloutLister = append(f.rolloutLister, r2) f.analysisTemplateLister = append(f.analysisTemplateLister, at) f.objects = append(f.objects, r2, at) @@ -1586,13 +1611,16 @@ func TestCreatePrePromotionAnalysisRun(t *testing.T) { rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true) + r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true, false) progressingCondition, _ := newProgressingCondition(conditions.RolloutPausedReason, r2, "") conditions.SetRolloutCondition(&r2.Status, progressingCondition) pausedCondition, _ := newPausedCondition(true) conditions.SetRolloutCondition(&r2.Status, pausedCondition) + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) + previewSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash} previewSvc := newService("preview", 80, previewSelector, r2) activeSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs1PodHash} @@ -1650,7 +1678,7 @@ func TestDoNotCreatePrePromotionAnalysisAfterPromotionRollout(t *testing.T) { f.analysisTemplateLister = append(f.analysisTemplateLister, at) f.objects = append(f.objects, at) - r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs2PodHash, 1, 1, 1, 1, false, true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs2PodHash, 1, 1, 1, 1, false, true, true) r2.Status.ObservedGeneration = strconv.Itoa(int(r2.Generation)) f.rolloutLister = append(f.rolloutLister, r2) @@ -1661,7 +1689,7 @@ func TestDoNotCreatePrePromotionAnalysisAfterPromotionRollout(t *testing.T) { f.run(getKey(r2, t)) - newConditions := generateConditionsPatchWithComplete(true, conditions.NewRSAvailableReason, rs2, true, "", true) + newConditions := generateConditionsPatchWithHealthy(true, conditions.NewRSAvailableReason, rs2, true, "", true, true) expectedPatch := fmt.Sprintf(`{ "status":{ "conditions":%s @@ -1723,7 +1751,7 @@ func TestDoNotCreatePrePromotionAnalysisRunOnNotReadyReplicaSet(t *testing.T) { rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 2, 2, 4, 2, false, true) + r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 2, 2, 4, 2, false, true, false) activeSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs1PodHash} activeSvc := newService("active", 80, activeSelector, r2) @@ -1766,7 +1794,7 @@ func TestRolloutPrePromotionAnalysisBecomesInconclusive(t *testing.T) { rs2 := newReplicaSetWithStatus(r2, 1, 1) rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, "", rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true, false) r2.Status.BlueGreen.PrePromotionAnalysisRunStatus = &v1alpha1.RolloutAnalysisRunStatus{ Name: ar.Name, Status: v1alpha1.AnalysisPhaseRunning, @@ -1777,6 +1805,9 @@ func TestRolloutPrePromotionAnalysisBecomesInconclusive(t *testing.T) { pausedCondition, _ := newPausedCondition(true) conditions.SetRolloutCondition(&r2.Status, pausedCondition) + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) + activeSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs1PodHash} activeSvc := newService("active", 80, activeSelector, r2) @@ -1834,7 +1865,7 @@ func TestRolloutPrePromotionAnalysisSwitchServiceAfterSuccess(t *testing.T) { rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, "", rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true, false) r2.Status.BlueGreen.PrePromotionAnalysisRunStatus = &v1alpha1.RolloutAnalysisRunStatus{ Name: ar.Name, Status: v1alpha1.AnalysisPhaseRunning, @@ -1903,7 +1934,7 @@ func TestRolloutPrePromotionAnalysisHonorAutoPromotionSeconds(t *testing.T) { rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, "", rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true, false) now := metav1.NewTime(timeutil.MetaNow().Add(-10 * time.Second)) r2.Status.PauseConditions[0].StartTime = now progressingCondition, _ := newProgressingCondition(conditions.RolloutPausedReason, r2, "") @@ -1966,7 +1997,7 @@ func TestRolloutPrePromotionAnalysisDoNothingOnInconclusiveAnalysis(t *testing.T rs2 := newReplicaSetWithStatus(r2, 1, 1) rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, "", rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true, false) inconclusivePauseCondition := v1alpha1.PauseCondition{ Reason: v1alpha1.PauseReasonInconclusiveAnalysis, StartTime: timeutil.MetaNow(), @@ -2021,12 +2052,15 @@ func TestAbortRolloutOnErrorPrePromotionAnalysis(t *testing.T) { rs2 := newReplicaSetWithStatus(r2, 1, 1) rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, "", rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true, false) progressingCondition, _ := newProgressingCondition(conditions.RolloutPausedReason, r2, "") conditions.SetRolloutCondition(&r2.Status, progressingCondition) pausedCondition, _ := newPausedCondition(true) conditions.SetRolloutCondition(&r2.Status, pausedCondition) + + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) r2.Status.Phase, r2.Status.Message = rolloututil.CalculateRolloutPhase(r2.Spec, r2.Status) activeSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs1PodHash} @@ -2083,7 +2117,7 @@ func TestCreatePostPromotionAnalysisRun(t *testing.T) { rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs1PodHash, 1, 1, 2, 1, false, true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs1PodHash, 1, 1, 2, 1, false, true, false) activeSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash} activeSvc := newService("active", 80, activeSelector, r2) @@ -2136,11 +2170,14 @@ func TestRolloutPostPromotionAnalysisSuccess(t *testing.T) { rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs1PodHash, 1, 1, 1, 1, false, true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs1PodHash, 1, 1, 1, 1, false, true, false) activeSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash} activeSvc := newService("active", 80, activeSelector, r2) + cond, _ := newCompletedCondition(true) + conditions.SetRolloutCondition(&r2.Status, cond) + f.objects = append(f.objects, r2, at, ar) f.kubeobjects = append(f.kubeobjects, activeSvc, rs1, rs2) f.rolloutLister = append(f.rolloutLister, r2) @@ -2190,7 +2227,7 @@ func TestPostPromotionAnalysisRunHandleInconclusive(t *testing.T) { rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs1PodHash, 1, 1, 2, 1, false, true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs1PodHash, 1, 1, 2, 1, false, true, false) r2.Status.PauseConditions = []v1alpha1.PauseCondition{{ Reason: v1alpha1.PauseReasonInconclusiveAnalysis, StartTime: timeutil.MetaNow(), @@ -2201,6 +2238,9 @@ func TestPostPromotionAnalysisRunHandleInconclusive(t *testing.T) { pausedCondition, _ := newPausedCondition(true) conditions.SetRolloutCondition(&r2.Status, pausedCondition) + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) + activeSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash} activeSvc := newService("active", 80, activeSelector, r2) @@ -2251,13 +2291,16 @@ func TestAbortRolloutOnErrorPostPromotionAnalysis(t *testing.T) { rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs1PodHash, 1, 1, 2, 1, true, true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs1PodHash, 1, 1, 2, 1, true, true, false) progressingCondition, _ := newProgressingCondition(conditions.RolloutPausedReason, r2, "") conditions.SetRolloutCondition(&r2.Status, progressingCondition) pausedCondition, _ := newPausedCondition(true) conditions.SetRolloutCondition(&r2.Status, pausedCondition) + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) + activeSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash} activeSvc := newService("active", 80, activeSelector, r2) diff --git a/rollout/bluegreen_test.go b/rollout/bluegreen_test.go index 5cae668da3..8ad0b1f838 100644 --- a/rollout/bluegreen_test.go +++ b/rollout/bluegreen_test.go @@ -38,15 +38,17 @@ func newBlueGreenRollout(name string, replicas int, revisionHistoryLimit *int32, return rollout } -func TestBlueGreenComplateRolloutRestart(t *testing.T) { +func TestBlueGreenCompletedRolloutRestart(t *testing.T) { f := newFixture(t) defer f.Close() r := newBlueGreenRollout("foo", 1, nil, "active", "preview") r.Status.Conditions = []v1alpha1.RolloutCondition{} - completedCond := conditions.NewRolloutCondition(v1alpha1.RolloutCompleted, corev1.ConditionTrue, conditions.RolloutCompletedReason, conditions.RolloutCompletedReason) - conditions.SetRolloutCondition(&r.Status, *completedCond) + completedHealthyCond := conditions.NewRolloutCondition(v1alpha1.RolloutHealthy, corev1.ConditionFalse, conditions.RolloutHealthyReason, conditions.RolloutNotHealthyMessage) + conditions.SetRolloutCondition(&r.Status, *completedHealthyCond) + completedCond, _ := newCompletedCondition(true) + conditions.SetRolloutCondition(&r.Status, completedCond) f.rolloutLister = append(f.rolloutLister, r) f.objects = append(f.objects, r) @@ -57,7 +59,7 @@ func TestBlueGreenComplateRolloutRestart(t *testing.T) { rs := newReplicaSet(r, 1) rsPodHash := rs.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - generatedConditions := generateConditionsPatchWithComplete(false, conditions.ReplicaSetNotAvailableReason, rs, false, "", false) + generatedConditions := generateConditionsPatchWithCompletedHealthy(false, conditions.ReplicaSetUpdatedReason, rs, false, "", false, true) f.expectCreateReplicaSetAction(rs) servicePatchIndex := f.expectPatchServiceAction(previewSvc, rsPodHash) @@ -107,7 +109,7 @@ func TestBlueGreenCreatesReplicaSet(t *testing.T) { rs := newReplicaSet(r, 1) rsPodHash := rs.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - generatedConditions := generateConditionsPatch(false, conditions.ReplicaSetUpdatedReason, rs, false, "") + generatedConditions := generateConditionsPatchWithCompleted(false, conditions.ReplicaSetUpdatedReason, rs, false, "", true) f.expectCreateReplicaSetAction(rs) servicePatchIndex := f.expectPatchServiceAction(previewSvc, rsPodHash) @@ -271,7 +273,7 @@ func TestBlueGreenHandlePause(t *testing.T) { rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 2, 2, 4, 2, false, true) + r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 2, 2, 4, 2, false, true, false) activeSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs1PodHash} activeSvc := newService("active", 80, activeSelector, r2) @@ -302,7 +304,7 @@ func TestBlueGreenHandlePause(t *testing.T) { rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, false, true) + r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, false, true, false) previewSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash} previewSvc := newService("preview", 80, previewSelector, r2) activeSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs1PodHash} @@ -350,7 +352,7 @@ func TestBlueGreenHandlePause(t *testing.T) { rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true) + r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true, false) previewSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash} previewSvc := newService("preview", 80, previewSelector, r2) @@ -373,7 +375,7 @@ func TestBlueGreenHandlePause(t *testing.T) { "conditions": %s } }` - addedConditions := generateConditionsPatchWithPause(true, conditions.RolloutPausedReason, rs2, true, "", true) + addedConditions := generateConditionsPatchWithPause(true, conditions.RolloutPausedReason, rs2, true, "", true, false) assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, addedConditions)), patch) }) @@ -390,12 +392,15 @@ func TestBlueGreenHandlePause(t *testing.T) { rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true) + r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true, false) progressingCondition, _ := newProgressingCondition(conditions.RolloutPausedReason, r2, "") conditions.SetRolloutCondition(&r2.Status, progressingCondition) pausedCondition, _ := newPausedCondition(true) conditions.SetRolloutCondition(&r2.Status, pausedCondition) + + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) r2.Status.Phase, r2.Status.Message = rolloututil.CalculateRolloutPhase(r2.Spec, r2.Status) previewSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash} @@ -433,7 +438,7 @@ func TestBlueGreenHandlePause(t *testing.T) { rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, false, true) + r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, false, true, false) now := timeutil.MetaNow() r2.Status.PauseConditions = append(r2.Status.PauseConditions, v1alpha1.PauseCondition{ Reason: v1alpha1.PauseReasonInconclusiveAnalysis, @@ -479,12 +484,15 @@ func TestBlueGreenHandlePause(t *testing.T) { rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true) + r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true, false) progressingCondition, _ := newProgressingCondition(conditions.RolloutPausedReason, r2, "") conditions.SetRolloutCondition(&r2.Status, progressingCondition) pausedCondition, _ := newPausedCondition(true) conditions.SetRolloutCondition(&r2.Status, pausedCondition) + + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) r2.Status.Phase, r2.Status.Message = rolloututil.CalculateRolloutPhase(r2.Spec, r2.Status) previewSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash} @@ -517,7 +525,7 @@ func TestBlueGreenHandlePause(t *testing.T) { rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true) + r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true, false) now := timeutil.MetaNow() before := metav1.NewTime(now.Add(-1 * time.Minute)) r2.Status.PauseConditions[0].StartTime = before @@ -575,7 +583,7 @@ func TestBlueGreenHandlePause(t *testing.T) { rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true) + r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true, false) now := timeutil.MetaNow() before := metav1.NewTime(now.Add(-1 * time.Minute)) r2.Status.PauseConditions[0].StartTime = before @@ -586,6 +594,9 @@ func TestBlueGreenHandlePause(t *testing.T) { pausedCondition, _ := newPausedCondition(true) conditions.SetRolloutCondition(&r2.Status, pausedCondition) + + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) r2.Status.Phase, r2.Status.Message = rolloututil.CalculateRolloutPhase(r2.Spec, r2.Status) activeSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs1PodHash} @@ -619,7 +630,7 @@ func TestBlueGreenHandlePause(t *testing.T) { rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, "", rs1PodHash, rs1PodHash, 1, 1, 2, 1, false, true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs1PodHash, rs1PodHash, 1, 1, 2, 1, false, true, false) r2.Spec.Strategy.BlueGreen.ScaleDownDelaySeconds = pointer.Int32Ptr(10) progressingCondition, _ := newProgressingCondition(conditions.NewReplicaSetReason, rs2, "") @@ -635,7 +646,7 @@ func TestBlueGreenHandlePause(t *testing.T) { servicePatchIndex := f.expectPatchServiceAction(activeSvc, rs2PodHash) - generatedConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs2, true, "") + generatedConditions := generateConditionsPatchWithCompleted(true, conditions.ReplicaSetUpdatedReason, rs2, true, "", true) newSelector := metav1.FormatLabelSelector(rs2.Spec.Selector) expectedPatchWithoutSubs := `{ "status": { @@ -670,10 +681,13 @@ func TestBlueGreenHandlePause(t *testing.T) { rs2 := newReplicaSetWithStatus(r2, 1, 1) rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, "", rs1PodHash, rs1PodHash, 1, 1, 2, 1, false, true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs1PodHash, rs1PodHash, 1, 1, 2, 1, false, true, false) progressingCondition, _ := newProgressingCondition(conditions.NewReplicaSetReason, rs2, "") conditions.SetRolloutCondition(&r2.Status, progressingCondition) + + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) activeSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs1PodHash} activeSvc := newService("active", 80, activeSelector, r2) @@ -713,7 +727,7 @@ func TestBlueGreenHandlePause(t *testing.T) { rs1 := newReplicaSetWithStatus(r1, 1, 1) rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r1 = updateBlueGreenRolloutStatus(r1, "", "", "", 1, 1, 1, 1, false, false) + r1 = updateBlueGreenRolloutStatus(r1, "", "", "", 1, 1, 1, 1, false, false, false) activeSelector := map[string]string{"foo": "bar"} @@ -739,7 +753,7 @@ func TestBlueGreenHandlePause(t *testing.T) { } }` - generateConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs1, false, "") + generateConditions := generateConditionsPatchWithCompleted(true, conditions.ReplicaSetUpdatedReason, rs1, false, "", true) newSelector := metav1.FormatLabelSelector(rs1.Spec.Selector) expectedPatch := calculatePatch(r1, fmt.Sprintf(expectedPatchWithoutSubs, rs1PodHash, rs1PodHash, generateConditions, newSelector)) patchRolloutIndex := f.expectPatchRolloutActionWithPatch(r1, expectedPatch) @@ -765,8 +779,10 @@ func TestBlueGreenHandlePause(t *testing.T) { rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] r2.Spec.Strategy.BlueGreen.ScaleDownDelaySeconds = pointer.Int32Ptr(10) - r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, false, true) + r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, false, true, false) r2.Status.ControllerPause = true + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) pausedCondition, _ := newProgressingCondition(conditions.RolloutPausedReason, rs2, "") conditions.SetRolloutCondition(&r2.Status, pausedCondition) @@ -788,7 +804,10 @@ func TestBlueGreenHandlePause(t *testing.T) { f.verifyPatchedService(servicePatchIndex, rs2PodHash, "") unpausePatch := f.getPatchedRollout(unpausePatchIndex) - unpauseConditions := generateConditionsPatch(true, conditions.RolloutResumedReason, rs2, true, "") + _, availableCondition := newAvailableCondition(true) + _, progressingCondition := newProgressingCondition(conditions.RolloutResumedReason, rs2, "") + _, compCondition := newCompletedCondition(false) + unpauseConditions := fmt.Sprintf("[%s, %s, %s]", availableCondition, compCondition, progressingCondition) expectedUnpausePatch := `{ "status": { "conditions": %s @@ -796,7 +815,7 @@ func TestBlueGreenHandlePause(t *testing.T) { }` assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedUnpausePatch, unpauseConditions)), unpausePatch) - generatedConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs2, true, "") + generatedConditions := generateConditionsPatchWithCompleted(true, conditions.ReplicaSetUpdatedReason, rs2, true, "", true) expected2ndPatchWithoutSubs := `{ "status": { "blueGreen": { @@ -835,7 +854,7 @@ func TestBlueGreenAddScaleDownDelayToPreviousActiveReplicaSet(t *testing.T) { f.replicaSetLister = append(f.replicaSetLister, rs1, rs2) r2.Spec.Strategy.BlueGreen.ScaleDownDelaySeconds = pointer.Int32Ptr(10) - r2 = updateBlueGreenRolloutStatus(r2, "", rs1PodHash, rs1PodHash, 1, 1, 2, 1, false, true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs1PodHash, rs1PodHash, 1, 1, 2, 1, false, true, false) f.rolloutLister = append(f.rolloutLister, r2) f.objects = append(f.objects, r2) f.serviceLister = append(f.serviceLister, s) @@ -858,7 +877,7 @@ func TestBlueGreenAddScaleDownDelayToPreviousActiveReplicaSet(t *testing.T) { } }` newSelector := metav1.FormatLabelSelector(rs2.Spec.Selector) - expectedCondition := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs2, true, "") + expectedCondition := generateConditionsPatchWithCompleted(true, conditions.ReplicaSetUpdatedReason, rs2, true, "", true) expectedPatch := calculatePatch(r2, fmt.Sprintf(expectedPatchWithoutSubs, rs2PodHash, rs2PodHash, expectedCondition, newSelector)) assert.Equal(t, expectedPatch, patch) } @@ -879,7 +898,7 @@ func TestBlueGreenRolloutStatusHPAStatusFieldsActiveSelectorSet(t *testing.T) { previewSvc := newService("preview", 80, map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash}, r2) activeSvc := newService("active", 80, map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs1PodHash}, r2) - r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 0, 0, 0, 0, true, false) + r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 0, 0, 0, 0, true, false, false) r2.Status.Selector = "" progressingCondition, _ := newProgressingCondition(conditions.RolloutPausedReason, rs2, "") conditions.SetRolloutCondition(&r2.Status, progressingCondition) @@ -940,6 +959,7 @@ func TestBlueGreenRolloutStatusHPAStatusFieldsNoActiveSelector(t *testing.T) { assert.Len(t, f.client.Actions(), 1) result := f.client.Actions()[0].(core.PatchAction).GetPatch() _, availableStr := newAvailableCondition(false) + _, compCond := newCompletedCondition(true) expectedPatchWithoutSub := `{ "status":{ "HPAReplicas":1, @@ -947,11 +967,11 @@ func TestBlueGreenRolloutStatusHPAStatusFieldsNoActiveSelector(t *testing.T) { "availableReplicas": 1, "updatedReplicas":1, "replicas":1, - "conditions":[%s, %s], + "conditions":[%s, %s, %s], "selector":"foo=bar" } }` - expectedPatch := calculatePatch(ro, fmt.Sprintf(expectedPatchWithoutSub, progressingConditionStr, availableStr)) + expectedPatch := calculatePatch(ro, fmt.Sprintf(expectedPatchWithoutSub, progressingConditionStr, availableStr, compCond)) assert.Equal(t, expectedPatch, string(result)) } @@ -973,7 +993,7 @@ func TestBlueGreenRolloutScaleUpdateActiveRS(t *testing.T) { rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 1, 1, false, true) + r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 1, 1, false, true, false) f.objects = append(f.objects, r2) previewSvc := newService("preview", 80, map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash}, r2) activeSvc := newService("active", 80, map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs1PodHash}, r2) @@ -1006,7 +1026,7 @@ func TestPreviewReplicaCountHandleScaleUpPreviewCheckPoint(t *testing.T) { activeSvc := newService("active", 80, map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs1PodHash}, r2) - r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 3, 3, 8, 5, false, true) + r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 3, 3, 8, 5, false, true, false) f.rolloutLister = append(f.rolloutLister, r2) f.objects = append(f.objects, r2) f.kubeobjects = append(f.kubeobjects, activeSvc) @@ -1038,7 +1058,7 @@ func TestPreviewReplicaCountHandleScaleUpPreviewCheckPoint(t *testing.T) { activeSvc := newService("active", 80, map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash}, r2) - r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 5, 5, 8, 5, false, true) + r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 5, 5, 8, 5, false, true, false) r2.Status.BlueGreen.ScaleUpPreviewCheckPoint = true f.rolloutLister = append(f.rolloutLister, r2) f.objects = append(f.objects, r2) @@ -1069,7 +1089,7 @@ func TestPreviewReplicaCountHandleScaleUpPreviewCheckPoint(t *testing.T) { activeSvc := newService("active", 80, map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs1PodHash}, r2) - r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 5, 5, 8, 5, false, true) + r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 5, 5, 8, 5, false, true, false) r2.Status.BlueGreen.ScaleUpPreviewCheckPoint = true f.rolloutLister = append(f.rolloutLister, r2) f.objects = append(f.objects, r2) @@ -1103,7 +1123,7 @@ func TestBlueGreenRolloutIgnoringScalingUsePreviewRSCount(t *testing.T) { previewSvc := newService("preview", 80, map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash}, r2) activeSvc := newService("active", 80, map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs1PodHash}, r2) - r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 2, 1, 1, 1, false, true) + r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 2, 1, 1, 1, false, true, true) // Scaling up the rollout r2.Spec.Replicas = pointer.Int32Ptr(2) f.rolloutLister = append(f.rolloutLister, r2) @@ -1136,7 +1156,7 @@ func TestBlueGreenRolloutCompleted(t *testing.T) { s := newService("bar", 80, serviceSelector, r2) f.kubeobjects = append(f.kubeobjects, s) - r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs2PodHash, 1, 1, 1, 1, false, true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs2PodHash, 1, 1, 1, 1, false, true, true) r2.Status.ObservedGeneration = strconv.Itoa(int(r2.Generation)) f.rolloutLister = append(f.rolloutLister, r2) @@ -1147,7 +1167,7 @@ func TestBlueGreenRolloutCompleted(t *testing.T) { f.run(getKey(r2, t)) - newConditions := generateConditionsPatchWithComplete(true, conditions.NewRSAvailableReason, rs2, true, "", true) + newConditions := generateConditionsPatchWithHealthy(true, conditions.NewRSAvailableReason, rs2, true, "", true, true) expectedPatch := fmt.Sprintf(`{ "status":{ "conditions":%s @@ -1162,7 +1182,7 @@ func TestBlueGreenRolloutCompletedFalse(t *testing.T) { defer f.Close() r1 := newBlueGreenRollout("foo", 1, nil, "bar", "") - completedCondition, _ := newCompletedCondition(true) + completedCondition, _ := newHealthyCondition(true) conditions.SetRolloutCondition(&r1.Status, completedCondition) r2 := bumpVersion(r1) @@ -1182,7 +1202,7 @@ func TestBlueGreenRolloutCompletedFalse(t *testing.T) { s := newService("bar", 80, serviceSelector, r2) f.kubeobjects = append(f.kubeobjects, s) - r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs2PodHash, 1, 1, 1, 1, true, false) + r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs2PodHash, 1, 1, 1, 1, true, false, false) r2.Status.ObservedGeneration = strconv.Itoa(int(r2.Generation)) f.rolloutLister = append(f.rolloutLister, r2) @@ -1197,8 +1217,8 @@ func TestBlueGreenRolloutCompletedFalse(t *testing.T) { err := json.Unmarshal([]byte(patch), &rolloutPatch) assert.NoError(t, err) - index := len(rolloutPatch.Status.Conditions) - 2 - assert.Equal(t, v1alpha1.RolloutCompleted, rolloutPatch.Status.Conditions[index].Type) + index := len(rolloutPatch.Status.Conditions) - 3 + assert.Equal(t, v1alpha1.RolloutHealthy, rolloutPatch.Status.Conditions[index].Type) assert.Equal(t, corev1.ConditionFalse, rolloutPatch.Status.Conditions[index].Status) } @@ -1220,7 +1240,7 @@ func TestBlueGreenUnableToReadScaleDownAt(t *testing.T) { f.kubeobjects = append(f.kubeobjects, s, rs1, rs2) f.replicaSetLister = append(f.replicaSetLister, rs1, rs2) - r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs2PodHash, 1, 1, 2, 1, false, true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs2PodHash, 1, 1, 2, 1, false, true, true) f.rolloutLister = append(f.rolloutLister, r2) f.objects = append(f.objects, r2) f.serviceLister = append(f.serviceLister, s) @@ -1257,7 +1277,7 @@ func TestBlueGreenNotReadyToScaleDownOldReplica(t *testing.T) { f.kubeobjects = append(f.kubeobjects, s, rs1, rs2) f.replicaSetLister = append(f.replicaSetLister, rs1, rs2) - r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs2PodHash, 1, 1, 2, 1, false, true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs2PodHash, 1, 1, 2, 1, false, true, true) f.rolloutLister = append(f.rolloutLister, r2) f.objects = append(f.objects, r2) f.serviceLister = append(f.serviceLister, s) @@ -1290,7 +1310,7 @@ func TestBlueGreenReadyToScaleDownOldReplica(t *testing.T) { f.kubeobjects = append(f.kubeobjects, s, rs1, rs2) f.replicaSetLister = append(f.replicaSetLister, rs1, rs2) - r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs2PodHash, 1, 1, 2, 1, false, true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs2PodHash, 1, 1, 2, 1, false, true, true) f.rolloutLister = append(f.rolloutLister, r2) f.objects = append(f.objects, r2) f.serviceLister = append(f.serviceLister, s) @@ -1335,7 +1355,7 @@ func TestFastRollback(t *testing.T) { r2.Status.CurrentPodHash = rs1PodHash rs1.Annotations[annotations.RevisionAnnotation] = "3" - r2 = updateBlueGreenRolloutStatus(r2, "", rs1PodHash, rs1PodHash, 1, 1, 2, 1, false, true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs1PodHash, rs1PodHash, 1, 1, 2, 1, false, true, true) f.rolloutLister = append(f.rolloutLister, r2) f.objects = append(f.objects, r2) f.serviceLister = append(f.serviceLister, s) @@ -1373,7 +1393,7 @@ func TestBlueGreenScaleDownLimit(t *testing.T) { f.kubeobjects = append(f.kubeobjects, s, rs1, rs2, rs3) f.replicaSetLister = append(f.replicaSetLister, rs1, rs2, rs3) - r3 = updateBlueGreenRolloutStatus(r3, "", rs3PodHash, rs3PodHash, 1, 1, 3, 1, false, true) + r3 = updateBlueGreenRolloutStatus(r3, "", rs3PodHash, rs3PodHash, 1, 1, 3, 1, false, true, true) f.rolloutLister = append(f.rolloutLister, r3) f.objects = append(f.objects, r3) f.serviceLister = append(f.serviceLister, s) @@ -1412,7 +1432,7 @@ func TestBlueGreenAbort(t *testing.T) { f.kubeobjects = append(f.kubeobjects, s, rs1, rs2) f.replicaSetLister = append(f.replicaSetLister, rs1, rs2) - r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs1PodHash, 1, 1, 2, 1, false, true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs1PodHash, 1, 1, 2, 1, false, true, true) f.rolloutLister = append(f.rolloutLister, r2) f.objects = append(f.objects, r2) f.serviceLister = append(f.serviceLister, s) @@ -1420,7 +1440,7 @@ func TestBlueGreenAbort(t *testing.T) { f.expectPatchServiceAction(s, rs1PodHash) patchIndex := f.expectPatchRolloutAction(r2) f.run(getKey(r2, t)) - expectedConditions := generateConditionsPatch(true, conditions.RolloutAbortedReason, r2, true, "") + expectedConditions := generateConditionsPatch(true, conditions.RolloutAbortedReason, r2, true, "", false) expectedPatch := fmt.Sprintf(`{ "status": { "blueGreen": { @@ -1449,7 +1469,7 @@ func TestBlueGreenHandlePauseAutoPromoteWithConditions(t *testing.T) { rs1PodHash := rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true) + r2 = updateBlueGreenRolloutStatus(r2, rs2PodHash, rs1PodHash, rs1PodHash, 1, 1, 2, 1, true, true, true) now := timeutil.MetaNow() before := metav1.NewTime(now.Add(-1 * time.Minute)) r2.Status.PauseConditions[0].StartTime = before @@ -1463,6 +1483,8 @@ func TestBlueGreenHandlePauseAutoPromoteWithConditions(t *testing.T) { availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) + //completedCondition, _ := newCompletedCondition(true) + //conditions.SetRolloutCondition(&r2.Status, completedCondition) r2.Status.Phase, r2.Status.Message = rolloututil.CalculateRolloutPhase(r2.Spec, r2.Status) activeSelector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs1PodHash} @@ -1481,7 +1503,7 @@ func TestBlueGreenHandlePauseAutoPromoteWithConditions(t *testing.T) { "blueGreen": { "activeSelector": "%s" }, - "conditions": [%s, %s, %s], + "conditions": [%s, %s, %s, %s], "stableRS": "%s", "pauseConditions": null, "controllerPause": null, @@ -1495,9 +1517,12 @@ func TestBlueGreenHandlePauseAutoPromoteWithConditions(t *testing.T) { updatedProgressingCond, _ := newProgressingCondition(conditions.ReplicaSetUpdatedReason, rs2, fmt.Sprintf("ReplicaSet \"%s\" is progressing.", rs2.Name)) progressingCondBytes, err := json.Marshal(updatedProgressingCond) assert.Nil(t, err) - pausedCondBytes, err := json.Marshal(r2.Status.Conditions[2]) + pausedCondBytes, err := json.Marshal(r2.Status.Conditions[3]) + assert.Nil(t, err) + completeCond, _ := newCompletedCondition(true) + completeCondBytes, err := json.Marshal(completeCond) assert.Nil(t, err) - expectedPatch := calculatePatch(r2, fmt.Sprintf(expectedPatchWithoutSubs, rs2PodHash, string(availableCondBytes), string(pausedCondBytes), string(progressingCondBytes), rs2PodHash, rs2PodHash)) + expectedPatch := calculatePatch(r2, fmt.Sprintf(expectedPatchWithoutSubs, rs2PodHash, string(availableCondBytes), string(completeCondBytes), string(pausedCondBytes), string(progressingCondBytes), rs2PodHash, rs2PodHash)) f.expectPatchServiceAction(activeSvc, rs2PodHash) patchRolloutIndex := f.expectPatchRolloutActionWithPatch(r2, expectedPatch) f.run(getKey(r2, t)) @@ -1521,8 +1546,8 @@ func TestBlueGreenAddScaleDownDelay(t *testing.T) { rs2 := newReplicaSetWithStatus(r2, 1, 1) rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] r2.Status.ObservedGeneration = strconv.Itoa(int(r2.Generation)) - r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs2PodHash, 1, 1, 2, 1, false, true) - completedCondition, _ := newCompletedCondition(true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs2PodHash, 1, 1, 2, 1, false, true, true) + completedCondition, _ := newHealthyCondition(true) conditions.SetRolloutCondition(&r2.Status, completedCondition) progressingCondition, _ := newProgressingCondition(conditions.NewRSAvailableReason, rs2, "") conditions.SetRolloutCondition(&r2.Status, progressingCondition) diff --git a/rollout/canary_test.go b/rollout/canary_test.go index 8cc1c3b0df..56445f3978 100644 --- a/rollout/canary_test.go +++ b/rollout/canary_test.go @@ -178,7 +178,7 @@ func TestCanaryRolloutEnterPauseState(t *testing.T) { } }` - conditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "") + conditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "", false) now := timeutil.MetaNow().UTC().Format(time.RFC3339) expectedPatchWithoutObservedGen := fmt.Sprintf(expectedPatchTemplate, v1alpha1.PauseReasonCanaryPauseStep, now, conditions, v1alpha1.PauseReasonCanaryPauseStep) expectedPatch := calculatePatch(r2, expectedPatchWithoutObservedGen) @@ -239,6 +239,9 @@ func TestCanaryRolloutUpdatePauseConditionWhilePaused(t *testing.T) { availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) + rs1 := newReplicaSetWithStatus(r1, 10, 10) rs2 := newReplicaSetWithStatus(r2, 0, 0) @@ -337,7 +340,7 @@ func TestCanaryRolloutIncrementStepAfterUnPaused(t *testing.T) { "currentStepIndex": 1 } }` - generatedConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs2, false, "") + generatedConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs2, false, "", false) expectedPatch := calculatePatch(r2, fmt.Sprintf(expectedPatchTemplate, generatedConditions)) assert.Equal(t, expectedPatch, patch) } @@ -379,7 +382,7 @@ func TestCanaryRolloutUpdateStatusWhenAtEndOfSteps(t *testing.T) { } }` - expectedPatch := fmt.Sprintf(expectedPatchWithoutStableRS, expectedStableRS, generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs2, false, "")) + expectedPatch := fmt.Sprintf(expectedPatchWithoutStableRS, expectedStableRS, generateConditionsPatchWithCompleted(true, conditions.ReplicaSetUpdatedReason, rs2, false, "", true)) assert.Equal(t, calculatePatch(r2, expectedPatch), patch) } @@ -421,7 +424,7 @@ func TestResetCurrentStepIndexOnStepChange(t *testing.T) { "conditions": %s } }` - newConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "") + newConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "", false) expectedPatch := fmt.Sprintf(expectedPatchWithoutPodHash, expectedCurrentPodHash, expectedCurrentStepHash, newConditions) assert.Equal(t, calculatePatch(r2, expectedPatch), patch) @@ -462,7 +465,7 @@ func TestResetCurrentStepIndexOnPodSpecChange(t *testing.T) { "conditions": %s } }` - newConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "") + newConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "", false) expectedPatch := fmt.Sprintf(expectedPatchWithoutPodHash, expectedCurrentPodHash, newConditions) assert.Equal(t, calculatePatch(r2, expectedPatch), patch) @@ -502,7 +505,7 @@ func TestCanaryRolloutCreateFirstReplicasetNoSteps(t *testing.T) { } }` - newConditions := generateConditionsPatch(false, conditions.ReplicaSetUpdatedReason, rs, false, "") + newConditions := generateConditionsPatchWithCompleted(false, conditions.ReplicaSetUpdatedReason, rs, false, "", true) assert.Equal(t, calculatePatch(r, fmt.Sprintf(expectedPatch, newConditions)), patch) } @@ -542,7 +545,7 @@ func TestCanaryRolloutCreateFirstReplicasetWithSteps(t *testing.T) { "conditions": %s } }` - expectedPatch := fmt.Sprintf(expectedPatchWithSub, generateConditionsPatch(false, conditions.ReplicaSetUpdatedReason, rs, false, "")) + expectedPatch := fmt.Sprintf(expectedPatchWithSub, generateConditionsPatchWithCompleted(false, conditions.ReplicaSetUpdatedReason, rs, false, "", true)) assert.Equal(t, calculatePatch(r, expectedPatch), patch) } @@ -840,7 +843,7 @@ func TestRollBackToStable(t *testing.T) { "conditions": %s } }` - newConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs1, false, "") + newConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs1, false, "", true) expectedPatch := fmt.Sprintf(expectedPatchWithoutSub, hash.ComputePodTemplateHash(&r2.Spec.Template, r2.Status.CollisionCount), newConditions) patch := f.getPatchedRollout(patchIndex) assert.Equal(t, calculatePatch(r2, expectedPatch), patch) @@ -883,7 +886,7 @@ func TestGradualShiftToNewStable(t *testing.T) { "conditions": %s } }` - newConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "") + newConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "", false) expectedPatch := fmt.Sprintf(expectedPatchWithoutSub, newConditions) patch := f.getPatchedRollout(patchIndex) assert.Equal(t, calculatePatch(r2, expectedPatch), patch) @@ -931,7 +934,7 @@ func TestRollBackToStableAndStepChange(t *testing.T) { }` newPodHash := hash.ComputePodTemplateHash(&r2.Spec.Template, r2.Status.CollisionCount) newStepHash := conditions.ComputeStepHash(r2) - newConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs1, false, "") + newConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs1, false, "", true) expectedPatch := fmt.Sprintf(expectedPatchWithoutSub, newPodHash, newStepHash, newConditions) patch := f.getPatchedRollout(patchIndex) assert.Equal(t, calculatePatch(r2, expectedPatch), patch) @@ -969,7 +972,7 @@ func TestCanaryRolloutIncrementStepIfSetWeightsAreCorrect(t *testing.T) { "conditions": %s } }` - newConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs3, false, "") + newConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs3, false, "", false) assert.Equal(t, calculatePatch(r3, fmt.Sprintf(expectedPatch, newConditions)), patch) } @@ -1005,6 +1008,9 @@ func TestSyncRolloutWaitAddToQueue(t *testing.T) { availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) + r2.Status.ObservedGeneration = strconv.Itoa(int(r2.Generation)) f.rolloutLister = append(f.rolloutLister, r2) f.objects = append(f.objects, r2) @@ -1053,6 +1059,9 @@ func TestSyncRolloutIgnoreWaitOutsideOfReconciliationPeriod(t *testing.T) { availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) + f.rolloutLister = append(f.rolloutLister, r2) f.objects = append(f.objects, r2) @@ -1617,6 +1626,9 @@ func TestHandleNilNewRSOnScaleAndImageChange(t *testing.T) { availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) + f.kubeobjects = append(f.kubeobjects, rs1) f.replicaSetLister = append(f.replicaSetLister, rs1) f.rolloutLister = append(f.rolloutLister, r2) @@ -1672,7 +1684,7 @@ func TestHandleCanaryAbort(t *testing.T) { } }` errmsg := fmt.Sprintf(conditions.RolloutAbortedMessage, 2) - newConditions := generateConditionsPatch(true, conditions.RolloutAbortedReason, r2, false, "") + newConditions := generateConditionsPatch(true, conditions.RolloutAbortedReason, r2, false, "", false) assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, newConditions, conditions.RolloutAbortedReason, errmsg)), patch) }) @@ -1710,7 +1722,7 @@ func TestHandleCanaryAbort(t *testing.T) { } }` errmsg := fmt.Sprintf(conditions.RolloutAbortedMessage, 1) - newConditions := generateConditionsPatch(true, conditions.RolloutAbortedReason, r1, false, "") + newConditions := generateConditionsPatch(true, conditions.RolloutAbortedReason, r1, false, "", true) assert.Equal(t, calculatePatch(r1, fmt.Sprintf(expectedPatch, newConditions, conditions.RolloutAbortedReason, errmsg)), patch) }) } diff --git a/rollout/controller_test.go b/rollout/controller_test.go index 7f324ea10b..0e97a405e9 100644 --- a/rollout/controller_test.go +++ b/rollout/controller_test.go @@ -193,6 +193,28 @@ func newPausedCondition(isPaused bool) (v1alpha1.RolloutCondition, string) { return condition, string(conditionBytes) } +func newHealthyCondition(isHealthy bool) (v1alpha1.RolloutCondition, string) { + status := corev1.ConditionTrue + msg := conditions.RolloutHealthyMessage + if !isHealthy { + status = corev1.ConditionFalse + msg = conditions.RolloutNotHealthyMessage + } + condition := v1alpha1.RolloutCondition{ + LastTransitionTime: timeutil.MetaNow(), + LastUpdateTime: timeutil.MetaNow(), + Message: msg, + Reason: conditions.RolloutHealthyReason, + Status: status, + Type: v1alpha1.RolloutHealthy, + } + conditionBytes, err := json.Marshal(condition) + if err != nil { + panic(err) + } + return condition, string(conditionBytes) +} + func newCompletedCondition(isCompleted bool) (v1alpha1.RolloutCondition, string) { status := corev1.ConditionTrue if !isCompleted { @@ -315,33 +337,57 @@ func newAvailableCondition(available bool) (v1alpha1.RolloutCondition, string) { return condition, string(conditionBytes) } -func generateConditionsPatch(available bool, progressingReason string, progressingResource runtime.Object, availableConditionFirst bool, progressingMessage string) string { +func generateConditionsPatch(available bool, progressingReason string, progressingResource runtime.Object, availableConditionFirst bool, progressingMessage string, isCompleted bool) string { _, availableCondition := newAvailableCondition(available) _, progressingCondition := newProgressingCondition(progressingReason, progressingResource, progressingMessage) + _, completedCondition := newCompletedCondition(isCompleted) if availableConditionFirst { - return fmt.Sprintf("[%s, %s]", availableCondition, progressingCondition) + return fmt.Sprintf("[%s, %s, %s]", availableCondition, progressingCondition, completedCondition) } - return fmt.Sprintf("[%s, %s]", progressingCondition, availableCondition) + return fmt.Sprintf("[%s, %s, %s]", progressingCondition, availableCondition, completedCondition) } -func generateConditionsPatchWithPause(available bool, progressingReason string, progressingResource runtime.Object, availableConditionFirst bool, progressingMessage string, isPaused bool) string { +func generateConditionsPatchWithPause(available bool, progressingReason string, progressingResource runtime.Object, availableConditionFirst bool, progressingMessage string, isPaused bool, isCompleted bool) string { _, availableCondition := newAvailableCondition(available) _, progressingCondition := newProgressingCondition(progressingReason, progressingResource, progressingMessage) _, pauseCondition := newPausedCondition(isPaused) + _, completedCondition := newCompletedCondition(isCompleted) + if availableConditionFirst { + return fmt.Sprintf("[%s, %s, %s, %s]", availableCondition, completedCondition, progressingCondition, pauseCondition) + } + return fmt.Sprintf("[%s, %s, %s, %s]", progressingCondition, pauseCondition, availableCondition, completedCondition) +} + +func generateConditionsPatchWithHealthy(available bool, progressingReason string, progressingResource runtime.Object, availableConditionFirst bool, progressingMessage string, isHealthy bool, isCompleted bool) string { + _, availableCondition := newAvailableCondition(available) + _, progressingCondition := newProgressingCondition(progressingReason, progressingResource, progressingMessage) + _, healthyCondition := newHealthyCondition(isHealthy) + _, completedCondition := newCompletedCondition(isCompleted) if availableConditionFirst { - return fmt.Sprintf("[%s, %s, %s]", availableCondition, progressingCondition, pauseCondition) + return fmt.Sprintf("[%s, %s, %s, %s]", availableCondition, completedCondition, healthyCondition, progressingCondition) } - return fmt.Sprintf("[%s, %s, %s]", progressingCondition, pauseCondition, availableCondition) + return fmt.Sprintf("[%s, %s, %s, %s]", completedCondition, healthyCondition, progressingCondition, availableCondition) } -func generateConditionsPatchWithComplete(available bool, progressingReason string, progressingResource runtime.Object, availableConditionFirst bool, progressingMessage string, isCompleted bool) string { +func generateConditionsPatchWithCompleted(available bool, progressingReason string, progressingResource runtime.Object, availableConditionFirst bool, progressingMessage string, isCompleted bool) string { _, availableCondition := newAvailableCondition(available) _, progressingCondition := newProgressingCondition(progressingReason, progressingResource, progressingMessage) _, completeCondition := newCompletedCondition(isCompleted) if availableConditionFirst { - return fmt.Sprintf("[%s, %s, %s]", availableCondition, completeCondition, progressingCondition) + return fmt.Sprintf("[%s, %s, %s]", availableCondition, progressingCondition, completeCondition) + } + return fmt.Sprintf("[%s, %s, %s]", progressingCondition, availableCondition, completeCondition) +} + +func generateConditionsPatchWithCompletedHealthy(available bool, progressingReason string, progressingResource runtime.Object, availableConditionFirst bool, progressingMessage string, isHealthy bool, isCompleted bool) string { + _, completedCondition := newCompletedCondition(isCompleted) + _, availableCondition := newAvailableCondition(available) + _, progressingCondition := newProgressingCondition(progressingReason, progressingResource, progressingMessage) + _, healthyCondition := newHealthyCondition(isHealthy) + if availableConditionFirst { + return fmt.Sprintf("[%s, %s, %s, %s]", availableCondition, healthyCondition, completedCondition, progressingCondition) } - return fmt.Sprintf("[%s, %s, %s]", completeCondition, progressingCondition, availableCondition) + return fmt.Sprintf("[%s, %s, %s, %s]", healthyCondition, completedCondition, progressingCondition, availableCondition) } func updateConditionsPatch(r v1alpha1.Rollout, newCondition v1alpha1.RolloutCondition) string { @@ -351,7 +397,7 @@ func updateConditionsPatch(r v1alpha1.Rollout, newCondition v1alpha1.RolloutCond } // func updateBlueGreenRolloutStatus(r *v1alpha1.Rollout, preview, active string, availableReplicas, updatedReplicas, hpaReplicas int32, pause bool, available bool, progressingStatus string) *v1alpha1.Rollout { -func updateBlueGreenRolloutStatus(r *v1alpha1.Rollout, preview, active, stable string, availableReplicas, updatedReplicas, totalReplicas, hpaReplicas int32, pause bool, available bool) *v1alpha1.Rollout { +func updateBlueGreenRolloutStatus(r *v1alpha1.Rollout, preview, active, stable string, availableReplicas, updatedReplicas, totalReplicas, hpaReplicas int32, pause bool, available bool, isCompleted bool) *v1alpha1.Rollout { newRollout := updateBaseRolloutStatus(r, availableReplicas, updatedReplicas, totalReplicas, hpaReplicas) selector := newRollout.Spec.Selector.DeepCopy() if active != "" { @@ -363,6 +409,8 @@ func updateBlueGreenRolloutStatus(r *v1alpha1.Rollout, preview, active, stable s newRollout.Status.StableRS = stable cond, _ := newAvailableCondition(available) newRollout.Status.Conditions = append(newRollout.Status.Conditions, cond) + completeCond, _ := newCompletedCondition(isCompleted) + newRollout.Status.Conditions = append(newRollout.Status.Conditions, completeCond) if pause { now := timeutil.MetaNow() cond := v1alpha1.PauseCondition{ @@ -1390,6 +1438,8 @@ func TestComputeHashChangeTolerationBlueGreen(t *testing.T) { conditions.SetRolloutCondition(&r.Status, availableCondition) progressingCondition, _ := newProgressingCondition(conditions.ReplicaSetUpdatedReason, rs, "") conditions.SetRolloutCondition(&r.Status, progressingCondition) + completedCondition, _ := newCompletedCondition(true) + conditions.SetRolloutCondition(&r.Status, completedCondition) r.Status.Phase, r.Status.Message = rolloututil.CalculateRolloutPhase(r.Spec, r.Status) podTemplate := corev1.PodTemplate{ @@ -1434,6 +1484,8 @@ func TestComputeHashChangeTolerationCanary(t *testing.T) { conditions.SetRolloutCondition(&r.Status, availableCondition) progressingCondition, _ := newProgressingCondition(conditions.ReplicaSetUpdatedReason, rs, "") conditions.SetRolloutCondition(&r.Status, progressingCondition) + completedCondition, _ := newCompletedCondition(true) + conditions.SetRolloutCondition(&r.Status, completedCondition) podTemplate := corev1.PodTemplate{ Template: rs.Spec.Template, @@ -1461,7 +1513,7 @@ func TestSwitchBlueGreenToCanary(t *testing.T) { activeSvc := newService("active", 80, nil, r) rs := newReplicaSetWithStatus(r, 1, 1) rsPodHash := rs.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] - r = updateBlueGreenRolloutStatus(r, "", rsPodHash, rsPodHash, 1, 1, 1, 1, false, true) + r = updateBlueGreenRolloutStatus(r, "", rsPodHash, rsPodHash, 1, 1, 1, 1, false, true, false) // StableRS is set to avoid running the migration code. When .status.canary.stableRS is removed, the line below can be deleted //r.Status.Canary.StableRS = rsPodHash r.Spec.Strategy.BlueGreen = nil @@ -1479,7 +1531,7 @@ func TestSwitchBlueGreenToCanary(t *testing.T) { f.run(getKey(r, t)) patch := f.getPatchedRollout(i) - addedConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs, true, "") + addedConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs, true, "", true) expectedPatch := fmt.Sprintf(`{ "status": { "blueGreen": { diff --git a/rollout/experiment_test.go b/rollout/experiment_test.go index c8b610a303..e2e50c1f28 100644 --- a/rollout/experiment_test.go +++ b/rollout/experiment_test.go @@ -68,7 +68,7 @@ func TestRolloutCreateExperiment(t *testing.T) { "conditions": %s } }` - conds := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "") + conds := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "", false) assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, ex.Name, conds)), patch) } @@ -125,7 +125,7 @@ func TestRolloutCreateClusterTemplateExperiment(t *testing.T) { "conditions": %s } }` - conds := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "") + conds := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "", false) assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, ex.Name, conds)), patch) } @@ -177,7 +177,7 @@ func TestCreateExperimentWithCollision(t *testing.T) { "conditions": %s } }` - conds := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "") + conds := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "", false) assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, createdEx.Name, conds)), patch) } @@ -228,7 +228,7 @@ func TestCreateExperimentWithCollisionAndSemanticEquality(t *testing.T) { "conditions": %s } }` - conds := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "") + conds := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, r2, false, "", false) assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, ex.Name, conds)), patch) } @@ -256,6 +256,8 @@ func TestRolloutExperimentProcessingDoNothing(t *testing.T) { conditions.SetRolloutCondition(&r2.Status, progressingCondition) availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) f.rolloutLister = append(f.rolloutLister, r2) f.experimentLister = append(f.experimentLister, ex) @@ -311,7 +313,7 @@ func TestAbortRolloutAfterFailedExperiment(t *testing.T) { } }` now := timeutil.Now().UTC().Format(time.RFC3339) - generatedConditions := generateConditionsPatch(true, conditions.RolloutAbortedReason, r2, false, "") + generatedConditions := generateConditionsPatch(true, conditions.RolloutAbortedReason, r2, false, "", false) assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, now, generatedConditions, conditions.RolloutAbortedReason, fmt.Sprintf(conditions.RolloutAbortedMessage, 2))), patch) } @@ -477,7 +479,7 @@ func TestRolloutExperimentFinishedIncrementStep(t *testing.T) { "conditions": %s } }` - generatedConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs2, false, "") + generatedConditions := generateConditionsPatch(true, conditions.ReplicaSetUpdatedReason, rs2, false, "", false) assert.Equal(t, calculatePatch(r2, fmt.Sprintf(expectedPatch, generatedConditions)), patch) } diff --git a/rollout/service_test.go b/rollout/service_test.go index aa4f1d020b..8a402d001c 100644 --- a/rollout/service_test.go +++ b/rollout/service_test.go @@ -302,13 +302,15 @@ func TestBlueGreenAWSVerifyTargetGroupsNotYetReady(t *testing.T) { rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] svc := newService("active", 80, map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash}, r2) - r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs1PodHash, 3, 3, 6, 3, false, true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs1PodHash, 3, 3, 6, 3, false, true, false) r2.Status.Message = "" r2.Status.ObservedGeneration = strconv.Itoa(int(r2.Generation)) - completedCondition, _ := newCompletedCondition(true) - conditions.SetRolloutCondition(&r2.Status, completedCondition) + completedHealthyCondition, _ := newHealthyCondition(true) + conditions.SetRolloutCondition(&r2.Status, completedHealthyCondition) progressingCondition, _ := newProgressingCondition(conditions.NewRSAvailableReason, rs2, "") conditions.SetRolloutCondition(&r2.Status, progressingCondition) + completedCondition, _ := newCompletedCondition(false) + conditions.SetRolloutCondition(&r2.Status, completedCondition) f.rolloutLister = append(f.rolloutLister, r2) f.objects = append(f.objects, r2, tgb) @@ -385,13 +387,15 @@ func TestBlueGreenAWSVerifyTargetGroupsReady(t *testing.T) { rs2PodHash := rs2.Labels[v1alpha1.DefaultRolloutUniqueLabelKey] svc := newService("active", 80, map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash}, r2) - r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs1PodHash, 3, 3, 6, 3, false, true) + r2 = updateBlueGreenRolloutStatus(r2, "", rs2PodHash, rs1PodHash, 3, 3, 6, 3, false, true, false) r2.Status.Message = "waiting for post-promotion verification to complete" r2.Status.ObservedGeneration = strconv.Itoa(int(r2.Generation)) - completedCondition, _ := newCompletedCondition(true) + completedCondition, _ := newHealthyCondition(true) conditions.SetRolloutCondition(&r2.Status, completedCondition) progressingCondition, _ := newProgressingCondition(conditions.NewRSAvailableReason, rs2, "") conditions.SetRolloutCondition(&r2.Status, progressingCondition) + completedCond := conditions.NewRolloutCondition(v1alpha1.RolloutCompleted, corev1.ConditionTrue, conditions.RolloutCompletedReason, conditions.RolloutCompletedReason) + conditions.SetRolloutCondition(&r2.Status, *completedCond) f.rolloutLister = append(f.rolloutLister, r2) f.objects = append(f.objects, r2, tgb) @@ -489,10 +493,12 @@ func TestCanaryAWSVerifyTargetGroupsNotYetReady(t *testing.T) { r2.Status.StableRS = rs2PodHash availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) - completedCondition, _ := newCompletedCondition(false) - conditions.SetRolloutCondition(&r2.Status, completedCondition) + healthyCondition, _ := newHealthyCondition(false) + conditions.SetRolloutCondition(&r2.Status, healthyCondition) progressingCondition, _ := newProgressingCondition(conditions.NewRSAvailableReason, rs2, "") conditions.SetRolloutCondition(&r2.Status, progressingCondition) + completedCondition, _ := newCompletedCondition(true) + conditions.SetRolloutCondition(&r2.Status, completedCondition) _, r2.Status.Canary.Weights = calculateWeightStatus(r2, rs2PodHash, rs2PodHash, 0) f.rolloutLister = append(f.rolloutLister, r2) @@ -585,10 +591,12 @@ func TestCanaryAWSVerifyTargetGroupsReady(t *testing.T) { r2.Status.StableRS = rs2PodHash availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) - completedCondition, _ := newCompletedCondition(false) - conditions.SetRolloutCondition(&r2.Status, completedCondition) + healthyCondition, _ := newHealthyCondition(false) + conditions.SetRolloutCondition(&r2.Status, healthyCondition) progressingCondition, _ := newProgressingCondition(conditions.NewRSAvailableReason, rs2, "") conditions.SetRolloutCondition(&r2.Status, progressingCondition) + completedCondition, _ := newCompletedCondition(true) + conditions.SetRolloutCondition(&r2.Status, completedCondition) _, r2.Status.Canary.Weights = calculateWeightStatus(r2, rs2PodHash, rs2PodHash, 0) f.rolloutLister = append(f.rolloutLister, r2) @@ -646,10 +654,12 @@ func TestCanaryAWSVerifyTargetGroupsSkip(t *testing.T) { r2.Status.StableRS = rs2PodHash availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) - completedCondition, _ := newCompletedCondition(false) - conditions.SetRolloutCondition(&r2.Status, completedCondition) + healthyCondition, _ := newHealthyCondition(false) + conditions.SetRolloutCondition(&r2.Status, healthyCondition) progressingCondition, _ := newProgressingCondition(conditions.NewRSAvailableReason, rs2, "") conditions.SetRolloutCondition(&r2.Status, progressingCondition) + completedCondition, _ := newCompletedCondition(true) + conditions.SetRolloutCondition(&r2.Status, completedCondition) _, r2.Status.Canary.Weights = calculateWeightStatus(r2, rs2PodHash, rs2PodHash, 0) f.rolloutLister = append(f.rolloutLister, r2) diff --git a/rollout/sync.go b/rollout/sync.go index fc260f8633..b9bc616552 100644 --- a/rollout/sync.go +++ b/rollout/sync.go @@ -547,15 +547,19 @@ func (c *rolloutContext) calculateRolloutConditions(newStatus v1alpha1.RolloutSt isPaused := len(c.rollout.Status.PauseConditions) > 0 || c.rollout.Spec.Paused isAborted := c.pauseContext.IsAborted() - var becameIncomplete bool // remember if we transitioned from completed - completeCond := conditions.GetRolloutCondition(c.rollout.Status, v1alpha1.RolloutCompleted) - if !isPaused && conditions.RolloutComplete(c.rollout, &newStatus) { - updateCompletedCond := conditions.NewRolloutCondition(v1alpha1.RolloutCompleted, corev1.ConditionTrue, conditions.RolloutCompletedReason, conditions.RolloutCompletedReason) - conditions.SetRolloutCondition(&newStatus, *updateCompletedCond) + var becameUnhealthy bool // remember if we transitioned from healthy to unhealthy + completeCond := conditions.GetRolloutCondition(c.rollout.Status, v1alpha1.RolloutHealthy) + if !isPaused && conditions.RolloutHealthy(c.rollout, &newStatus) { + updateHealthyCond := conditions.NewRolloutCondition(v1alpha1.RolloutHealthy, corev1.ConditionTrue, conditions.RolloutHealthyReason, conditions.RolloutHealthyMessage) + conditions.SetRolloutCondition(&newStatus, *updateHealthyCond) + // If we ever wanted to emit a healthy event here it would be noisy and somewhat unpredictable for tests and so should probably be skipped + // when checking in e2e and unit tests. + //c.recorder.Warnf(c.rollout, record.EventOptions{EventReason: conditions.RolloutHealthyReason}, conditions.RolloutHealthyMessage) } else { if completeCond != nil { - updateCompletedCond := conditions.NewRolloutCondition(v1alpha1.RolloutCompleted, corev1.ConditionFalse, conditions.RolloutCompletedReason, conditions.RolloutCompletedReason) - becameIncomplete = conditions.SetRolloutCondition(&newStatus, *updateCompletedCond) + updateHealthyCond := conditions.NewRolloutCondition(v1alpha1.RolloutHealthy, corev1.ConditionFalse, conditions.RolloutHealthyReason, conditions.RolloutNotHealthyMessage) + becameUnhealthy = conditions.SetRolloutCondition(&newStatus, *updateHealthyCond) + //c.recorder.Warnf(c.rollout, record.EventOptions{EventReason: conditions.RolloutHealthyReason}, conditions.RolloutNotHealthyMessage) } } @@ -576,11 +580,11 @@ func (c *rolloutContext) calculateRolloutConditions(newStatus v1alpha1.RolloutSt // In such a case, we should simply not estimate any progress for this rollout. currentCond := conditions.GetRolloutCondition(c.rollout.Status, v1alpha1.RolloutProgressing) - isCompleteRollout := newStatus.Replicas == newStatus.AvailableReplicas && currentCond != nil && currentCond.Reason == conditions.NewRSAvailableReason && currentCond.Type != v1alpha1.RolloutProgressing + isHealthyRollout := newStatus.Replicas == newStatus.AvailableReplicas && currentCond != nil && currentCond.Reason == conditions.NewRSAvailableReason && currentCond.Type != v1alpha1.RolloutProgressing // Check for progress. Only do this if the latest rollout hasn't completed yet and it is not aborted - if !isCompleteRollout && !isAborted { + if !isHealthyRollout && !isAborted { switch { - case conditions.RolloutComplete(c.rollout, &newStatus): + case conditions.RolloutHealthy(c.rollout, &newStatus): // Update the rollout conditions with a message for the new replica set that // was successfully deployed. If the condition already exists, we ignore this update. rsName := "" @@ -590,7 +594,7 @@ func (c *rolloutContext) calculateRolloutConditions(newStatus v1alpha1.RolloutSt msg := fmt.Sprintf(conditions.ReplicaSetCompletedMessage, rsName) progressingCondition := conditions.NewRolloutCondition(v1alpha1.RolloutProgressing, corev1.ConditionTrue, conditions.NewRSAvailableReason, msg) conditions.SetRolloutCondition(&newStatus, *progressingCondition) - case conditions.RolloutProgressing(c.rollout, &newStatus) || becameIncomplete: + case conditions.RolloutProgressing(c.rollout, &newStatus) || becameUnhealthy: // If there is any progress made, continue by not checking if the rollout failed. This // behavior emulates the rolling updater progressDeadline check. msg := fmt.Sprintf(conditions.RolloutProgressingMessage, c.rollout.Name) @@ -599,7 +603,7 @@ func (c *rolloutContext) calculateRolloutConditions(newStatus v1alpha1.RolloutSt } var reason string - if newStatus.StableRS == newStatus.CurrentPodHash && becameIncomplete { + if newStatus.StableRS == newStatus.CurrentPodHash && becameUnhealthy { // When a fully promoted rollout becomes Incomplete, e.g., due to the ReplicaSet status changes like // pod restarts, evicted -> recreated, we'll need to reset the rollout's condition to `PROGRESSING` to // avoid any timeouts. @@ -672,6 +676,22 @@ func (c *rolloutContext) calculateRolloutConditions(newStatus v1alpha1.RolloutSt } else { conditions.RemoveRolloutCondition(&newStatus, v1alpha1.RolloutReplicaFailure) } + + if conditions.RolloutCompleted(c.rollout, &newStatus) { + // The event gets triggered in function promoteStable + updateCompletedCond := conditions.NewRolloutCondition(v1alpha1.RolloutCompleted, corev1.ConditionTrue, + conditions.RolloutCompletedReason, conditions.RolloutCompletedReason) + conditions.SetRolloutCondition(&newStatus, *updateCompletedCond) + } else { + updateCompletedCond := conditions.NewRolloutCondition(v1alpha1.RolloutCompleted, corev1.ConditionFalse, + conditions.RolloutCompletedReason, conditions.RolloutCompletedReason) + if conditions.SetRolloutCondition(&newStatus, *updateCompletedCond) { + revision, _ := replicasetutil.Revision(c.rollout) + c.recorder.Eventf(c.rollout, record.EventOptions{EventReason: conditions.RolloutNotCompletedReason}, + conditions.RolloutNotCompletedMessage, revision+1, newStatus.CurrentPodHash) + } + } + return newStatus } @@ -754,7 +774,7 @@ func (c *rolloutContext) requeueStuckRollout(newStatus v1alpha1.RolloutStatus) t } // No need to estimate progress if the rollout is complete or already timed out. isPaused := len(c.rollout.Status.PauseConditions) > 0 || c.rollout.Spec.Paused - if conditions.RolloutComplete(c.rollout, &newStatus) || currentCond.Reason == conditions.TimedOutReason || isPaused || c.rollout.Status.Abort || isIndefiniteStep(c.rollout) { + if conditions.RolloutHealthy(c.rollout, &newStatus) || currentCond.Reason == conditions.TimedOutReason || isPaused || c.rollout.Status.Abort || isIndefiniteStep(c.rollout) { return time.Duration(-1) } // If there is no sign of progress at this point then there is a high chance that the @@ -923,6 +943,7 @@ func (c *rolloutContext) promoteStable(newStatus *v1alpha1.RolloutStatus, reason } } newStatus.StableRS = newStatus.CurrentPodHash + revision, _ := replicasetutil.Revision(c.rollout) c.recorder.Eventf(c.rollout, record.EventOptions{EventReason: conditions.RolloutCompletedReason}, conditions.RolloutCompletedMessage, revision, newStatus.CurrentPodHash, reason) diff --git a/rollout/trafficrouting_test.go b/rollout/trafficrouting_test.go index abb0cc09f6..6c1e49f476 100644 --- a/rollout/trafficrouting_test.go +++ b/rollout/trafficrouting_test.go @@ -739,6 +739,8 @@ func TestCanaryWithTrafficRoutingAddScaleDownDelay(t *testing.T) { r2.Status.ObservedGeneration = strconv.Itoa(int(r2.Generation)) availableCondition, _ := newAvailableCondition(true) conditions.SetRolloutCondition(&r2.Status, availableCondition) + completedCondition, _ := newCompletedCondition(true) + conditions.SetRolloutCondition(&r2.Status, completedCondition) _, r2.Status.Canary.Weights = calculateWeightStatus(r2, rs2PodHash, rs2PodHash, 0) selector := map[string]string{v1alpha1.DefaultRolloutUniqueLabelKey: rs2PodHash} diff --git a/test/e2e/functional_test.go b/test/e2e/functional_test.go index f4380c3562..8ca5a026ac 100644 --- a/test/e2e/functional_test.go +++ b/test/e2e/functional_test.go @@ -90,10 +90,12 @@ spec: ExpectRevisionPodCount("1", 0). ExpectRevisionPodCount("2", 1). ExpectRolloutEvents([]string{ + "RolloutNotCompleted", // Rollout not completed, started update to revision 0 (7fd9b5545c) "RolloutUpdated", // Rollout updated to revision 1 "NewReplicaSetCreated", // Created ReplicaSet abort-retry-promote-698fbfb9dc (revision 1) "ScalingReplicaSet", // Scaled up ReplicaSet abort-retry-promote-698fbfb9dc (revision 1) from 0 to 1 "RolloutCompleted", // Rollout completed update to revision 1 (698fbfb9dc): Initial deploy + "RolloutNotCompleted", "RolloutUpdated", // Rollout updated to revision 2 "NewReplicaSetCreated", // Created ReplicaSet abort-retry-promote-75dcb5ddd6 (revision 2) "ScalingReplicaSet", // Scaled up ReplicaSet abort-retry-promote-75dcb5ddd6 (revision 2) from 0 to 1 @@ -706,6 +708,7 @@ func (s *FunctionalSuite) TestBlueGreenUpdate() { "SwitchService", // Switched selector for service 'bluegreen' from '' to '7dcd8f8869' "RolloutUpdated", // Rollout updated to revision 2 "NewReplicaSetCreated", // Created ReplicaSet bluegreen-5498785cd6 (revision 2) + "RolloutNotCompleted", // Rollout went to not completed state started update to revision 2 (85c6899) "ScalingReplicaSet", // Scaled up ReplicaSet bluegreen-5498785cd6 (revision 2) from 0 to 3 "SwitchService", // Switched selector for service 'bluegreen' from '7dcd8f8869' to '6c779b88b6' "RolloutCompleted", // Rollout completed update to revision 2 (6c779b88b6): Completed blue-green update @@ -959,7 +962,7 @@ spec: Then(). ExpectRevisionPodCount("2", 0). ExpectRollout("Abort=True", func(r *v1alpha1.Rollout) bool { - return r.Status.Abort == true && len(r.Status.Conditions) == 3 + return r.Status.Abort == true && len(r.Status.Conditions) == 4 }) } @@ -1120,10 +1123,10 @@ func (s *FunctionalSuite) TestKubectlWaitForCompleted() { kind: Service apiVersion: v1 metadata: - name: kubectl-wait-completed + name: kubectl-wait-healthy spec: selector: - app: kubectl-wait-completed + app: kubectl-wait-healthy ports: - protocol: TCP port: 80 @@ -1132,19 +1135,19 @@ spec: apiVersion: argoproj.io/v1alpha1 kind: Rollout metadata: - name: kubectl-wait-completed + name: kubectl-wait-healthy spec: replicas: 1 selector: matchLabels: - app: kubectl-wait-completed + app: kubectl-wait-healthy template: metadata: labels: - app: kubectl-wait-completed + app: kubectl-wait-healthy spec: containers: - - name: kubectl-wait-completed + - name: kubectl-wait-healthy image: nginx:1.19-alpine imagePullPolicy: Always ports: @@ -1158,21 +1161,21 @@ spec: strategy: blueGreen: - activeService: kubectl-wait-completed + activeService: kubectl-wait-healthy autoPromotionEnabled: true `). When(). UpdateSpec(). Then(). - ExpectRollout("Completed=False", func(r *v1alpha1.Rollout) bool { - cmd := exec.Command("kubectl", "wait", "--for=condition=Completed=False", fmt.Sprintf("rollout/%s", r.Name)) + ExpectRollout("Healthy=False", func(r *v1alpha1.Rollout) bool { + cmd := exec.Command("kubectl", "wait", "--for=condition=Healthy=False", fmt.Sprintf("rollout/%s", r.Name)) out, err := cmd.CombinedOutput() return err == nil && strings.Contains(string(out), fmt.Sprintf("rollout.argoproj.io/%s condition met", r.Name)) }). ExpectRolloutStatus("Progressing"). ExpectActiveRevision("1"). - ExpectRollout("Completed=True", func(r *v1alpha1.Rollout) bool { - cmd := exec.Command("kubectl", "wait", "--for=condition=Completed=True", fmt.Sprintf("rollout/%s", r.Name)) + ExpectRollout("Healthy=True", func(r *v1alpha1.Rollout) bool { + cmd := exec.Command("kubectl", "wait", "--for=condition=Healthy=True", fmt.Sprintf("rollout/%s", r.Name)) out, err := cmd.CombinedOutput() return err == nil && strings.Contains(string(out), fmt.Sprintf("rollout.argoproj.io/%s condition met", r.Name)) }). diff --git a/utils/conditions/conditions.go b/utils/conditions/conditions.go index 99b6d59ddf..c2aaece787 100644 --- a/utils/conditions/conditions.go +++ b/utils/conditions/conditions.go @@ -68,6 +68,17 @@ const ( RolloutCompletedReason = "RolloutCompleted" // RolloutCompletedMessage is added when the rollout is completed RolloutCompletedMessage = "Rollout completed update to revision %d (%s): %s" + // RolloutNotCompletedReason is added in a rollout when it is completed. + RolloutNotCompletedReason = "RolloutNotCompleted" + // RolloutNotCompletedMessage is added when the rollout is completed + RolloutNotCompletedMessage = "Rollout not completed, started update to revision %d (%s)" + + // RolloutHealthyReason is added in a rollout when it is healthy. + RolloutHealthyReason = "RolloutHealthy" + // RolloutHealthyMessage is added when the rollout is completed and is healthy or not. + RolloutHealthyMessage = "Rollout is healthy" + // RolloutNotHealthyMessage is added when the rollout is completed and is healthy or not. + RolloutNotHealthyMessage = "Rollout is not healthy" // RolloutAbortedReason indicates that the rollout was aborted RolloutAbortedReason = "RolloutAborted" @@ -125,7 +136,7 @@ const ( // TimedOutReason is added in a rollout when its newest replica set fails to show any progress // within the given deadline (progressDeadlineSeconds). TimedOutReason = "ProgressDeadlineExceeded" - // RolloutTimeOutMessage is is added in a rollout when the rollout fails to show any progress + // RolloutTimeOutMessage is added in a rollout when the rollout fails to show any progress // within the given deadline (progressDeadlineSeconds). RolloutTimeOutMessage = "Rollout %q has timed out progressing." @@ -257,9 +268,9 @@ func RolloutProgressing(rollout *v1alpha1.Rollout, newStatus *v1alpha1.RolloutSt strategySpecificProgress } -// RolloutComplete considers a rollout to be complete once all of its desired replicas +// RolloutHealthy considers a rollout to be healthy once all of its desired replicas // are updated, available, and receiving traffic from the active service, and no old pods are running. -func RolloutComplete(rollout *v1alpha1.Rollout, newStatus *v1alpha1.RolloutStatus) bool { +func RolloutHealthy(rollout *v1alpha1.Rollout, newStatus *v1alpha1.RolloutStatus) bool { completedStrategy := true replicas := defaults.GetReplicasOrDefault(rollout.Spec.Replicas) @@ -288,6 +299,11 @@ func RolloutComplete(rollout *v1alpha1.Rollout, newStatus *v1alpha1.RolloutStatu completedStrategy } +// RolloutCompleted considers a rollout to be complete once StableRS == CurrentPodHash +func RolloutCompleted(rollout *v1alpha1.Rollout, newStatus *v1alpha1.RolloutStatus) bool { + return newStatus.StableRS != "" && newStatus.StableRS == newStatus.CurrentPodHash +} + // ComputeStepHash returns a hash value calculated from the Rollout's steps. The hash will // be safe encoded to avoid bad words. func ComputeStepHash(rollout *v1alpha1.Rollout) string { diff --git a/utils/conditions/rollouts_test.go b/utils/conditions/rollouts_test.go index f6e3e02550..842f01f594 100644 --- a/utils/conditions/rollouts_test.go +++ b/utils/conditions/rollouts_test.go @@ -350,7 +350,7 @@ func TestRolloutProgressing(t *testing.T) { } -func TestRolloutComplete(t *testing.T) { +func TestRolloutHealthy(t *testing.T) { rollout := func(desired, current, updated, available int32, correctObservedGeneration bool) *v1alpha1.Rollout { r := &v1alpha1.Rollout{ Spec: v1alpha1.RolloutSpec{ @@ -475,12 +475,36 @@ func TestRolloutComplete(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - assert.Equal(t, test.expected, RolloutComplete(test.r, &test.r.Status)) + assert.Equal(t, test.expected, RolloutHealthy(test.r, &test.r.Status)) }) } } +func TestRolloutComplete(t *testing.T) { + rollout := func(desired, current, updated, available int32) *v1alpha1.Rollout { + r := &v1alpha1.Rollout{ + Spec: v1alpha1.RolloutSpec{ + Replicas: &desired, + }, + Status: v1alpha1.RolloutStatus{ + Replicas: current, + UpdatedReplicas: updated, + AvailableReplicas: available, + }, + } + podHash := hash.ComputePodTemplateHash(&r.Spec.Template, r.Status.CollisionCount) + r.Status.CurrentPodHash = podHash + r.Status.StableRS = podHash + return r + } + r := rollout(5, 5, 5, 5) + assert.Equal(t, true, RolloutCompleted(r, &r.Status)) + + r.Status.StableRS = "not-current-pod-hash" + assert.Equal(t, false, RolloutCompleted(r, &r.Status)) +} + func TestRolloutTimedOut(t *testing.T) { before := metav1.Time{ From 0de9d459249ab43e33add122188364ecbf74363e Mon Sep 17 00:00:00 2001 From: Siavash Safi Date: Thu, 25 Aug 2022 21:53:22 +0200 Subject: [PATCH 166/175] feat: Add support for spec.ingressClassName (#2178) This change adds support for `spec.ingressClassName` while still supporting `kubernetes.io/ingress.class` annotation for backwards compatibility. Fixes #1277 Signed-off-by: Siavash Safi Signed-off-by: Siavash Safi --- docs/features/traffic-management/alb.md | 26 ++++--- docs/features/traffic-management/nginx.md | 4 +- ingress/ingress.go | 7 +- ingress/ingress_test.go | 35 ++++++++- utils/ingress/wrapper.go | 21 ++++++ utils/ingress/wrapper_test.go | 87 +++++++++++++++++++++++ 6 files changed, 161 insertions(+), 19 deletions(-) diff --git a/docs/features/traffic-management/alb.md b/docs/features/traffic-management/alb.md index 7139c3db7a..8255b74852 100644 --- a/docs/features/traffic-management/alb.md +++ b/docs/features/traffic-management/alb.md @@ -212,7 +212,7 @@ controller to verify that TargetGroups are accurate before marking newly created preventing premature scale down of the older ReplicaSet. Pod readiness gate injection uses a mutating webhook which decides to inject readiness gates when a -pod is created based on the following conditions: +pod is created based on the following conditions: * There exists a service matching the pod labels in the same namespace * There exists at least one target group binding that refers to the matching service @@ -343,8 +343,8 @@ The Rollout status object holds the value of who is currently the stable ping or And this way allows the rollout to use pod readiness gate injection as the services are not changing their labels at the end of the rollout progress. -!!!important - +!!!important + Ping-Pong feature available since Argo Rollouts v1.2 ## Example @@ -368,7 +368,7 @@ spec: ports: - containerPort: 80 strategy: - canary: + canary: pingPong: #Indicates that the ping-pong services enabled pingService: ping-service pongService: pong-service @@ -401,7 +401,7 @@ spec: annotationPrefix: custom.alb.ingress.kubernetes.io ``` -### Custom kubernetes.io/ingress.class +### Custom Ingress Class By default, Argo Rollout will operate on Ingresses with the annotation: @@ -413,14 +413,22 @@ metadata: kubernetes.io/ingress.class: alb ``` -To configure the controller to operate on Ingresses with different `kubernetes.io/ingress.class` -values, the controller can specify a different value through the `--alb-ingress-classes` flag in +Or with the `ingressClassName`: +```yaml +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +spec: + ingressClassName: alb +``` + +To configure the controller to operate on Ingresses with a different class name, +you can specify a different value through the `--alb-ingress-classes` flag in the controller command line arguments. Note that the `--alb-ingress-classes` flag can be specified multiple times if the Argo Rollouts controller should operate on multiple values. This may be desired when a cluster has multiple -Ingress controllers that operate on different `kubernetes.io/ingress.class` values. +Ingress controllers that operate on different `kubernetes.io/ingress.class` or `spec.ingressClassName` values. If the controller needs to operate on any Ingress without the `kubernetes.io/ingress.class` -annotation, the flag can be specified with an empty string (e.g. `--alb-ingress-classes ''`). +annotation or `spec.ingressClassName`, the flag can be specified with an empty string (e.g. `--alb-ingress-classes ''`). diff --git a/docs/features/traffic-management/nginx.md b/docs/features/traffic-management/nginx.md index ae87db0d30..414c91cc46 100644 --- a/docs/features/traffic-management/nginx.md +++ b/docs/features/traffic-management/nginx.md @@ -39,6 +39,6 @@ Since the Nginx Ingress controller allows users to configure the annotation pref ## Using Argo Rollouts with multiple NGINX ingress controllers -As a default, the Argo Rollouts controller only operates on ingresses with the `kubernetes.io/ingress.class` annotation set to `nginx`. A user can configure the controller to operate on Ingresses with different `kubernetes.io/ingress.class` values by specifying the `--nginx-ingress-classes` flag. A user can list the `--nginx-ingress-classes` flag multiple times if the Argo Rollouts controller should operate on multiple values. This solves the case where a cluster has multiple Ingress controllers operating on different `kubernetes.io/ingress.class` values. +As a default, the Argo Rollouts controller only operates on ingresses with the `kubernetes.io/ingress.class` annotation or `spec.ingressClassName` set to `nginx`. A user can configure the controller to operate on Ingresses with different class name by specifying the `--nginx-ingress-classes` flag. A user can list the `--nginx-ingress-classes` flag multiple times if the Argo Rollouts controller should operate on multiple values. This solves the case where a cluster has multiple Ingress controllers operating on different class values. -If the user would like the controller to operate on any Ingress without the `kubernetes.io/ingress.class` annotation, a user should add the following `--nginx-ingress-classes ''`. \ No newline at end of file +If the user would like the controller to operate on any Ingress without the `kubernetes.io/ingress.class` annotation or `spec.ingressClassName`, a user should add the following `--nginx-ingress-classes ''`. diff --git a/ingress/ingress.go b/ingress/ingress.go index bbe5f2f0d6..7bbf856b89 100644 --- a/ingress/ingress.go +++ b/ingress/ingress.go @@ -140,12 +140,7 @@ func (c *Controller) syncIngress(key string) error { if err != nil { return nil } - // An ingress without annotations cannot be a alb or nginx ingress - if ingress.GetAnnotations() == nil { - return nil - } - annotations := ingress.GetAnnotations() - class := annotations["kubernetes.io/ingress.class"] + class := ingress.GetClass() switch { case hasClass(c.albClasses, class): return c.syncALBIngress(ingress, rollouts) diff --git a/ingress/ingress_test.go b/ingress/ingress_test.go index b26b213e25..3db4f1bcca 100644 --- a/ingress/ingress_test.go +++ b/ingress/ingress_test.go @@ -23,6 +23,37 @@ import ( ) func newNginxIngress(name string, port int, serviceName string) *extensionsv1beta1.Ingress { + class := "nginx" + return &extensionsv1beta1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: metav1.NamespaceDefault, + }, + Spec: extensionsv1beta1.IngressSpec{ + IngressClassName: &class, + Rules: []extensionsv1beta1.IngressRule{ + { + Host: "fakehost.example.com", + IngressRuleValue: extensionsv1beta1.IngressRuleValue{ + HTTP: &extensionsv1beta1.HTTPIngressRuleValue{ + Paths: []extensionsv1beta1.HTTPIngressPath{ + { + Path: "/foo", + Backend: extensionsv1beta1.IngressBackend{ + ServiceName: serviceName, + ServicePort: intstr.FromInt(port), + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func newNginxIngressWithAnnotation(name string, port int, serviceName string) *extensionsv1beta1.Ingress { return &extensionsv1beta1.Ingress{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -165,8 +196,8 @@ func TestSyncIngressReferencedByRollout(t *testing.T) { assert.Equal(t, 1, enqueuedObjects["default/rollout"]) } -func TestSkipIngressWithNoAnnotations(t *testing.T) { - ing := newNginxIngress("test-stable-ingress", 80, "stable-service") +func TestSkipIngressWithNoClass(t *testing.T) { + ing := newNginxIngressWithAnnotation("test-stable-ingress", 80, "stable-service") ing.Annotations = nil rollout := &v1alpha1.Rollout{ ObjectMeta: metav1.ObjectMeta{ diff --git a/utils/ingress/wrapper.go b/utils/ingress/wrapper.go index 1d28c8021d..a460baac70 100644 --- a/utils/ingress/wrapper.go +++ b/utils/ingress/wrapper.go @@ -95,6 +95,27 @@ func (i *Ingress) GetAnnotations() map[string]string { } } +// GetClass returns the ingress class. +// For backwards compatibility `kubernetes.io/ingress.class` annotation will be used if set, +// otherwise `spec.ingressClassName` is used. +func (i *Ingress) GetClass() string { + annotations := i.GetAnnotations() + class := annotations["kubernetes.io/ingress.class"] + if class == "" { + switch i.mode { + case IngressModeNetworking: + if c := i.ingress.Spec.IngressClassName; c != nil { + class = *c + } + case IngressModeExtensions: + if c := i.legacyIngress.Spec.IngressClassName; c != nil { + class = *c + } + } + } + return class +} + func (i *Ingress) GetLabels() map[string]string { switch i.mode { case IngressModeNetworking: diff --git a/utils/ingress/wrapper_test.go b/utils/ingress/wrapper_test.go index eae08b4828..8611dcd395 100644 --- a/utils/ingress/wrapper_test.go +++ b/utils/ingress/wrapper_test.go @@ -124,6 +124,93 @@ func TestGetNetworkingIngress(t *testing.T) { }) } +func TestGetClass(t *testing.T) { + t.Run("will get the class from network Ingress annotation", func(t *testing.T) { + // given + t.Parallel() + i := getNetworkingIngress() + annotations := map[string]string{"kubernetes.io/ingress.class": "ingress-name-annotation"} + i.SetAnnotations(annotations) + emptyClass := "" + i.Spec.IngressClassName = &emptyClass + w := ingress.NewIngress(i) + + // when + class := w.GetClass() + + // then + assert.Equal(t, "ingress-name-annotation", class) + }) + t.Run("will get the class from network Ingress annotation with priority", func(t *testing.T) { + // given + t.Parallel() + i := getNetworkingIngress() + annotations := map[string]string{"kubernetes.io/ingress.class": "ingress-name-annotation"} + i.SetAnnotations(annotations) + w := ingress.NewIngress(i) + + // when + class := w.GetClass() + + // then + assert.Equal(t, "ingress-name-annotation", class) + }) + t.Run("will get the class from network Ingress spec", func(t *testing.T) { + // given + t.Parallel() + i := getNetworkingIngress() + w := ingress.NewIngress(i) + + // when + class := w.GetClass() + + // then + assert.Equal(t, "ingress-name", class) + }) + t.Run("will get the class from extensions Ingress annotation", func(t *testing.T) { + // given + t.Parallel() + i := getExtensionsIngress() + annotations := map[string]string{"kubernetes.io/ingress.class": "ingress-name-annotation"} + i.SetAnnotations(annotations) + emptyClass := "" + i.Spec.IngressClassName = &emptyClass + w := ingress.NewLegacyIngress(i) + + // when + class := w.GetClass() + + // then + assert.Equal(t, "ingress-name-annotation", class) + }) + t.Run("will get the class from extensions Ingress annotation with priority", func(t *testing.T) { + // given + t.Parallel() + i := getExtensionsIngress() + annotations := map[string]string{"kubernetes.io/ingress.class": "ingress-name-annotation"} + i.SetAnnotations(annotations) + w := ingress.NewLegacyIngress(i) + + // when + class := w.GetClass() + + // then + assert.Equal(t, "ingress-name-annotation", class) + }) + t.Run("will get the class from extensions Ingress spec", func(t *testing.T) { + // given + t.Parallel() + i := getExtensionsIngress() + w := ingress.NewLegacyIngress(i) + + // when + class := w.GetClass() + + // then + assert.Equal(t, "ingress-name", class) + }) +} + func TestGetLabels(t *testing.T) { t.Run("will get the labels from network Ingress successfully", func(t *testing.T) { // given From c99628b2e4e24bec14a6c26be5e930fa8c19e66d Mon Sep 17 00:00:00 2001 From: Travis Perdue Date: Tue, 30 Aug 2022 15:13:51 -0500 Subject: [PATCH 167/175] Cut v1.2.1 rallyhealth (#3) * fix: Add pagination to FindLoadBalancerByDNSName (#1971) * fix: this close issue #1963 by adding pagination to FindLoadBalancerByDNSName This adds pagination to the FindLoadBalancerByDNSName function this should allow argo rollouts to work with any number of loadbalancers. Signed-off-by: zachaller * fix: missing lb event (#2021) * fix: turn missing load balancer log into an event Signed-off-by: zachaller * consistent naming Signed-off-by: zachaller * fix: Use actual weight from status field on rollout object (#1937) fix: Use actual weight from status field on rollout object (#1937) Signed-off-by: zachaller * fix: build/lint is broken due to dependencies changes (#1958) Signed-off-by: zachaller * following github workflow error prompt to fix Signed-off-by: Travis Perdue * go fmt Signed-off-by: Travis Perdue * make go-mod-vendor Signed-off-by: Travis Perdue * fix path Signed-off-by: Travis Perdue Signed-off-by: zachaller Signed-off-by: Travis Perdue Co-authored-by: Zach Aller Co-authored-by: Travis Perdue --- .github/workflows/go.yml | 8 ++------ go.mod | 2 +- go.sum | 4 ++-- ingress/ingress_test.go | 4 ++-- rollout/controller_test.go | 2 +- utils/ingress/ingress_test.go | 4 ++-- 6 files changed, 10 insertions(+), 14 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 1e064f306f..2460360380 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -11,10 +11,6 @@ env: # Golang version to use across CI steps GOLANG_VERSION: '1.17' -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - jobs: lint-go: name: Lint Go code @@ -87,8 +83,8 @@ jobs: # This symlink is necessary to ensure that `git diff` detects changes - name: Create symlink in GOPATH run: | - mkdir -p ~/go/src/github.com/argoproj - ln -s $(pwd) ~/go/src/github.com/argoproj/argo-rollouts + mkdir -p ~/go/src/github.com/rallyhealth + ln -s $(pwd) ~/go/src/github.com/rallyhealth/argo-rollouts - uses: actions/cache@v2 with: path: /home/runner/.cache/go-build diff --git a/go.mod b/go.mod index 37bebd331e..0a0e391e9b 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.17 require ( github.com/antonmedv/expr v1.9.0 github.com/argoproj/notifications-engine v0.3.1-0.20220129012210-32519f8f68ec - github.com/argoproj/pkg v0.11.1-0.20211203175135-36c59d8fafe0 + github.com/argoproj/pkg v0.9.0 github.com/aws/aws-sdk-go-v2 v1.13.0 github.com/aws/aws-sdk-go-v2/config v1.13.1 github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.15.0 diff --git a/go.sum b/go.sum index 146e68a910..f45bf974f5 100644 --- a/go.sum +++ b/go.sum @@ -114,8 +114,8 @@ github.com/antonmedv/expr v1.9.0/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmH github.com/appscode/go v0.0.0-20190808133642-1d4ef1f1c1e0/go.mod h1:iy07dV61Z7QQdCKJCIvUoDL21u6AIceRhZzyleh2ymc= github.com/argoproj/notifications-engine v0.3.1-0.20220129012210-32519f8f68ec h1:ulv8ieYQZLyQrTVR4za1ucLFnemS0Dksz8y5e91xxak= github.com/argoproj/notifications-engine v0.3.1-0.20220129012210-32519f8f68ec/go.mod h1:QF4tr3wfWOnhkKSaRpx7k/KEErQAh8iwKQ2pYFu/SfA= -github.com/argoproj/pkg v0.11.1-0.20211203175135-36c59d8fafe0 h1:Cfp7rO/HpVxnwlRqJe0jHiBbZ77ZgXhB6HWlYD02Xdc= -github.com/argoproj/pkg v0.11.1-0.20211203175135-36c59d8fafe0/go.mod h1:ra+bQPmbVAoEL+gYSKesuigt4m49i3Qa3mE/xQcjCiA= +github.com/argoproj/pkg v0.9.0 h1:PfWWYykfcEQdN0g41XLbVh/aonTjD+dPkvDp3hwpLYM= +github.com/argoproj/pkg v0.9.0/go.mod h1:ra+bQPmbVAoEL+gYSKesuigt4m49i3Qa3mE/xQcjCiA= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= diff --git a/ingress/ingress_test.go b/ingress/ingress_test.go index 679eba81f6..41461bbb02 100644 --- a/ingress/ingress_test.go +++ b/ingress/ingress_test.go @@ -216,7 +216,7 @@ func TestSyncIngressReferencedByRolloutMultiIngress(t *testing.T) { CanaryService: "canary-service", TrafficRouting: &v1alpha1.RolloutTrafficRouting{ Nginx: &v1alpha1.NginxTrafficRouting{ - StableIngress: "test-stable-ingress", + StableIngress: "test-stable-ingress", AdditionalStableIngresses: []string{"test-stable-ingress-additional"}, }, }, @@ -287,7 +287,7 @@ func TestSkipIngressWithNoAnnotationsMultiIngress(t *testing.T) { CanaryService: "canary-service", TrafficRouting: &v1alpha1.RolloutTrafficRouting{ Nginx: &v1alpha1.NginxTrafficRouting{ - StableIngress: "test-stable-ingress", + StableIngress: "test-stable-ingress", AdditionalStableIngresses: []string{"test-stable-ingress-additional"}, }, }, diff --git a/rollout/controller_test.go b/rollout/controller_test.go index 04424f491b..99ecf967e1 100644 --- a/rollout/controller_test.go +++ b/rollout/controller_test.go @@ -1693,7 +1693,7 @@ func TestGetReferencedIngressesNginxMultiIngress(t *testing.T) { r := newCanaryRollout("rollout", 1, nil, nil, nil, intstr.FromInt(0), intstr.FromInt(1)) r.Spec.Strategy.Canary.TrafficRouting = &v1alpha1.RolloutTrafficRouting{ Nginx: &v1alpha1.NginxTrafficRouting{ - StableIngress: "nginx-ingress-name", + StableIngress: "nginx-ingress-name", AdditionalStableIngresses: []string{"nginx-ingress-additional"}, }, } diff --git a/utils/ingress/ingress_test.go b/utils/ingress/ingress_test.go index eb82a4f967..a11fd5abc2 100644 --- a/utils/ingress/ingress_test.go +++ b/utils/ingress/ingress_test.go @@ -74,7 +74,7 @@ func TestGetRolloutIngressKeysForCanaryWithTrafficRoutingMultiIngress(t *testing StableService: "stable-service", TrafficRouting: &v1alpha1.RolloutTrafficRouting{ Nginx: &v1alpha1.NginxTrafficRouting{ - StableIngress: "stable-ingress", + StableIngress: "stable-ingress", AdditionalStableIngresses: []string{"stable-ingress-additional"}, }, ALB: &v1alpha1.ALBTrafficRouting{ @@ -101,7 +101,7 @@ func TestGetCanaryIngressName(t *testing.T) { StableService: "stable-service", TrafficRouting: &v1alpha1.RolloutTrafficRouting{ Nginx: &v1alpha1.NginxTrafficRouting{ - StableIngress: "stable-ingress", + StableIngress: "stable-ingress", AdditionalStableIngresses: []string{"stable-ingress-additional"}, }, }, From 3b3b41b0fcae77c01d06e5d5bb7267c8c6038b99 Mon Sep 17 00:00:00 2001 From: Shlomo Sanders Date: Thu, 15 Sep 2022 12:07:23 +0300 Subject: [PATCH 168/175] add v1.2.2 patch for issue#2024 Signed-off-by: Shlomo Sanders --- analysis/analysis.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/analysis/analysis.go b/analysis/analysis.go index 5bae4a8892..53d5358647 100644 --- a/analysis/analysis.go +++ b/analysis/analysis.go @@ -316,7 +316,7 @@ func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTa for _, task := range tasks { wg.Add(1) - go func(t metricTask) error { + go func(t metricTask) { defer wg.Done() //redact secret values from logs logger := logutil.WithRedactor(*logutil.WithAnalysisRun(run).WithField("metric", t.metric.Name), secrets) @@ -326,9 +326,12 @@ func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTa resultsLock.Unlock() provider, err := c.newProvider(*logger, t.metric) + //Fix for https://github.com/argoproj/argo-rollouts/issues/2024 this error is not bubbled to runMeasurements function + //it just stops the go routine to prevent nil pointer usage. Just keeping this simple due to it being a patch for a bug. + //We probably want to handle errors in this goroutine in a different way in master but for now just prevent crashing. if err != nil { log.Errorf("Error in getting provider :%v", err) - return err + return } if metricResult == nil { metricResult = &v1alpha1.MetricResult{ @@ -408,7 +411,7 @@ func (c *Controller) runMeasurements(run *v1alpha1.AnalysisRun, tasks []metricTa resultsLock.Lock() analysisutil.SetResult(run, *metricResult) resultsLock.Unlock() - return nil + }(task) } wg.Wait() From fa460078f770733c66298a3681d4d233ee07ed9d Mon Sep 17 00:00:00 2001 From: RaviHari Date: Thu, 15 Sep 2022 01:36:02 +0530 Subject: [PATCH 169/175] fix: enable notifications without when condition (#2231) * fix: enable notifications without when condition Signed-off-by: Ravi Hari * fix: use trigger action item from the list Signed-off-by: Ravi Hari * fix: add emptycondition logic to make notifications work with/without conditions Signed-off-by: Ravi Hari * fix: linting Signed-off-by: Ravi Hari Signed-off-by: Ravi Hari --- utils/record/record.go | 47 ++++++++++++++++++++++++------------- utils/record/record_test.go | 41 ++++++++++++++++++++++++++++---- 2 files changed, 68 insertions(+), 20 deletions(-) diff --git a/utils/record/record.go b/utils/record/record.go index 3ad05671b2..f255b02c24 100644 --- a/utils/record/record.go +++ b/utils/record/record.go @@ -2,6 +2,8 @@ package record import ( "context" + "crypto/sha1" + "encoding/base64" "encoding/json" "regexp" "strings" @@ -266,29 +268,32 @@ func (e *EventRecorderAdapter) sendNotifications(object runtime.Object, opts Eve return nil } - // Creates config for notifications for built-in triggers - triggerActions, ok := cfg.Triggers[trigger] - if !ok { - logCtx.Debugf("No configured template for trigger: %s", trigger) - return nil - } - objMap, err := toObjectMap(object) if err != nil { return err } - res, err := notificationsAPI.RunTrigger(trigger, objMap) - if err != nil { - log.Errorf("Failed to execute condition of trigger %s: %v", trigger, err) - return err - } - log.Infof("Trigger %s result: %v", trigger, res) + emptyCondition := hash("") + + for _, destination := range destinations { + res, err := notificationsAPI.RunTrigger(trigger, objMap) + if err != nil { + log.Errorf("Failed to execute condition of trigger %s: %v", trigger, err) + return err + } + log.Infof("Trigger %s result: %v", trigger, res) - for _, dest := range destinations { for _, c := range res { - if c.Triggered == true { - err = notificationsAPI.Send(objMap, triggerActions[0].Send, dest) + log.Infof("Res When Condition hash: %s, Templates: %s", c.Key, c.Templates) + s := strings.Split(c.Key, ".")[1] + if s != emptyCondition && c.Triggered == true { + err = notificationsAPI.Send(objMap, c.Templates, destination) + if err != nil { + log.Errorf("notification error: %s", err.Error()) + return err + } + } else if s == emptyCondition { + err = notificationsAPI.Send(objMap, c.Templates, destination) if err != nil { log.Errorf("notification error: %s", err.Error()) return err @@ -296,9 +301,19 @@ func (e *EventRecorderAdapter) sendNotifications(object runtime.Object, opts Eve } } } + return nil } +// This function is copied over from notification engine to make sure we honour emptyCondition +// emptyConditions today are not handled well in notification engine. +// TODO: update notification engine to handle emptyConditions and remove this function and its usage +func hash(input string) string { + h := sha1.New() + _, _ = h.Write([]byte(input)) + return base64.RawURLEncoding.EncodeToString(h.Sum(nil)) +} + // toObjectMap converts an object to a map for the purposes of sending to the notification engine func toObjectMap(object interface{}) (map[string]interface{}, error) { objBytes, err := json.Marshal(object) diff --git a/utils/record/record_test.go b/utils/record/record_test.go index 931ce42c9b..c99f55985b 100644 --- a/utils/record/record_test.go +++ b/utils/record/record_test.go @@ -96,7 +96,7 @@ func TestSendNotifications(t *testing.T) { mockCtrl := gomock.NewController(t) mockAPI := mocks.NewMockAPI(mockCtrl) cr := []triggers.ConditionResult{{ - Key: "", + Key: "1." + hash(""), Triggered: true, Templates: []string{"my-template"}, }} @@ -112,6 +112,33 @@ func TestSendNotifications(t *testing.T) { assert.NoError(t, err) } +func TestSendNotificationsWhenCondition(t *testing.T) { + r := v1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Name: "guestbook", + Namespace: "default", + Annotations: map[string]string{"notifications.argoproj.io/subscribe.on-foo-reason.console": "console"}, + }, + } + mockCtrl := gomock.NewController(t) + mockAPI := mocks.NewMockAPI(mockCtrl) + cr := []triggers.ConditionResult{{ + Key: "1." + hash(""), + Triggered: true, + Templates: []string{"my-template"}, + }} + mockAPI.EXPECT().RunTrigger(gomock.Any(), gomock.Any()).Return(cr, nil).AnyTimes() + mockAPI.EXPECT().Send(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + mockAPI.EXPECT().GetConfig().Return(api.Config{ + Triggers: map[string][]triggers.Condition{"on-foo-reason": {triggers.Condition{When: "rollout.spec.template.spec.containers[0].image == test:blue", Send: []string{"my-template"}}}}}).AnyTimes() + apiFactory := &mocks.FakeFactory{Api: mockAPI} + rec := NewFakeEventRecorder() + rec.EventRecorderAdapter.apiFactory = apiFactory + //ch := make(chan prometheus.HistogramVec, 1) + err := rec.sendNotifications(&r, EventOptions{EventReason: "FooReason"}) + assert.NoError(t, err) +} + func TestNotificationFailedCounter(t *testing.T) { r := v1alpha1.Rollout{ ObjectMeta: metav1.ObjectMeta{ @@ -201,7 +228,7 @@ func TestSendNotificationsFails(t *testing.T) { mockCtrl := gomock.NewController(t) mockAPI := mocks.NewMockAPI(mockCtrl) cr := []triggers.ConditionResult{{ - Key: "", + Key: "1." + hash(""), Triggered: true, Templates: []string{"my-template"}, }} @@ -241,7 +268,7 @@ func TestSendNotificationsFailsWithRunTriggerError(t *testing.T) { mockCtrl := gomock.NewController(t) mockAPI := mocks.NewMockAPI(mockCtrl) cr := []triggers.ConditionResult{{ - Key: "", + Key: "1." + hash(""), Triggered: true, Templates: []string{"my-template"}, }} @@ -279,6 +306,12 @@ func TestSendNotificationsNoTrigger(t *testing.T) { mockCtrl := gomock.NewController(t) mockAPI := mocks.NewMockAPI(mockCtrl) + cr := []triggers.ConditionResult{{ + Key: "1." + hash(""), + Triggered: false, + Templates: []string{"my-template"}, + }} + mockAPI.EXPECT().RunTrigger(gomock.Any(), gomock.Any()).Return(cr, errors.New("trigger 'on-missing-reason' is not configured")).AnyTimes() mockAPI.EXPECT().GetConfig().Return(api.Config{ Triggers: map[string][]triggers.Condition{"on-foo-reason": {triggers.Condition{Send: []string{"my-template"}}}}}).AnyTimes() mockAPI.EXPECT().Send(gomock.Any(), gomock.Any(), gomock.Any()).Return(fmt.Errorf("failed to send")).Times(0) @@ -287,7 +320,7 @@ func TestSendNotificationsNoTrigger(t *testing.T) { rec.EventRecorderAdapter.apiFactory = apiFactory err := rec.sendNotifications(&r, EventOptions{EventReason: "MissingReason"}) - assert.NoError(t, err) + assert.Error(t, err) } func TestNewAPIFactorySettings(t *testing.T) { From 93ed7a497b021051bf6845da90907d67c231e703 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Fri, 16 Sep 2022 15:57:18 -0500 Subject: [PATCH 170/175] Use standard cli format for dashboard root path (#2244) Signed-off-by: zachaller Signed-off-by: zachaller --- pkg/kubectl-argo-rollouts/cmd/dashboard/dashboard.go | 2 +- server/server.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/kubectl-argo-rollouts/cmd/dashboard/dashboard.go b/pkg/kubectl-argo-rollouts/cmd/dashboard/dashboard.go index b3acb06854..3f3cd1687a 100644 --- a/pkg/kubectl-argo-rollouts/cmd/dashboard/dashboard.go +++ b/pkg/kubectl-argo-rollouts/cmd/dashboard/dashboard.go @@ -35,7 +35,7 @@ func NewCmdDashboard(o *options.ArgoRolloutsOptions) *cobra.Command { } }, } - cmd.Flags().StringVar(&rootPath, "rootPath", "rollouts", "renders the ui url with rootPath prefixed") + cmd.Flags().StringVar(&rootPath, "root-path", "rollouts", "changes the root path of the dashboard") return cmd } diff --git a/server/server.go b/server/server.go index df19f4cfc4..f90b372d1c 100644 --- a/server/server.go +++ b/server/server.go @@ -253,7 +253,7 @@ func (s *ArgoRolloutsServer) Run(ctx context.Context, port int, dashboard bool) startupMessage := fmt.Sprintf("Argo Rollouts api-server serving on port %d (namespace: %s)", port, s.Options.Namespace) if dashboard { - startupMessage = fmt.Sprintf("Argo Rollouts Dashboard is now available at localhost %d", port) + startupMessage = fmt.Sprintf("Argo Rollouts Dashboard is now available at http://localhost:%d/%s", port, s.Options.RootPath) } log.Info(startupMessage) From 60944c29dca35f020cf3a6b3ec706652cd372ecc Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Tue, 27 Sep 2022 13:25:27 -0500 Subject: [PATCH 171/175] fix: UI not redirecting on / (#2252) Signed-off-by: zachaller Signed-off-by: zachaller --- server/server.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/server/server.go b/server/server.go index f90b372d1c..62c8714b9f 100644 --- a/server/server.go +++ b/server/server.go @@ -124,6 +124,12 @@ func (s *ArgoRolloutsServer) newHTTPServer(ctx context.Context, port int) *http. mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { requestedURI := path.Clean(r.RequestURI) rootPath := path.Clean("/" + s.Options.RootPath) + + if requestedURI == "/" { + http.Redirect(w, r, rootPath+"/", http.StatusFound) + return + } + //If the rootPath is not in the prefix 404 if !strings.HasPrefix(requestedURI, rootPath) { http.NotFound(w, r) From 20ec1c7a88dc98fb2edea1f5cce9dd6e185906be Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Tue, 27 Sep 2022 13:24:38 -0500 Subject: [PATCH 172/175] fix: nil pointer while linting with basic canary and ingresses (#2256) * fix: nil pointer while linting basic canary with Ingress resources Signed-off-by: zachaller * Add test case Signed-off-by: zachaller Signed-off-by: zachaller --- pkg/kubectl-argo-rollouts/cmd/lint/lint.go | 5 ++ .../cmd/lint/lint_test.go | 1 + .../testdata/valid-nginx-basic-canary.yml | 58 +++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-nginx-basic-canary.yml diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/lint.go b/pkg/kubectl-argo-rollouts/cmd/lint/lint.go index 2969b53034..66e28318eb 100644 --- a/pkg/kubectl-argo-rollouts/cmd/lint/lint.go +++ b/pkg/kubectl-argo-rollouts/cmd/lint/lint.go @@ -261,6 +261,11 @@ func setIngressManagedAnnotation(rollouts []v1alpha1.Rollout, refResource valida for _, rollout := range rollouts { for i := range refResource.Ingresses { var serviceName string + + // Basic Canary so ingress is only pointing a single service and so no linting is needed for this case. + if rollout.Spec.Strategy.Canary == nil || rollout.Spec.Strategy.Canary.TrafficRouting == nil { + return + } if rollout.Spec.Strategy.Canary.TrafficRouting.Nginx != nil { serviceName = rollout.Spec.Strategy.Canary.StableService } else if rollout.Spec.Strategy.Canary.TrafficRouting.ALB != nil { diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/lint_test.go b/pkg/kubectl-argo-rollouts/cmd/lint/lint_test.go index 554c4820db..29fce3afe3 100644 --- a/pkg/kubectl-argo-rollouts/cmd/lint/lint_test.go +++ b/pkg/kubectl-argo-rollouts/cmd/lint/lint_test.go @@ -27,6 +27,7 @@ func TestLintValidRollout(t *testing.T) { "testdata/valid-ingress-smi-multi.yml", "testdata/valid-alb-canary.yml", "testdata/valid-nginx-canary.yml", + "testdata/valid-nginx-basic-canary.yml", "testdata/valid-istio-v1beta1-mulitiple-virtualsvcs.yml", } diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-nginx-basic-canary.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-nginx-basic-canary.yml new file mode 100644 index 0000000000..4d295c6c86 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-nginx-basic-canary.yml @@ -0,0 +1,58 @@ +apiVersion: v1 +kind: Service +metadata: + name: nginx-rollout-stable +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: nginx-rollout +--- +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: nginx-rollout-ingress +spec: + rules: + - http: + paths: + - path: /* + backend: + serviceName: nginx-rollout-root + servicePort: use-annotation +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: nginx-rollout +spec: + selector: + matchLabels: + app: nginx-rollout + template: + metadata: + labels: + app: nginx-rollout + spec: + containers: + - name: nginx-rollout + image: argoproj/rollouts-demo:blue + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m + strategy: + canary: + steps: + - setWeight: 10 + - pause: {} + - setWeight: 50 + - pause: {} From 009fdfbd3b5ee8669607f7d496a59c8518f1157a Mon Sep 17 00:00:00 2001 From: nikhil1raghav <44281594+nikhil1raghav@users.noreply.github.com> Date: Tue, 27 Sep 2022 23:43:37 +0530 Subject: [PATCH 173/175] fix(controller): Fix k8s clientset controller metrics. Fixes #2139 (#2261) * Add roundtripper to kubeconfig before creating kubeclient Signed-off-by: Nikhil * Check if k8sRequestsCount is nil before attempting increase Signed-off-by: Nikhil * Added Flipkart to Users.md Signed-off-by: Nikhil * gofmt controller/metrics/client.go Signed-off-by: Nikhil Signed-off-by: Nikhil --- USERS.md | 1 + cmd/rollouts-controller/main.go | 5 +++-- controller/metrics/client.go | 5 +++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/USERS.md b/USERS.md index 9d7d511bbe..be3ec11e5f 100644 --- a/USERS.md +++ b/USERS.md @@ -13,6 +13,7 @@ Organizations below are **officially** using Argo Rollouts. Please send a PR wit 1. [Databricks](https://github.com/databricks) 1. [Devtron Labs](https://github.com/devtron-labs/devtron) 1. [Farfetch](https://www.farfetch.com/) +1. [Flipkart](https://flipkart.com) 1. [Gllue](https://gllue.com) 1. [Ibotta](https://home.ibotta.com/) 1. [Intuit](https://www.intuit.com/) diff --git a/cmd/rollouts-controller/main.go b/cmd/rollouts-controller/main.go index 401b579323..65a1374542 100644 --- a/cmd/rollouts-controller/main.go +++ b/cmd/rollouts-controller/main.go @@ -107,6 +107,9 @@ func newCommand() *cobra.Command { log.Infof("Using namespace %s", namespace) } + k8sRequestProvider := &metrics.K8sRequestsCountProvider{} + kubeclientmetrics.AddMetricsTransportWrapper(config, k8sRequestProvider.IncKubernetesRequest) + kubeClient, err := kubernetes.NewForConfig(config) checkError(err) argoprojClient, err := clientset.NewForConfig(config) @@ -154,8 +157,6 @@ func newCommand() *cobra.Command { configMapInformer := controllerNamespaceInformerFactory.Core().V1().ConfigMaps() secretInformer := controllerNamespaceInformerFactory.Core().V1().Secrets() - k8sRequestProvider := &metrics.K8sRequestsCountProvider{} - kubeclientmetrics.AddMetricsTransportWrapper(config, k8sRequestProvider.IncKubernetesRequest) mode, err := ingressutil.DetermineIngressMode(ingressVersion, kubeClient.DiscoveryClient) checkError(err) ingressWrapper, err := ingressutil.NewIngressWrapper(mode, kubeClient, kubeInformerFactory) diff --git a/controller/metrics/client.go b/controller/metrics/client.go index f2e2624d20..01367745ef 100644 --- a/controller/metrics/client.go +++ b/controller/metrics/client.go @@ -35,7 +35,8 @@ func (m *K8sRequestsCountProvider) IncKubernetesRequest(resourceInfo kubeclientm name = "Unknown" kind = "Unknown" } - - m.k8sRequestsCount.WithLabelValues(kind, namespace, name, string(resourceInfo.Verb), statusCode).Inc() + if m.k8sRequestsCount != nil { + m.k8sRequestsCount.WithLabelValues(kind, namespace, name, string(resourceInfo.Verb), statusCode).Inc() + } return nil } From b0b95cade830d8a70624fcaaf8e92e1fe2ecd355 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Thu, 29 Sep 2022 09:16:47 -0500 Subject: [PATCH 174/175] fixes(controller): istio dropping fields not defined in type (#2268) * fixes #2266 Signed-off-by: zachaller * typo Signed-off-by: zachaller * test after calling set mirror Signed-off-by: zachaller * Keep port on user defined service by adding to internal types Signed-off-by: zachaller * github trigger re-run Signed-off-by: zachaller * Drop port on virtual service to be consistent with added routes Drop the port on the virtual service with the statment that rollouts only supports one port services. Signed-off-by: zachaller * cleanup test to just test extra fields and add a port check on destination as well Signed-off-by: zachaller * keep port for both mirroring and header routes Signed-off-by: zachaller * github trigger re-run Signed-off-by: zachaller * github trigger re-run Signed-off-by: zachaller * add function comment Signed-off-by: zachaller Signed-off-by: zachaller --- rollout/trafficrouting/istio/istio.go | 87 +++++++--- rollout/trafficrouting/istio/istio_test.go | 181 ++++++++++++++++++++ rollout/trafficrouting/istio/istio_types.go | 5 + 3 files changed, 251 insertions(+), 22 deletions(-) diff --git a/rollout/trafficrouting/istio/istio.go b/rollout/trafficrouting/istio/istio.go index f001c585a3..c03bc41f41 100644 --- a/rollout/trafficrouting/istio/istio.go +++ b/rollout/trafficrouting/istio/istio.go @@ -652,7 +652,7 @@ func (r *Reconciler) getVirtualService(namespace string, vsvcName string, client return vsvc, err } -func (r *Reconciler) reconcileVirtualServiceHeaderRoutes(obj *unstructured.Unstructured, headerRouting *v1alpha1.SetHeaderRoute) error { +func (r *Reconciler) reconcileVirtualServiceHeaderRoutes(virtualService v1alpha1.IstioVirtualService, obj *unstructured.Unstructured, headerRouting *v1alpha1.SetHeaderRoute) error { // HTTP Routes httpRoutesI, err := GetHttpRoutesI(obj) if err != nil { @@ -687,7 +687,7 @@ func (r *Reconciler) reconcileVirtualServiceHeaderRoutes(obj *unstructured.Unstr return fmt.Errorf("[reconcileVirtualServiceHeaderRoutes] failed to remove http route from virtual service: %w", err) } - httpRoutesI = append(httpRoutesI, createHeaderRoute(headerRouting, canarySvc, canarySubset)) + httpRoutesI = append(httpRoutesI, createHeaderRoute(virtualService, obj, headerRouting, canarySvc, canarySubset)) err = unstructured.SetNestedSlice(obj.Object, httpRoutesI, "spec", Http) if err != nil { @@ -712,7 +712,7 @@ func (r *Reconciler) SetHeaderRoute(headerRouting *v1alpha1.SetHeaderRoute) erro return fmt.Errorf("[SetHeaderRoute] failed to get istio virtual service: %w", err) } - err = r.reconcileVirtualServiceHeaderRoutes(vsvc, headerRouting) + err = r.reconcileVirtualServiceHeaderRoutes(virtualService, vsvc, headerRouting) if err != nil { return fmt.Errorf("[SetHeaderRoute] failed to reconcile header routes: %w", err) } @@ -765,12 +765,19 @@ func (r *Reconciler) getDestinationRule(dRuleSpec *v1alpha1.IstioDestinationRule return origBytes, dRule, dRuleNew, nil } -func createHeaderRoute(headerRouting *v1alpha1.SetHeaderRoute, host string, subset string) map[string]interface{} { +func createHeaderRoute(virtualService v1alpha1.IstioVirtualService, unVsvc *unstructured.Unstructured, headerRouting *v1alpha1.SetHeaderRoute, host string, subset string) map[string]interface{} { var routeMatches []interface{} for _, hrm := range headerRouting.Match { routeMatches = append(routeMatches, createHeaderRouteMatch(hrm)) } - canaryDestination := routeDestination(host, subset, 100) + + port, err := getVirtualServiceCanaryPort(unVsvc, virtualService) + if err != nil { + port = Port{Number: 0} + } + + canaryDestination := routeDestination(host, port.Number, subset, 100) + return map[string]interface{}{ "name": headerRouting.Name, "match": routeMatches, @@ -795,10 +802,13 @@ func setMapValueIfNotEmpty(m map[string]interface{}, key string, value string) { } } -func routeDestination(host, subset string, weight int64) map[string]interface{} { +func routeDestination(host string, port uint32, subset string, weight int64) map[string]interface{} { dest := map[string]interface{}{ "host": host, } + if port > 0 { + dest["port"] = map[string]interface{}{"number": int64(port)} + } if subset != "" { dest["subset"] = subset } @@ -1141,14 +1151,20 @@ func createMirrorRoute(virtualService v1alpha1.IstioVirtualService, httpRoutes [ }) } + mirrorDestinations := VirtualServiceDestination{ + Host: canarySvc, + Subset: subset, + } + if len(route) >= 0 && route[0].Destination.Port != nil { + // We try to pull the port from any of the routes destinations that are supposed to be updated via SetWeight + mirrorDestinations.Port = &Port{Number: route[0].Destination.Port.Number} + } + mirrorRoute := map[string]interface{}{ - "name": mirrorRouting.Name, - "match": istioMatch, - "route": route, - "mirror": VirtualServiceDestination{ - Host: canarySvc, - Subset: subset, - }, + "name": mirrorRouting.Name, + "match": istioMatch, + "route": route, + "mirror": mirrorDestinations, "mirrorPercentage": map[string]interface{}{"value": float64(percent)}, } @@ -1232,7 +1248,7 @@ func (r *Reconciler) orderRoutes(istioVirtualService *unstructured.Unstructured) return fmt.Errorf("[orderRoutes] could not split routes between managed and non managed: %w", err) } - finalRoutes, err := getOrderedVirtualServiceRoutes(managedRoutes, httpRoutesWithinManagedRoutes, httpRoutesNotWithinManagedRoutes) + finalRoutes, err := getOrderedVirtualServiceRoutes(httpRouteI, managedRoutes, httpRoutesWithinManagedRoutes, httpRoutesNotWithinManagedRoutes) if err != nil { return fmt.Errorf("[orderRoutes] could not get ordered virtual service routes: %w", err) } @@ -1279,7 +1295,7 @@ func splitManagedRoutesAndNonManagedRoutes(managedRoutes []v1alpha1.MangedRoutes // getOrderedVirtualServiceRoutes This returns an []interface{} of istio virtual routes where the routes are ordered based // on the rollouts managedRoutes field. We take the routes from the rollouts managedRoutes field order them and place them on top // of routes that are manually defined within the virtual service (aka. routes that users have defined manually) -func getOrderedVirtualServiceRoutes(managedRoutes []v1alpha1.MangedRoutes, httpRoutesWithinManagedRoutes []VirtualServiceHTTPRoute, httpRoutesNotWithinManagedRoutes []VirtualServiceHTTPRoute) ([]interface{}, error) { +func getOrderedVirtualServiceRoutes(httpRouteI []interface{}, managedRoutes []v1alpha1.MangedRoutes, httpRoutesWithinManagedRoutes []VirtualServiceHTTPRoute, httpRoutesNotWithinManagedRoutes []VirtualServiceHTTPRoute) ([]interface{}, error) { var orderedManagedRoutes []VirtualServiceHTTPRoute for _, route := range managedRoutes { for _, managedRoute := range httpRoutesWithinManagedRoutes { @@ -1289,18 +1305,45 @@ func getOrderedVirtualServiceRoutes(managedRoutes []v1alpha1.MangedRoutes, httpR } } - allIstioRoutes := append(orderedManagedRoutes, httpRoutesNotWithinManagedRoutes...) + orderedVirtualServiceHTTPRoutes := append(orderedManagedRoutes, httpRoutesNotWithinManagedRoutes...) - jsonAllIstioRoutes, err := json.Marshal(allIstioRoutes) + var orderedInterfaceVSVCHTTPRoutes []interface{} + for _, routeTyped := range orderedVirtualServiceHTTPRoutes { + for _, route := range httpRouteI { + r := route.(map[string]interface{}) + + // No need to check if exist because the empty string returned on cast failure is good for this check + name, _ := r["name"].(string) + if name == routeTyped.Name { + orderedInterfaceVSVCHTTPRoutes = append(orderedInterfaceVSVCHTTPRoutes, route) + } + } + } + + return orderedInterfaceVSVCHTTPRoutes, nil +} + +// getVirtualServiceCanaryPort This function returns the port that the canary service is running on. It does this by looking at the +// istio Virtual Service and finding any port from a destination that is suppose to be update via SetWeight. +func getVirtualServiceCanaryPort(unVsvc *unstructured.Unstructured, virtualService v1alpha1.IstioVirtualService) (Port, error) { + httpRoutes, _, err := getVirtualServiceHttpRoutes(unVsvc) if err != nil { - return nil, fmt.Errorf("[getOrderedVirtualServiceRoutes] failed to marsharl istio routes: %w", err) + return Port{}, fmt.Errorf("[getVirtualServiceCanaryPort] failed to get virtual service http routes: %w", err) } - var orderedRoutes []interface{} - if err := json.Unmarshal(jsonAllIstioRoutes, &orderedRoutes); err != nil { - return nil, fmt.Errorf("[getOrderedVirtualServiceRoutes] failed to unmarsharl istio routes: %w", err) + + route, err := getVirtualServiceSetWeightRoute(virtualService.Routes, httpRoutes) + if err != nil { + return Port{}, fmt.Errorf("[getVirtualServiceCanaryPort] failed to get virtual service set weight route: %w", err) + } + + var port uint32 = 0 + if len(route) > 0 && route[0].Destination.Port != nil { + port = route[0].Destination.Port.Number } - return orderedRoutes, nil + return Port{ + Number: port, + }, nil } // RemoveManagedRoutes this removes all the routes in all the istio virtual services rollouts is managing by getting two slices diff --git a/rollout/trafficrouting/istio/istio_test.go b/rollout/trafficrouting/istio/istio_test.go index 3c57dcfbdb..bde05ff034 100644 --- a/rollout/trafficrouting/istio/istio_test.go +++ b/rollout/trafficrouting/istio/istio_test.go @@ -603,6 +603,80 @@ spec: assert.Equal(t, httpRoutes[0].Route[0].Destination.Subset, "canary-subset") } +func TestHttpReconcileHeaderRouteWithExtra(t *testing.T) { + ro := rolloutWithHttpRoutes("stable", "canary", "vsvc", []string{"primary"}) + obj := unstructuredutil.StrToUnstructuredUnsafe(regularVsvcWithExtra) + client := testutil.NewFakeDynamicClient(obj) + vsvcLister, druleLister := getIstioListers(client) + r := NewReconciler(ro, client, record.NewFakeEventRecorder(), vsvcLister, druleLister) + client.ClearActions() + + const headerName = "test-header-route" + r.rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes = append(r.rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes, []v1alpha1.MangedRoutes{{ + Name: headerName, + }, + }...) + + // Test for both the HTTP VS & Mixed VS + hr := &v1alpha1.SetHeaderRoute{ + Name: headerName, + Match: []v1alpha1.HeaderRoutingMatch{ + { + HeaderName: "agent", + HeaderValue: &v1alpha1.StringMatch{Exact: "firefox"}, + }, + }, + } + + err := r.SetHeaderRoute(hr) + assert.Nil(t, err) + + iVirtualService, err := client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(r.rollout.Namespace).Get(context.TODO(), ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name, metav1.GetOptions{}) + assert.NoError(t, err) + + // HTTP Routes + httpRoutes := extractHttpRoutes(t, iVirtualService) + + // Assertions + assert.Equal(t, httpRoutes[0].Name, headerName) + checkDestination(t, httpRoutes[0].Route, "canary", 100) + assert.Equal(t, len(httpRoutes[0].Route), 1) + assert.Equal(t, httpRoutes[1].Name, "primary") + checkDestination(t, httpRoutes[1].Route, "stable", 100) + assert.Equal(t, httpRoutes[2].Name, "secondary") + + iVirtualService, err = client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(r.rollout.Namespace).Get(context.TODO(), ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name, metav1.GetOptions{}) + assert.NoError(t, err) + // HTTP Routes + httpRoutes = extractHttpRoutes(t, iVirtualService) + // Assertions + assert.Equal(t, httpRoutes[0].Name, headerName) + assert.Equal(t, httpRoutes[1].Name, "primary") + assert.Equal(t, httpRoutes[2].Name, "secondary") + + routes, found, err := unstructured.NestedSlice(iVirtualService.Object, "spec", "http") + assert.NoError(t, err) + assert.True(t, found) + + r0 := routes[0].(map[string]interface{}) + route, found := r0["route"].([]interface{}) + assert.True(t, found) + + port1 := route[0].(map[string]interface{})["destination"].(map[string]interface{})["port"].(map[string]interface{})["number"] + assert.True(t, port1 == int64(8443)) + + r1 := routes[1].(map[string]interface{}) + _, found = r1["retries"] + assert.True(t, found) + + r2 := routes[2].(map[string]interface{}) + _, found = r2["retries"] + assert.True(t, found) + _, found = r2["corsPolicy"] + assert.True(t, found) + +} + func TestReconcileUpdateHeader(t *testing.T) { ro := rolloutWithHttpRoutes("stable", "canary", "vsvc", []string{"primary"}) ro.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes = append(ro.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes, v1alpha1.MangedRoutes{ @@ -610,6 +684,7 @@ func TestReconcileUpdateHeader(t *testing.T) { }) AssertReconcileUpdateHeader(t, regularVsvc, ro) } + func AssertReconcileUpdateHeader(t *testing.T, vsvc string, ro *v1alpha1.Rollout) *dynamicfake.FakeDynamicClient { obj := unstructuredutil.StrToUnstructuredUnsafe(vsvc) client := testutil.NewFakeDynamicClient(obj) @@ -1642,6 +1717,60 @@ spec: host: canary weight: 0` +const regularVsvcWithExtra = `apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: vsvc + namespace: default +spec: + gateways: + - istio-rollout-gateway + hosts: + - istio-rollout.dev.argoproj.io + http: + - name: primary + retries: + attempts: 3 + perTryTimeout: 10s + retryOn: 'gateway-error,connect-failure,refused-stream' + route: + - destination: + host: 'stable' + port: + number: 8443 + weight: 100 + - destination: + host: canary + port: + number: 8443 + weight: 0 + - name: secondary + retries: + attempts: 3 + perTryTimeout: 10s + retryOn: 'gateway-error,connect-failure,refused-stream' + corsPolicy: + allowOrigins: + - exact: https://example.com + allowMethods: + - POST + - GET + allowCredentials: false + allowHeaders: + - X-Foo-Bar + maxAge: "24h" + route: + - destination: + host: 'stable' + port: + number: 8443 + weight: 100 + - destination: + host: canary + port: + number: 8443 + weight: 0` + func TestMultipleVirtualServiceConfigured(t *testing.T) { multipleVirtualService := []v1alpha1.IstioVirtualService{{Name: "vsvc1", Routes: []string{"primary", "secondary"}}, {Name: "vsvc2", Routes: []string{"blue-green"}}} ro := multiVsRollout("stable", "canary", multipleVirtualService) @@ -1874,6 +2003,58 @@ func TestHttpReconcileMirrorRoute(t *testing.T) { } +func TestHttpReconcileMirrorRouteWithExtraFields(t *testing.T) { + ro := rolloutWithHttpRoutes("stable", "canary", "vsvc", []string{"primary"}) + obj := unstructuredutil.StrToUnstructuredUnsafe(regularVsvcWithExtra) + client := testutil.NewFakeDynamicClient(obj) + vsvcLister, druleLister := getIstioListers(client) + r := NewReconciler(ro, client, record.NewFakeEventRecorder(), vsvcLister, druleLister) + client.ClearActions() + + // Test for both the HTTP VS & Mixed VS + setMirror1 := &v1alpha1.SetMirrorRoute{ + Name: "test-mirror-1", + Match: []v1alpha1.RouteMatch{{ + Method: &v1alpha1.StringMatch{ + Exact: "GET", + }, + }}, + } + r.rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes = append(r.rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes, []v1alpha1.MangedRoutes{{ + Name: "test-mirror-1", + }, + }...) + + err := r.SetMirrorRoute(setMirror1) + assert.Nil(t, err) + iVirtualService, err := client.Resource(istioutil.GetIstioVirtualServiceGVR()).Namespace(r.rollout.Namespace).Get(context.TODO(), ro.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name, metav1.GetOptions{}) + assert.NoError(t, err) + + routes, found, err := unstructured.NestedSlice(iVirtualService.Object, "spec", "http") + assert.NoError(t, err) + assert.True(t, found) + + r0 := routes[0].(map[string]interface{}) + mirrorRoute, found := r0["route"].([]interface{}) + assert.True(t, found) + + port1 := mirrorRoute[0].(map[string]interface{})["destination"].(map[string]interface{})["port"].(map[string]interface{})["number"] + port2 := mirrorRoute[1].(map[string]interface{})["destination"].(map[string]interface{})["port"].(map[string]interface{})["number"] + assert.True(t, port1 == float64(8443)) + assert.True(t, port2 == float64(8443)) + + r1 := routes[1].(map[string]interface{}) + _, found = r1["retries"] + assert.True(t, found) + + r2 := routes[2].(map[string]interface{}) + _, found = r2["retries"] + assert.True(t, found) + _, found = r2["corsPolicy"] + assert.True(t, found) + +} + func TestHttpReconcileMirrorRouteOrder(t *testing.T) { ro := rolloutWithHttpRoutes("stable", "canary", "vsvc", []string{"primary", "secondary"}) obj := unstructuredutil.StrToUnstructuredUnsafe(regularVsvc) diff --git a/rollout/trafficrouting/istio/istio_types.go b/rollout/trafficrouting/istio/istio_types.go index ce714757d2..bb09693177 100644 --- a/rollout/trafficrouting/istio/istio_types.go +++ b/rollout/trafficrouting/istio/istio_types.go @@ -70,6 +70,11 @@ type VirtualServiceRouteDestination struct { type VirtualServiceDestination struct { Host string `json:"host,omitempty"` Subset string `json:"subset,omitempty"` + Port *Port `json:"port,omitempty"` +} + +type Port struct { + Number uint32 `json:"number,omitempty"` } // DestinationRule is an Istio DestinationRule containing only the fields which we care about From 3a636521b283b79f1e2b1d9bebae490681fd7822 Mon Sep 17 00:00:00 2001 From: bsagiv Date: Thu, 17 Nov 2022 14:38:26 +0200 Subject: [PATCH 175/175] cherry-picked commit 4848fb12 from master --- ingress/alb.go | 41 +-- ingress/alb_test.go | 19 +- pkg/apis/rollouts/validation/validation.go | 40 ++- .../rollouts/validation/validation_test.go | 90 +++++- rollout/trafficrouting/alb/alb.go | 213 ++++++++++++- rollout/trafficrouting/alb/alb_test.go | 107 ++++++- test/e2e/aws_test.go | 72 +++++ test/e2e/header-routing/alb-header-route.yaml | 107 +++++++ utils/defaults/defaults.go | 8 + utils/defaults/defaults_test.go | 5 + utils/ingress/ingress.go | 67 ++++- utils/ingress/ingress_test.go | 52 ++++ utils/ingress/wrapper.go | 138 +++++++++ utils/ingress/wrapper_test.go | 282 +++++++++++++++++- 14 files changed, 1171 insertions(+), 70 deletions(-) create mode 100644 test/e2e/header-routing/alb-header-route.yaml diff --git a/ingress/alb.go b/ingress/alb.go index 3fdff50932..3803f53810 100644 --- a/ingress/alb.go +++ b/ingress/alb.go @@ -18,7 +18,7 @@ import ( func (c *Controller) syncALBIngress(ingress *ingressutil.Ingress, rollouts []*v1alpha1.Rollout) error { ctx := context.TODO() annotations := ingress.GetAnnotations() - managedActions, err := ingressutil.NewManagedALBActions(annotations[ingressutil.ManagedActionsAnnotation]) + managedActions, err := ingressutil.NewManagedALBAnnotations(annotations[ingressutil.ManagedAnnotations]) if err != nil { return nil } @@ -35,31 +35,38 @@ func (c *Controller) syncALBIngress(ingress *ingressutil.Ingress, rollouts []*v1 for roName := range managedActions { if _, ok := actionHasExistingRollout[roName]; !ok { modified = true - actionKey := managedActions[roName] + actionKeys := managedActions[roName] delete(managedActions, roName) - resetALBAction, err := getResetALBActionStr(ingress, actionKey) - if err != nil { - log.WithField(logutil.RolloutKey, roName). - WithField(logutil.IngressKey, ingress.GetName()). - WithField(logutil.NamespaceKey, ingress.GetNamespace()). - Error(err) - return nil + for _, actionKey := range actionKeys { + if !strings.Contains(actionKey, ingressutil.ALBActionPrefix) { + continue + } + resetALBAction, err := getResetALBActionStr(ingress, actionKey) + if err != nil { + log.WithField(logutil.RolloutKey, roName). + WithField(logutil.IngressKey, ingress.GetName()). + WithField(logutil.NamespaceKey, ingress.GetNamespace()). + Error(err) + return nil + } + annotations := newIngress.GetAnnotations() + annotations[actionKey] = resetALBAction + newIngress.SetAnnotations(annotations) } - annotations := newIngress.GetAnnotations() - annotations[actionKey] = resetALBAction - newIngress.SetAnnotations(annotations) } } if !modified { return nil } - newManagedStr := managedActions.String() newAnnotations := newIngress.GetAnnotations() - newAnnotations[ingressutil.ManagedActionsAnnotation] = newManagedStr - newIngress.SetAnnotations(newAnnotations) - if newManagedStr == "" { - delete(newIngress.GetAnnotations(), ingressutil.ManagedActionsAnnotation) + if len(managedActions) == 0 { + delete(newAnnotations, ingressutil.ManagedAnnotations) + } else { + newAnnotations[ingressutil.ManagedAnnotations] = managedActions.String() } + // delete leftovers from old implementation ManagedActionsAnnotation + delete(newAnnotations, ingressutil.ManagedActionsAnnotation) + newIngress.SetAnnotations(newAnnotations) _, err = c.ingressWrapper.Update(ctx, ingress.GetNamespace(), newIngress) return err } diff --git a/ingress/alb_test.go b/ingress/alb_test.go index d3b9a8bfe2..79a1c915a1 100644 --- a/ingress/alb_test.go +++ b/ingress/alb_test.go @@ -60,7 +60,10 @@ func albActionAnnotation(stable string) string { func newALBIngress(name string, port int, serviceName string, rollout string, includeStickyConfig bool) *extensionsv1beta1.Ingress { canaryService := fmt.Sprintf("%s-canary", serviceName) albActionKey := albActionAnnotation(serviceName) - managedBy := fmt.Sprintf("%s:%s", rollout, albActionKey) + albConditionKey := fmt.Sprintf("%s%s%s", ingressutil.ALBIngressAnnotation, ingressutil.ALBConditionPrefix, serviceName) + managedBy := ingressutil.ManagedALBAnnotations{ + rollout: ingressutil.ManagedALBAnnotation{albActionKey, albConditionKey}, + } action := fmt.Sprintf(actionTemplate, serviceName, port, canaryService, port) if includeStickyConfig { action = fmt.Sprintf(actionTemplateWithStickyConfig, serviceName, port, canaryService, port) @@ -70,9 +73,9 @@ func newALBIngress(name string, port int, serviceName string, rollout string, in Name: name, Namespace: metav1.NamespaceDefault, Annotations: map[string]string{ - "kubernetes.io/ingress.class": "alb", - albActionKey: action, - ingressutil.ManagedActionsAnnotation: managedBy, + "kubernetes.io/ingress.class": "alb", + albActionKey: action, + ingressutil.ManagedAnnotations: managedBy.String(), }, }, Spec: extensionsv1beta1.IngressSpec{ @@ -123,7 +126,7 @@ func rollout(name, service, ingress string) *v1alpha1.Rollout { func TestInvalidManagedALBActions(t *testing.T) { rollout := rollout("rollout", "stable-service", "test-ingress") ing := newALBIngress("test-ingress", 80, "stable-service", rollout.Name, false) - ing.Annotations[ingressutil.ManagedActionsAnnotation] = "invalid-managed-by" + ing.Annotations[ingressutil.ManagedAnnotations] = "invalid-managed-by" ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, rollout) @@ -147,7 +150,7 @@ func TestInvalidPreviousALBActionAnnotationValue(t *testing.T) { func TestInvalidPreviousALBActionAnnotationKey(t *testing.T) { ing := newALBIngress("test-ingress", 80, "stable-service", "also-not-existing-rollout", false) - ing.Annotations[ingressutil.ManagedActionsAnnotation] = "invalid-action-key" + ing.Annotations[ingressutil.ManagedAnnotations] = "invalid-action-key" ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, nil) err := ctrl.syncIngress("default/test-ingress") @@ -199,7 +202,7 @@ func TestALBIngressResetAction(t *testing.T) { panic(err) } annotations := acc.GetAnnotations() - assert.NotContains(t, annotations, ingressutil.ManagedActionsAnnotation) + assert.NotContains(t, annotations, ingressutil.ManagedAnnotations) expectedAction := `{"Type":"forward","ForwardConfig":{"TargetGroups":[{"ServiceName":"stable-service","ServicePort":"80","Weight":100}]}}` assert.Equal(t, expectedAction, annotations[albActionAnnotation("stable-service")]) } @@ -223,7 +226,7 @@ func TestALBIngressResetActionWithStickyConfig(t *testing.T) { panic(err) } annotations := acc.GetAnnotations() - assert.NotContains(t, annotations, ingressutil.ManagedActionsAnnotation) + assert.NotContains(t, annotations, ingressutil.ManagedAnnotations) expectedAction := `{"Type":"forward","ForwardConfig":{"TargetGroups":[{"ServiceName":"stable-service","ServicePort":"80","Weight":100}],"TargetGroupStickinessConfig":{"Enabled":true,"DurationSeconds":300}}}` assert.Equal(t, expectedAction, annotations[albActionAnnotation("stable-service")]) } diff --git a/pkg/apis/rollouts/validation/validation.go b/pkg/apis/rollouts/validation/validation.go index de07fa9581..37bf7eaa63 100644 --- a/pkg/apis/rollouts/validation/validation.go +++ b/pkg/apis/rollouts/validation/validation.go @@ -33,14 +33,16 @@ const ( InvalidCanaryExperimentTemplateWeightWithoutTrafficRouting = "Experiment template weight cannot be set unless TrafficRouting is enabled" // InvalidSetCanaryScaleTrafficPolicy indicates that TrafficRouting, required for SetCanaryScale, is missing InvalidSetCanaryScaleTrafficPolicy = "SetCanaryScale requires TrafficRouting to be set" - // InvalidSetHeaderRoutingTrafficPolicy indicates that TrafficRouting, required for SetCanaryScale, is missing - InvalidSetHeaderRoutingTrafficPolicy = "SetHeaderRoute requires TrafficRouting, supports Istio only" + // InvalidSetHeaderRouteTrafficPolicy indicates that TrafficRouting required for SetHeaderRoute is missing + InvalidSetHeaderRouteTrafficPolicy = "SetHeaderRoute requires TrafficRouting, supports Istio and ALB" // InvalidSetMirrorRouteTrafficPolicy indicates that TrafficRouting, required for SetCanaryScale, is missing InvalidSetMirrorRouteTrafficPolicy = "SetMirrorRoute requires TrafficRouting, supports Istio only" // InvalidStringMatchMultipleValuePolicy indicates that SetCanaryScale, has multiple values set InvalidStringMatchMultipleValuePolicy = "StringMatch match value must have exactly one of the following: exact, regex, prefix" // InvalidStringMatchMissedValuePolicy indicates that SetCanaryScale, has multiple values set InvalidStringMatchMissedValuePolicy = "StringMatch value missed, match value must have one of the following: exact, regex, prefix" + // InvalidSetHeaderRouteALBValuePolicy indicates that SetHeaderRouting using with ALB missed the 'exact' value + InvalidSetHeaderRouteALBValuePolicy = "SetHeaderRoute match value invalid. ALB supports 'exact' value only" // InvalidDurationMessage indicates the Duration value needs to be greater than 0 InvalidDurationMessage = "Duration needs to be greater than 0" // InvalidMaxSurgeMaxUnavailable indicates both maxSurge and MaxUnavailable can not be set to zero @@ -78,8 +80,6 @@ const ( MissedAlbRootServiceMessage = "Root service field is required for the configuration with ALB and ping-pong feature enabled" // PingPongWithAlbOnlyMessage At this moment ping-pong feature works with the ALB traffic routing only PingPongWithAlbOnlyMessage = "Ping-pong feature works with the ALB traffic routing only" - // InvalidStepMissingManagedRoutesField We have a step configured that requires managedRoutes to be configured which is not. - InvalidStepMissingManagedRoutesField = "Step requires spec.strategy.canary.trafficRouting.managedRoutes to be configured" // InvalideStepRouteNameNotFoundInManagedRoutes A step has been configured that requires managedRoutes and the route name // is missing from managedRoutes InvalideStepRouteNameNotFoundInManagedRoutes = "Steps define a route that does not exist in spec.strategy.canary.trafficRouting.managedRoutes" @@ -305,13 +305,17 @@ func ValidateRolloutStrategyCanary(rollout *v1alpha1.Rollout, fldPath *field.Pat if step.SetHeaderRoute != nil { trafficRouting := rollout.Spec.Strategy.Canary.TrafficRouting - if trafficRouting == nil || trafficRouting.Istio == nil { - allErrs = append(allErrs, field.Invalid(stepFldPath.Child("setHeaderRoute"), step.SetHeaderRoute, InvalidSetHeaderRoutingTrafficPolicy)) - } - if step.SetHeaderRoute.Match != nil && len(step.SetHeaderRoute.Match) > 0 { + if trafficRouting == nil || (trafficRouting.Istio == nil && trafficRouting.ALB == nil) { + allErrs = append(allErrs, field.Invalid(stepFldPath.Child("setHeaderRoute"), step.SetHeaderRoute, InvalidSetHeaderRouteTrafficPolicy)) + } else if step.SetHeaderRoute.Match != nil && len(step.SetHeaderRoute.Match) > 0 { for j, match := range step.SetHeaderRoute.Match { - matchFld := stepFldPath.Child("setHeaderRoute").Child("match").Index(j) - allErrs = append(allErrs, hasMultipleMatchValues(match.HeaderValue, matchFld)...) + if trafficRouting.ALB != nil { + matchFld := stepFldPath.Child("setHeaderRoute").Child("match").Index(j) + allErrs = append(allErrs, hasALBInvalidValues(match.HeaderValue, matchFld)...) + } else { + matchFld := stepFldPath.Child("setHeaderRoute").Child("match").Index(j) + allErrs = append(allErrs, hasMultipleMatchValues(match.HeaderValue, matchFld)...) + } } } } @@ -340,7 +344,8 @@ func ValidateRolloutStrategyCanary(rollout *v1alpha1.Rollout, fldPath *field.Pat if rollout.Spec.Strategy.Canary.TrafficRouting != nil { if step.SetHeaderRoute != nil || step.SetMirrorRoute != nil { if rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes == nil { - allErrs = append(allErrs, field.Invalid(stepFldPath, step, InvalidStepMissingManagedRoutesField)) + message := fmt.Sprintf(MissingFieldMessage, "spec.strategy.canary.trafficRouting.managedRoutes") + allErrs = append(allErrs, field.Required(fldPath.Child("trafficRouting", "managedRoutes"), message)) } } } @@ -473,6 +478,19 @@ func hasMultipleStepsType(s v1alpha1.CanaryStep, fldPath *field.Path) field.Erro return allErrs } +func hasALBInvalidValues(match *v1alpha1.StringMatch, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if match == nil { + e := field.Invalid(fldPath, match, InvalidStringMatchMissedValuePolicy) + allErrs = append(allErrs, e) + return allErrs + } + if match.Exact == "" || match.Regex != "" || match.Prefix != "" { + return append(allErrs, field.Invalid(fldPath, match, InvalidSetHeaderRouteALBValuePolicy)) + } + return allErrs +} + func hasMultipleMatchValues(match *v1alpha1.StringMatch, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} diff --git a/pkg/apis/rollouts/validation/validation_test.go b/pkg/apis/rollouts/validation/validation_test.go index 8888ac29ac..9722d0d093 100644 --- a/pkg/apis/rollouts/validation/validation_test.go +++ b/pkg/apis/rollouts/validation/validation_test.go @@ -281,21 +281,15 @@ func TestValidateRolloutStrategyAntiAffinity(t *testing.T) { assert.Equal(t, InvalidAntiAffinityWeightMessage, allErrs[0].Detail) } -func TestValidateRolloutStrategyCanarySetHeaderRouteIstio(t *testing.T) { +func TestValidateRolloutStrategyCanarySetHeaderRoute(t *testing.T) { ro := &v1alpha1.Rollout{} ro.Spec.Strategy.Canary = &v1alpha1.CanaryStrategy{ CanaryService: "canary", StableService: "stable", - TrafficRouting: &v1alpha1.RolloutTrafficRouting{ - Istio: &v1alpha1.IstioTrafficRouting{ - VirtualService: &v1alpha1.IstioVirtualService{Name: "virtual-service"}, - }, - }, } t.Run("using SetHeaderRoute step without the traffic routing", func(t *testing.T) { invalidRo := ro.DeepCopy() - invalidRo.Spec.Strategy.Canary.TrafficRouting = nil invalidRo.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{ SetHeaderRoute: &v1alpha1.SetHeaderRoute{ Match: []v1alpha1.HeaderRoutingMatch{ @@ -307,8 +301,21 @@ func TestValidateRolloutStrategyCanarySetHeaderRouteIstio(t *testing.T) { }, }} allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) - assert.Equal(t, InvalidSetHeaderRoutingTrafficPolicy, allErrs[0].Detail) + assert.Equal(t, InvalidSetHeaderRouteTrafficPolicy, allErrs[0].Detail) }) +} + +func TestValidateRolloutStrategyCanarySetHeaderRouteIstio(t *testing.T) { + ro := &v1alpha1.Rollout{} + ro.Spec.Strategy.Canary = &v1alpha1.CanaryStrategy{ + CanaryService: "canary", + StableService: "stable", + TrafficRouting: &v1alpha1.RolloutTrafficRouting{ + Istio: &v1alpha1.IstioTrafficRouting{ + VirtualService: &v1alpha1.IstioVirtualService{Name: "virtual-service"}, + }, + }, + } t.Run("using SetHeaderRoute step with multiple values", func(t *testing.T) { invalidRo := ro.DeepCopy() @@ -364,6 +371,71 @@ func TestValidateRolloutStrategyCanarySetHeaderRouteIstio(t *testing.T) { }) } +func TestValidateRolloutStrategyCanarySetHeaderRoutingALB(t *testing.T) { + ro := &v1alpha1.Rollout{} + ro.Spec.Strategy.Canary = &v1alpha1.CanaryStrategy{ + CanaryService: "canary", + StableService: "stable", + TrafficRouting: &v1alpha1.RolloutTrafficRouting{ + ALB: &v1alpha1.ALBTrafficRouting{ + RootService: "action_name", + }, + }, + } + + t.Run("using SetHeaderRouting step with multiple values", func(t *testing.T) { + invalidRo := ro.DeepCopy() + invalidRo.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{ + SetHeaderRoute: &v1alpha1.SetHeaderRoute{ + Match: []v1alpha1.HeaderRoutingMatch{ + { + HeaderName: "agent", + HeaderValue: &v1alpha1.StringMatch{ + Exact: "chrome", + Regex: "chrome(.*)", + }, + }, + }, + }, + }} + allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) + assert.Equal(t, InvalidSetHeaderRouteALBValuePolicy, allErrs[0].Detail) + }) + + t.Run("using SetHeaderRouting step with missed values", func(t *testing.T) { + invalidRo := ro.DeepCopy() + invalidRo.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{ + SetHeaderRoute: &v1alpha1.SetHeaderRoute{ + Match: []v1alpha1.HeaderRoutingMatch{ + { + HeaderName: "agent", + }, + }, + }, + }} + allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) + assert.Equal(t, InvalidStringMatchMissedValuePolicy, allErrs[0].Detail) + }) + + t.Run("using SetHeaderRouting step with invalid ALB match value", func(t *testing.T) { + invalidRo := ro.DeepCopy() + invalidRo.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{{ + SetHeaderRoute: &v1alpha1.SetHeaderRoute{ + Match: []v1alpha1.HeaderRoutingMatch{ + { + HeaderName: "agent", + HeaderValue: &v1alpha1.StringMatch{ + Prefix: "chrome", + }, + }, + }, + }, + }} + allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) + assert.Equal(t, InvalidSetHeaderRouteALBValuePolicy, allErrs[0].Detail) + }) +} + func TestValidateRolloutStrategyCanarySetMirrorRouteIstio(t *testing.T) { ro := &v1alpha1.Rollout{} ro.Spec.Strategy.Canary = &v1alpha1.CanaryStrategy{ @@ -441,7 +513,7 @@ func TestValidateRolloutStrategyCanarySetMirrorRouteIstio(t *testing.T) { }, }} allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) - assert.Equal(t, InvalidStepMissingManagedRoutesField, allErrs[0].Detail) + assert.Equal(t, fmt.Sprintf(MissingFieldMessage, "spec.strategy.canary.trafficRouting.managedRoutes"), allErrs[0].Detail) }) t.Run("using SetMirrorRoute step without managedRoutes defined but missing route", func(t *testing.T) { diff --git a/rollout/trafficrouting/alb/alb.go b/rollout/trafficrouting/alb/alb.go index 62d1a465d4..103e3f5e9a 100644 --- a/rollout/trafficrouting/alb/alb.go +++ b/rollout/trafficrouting/alb/alb.go @@ -115,7 +115,50 @@ func (r *Reconciler) SetWeight(desiredWeight int32, additionalDestinations ...v1 return nil } -func (r *Reconciler) SetHeaderRoute(headerRouting *v1alpha1.SetHeaderRoute) error { +func (r *Reconciler) SetHeaderRoute(headerRoute *v1alpha1.SetHeaderRoute) error { + if headerRoute == nil { + return nil + } + ctx := context.TODO() + rollout := r.cfg.Rollout + ingressName := rollout.Spec.Strategy.Canary.TrafficRouting.ALB.Ingress + action := headerRoute.Name + port := rollout.Spec.Strategy.Canary.TrafficRouting.ALB.ServicePort + + ingress, err := r.cfg.IngressWrapper.GetCached(rollout.Namespace, ingressName) + if err != nil { + return err + } + + desiredAnnotations, err := getDesiredHeaderAnnotations(ingress, rollout, port, headerRoute) + if err != nil { + return err + } + desiredIngress := ingressutil.NewIngressWithSpecAndAnnotations(ingress, desiredAnnotations) + hasRule := ingressutil.HasRuleWithService(ingress, action) + if hasRule && headerRoute.Match == nil { + desiredIngress.RemovePathByServiceName(action) + } + if !hasRule && headerRoute.Match != nil { + desiredIngress.CreateAnnotationBasedPath(action) + } + desiredIngress.SortHttpPaths(rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes) + patch, modified, err := ingressutil.BuildIngressPatch(ingress.Mode(), ingress, desiredIngress, ingressutil.WithAnnotations(), ingressutil.WithSpec()) + if err != nil { + return nil + } + if !modified { + r.log.Info("no changes to the ALB Ingress for header routing") + return nil + } + r.log.WithField("patch", string(patch)).Debug("applying ALB Ingress patch") + r.cfg.Recorder.Eventf(rollout, record.EventOptions{EventReason: "PatchingALBIngress"}, "Updating Ingress `%s` to headerRoute '%d'", ingressName, headerRoute) + + _, err = r.cfg.IngressWrapper.Patch(ctx, ingress.GetNamespace(), ingress.GetName(), types.MergePatchType, patch, metav1.PatchOptions{}) + if err != nil { + r.log.WithField("err", err.Error()).Error("error patching alb ingress") + return fmt.Errorf("error patching alb ingress `%s`: %v", ingressName, err) + } return nil } @@ -294,13 +337,125 @@ func getDesiredAnnotations(current *ingressutil.Ingress, r *v1alpha1.Rollout, po return nil, err } desired[key] = value - m, err := ingressutil.NewManagedALBActions(desired[ingressutil.ManagedActionsAnnotation]) + return modifyManagedAnnotation(desired, r.Name, true, key) +} + +func getDesiredHeaderAnnotations(current *ingressutil.Ingress, r *v1alpha1.Rollout, port int32, headerRoute *v1alpha1.SetHeaderRoute) (map[string]string, error) { + desired := current.DeepCopy().GetAnnotations() + actionKey := ingressutil.ALBHeaderBasedActionAnnotationKey(r, headerRoute.Name) + conditionKey := ingressutil.ALBHeaderBasedConditionAnnotationKey(r, headerRoute.Name) + add := headerRoute.Match != nil + if add { + actionValue, err := getTrafficForwardActionString(r, port) + if err != nil { + return nil, err + } + conditionValue, err := getTrafficForwardConditionString(headerRoute) + if err != nil { + return nil, err + } + desired[actionKey] = actionValue + desired[conditionKey] = conditionValue + } else { + delete(desired, actionKey) + delete(desired, conditionKey) + } + + return modifyManagedAnnotation(desired, r.Name, add, actionKey, conditionKey) +} + +func modifyManagedAnnotation(annotations map[string]string, rolloutName string, add bool, annotationKeys ...string) (map[string]string, error) { + m, err := ingressutil.NewManagedALBAnnotations(annotations[ingressutil.ManagedAnnotations]) if err != nil { return nil, err } - m[r.Name] = key - desired[ingressutil.ManagedActionsAnnotation] = m.String() - return desired, nil + managedAnnotation := m[rolloutName] + if managedAnnotation == nil { + managedAnnotation = ingressutil.ManagedALBAnnotation{} + } + for _, annotationKey := range annotationKeys { + if add { + if !hasValue(managedAnnotation, annotationKey) { + managedAnnotation = append(managedAnnotation, annotationKey) + } + } else { + managedAnnotation = removeValue(managedAnnotation, annotationKey) + } + } + m[rolloutName] = managedAnnotation + annotations[ingressutil.ManagedAnnotations] = m.String() + return annotations, nil +} + +func hasValue(array []string, key string) bool { + for _, item := range array { + if item == key { + return true + } + } + return false +} + +func removeValue(array []string, key string) []string { + for i, v := range array { + if v == key { + array = append(array[:i], array[i+1:]...) + } + } + return array +} + +func getTrafficForwardActionString(r *v1alpha1.Rollout, port int32) (string, error) { + _, canaryService := trafficrouting.GetStableAndCanaryServices(r) + portStr := strconv.Itoa(int(port)) + weight := int64(100) + targetGroups := make([]ingressutil.ALBTargetGroup, 0) + // create target group for canary + targetGroups = append(targetGroups, ingressutil.ALBTargetGroup{ + ServiceName: canaryService, + ServicePort: portStr, + Weight: pointer.Int64Ptr(weight), + }) + + action := ingressutil.ALBAction{ + Type: "forward", + ForwardConfig: ingressutil.ALBForwardConfig{ + TargetGroups: targetGroups, + }, + } + + var stickinessConfig = r.Spec.Strategy.Canary.TrafficRouting.ALB.StickinessConfig + if stickinessConfig != nil && stickinessConfig.Enabled { + // AWS API valid range + // https://docs.aws.amazon.com/elasticloadbalancing/latest/APIReference/API_TargetGroupStickinessConfig.html + if stickinessConfig.DurationSeconds < 1 || stickinessConfig.DurationSeconds > 604800 { + return "", fmt.Errorf("TargetGroupStickinessConfig's duration must be between 1 and 604800 seconds (7 days)!") + } + newStickyConfig := ingressutil.ALBTargetGroupStickinessConfig{ + Enabled: true, + DurationSeconds: stickinessConfig.DurationSeconds, + } + action.ForwardConfig.TargetGroupStickinessConfig = &newStickyConfig + } + + bytes := jsonutil.MustMarshal(action) + return string(bytes), nil +} + +func getTrafficForwardConditionString(headerRoute *v1alpha1.SetHeaderRoute) (string, error) { + var res []ingressutil.ALBCondition + for _, match := range headerRoute.Match { + condition := ingressutil.ALBCondition{ + Field: "http-header", + HttpHeaderConfig: ingressutil.HttpHeaderConfig{ + HttpHeaderName: match.HeaderName, + Values: []string{match.HeaderValue.Exact}, + }, + } + res = append(res, condition) + } + bytes := jsonutil.MustMarshal(res) + return string(bytes), nil } // UpdateHash informs a traffic routing reconciler about new canary/stable pod hashes @@ -313,5 +468,53 @@ func (r *Reconciler) SetMirrorRoute(setMirrorRoute *v1alpha1.SetMirrorRoute) err } func (r *Reconciler) RemoveManagedRoutes() error { + if len(r.cfg.Rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes) == 0 { + return nil + } + ctx := context.TODO() + rollout := r.cfg.Rollout + ingressName := rollout.Spec.Strategy.Canary.TrafficRouting.ALB.Ingress + + ingress, err := r.cfg.IngressWrapper.GetCached(rollout.Namespace, ingressName) + if err != nil { + return err + } + + desiredAnnotations := ingress.DeepCopy().GetAnnotations() + var actionKeys []string + for _, managedRoute := range rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes { + actionKey := ingressutil.ALBHeaderBasedActionAnnotationKey(rollout, managedRoute.Name) + conditionKey := ingressutil.ALBHeaderBasedConditionAnnotationKey(rollout, managedRoute.Name) + delete(desiredAnnotations, actionKey) + delete(desiredAnnotations, conditionKey) + actionKeys = append(actionKeys, actionKey, conditionKey) + } + desiredAnnotations, err = modifyManagedAnnotation(desiredAnnotations, rollout.Name, false, actionKeys...) + if err != nil { + return err + } + + desiredIngress := ingressutil.NewIngressWithSpecAndAnnotations(ingress, desiredAnnotations) + + for _, managedRoute := range rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes { + desiredIngress.RemovePathByServiceName(managedRoute.Name) + } + + patch, modified, err := ingressutil.BuildIngressPatch(ingress.Mode(), ingress, desiredIngress, ingressutil.WithAnnotations(), ingressutil.WithSpec()) + if err != nil { + return nil + } + if !modified { + r.log.Info("no changes to the ALB Ingress for header routing") + return nil + } + r.log.WithField("patch", string(patch)).Debug("applying ALB Ingress patch") + r.cfg.Recorder.Eventf(rollout, record.EventOptions{EventReason: "PatchingALBIngress"}, "Updating Ingress `%s` removing managed routes", ingressName) + + _, err = r.cfg.IngressWrapper.Patch(ctx, ingress.GetNamespace(), ingress.GetName(), types.MergePatchType, patch, metav1.PatchOptions{}) + if err != nil { + r.log.WithField("err", err.Error()).Error("error patching alb ingress") + return fmt.Errorf("error patching alb ingress `%s`: %v", ingressName, err) + } return nil } diff --git a/rollout/trafficrouting/alb/alb_test.go b/rollout/trafficrouting/alb/alb_test.go index 7e26f6f16e..3a044c537f 100644 --- a/rollout/trafficrouting/alb/alb_test.go +++ b/rollout/trafficrouting/alb/alb_test.go @@ -101,7 +101,9 @@ func albActionAnnotation(stable string) string { } func ingress(name, stableSvc, canarySvc, actionService string, port, weight int32, managedBy string, includeStickyConfig bool) *extensionsv1beta1.Ingress { - managedByValue := fmt.Sprintf("%s:%s", managedBy, albActionAnnotation(actionService)) + managedByValue := ingressutil.ManagedALBAnnotations{ + managedBy: ingressutil.ManagedALBAnnotation{albActionAnnotation(actionService)}, + } action := fmt.Sprintf(actionTemplate, canarySvc, port, weight, stableSvc, port, 100-weight) if includeStickyConfig { action = fmt.Sprintf(actionTemplateWithStickyConfig, canarySvc, port, weight, stableSvc, port, 100-weight) @@ -117,8 +119,8 @@ func ingress(name, stableSvc, canarySvc, actionService string, port, weight int3 Name: name, Namespace: metav1.NamespaceDefault, Annotations: map[string]string{ - albActionAnnotation(actionService): string(jsonutil.MustMarshal(a)), - ingressutil.ManagedActionsAnnotation: managedByValue, + albActionAnnotation(actionService): string(jsonutil.MustMarshal(a)), + ingressutil.ManagedAnnotations: managedByValue.String(), }, }, Spec: extensionsv1beta1.IngressSpec{ @@ -156,6 +158,13 @@ func TestType(t *testing.T) { assert.NoError(t, err) } +func TestAddManagedAnnotation(t *testing.T) { + annotations, _ := modifyManagedAnnotation(map[string]string{}, "argo-rollouts", true, "alb.ingress.kubernetes.io/actions.action1", "alb.ingress.kubernetes.io/conditions.action1") + assert.Equal(t, annotations[ingressutil.ManagedAnnotations], "{\"argo-rollouts\":[\"alb.ingress.kubernetes.io/actions.action1\",\"alb.ingress.kubernetes.io/conditions.action1\"]}") + _, err := modifyManagedAnnotation(map[string]string{ingressutil.ManagedAnnotations: "invalid, non-json value"}, "some-rollout", false) + assert.Error(t, err) +} + func TestIngressNotFound(t *testing.T) { ro := fakeRollout("stable-service", "canary-service", nil, "stable-ingress", 443) client := fake.NewSimpleClientset() @@ -225,7 +234,7 @@ func TestNoChanges(t *testing.T) { func TestErrorOnInvalidManagedBy(t *testing.T) { ro := fakeRollout(STABLE_SVC, CANARY_SVC, nil, "ingress", 443) i := ingress("ingress", STABLE_SVC, CANARY_SVC, STABLE_SVC, 443, 5, ro.Name, false) - i.Annotations[ingressutil.ManagedActionsAnnotation] = "test" + i.Annotations[ingressutil.ManagedAnnotations] = "test" client := fake.NewSimpleClientset(i) k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) @@ -863,8 +872,11 @@ func TestVerifyWeightWithAdditionalDestinations(t *testing.T) { func TestSetHeaderRoute(t *testing.T) { ro := fakeRollout(STABLE_SVC, CANARY_SVC, nil, "ingress", 443) - i := ingress("ingress", STABLE_SVC, CANARY_SVC, STABLE_SVC, 443, 10, ro.Name, false) - client := fake.NewSimpleClientset() + ro.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes = []v1alpha1.MangedRoutes{ + {Name: "header-route"}, + } + i := ingress("ingress", STABLE_SVC, CANARY_SVC, "action1", 443, 10, ro.Name, false) + client := fake.NewSimpleClientset(i) k8sI := kubeinformers.NewSharedInformerFactory(client, 0) k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) @@ -880,20 +892,95 @@ func TestSetHeaderRoute(t *testing.T) { }) assert.NoError(t, err) err = r.SetHeaderRoute(&v1alpha1.SetHeaderRoute{ - Name: "set-header", + Name: "header-route", Match: []v1alpha1.HeaderRoutingMatch{{ - HeaderName: "header-name", + HeaderName: "Agent", HeaderValue: &v1alpha1.StringMatch{ - Exact: "value", + Prefix: "Chrome", }, }}, }) assert.Nil(t, err) + assert.Len(t, client.Actions(), 1) + // no managed routes, no changes expected err = r.RemoveManagedRoutes() assert.Nil(t, err) + assert.Len(t, client.Actions(), 1) +} - assert.Len(t, client.Actions(), 0) +func TestRemoveManagedRoutes(t *testing.T) { + ro := fakeRollout(STABLE_SVC, CANARY_SVC, nil, "ingress", 443) + ro.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes = []v1alpha1.MangedRoutes{ + {Name: "header-route"}, + } + i := ingress("ingress", STABLE_SVC, CANARY_SVC, "action1", 443, 10, ro.Name, false) + managedByValue := ingressutil.ManagedALBAnnotations{ + ro.Name: ingressutil.ManagedALBAnnotation{ + "alb.ingress.kubernetes.io/actions.action1", + "alb.ingress.kubernetes.io/actions.header-route", + "alb.ingress.kubernetes.io/conditions.header-route", + }, + } + i.Annotations["alb.ingress.kubernetes.io/actions.header-route"] = "{}" + i.Annotations["alb.ingress.kubernetes.io/conditions.header-route"] = "{}" + i.Annotations[ingressutil.ManagedAnnotations] = managedByValue.String() + i.Spec.Rules = []extensionsv1beta1.IngressRule{ + { + IngressRuleValue: extensionsv1beta1.IngressRuleValue{ + HTTP: &extensionsv1beta1.HTTPIngressRuleValue{ + Paths: []extensionsv1beta1.HTTPIngressPath{ + { + Backend: extensionsv1beta1.IngressBackend{ + ServiceName: "action1", + ServicePort: intstr.Parse("use-annotation"), + }, + }, + }, + }, + }, + }, + { + IngressRuleValue: extensionsv1beta1.IngressRuleValue{ + HTTP: &extensionsv1beta1.HTTPIngressRuleValue{ + Paths: []extensionsv1beta1.HTTPIngressPath{ + { + Backend: extensionsv1beta1.IngressBackend{ + ServiceName: "header-route", + ServicePort: intstr.Parse("use-annotation"), + }, + }, + }, + }, + }, + }, + } + + client := fake.NewSimpleClientset(i) + k8sI := kubeinformers.NewSharedInformerFactory(client, 0) + k8sI.Extensions().V1beta1().Ingresses().Informer().GetIndexer().Add(i) + ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, client, k8sI) + if err != nil { + t.Fatal(err) + } + r, err := NewReconciler(ReconcilerConfig{ + Rollout: ro, + Client: client, + Recorder: record.NewFakeEventRecorder(), + ControllerKind: schema.GroupVersionKind{Group: "foo", Version: "v1", Kind: "Bar"}, + IngressWrapper: ingressWrapper, + }) + assert.NoError(t, err) + + err = r.SetHeaderRoute(&v1alpha1.SetHeaderRoute{ + Name: "header-route", + }) + assert.Nil(t, err) + assert.Len(t, client.Actions(), 1) + + err = r.RemoveManagedRoutes() + assert.Nil(t, err) + assert.Len(t, client.Actions(), 2) } func TestSetMirrorRoute(t *testing.T) { diff --git a/test/e2e/aws_test.go b/test/e2e/aws_test.go index 5525d4650d..a2a4434781 100644 --- a/test/e2e/aws_test.go +++ b/test/e2e/aws_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/tj/assert" + "k8s.io/utils/pointer" "github.com/argoproj/argo-rollouts/test/fixtures" ingress2 "github.com/argoproj/argo-rollouts/utils/ingress" @@ -171,3 +172,74 @@ func (s *AWSSuite) TestALBExperimentStepNoSetWeight() { Then(). Assert(assertWeights(s, "alb-rollout-canary", "alb-rollout-stable", 0, 100)) } + +func (s *AWSSuite) TestAlbHeaderRoute() { + s.Given(). + RolloutObjects("@header-routing/alb-header-route.yaml"). + When(). + ApplyManifests(). + WaitForRolloutStatus("Healthy"). + Then(). + Assert(func(t *fixtures.Then) { + assertAlbActionDoesNotExist(t, s, "header-route") + assertAlbActionServiceWeight(t, s, "action1", "canary-service", 0) + assertAlbActionServiceWeight(t, s, "action1", "stable-service", 100) + }). + When(). + UpdateSpec(). + WaitForRolloutStatus("Paused"). + Sleep(1 * time.Second). + Then(). + Assert(func(t *fixtures.Then) { + assertAlbActionDoesNotExist(t, s, "header-route") + assertAlbActionServiceWeight(t, s, "action1", "canary-service", 20) + assertAlbActionServiceWeight(t, s, "action1", "stable-service", 80) + }). + When(). + PromoteRollout(). + WaitForRolloutStatus("Paused"). + Sleep(1 * time.Second). + Then(). + Assert(func(t *fixtures.Then) { + assertAlbActionServiceWeight(t, s, "header-route", "canary-service", 100) + assertAlbActionServiceWeight(t, s, "action1", "canary-service", 20) + assertAlbActionServiceWeight(t, s, "action1", "stable-service", 80) + }). + When(). + PromoteRollout(). + WaitForRolloutStatus("Paused"). + Sleep(1 * time.Second). + Then(). + Assert(func(t *fixtures.Then) { + assertAlbActionDoesNotExist(t, s, "header-route") + }) +} + +func assertAlbActionServiceWeight(t *fixtures.Then, s *AWSSuite, actionName, serviceName string, expectedWeight int64) { + ingress := t.GetALBIngress() + key := "alb.ingress.kubernetes.io/actions." + actionName + actionStr, ok := ingress.Annotations[key] + assert.True(s.T(), ok, "Annotation for action was not found: %s", key) + + var albAction ingress2.ALBAction + err := json.Unmarshal([]byte(actionStr), &albAction) + if err != nil { + panic(err) + } + + found := false + for _, group := range albAction.ForwardConfig.TargetGroups { + if group.ServiceName == serviceName { + assert.Equal(s.T(), pointer.Int64(expectedWeight), group.Weight) + found = true + } + } + assert.True(s.T(), found, "Service %s was not found", serviceName) +} + +func assertAlbActionDoesNotExist(t *fixtures.Then, s *AWSSuite, actionName string) { + ingress := t.GetALBIngress() + key := "alb.ingress.kubernetes.io/actions." + actionName + _, ok := ingress.Annotations[key] + assert.False(s.T(), ok, "Annotation for action should not exist: %s", key) +} diff --git a/test/e2e/header-routing/alb-header-route.yaml b/test/e2e/header-routing/alb-header-route.yaml new file mode 100644 index 0000000000..71c9e7aa6f --- /dev/null +++ b/test/e2e/header-routing/alb-header-route.yaml @@ -0,0 +1,107 @@ +apiVersion: v1 +kind: Service +metadata: + name: canary-service +spec: + type: NodePort + ports: + - port: 8080 + targetPort: 8080 + protocol: TCP + name: http + selector: + app: alb-rollout +--- +apiVersion: v1 +kind: Service +metadata: + name: stable-service +spec: + type: NodePort + ports: + - port: 8080 + targetPort: 8080 + protocol: TCP + name: http + selector: + app: alb-rollout +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: alb-rollout-ingress + annotations: + alb.ingress.kubernetes.io/security-groups: 'iks-intuit-cidr-ingress-tcp-443' + alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-east-2:795188202216:certificate/27d920c5-a8a6-4210-9f31-bd4a2d439039 + alb.ingress.kubernetes.io/load-balancer-attributes: access_logs.s3.enabled=false + alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS-1-2-2017-01 + kubernetes.io/ingress.class: aws-alb + alb.ingress.kubernetes.io/load-balancer-name: rollouts-sample + alb.ingress.kubernetes.io/target-type: ip + alb.ingress.kubernetes.io/healthcheck-protocol: HTTP + alb.ingress.kubernetes.io/healthcheck-port: traffic-port + alb.ingress.kubernetes.io/healthcheck-path: /color + alb.ingress.kubernetes.io/backend-protocol: HTTP + alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS": 443}]' + alb.ingress.kubernetes.io/ssl-redirect: '443' + alb.ingress.kubernetes.io/scheme: internet-facing + alb.ingress.kubernetes.io/subnets: IngressSubnetAz1, IngressSubnetAz2, IngressSubnetAz3 +spec: + rules: + - http: + paths: + - path: /* + pathType: ImplementationSpecific + backend: + service: + name: action1 + port: + name: use-annotation + +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollouts-demo +spec: + replicas: 5 + selector: + matchLabels: + app: alb-rollout + template: + metadata: + labels: + app: alb-rollout + spec: + containers: + - name: alb-rollout + image: "argoproj/rollouts-demo:yellow" + ports: + - name: http + containerPort: 8080 + protocol: TCP + strategy: + canary: + scaleDownDelaySeconds: 5 + stableService: stable-service + canaryService: canary-service + trafficRouting: + managedRoutes: + - name: header-route + alb: + ingress: alb-rollout-ingress + rootService: action1 + servicePort: 8080 + steps: + - setWeight: 20 + - pause: {} + - setHeaderRoute: + name: header-route + match: + - headerName: Custom-Header + headerValue: + exact: Mozilla* + - pause: {} + - setHeaderRoute: + name: header-route + - pause: {} diff --git a/utils/defaults/defaults.go b/utils/defaults/defaults.go index c38a044c25..9b18b16db1 100644 --- a/utils/defaults/defaults.go +++ b/utils/defaults/defaults.go @@ -85,6 +85,14 @@ func init() { } } +func GetStringOrDefault(value, defaultValue string) string { + if value == "" { + return defaultValue + } else { + return value + } +} + // GetReplicasOrDefault returns the deferenced number of replicas or the default number func GetReplicasOrDefault(replicas *int32) int32 { if replicas == nil { diff --git a/utils/defaults/defaults_test.go b/utils/defaults/defaults_test.go index d099cc0343..2162f1be82 100644 --- a/utils/defaults/defaults_test.go +++ b/utils/defaults/defaults_test.go @@ -12,6 +12,11 @@ import ( "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" ) +func TestGetStringOrDefault(t *testing.T) { + assert.Equal(t, "some value", GetStringOrDefault("some value", "default value")) + assert.Equal(t, "default value", GetStringOrDefault("", "default value")) +} + func TestGetReplicasOrDefault(t *testing.T) { replicas := int32(2) assert.Equal(t, replicas, GetReplicasOrDefault(&replicas)) diff --git a/utils/ingress/ingress.go b/utils/ingress/ingress.go index 42dc61ca20..c4036dff8f 100644 --- a/utils/ingress/ingress.go +++ b/utils/ingress/ingress.go @@ -1,6 +1,7 @@ package ingress import ( + json2 "encoding/json" "errors" "fmt" "strconv" @@ -11,18 +12,25 @@ import ( "k8s.io/client-go/discovery" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + "github.com/argoproj/argo-rollouts/utils/defaults" "github.com/argoproj/argo-rollouts/utils/diff" + "github.com/argoproj/argo-rollouts/utils/json" ) const ( // CanaryIngressSuffix is the name suffix all canary ingresses created by the rollouts controller will have CanaryIngressSuffix = "-canary" // ManagedActionsAnnotation holds list of ALB actions that are managed by rollouts + // DEPRECATED in favor of ManagedAnnotations ManagedActionsAnnotation = "rollouts.argoproj.io/managed-alb-actions" + // ManagedAnnotations holds list of ALB annotations that are managed by rollouts supports multiple annotations + ManagedAnnotations = "rollouts.argoproj.io/managed-alb-annotations" //ALBIngressAnnotation is the prefix annotation that is used by the ALB Ingress controller to configure an ALB ALBIngressAnnotation = "alb.ingress.kubernetes.io" // ALBActionPrefix the prefix to specific actions within an ALB ingress. ALBActionPrefix = "/actions." + // ALBConditionPrefix the prefix to specific conditions within an ALB ingress. + ALBConditionPrefix = "/conditions." ) // ALBAction describes an ALB action that configure the behavior of an ALB. This struct is marshaled into a string @@ -32,6 +40,19 @@ type ALBAction struct { ForwardConfig ALBForwardConfig `json:"ForwardConfig"` } +// ALBCondition describes an ALB action condition that configure the behavior of an ALB. This struct is marshaled into a string +// that is added to the Ingress's annotations. +type ALBCondition struct { + Field string `json:"field"` + HttpHeaderConfig HttpHeaderConfig `json:"httpHeaderConfig"` +} + +// HttpHeaderConfig describes header config for the ALB action condition +type HttpHeaderConfig struct { + HttpHeaderName string `json:"httpHeaderName"` + Values []string `json:"values"` +} + // ALBForwardConfig describes a list of target groups that the ALB should route traffic towards type ALBForwardConfig struct { TargetGroups []ALBTargetGroup `json:"TargetGroups"` @@ -142,6 +163,26 @@ func hasLegacyIngressRuleWithService(ingress *extensionsv1beta1.Ingress, svc str // ManagedALBActions a mapping of Rollout names to the ALB action that the Rollout manages type ManagedALBActions map[string]string +type ManagedALBAnnotations map[string]ManagedALBAnnotation + +type ManagedALBAnnotation []string + +// String outputs a string of all the managed ALB annotations that is stored in the Ingress's annotations +func (m ManagedALBAnnotations) String() string { + return string(json.MustMarshal(m)) +} + +func NewManagedALBAnnotations(json string) (ManagedALBAnnotations, error) { + res := ManagedALBAnnotations{} + if json == "" { + return res, nil + } + if err := json2.Unmarshal([]byte(json), &res); err != nil { + return nil, err + } + return res, nil +} + // String outputs a string of all the managed ALB actions that is stored in the Ingress's annotations func (m ManagedALBActions) String() string { str := "" @@ -173,15 +214,23 @@ func NewManagedALBActions(annotation string) (ManagedALBActions, error) { // ALBActionAnnotationKey returns the annotation key for a specific action func ALBActionAnnotationKey(r *v1alpha1.Rollout) string { - prefix := ALBIngressAnnotation - if r.Spec.Strategy.Canary.TrafficRouting.ALB.AnnotationPrefix != "" { - prefix = r.Spec.Strategy.Canary.TrafficRouting.ALB.AnnotationPrefix - } - actionService := r.Spec.Strategy.Canary.StableService - if r.Spec.Strategy.Canary.TrafficRouting.ALB.RootService != "" { - actionService = r.Spec.Strategy.Canary.TrafficRouting.ALB.RootService - } - return fmt.Sprintf("%s%s%s", prefix, ALBActionPrefix, actionService) + actionService := defaults.GetStringOrDefault(r.Spec.Strategy.Canary.TrafficRouting.ALB.RootService, r.Spec.Strategy.Canary.StableService) + return albIngressKubernetesIoKey(r, ALBActionPrefix, actionService) +} + +// ALBHeaderBasedActionAnnotationKey returns the annotation key for a specific action +func ALBHeaderBasedActionAnnotationKey(r *v1alpha1.Rollout, action string) string { + return albIngressKubernetesIoKey(r, ALBActionPrefix, action) +} + +// ALBHeaderBasedConditionAnnotationKey returns the annotation key for a specific condition +func ALBHeaderBasedConditionAnnotationKey(r *v1alpha1.Rollout, action string) string { + return albIngressKubernetesIoKey(r, ALBConditionPrefix, action) +} + +func albIngressKubernetesIoKey(r *v1alpha1.Rollout, action, service string) string { + prefix := defaults.GetStringOrDefault(r.Spec.Strategy.Canary.TrafficRouting.ALB.AnnotationPrefix, ALBIngressAnnotation) + return fmt.Sprintf("%s%s%s", prefix, action, service) } type patchConfig struct { diff --git a/utils/ingress/ingress_test.go b/utils/ingress/ingress_test.go index eaca7e6a86..08f2a2e42f 100644 --- a/utils/ingress/ingress_test.go +++ b/utils/ingress/ingress_test.go @@ -514,3 +514,55 @@ func getExtensionsIngress() *extensionsv1beta1.Ingress { }, } } + +func TestManagedALBAnnotations(t *testing.T) { + emptyJson, _ := NewManagedALBAnnotations("") + assert.NotNil(t, emptyJson) + assert.Equal(t, 0, len(emptyJson)) + assert.Equal(t, "{}", emptyJson.String()) + + _, err := NewManagedALBAnnotations("invalid json") + assert.Error(t, err) + + json := "{\"rollouts-demo\":[\"alb.ingress.kubernetes.io/actions.action1\", \"alb.ingress.kubernetes.io/actions.header-action\", \"alb.ingress.kubernetes.io/conditions.header-action\"]}" + actual, err := NewManagedALBAnnotations(json) + assert.NoError(t, err) + + rolloutsDemoAnnotation := actual["rollouts-demo"] + assert.NotNil(t, rolloutsDemoAnnotation) + assert.Equal(t, 3, len(rolloutsDemoAnnotation)) +} + +func TestALBHeaderBasedActionAnnotationKey(t *testing.T) { + r := &v1alpha1.Rollout{ + Spec: v1alpha1.RolloutSpec{ + Strategy: v1alpha1.RolloutStrategy{ + Canary: &v1alpha1.CanaryStrategy{ + TrafficRouting: &v1alpha1.RolloutTrafficRouting{ + ALB: &v1alpha1.ALBTrafficRouting{ + AnnotationPrefix: "alb.ingress.kubernetes.io", + }, + }, + }, + }, + }, + } + assert.Equal(t, "alb.ingress.kubernetes.io/actions.route", ALBHeaderBasedActionAnnotationKey(r, "route")) +} + +func TestALBHeaderBasedConditionAnnotationKey(t *testing.T) { + r := &v1alpha1.Rollout{ + Spec: v1alpha1.RolloutSpec{ + Strategy: v1alpha1.RolloutStrategy{ + Canary: &v1alpha1.CanaryStrategy{ + TrafficRouting: &v1alpha1.RolloutTrafficRouting{ + ALB: &v1alpha1.ALBTrafficRouting{ + AnnotationPrefix: "alb.ingress.kubernetes.io", + }, + }, + }, + }, + }, + } + assert.Equal(t, "alb.ingress.kubernetes.io/conditions.route", ALBHeaderBasedConditionAnnotationKey(r, "route")) +} diff --git a/utils/ingress/wrapper.go b/utils/ingress/wrapper.go index a460baac70..d70b6a96ed 100644 --- a/utils/ingress/wrapper.go +++ b/utils/ingress/wrapper.go @@ -3,6 +3,7 @@ package ingress import ( "context" "errors" + "sort" "sync" corev1 "k8s.io/api/core/v1" @@ -10,11 +11,14 @@ import ( v1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/client-go/informers" extensionsv1beta1 "k8s.io/client-go/informers/extensions/v1beta1" networkingv1 "k8s.io/client-go/informers/networking/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/cache" + + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" ) // Ingress defines an Ingress resource abstraction used to allow Rollouts to @@ -68,6 +72,29 @@ func NewIngressWithAnnotations(mode IngressMode, annotations map[string]string) } } +func NewIngressWithSpecAndAnnotations(ingress *Ingress, annotations map[string]string) *Ingress { + switch ingress.mode { + case IngressModeNetworking: + i := &v1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: annotations, + }, + Spec: *ingress.ingress.Spec.DeepCopy(), + } + return NewIngress(i) + case IngressModeExtensions: + i := &v1beta1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: annotations, + }, + Spec: *ingress.legacyIngress.Spec.DeepCopy(), + } + return NewLegacyIngress(i) + default: + return nil + } +} + func (i *Ingress) GetExtensionsIngress() (*v1beta1.Ingress, error) { if i.legacyIngress == nil { return nil, errors.New("extensions Ingress is nil in this wrapper") @@ -149,6 +176,117 @@ func (i *Ingress) SetAnnotations(annotations map[string]string) { } } +func (i *Ingress) CreateAnnotationBasedPath(actionName string) { + i.mux.Lock() + defer i.mux.Unlock() + if HasRuleWithService(i, actionName) { + return + } + switch i.mode { + case IngressModeNetworking: + t := v1.PathTypeImplementationSpecific + p := v1.HTTPIngressPath{ + Path: "/*", + PathType: &t, + Backend: v1.IngressBackend{ + Service: &v1.IngressServiceBackend{ + Name: actionName, + Port: v1.ServiceBackendPort{ + Name: "use-annotation", + }, + }, + }, + } + for _, rule := range i.ingress.Spec.Rules { + rule.HTTP.Paths = append(rule.HTTP.Paths[:1], rule.HTTP.Paths[0:]...) + rule.HTTP.Paths[0] = p + } + case IngressModeExtensions: + t := v1beta1.PathTypeImplementationSpecific + p := v1beta1.HTTPIngressPath{ + Path: "/*", + PathType: &t, + Backend: v1beta1.IngressBackend{ + ServiceName: actionName, + ServicePort: intstr.FromString("use-annotation"), + }, + } + for _, rule := range i.legacyIngress.Spec.Rules { + rule.HTTP.Paths = append(rule.HTTP.Paths[:1], rule.HTTP.Paths[0:]...) + rule.HTTP.Paths[0] = p + } + } +} + +func (i *Ingress) RemovePathByServiceName(actionName string) { + i.mux.Lock() + defer i.mux.Unlock() + switch i.mode { + case IngressModeNetworking: + for _, rule := range i.ingress.Spec.Rules { + if j := indexPathByService(rule, actionName); j != -1 { + rule.HTTP.Paths = append(rule.HTTP.Paths[:j], rule.HTTP.Paths[j+1:]...) + } + } + case IngressModeExtensions: + for _, rule := range i.legacyIngress.Spec.Rules { + if j := indexLegacyPathByService(rule, actionName); j != -1 { + rule.HTTP.Paths = append(rule.HTTP.Paths[:j], rule.HTTP.Paths[j+1:]...) + } + } + } +} + +func (i *Ingress) SortHttpPaths(routes []v1alpha1.MangedRoutes) { + var routeWeight = make(map[string]int) // map of route name for ordering + for j, route := range routes { + routeWeight[route.Name] = j + } + + i.mux.Lock() + defer i.mux.Unlock() + switch i.mode { + case IngressModeNetworking: + for _, rule := range i.ingress.Spec.Rules { + sort.SliceStable(rule.HTTP.Paths, func(i, j int) bool { + return getKeyWeight(routeWeight, rule.HTTP.Paths[i].Backend.Service.Name) < getKeyWeight(routeWeight, rule.HTTP.Paths[j].Backend.Service.Name) + }) + } + case IngressModeExtensions: + for _, rule := range i.legacyIngress.Spec.Rules { + sort.SliceStable(rule.HTTP.Paths, func(i, j int) bool { + return getKeyWeight(routeWeight, rule.HTTP.Paths[i].Backend.ServiceName) < getKeyWeight(routeWeight, rule.HTTP.Paths[j].Backend.ServiceName) + }) + } + } +} + +func getKeyWeight(weight map[string]int, key string) int { + if val, ok := weight[key]; ok { + return val + } else { + return len(weight) + } +} + +func indexPathByService(rule v1.IngressRule, name string) int { + for i, path := range rule.HTTP.Paths { + if path.Backend.Service.Name == name { + return i + } + } + return -1 +} + +func indexLegacyPathByService(rule v1beta1.IngressRule, name string) int { + for i, path := range rule.HTTP.Paths { + if path.Backend.ServiceName == name { + return i + } + } + return -1 +} + func (i *Ingress) DeepCopy() *Ingress { switch i.mode { case IngressModeNetworking: diff --git a/utils/ingress/wrapper_test.go b/utils/ingress/wrapper_test.go index 8611dcd395..9e8f511494 100644 --- a/utils/ingress/wrapper_test.go +++ b/utils/ingress/wrapper_test.go @@ -4,7 +4,6 @@ import ( "context" "testing" - "github.com/argoproj/argo-rollouts/utils/ingress" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" "k8s.io/api/extensions/v1beta1" @@ -14,6 +13,10 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" kubeinformers "k8s.io/client-go/informers" k8sfake "k8s.io/client-go/kubernetes/fake" + "k8s.io/utils/pointer" + + "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + "github.com/argoproj/argo-rollouts/utils/ingress" ) func TestNewIngressWithAnnotations(t *testing.T) { @@ -68,6 +71,57 @@ func TestNewIngressWithAnnotations(t *testing.T) { }) } +func TestNewIngressWithSpecAndAnnotations(t *testing.T) { + annotations := make(map[string]string) + annotations["some.annotation.key1"] = "some.annotation.value1" + annotations["some.annotation.key2"] = "some.annotation.value2" + getAnnotations := func() map[string]string { + annotations := make(map[string]string) + annotations["some.annotation.key1"] = "some.annotation.value1" + annotations["some.annotation.key2"] = "some.annotation.value2" + return annotations + } + t.Run("will instantiate an Ingress wrapped with an annotated networkingv1.Ingress", func(t *testing.T) { + ing := networkingIngress() + + // given + t.Parallel() + + // when + i := ingress.NewIngressWithSpecAndAnnotations(ing, getAnnotations()) + + // then + assert.NotNil(t, i) + a := i.GetAnnotations() + assert.Equal(t, 2, len(a)) + a["extra-annotation-key"] = "extra-annotation-value" + i.SetAnnotations(a) + assert.Equal(t, 3, len(a)) + actualIngress, _ := i.GetNetworkingIngress() + expectedIngress, _ := ing.GetNetworkingIngress() + assert.Equal(t, expectedIngress.Spec, actualIngress.Spec) + }) + t.Run("will instantiate an Ingress wrapped with an annotated extensions/v1beta1.Ingress", func(t *testing.T) { + ing := extensionsIngress() + // given + t.Parallel() + + // when + i := ingress.NewIngressWithSpecAndAnnotations(ing, getAnnotations()) + + // then + assert.NotNil(t, i) + a := i.GetAnnotations() + assert.Equal(t, 2, len(a)) + a["extra-annotation-key"] = "extra-annotation-value" + i.SetAnnotations(a) + assert.Equal(t, 3, len(a)) + actualIngress, _ := i.GetExtensionsIngress() + expectedIngress, _ := ing.GetExtensionsIngress() + assert.Equal(t, expectedIngress.Spec, actualIngress.Spec) + }) +} + func TestGetExtensionsIngress(t *testing.T) { extensionsIngress := &v1beta1.Ingress{} t.Run("will get extensions ingress successfully", func(t *testing.T) { @@ -275,6 +329,100 @@ func TestGetObjectMeta(t *testing.T) { }) } +func TestCreateAnnotationBasedPath(t *testing.T) { + t.Run("v1 ingress, create path", func(t *testing.T) { + ing := networkingIngress() + ni, _ := ing.GetNetworkingIngress() + + assert.Equal(t, 1, len(ni.Spec.Rules[0].HTTP.Paths)) + ing.CreateAnnotationBasedPath("test-route") + assert.Equal(t, 2, len(ni.Spec.Rules[0].HTTP.Paths)) + }) + t.Run("v1 ingress, create existing path", func(t *testing.T) { + ing := networkingIngress() + ni, _ := ing.GetNetworkingIngress() + + ing.CreateAnnotationBasedPath("v1backend") + assert.Equal(t, 1, len(ni.Spec.Rules[0].HTTP.Paths)) + }) + t.Run("v1beta1 ingress, create path", func(t *testing.T) { + ing := extensionsIngress() + ni, _ := ing.GetExtensionsIngress() + + assert.Equal(t, 1, len(ni.Spec.Rules[0].HTTP.Paths)) + ing.CreateAnnotationBasedPath("test-route") + assert.Equal(t, 2, len(ni.Spec.Rules[0].HTTP.Paths)) + }) + t.Run("v1beta1 ingress, create existing path", func(t *testing.T) { + ing := extensionsIngress() + ni, _ := ing.GetExtensionsIngress() + + ing.CreateAnnotationBasedPath("v1beta1backend") + assert.Equal(t, 1, len(ni.Spec.Rules[0].HTTP.Paths)) + }) +} + +func TestRemoveAnnotationBasedPath(t *testing.T) { + t.Run("v1 ingress, remove path", func(t *testing.T) { + ing := networkingIngress() + ni, _ := ing.GetNetworkingIngress() + + assert.Equal(t, 1, len(ni.Spec.Rules[0].HTTP.Paths)) + ing.RemovePathByServiceName("v1backend") + assert.Equal(t, 0, len(ni.Spec.Rules[0].HTTP.Paths)) + }) + t.Run("v1 ingress, remove non existing path", func(t *testing.T) { + ing := networkingIngress() + ni, _ := ing.GetNetworkingIngress() + + assert.Equal(t, 1, len(ni.Spec.Rules[0].HTTP.Paths)) + ing.RemovePathByServiceName("non-exsisting-route") + assert.Equal(t, 1, len(ni.Spec.Rules[0].HTTP.Paths)) + }) + t.Run("v1beta1 ingress, remove path", func(t *testing.T) { + ing := extensionsIngress() + ni, _ := ing.GetExtensionsIngress() + + assert.Equal(t, 1, len(ni.Spec.Rules[0].HTTP.Paths)) + ing.RemovePathByServiceName("v1beta1backend") + assert.Equal(t, 0, len(ni.Spec.Rules[0].HTTP.Paths)) + }) + t.Run("v1beta1 ingress, remove non existing path", func(t *testing.T) { + ing := extensionsIngress() + ni, _ := ing.GetExtensionsIngress() + + assert.Equal(t, 1, len(ni.Spec.Rules[0].HTTP.Paths)) + ing.RemovePathByServiceName("non-exsisting-route") + assert.Equal(t, 1, len(ni.Spec.Rules[0].HTTP.Paths)) + }) +} + +func TestSortHttpPaths(t *testing.T) { + managedRoutes := []v1alpha1.MangedRoutes{{Name: "route1"}, {Name: "route2"}, {Name: "route3"}} + t.Run("v1 ingress, sort path", func(t *testing.T) { + ing := networkingIngressWithPath("action1", "route3", "route1", "route2") + ing.SortHttpPaths(managedRoutes) + ni, _ := ing.GetNetworkingIngress() + + assert.Equal(t, 4, len(ni.Spec.Rules[0].HTTP.Paths)) + assert.Equal(t, "route1", ni.Spec.Rules[0].HTTP.Paths[0].Backend.Service.Name) + assert.Equal(t, "route2", ni.Spec.Rules[0].HTTP.Paths[1].Backend.Service.Name) + assert.Equal(t, "route3", ni.Spec.Rules[0].HTTP.Paths[2].Backend.Service.Name) + assert.Equal(t, "action1", ni.Spec.Rules[0].HTTP.Paths[3].Backend.Service.Name) + }) + t.Run("v1beta1 ingress, sort path", func(t *testing.T) { + ing := extensionsIngressWithPath("action1", "route3", "route1", "route2") + ing.SortHttpPaths(managedRoutes) + ni, _ := ing.GetExtensionsIngress() + + assert.Equal(t, 4, len(ni.Spec.Rules[0].HTTP.Paths)) + assert.Equal(t, "route1", ni.Spec.Rules[0].HTTP.Paths[0].Backend.ServiceName) + assert.Equal(t, "route2", ni.Spec.Rules[0].HTTP.Paths[1].Backend.ServiceName) + assert.Equal(t, "route3", ni.Spec.Rules[0].HTTP.Paths[2].Backend.ServiceName) + assert.Equal(t, "action1", ni.Spec.Rules[0].HTTP.Paths[3].Backend.ServiceName) + }) +} + func TestDeepCopy(t *testing.T) { t.Run("will deepcopy ingress wrapped with networking.Ingress", func(t *testing.T) { // given @@ -823,3 +971,135 @@ func getExtensionsIngress() *v1beta1.Ingress { }, } } + +func networkingIngress() *ingress.Ingress { + pathType := v1.PathTypeImplementationSpecific + res := v1.Ingress{ + Spec: v1.IngressSpec{ + IngressClassName: pointer.String("v1ingress"), + Rules: []v1.IngressRule{ + { + Host: "v1host", + IngressRuleValue: v1.IngressRuleValue{ + HTTP: &v1.HTTPIngressRuleValue{ + Paths: []v1.HTTPIngressPath{ + { + Backend: v1.IngressBackend{ + Service: &v1.IngressServiceBackend{ + Name: "v1backend", + Port: v1.ServiceBackendPort{Name: "use-annotation"}, + }, + }, + Path: "/*", + PathType: &pathType, + }, + }, + }, + }, + }, + }, + }, + } + return ingress.NewIngress(&res) +} + +func networkingIngressWithPath(paths ...string) *ingress.Ingress { + var ingressPaths []v1.HTTPIngressPath + for _, path := range paths { + ingressPaths = append(ingressPaths, v1IngressPath(path)) + } + res := v1.Ingress{ + Spec: v1.IngressSpec{ + IngressClassName: pointer.String("v1ingress"), + Rules: []v1.IngressRule{ + { + Host: "v1host", + IngressRuleValue: v1.IngressRuleValue{ + HTTP: &v1.HTTPIngressRuleValue{ + Paths: ingressPaths, + }, + }, + }, + }, + }, + } + return ingress.NewIngress(&res) +} + +func v1IngressPath(serviceName string) v1.HTTPIngressPath { + pathType := v1.PathTypeImplementationSpecific + return v1.HTTPIngressPath{ + Backend: v1.IngressBackend{ + Service: &v1.IngressServiceBackend{ + Name: serviceName, + Port: v1.ServiceBackendPort{Name: "use-annotation"}, + }, + }, + Path: "/*", + PathType: &pathType, + } +} + +func extensionsIngress() *ingress.Ingress { + pathType := v1beta1.PathTypeImplementationSpecific + res := v1beta1.Ingress{ + Spec: v1beta1.IngressSpec{ + IngressClassName: pointer.String("v1beta1ingress"), + Rules: []v1beta1.IngressRule{ + { + Host: "v1beta1host", + IngressRuleValue: v1beta1.IngressRuleValue{ + HTTP: &v1beta1.HTTPIngressRuleValue{ + Paths: []v1beta1.HTTPIngressPath{ + { + Backend: v1beta1.IngressBackend{ + ServiceName: "v1beta1backend", + ServicePort: intstr.FromString("use-annotation"), + }, + Path: "/*", + PathType: &pathType, + }, + }, + }, + }, + }, + }, + }, + } + return ingress.NewLegacyIngress(&res) +} + +func extensionsIngressWithPath(paths ...string) *ingress.Ingress { + var ingressPaths []v1beta1.HTTPIngressPath + for _, path := range paths { + ingressPaths = append(ingressPaths, extensionIngressPath(path)) + } + res := v1beta1.Ingress{ + Spec: v1beta1.IngressSpec{ + IngressClassName: pointer.String("v1beta1ingress"), + Rules: []v1beta1.IngressRule{ + { + Host: "v1beta1host", + IngressRuleValue: v1beta1.IngressRuleValue{ + HTTP: &v1beta1.HTTPIngressRuleValue{ + Paths: ingressPaths, + }, + }, + }, + }, + }, + } + return ingress.NewLegacyIngress(&res) +} + +func extensionIngressPath(serviceName string) v1beta1.HTTPIngressPath { + pathType := v1beta1.PathTypeImplementationSpecific + return v1beta1.HTTPIngressPath{ + Backend: v1beta1.IngressBackend{ + ServiceName: serviceName, + ServicePort: intstr.FromString("use-annotation"), + }, + Path: "/*", + PathType: &pathType, + } +}