From 637354b2594e3898fb5e636f9ee466b8b9d98760 Mon Sep 17 00:00:00 2001 From: Ariel Simhon Date: Tue, 11 Oct 2022 09:42:02 +0300 Subject: [PATCH 01/68] docs: Added blog post for minimize impact in Kubernetes using Progressive Delivery and customer side impact --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f044877ab3..ff667c3f64 100644 --- a/README.md +++ b/README.md @@ -72,5 +72,5 @@ You can reach the Argo Rollouts community and developers via the following chann * [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) - +* [Minimize Impact in Kubernetes Using Argo Rollouts](https://medium.com/@arielsimhon/minimize-impact-in-kubernetes-using-argo-rollouts-992fb9519969) From f6864c19f8996deac84d566197d48f20fa7bc7c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Oct 2022 00:49:57 +0000 Subject: [PATCH 02/68] chore(deps): bump github.com/newrelic/newrelic-client-go (#2267) Bumps [github.com/newrelic/newrelic-client-go](https://github.com/newrelic/newrelic-client-go) from 0.86.5 to 1.0.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.86.5...v1.0.0) --- updated-dependencies: - dependency-name: github.com/newrelic/newrelic-client-go dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b1b6a8d17e..9218c15c19 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/influxdata/influxdb-client-go/v2 v2.11.0 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/newrelic/newrelic-client-go v1.0.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.12.2-0.20220620141757-4ad265f1b4ee github.com/prometheus/client_model v0.2.0 diff --git a/go.sum b/go.sum index 18fd48f4a8..5441629136 100644 --- a/go.sum +++ b/go.sum @@ -804,8 +804,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.86.5 h1:RxjhA/xdjcnMTxl1oq+ms6tGTuZOOL+h8IcfBCD1PVY= -github.com/newrelic/newrelic-client-go v0.86.5/go.mod h1:RYMXt7hgYw7nzuXIGd2BH0F1AivgWw7WrBhNBQZEB4k= +github.com/newrelic/newrelic-client-go v1.0.0 h1:0ugZUujCiJg3WGDxnmOT1QRP2gDiZKIMN0Z04SvxVBc= +github.com/newrelic/newrelic-client-go v1.0.0/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/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= From ae8120ecf6f0dd674e5b3e4f4af637ea4a5b4c37 Mon Sep 17 00:00:00 2001 From: Ariel Simhon Date: Tue, 11 Oct 2022 09:42:02 +0300 Subject: [PATCH 03/68] docs: Added blog post for minimize impact in Kubernetes using Progressive Delivery and customer side impact Signed-off-by: Ariel Simhon --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f044877ab3..ff667c3f64 100644 --- a/README.md +++ b/README.md @@ -72,5 +72,5 @@ You can reach the Argo Rollouts community and developers via the following chann * [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) - +* [Minimize Impact in Kubernetes Using Argo Rollouts](https://medium.com/@arielsimhon/minimize-impact-in-kubernetes-using-argo-rollouts-992fb9519969) From 53cc7fe059c32c50738e3e86484cccdb0cc3a680 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Oct 2022 00:11:21 +0000 Subject: [PATCH 04/68] chore(deps): bump docker/build-push-action from 2 to 3 (#2306) Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 2 to 3. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v2...v3) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- .github/workflows/release.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 6786339c54..7bb0c1dfb5 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -76,7 +76,7 @@ jobs: password: ${{ secrets.QUAY_ROBOT_TOKEN }} - name: Build and push (controller-image) - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v3 with: context: . platforms: linux/amd64,linux/arm64 @@ -84,7 +84,7 @@ jobs: 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: context: . target: kubectl-argo-rollouts From e286cd0601d91d0d6a263c820876f3049379cf8f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Oct 2022 00:11:58 +0000 Subject: [PATCH 05/68] chore(deps): bump github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 (#2307) Bumps [github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2](https://github.com/aws/aws-sdk-go-v2) from 1.18.19 to 1.18.20. - [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/service/ecs/v1.18.19...service/ecs/v1.18.20) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 208ba4d61e..b1b6a8d17e 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/aws/aws-sdk-go-v2 v1.16.16 github.com/aws/aws-sdk-go-v2/config v1.17.8 github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.21.6 - github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.18.19 + github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.18.20 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 8b0b0affe0..18fd48f4a8 100644 --- a/go.sum +++ b/go.sum @@ -168,8 +168,8 @@ github.com/aws/aws-sdk-go-v2/internal/ini v1.3.24 h1:wj5Rwc05hvUSvKuOF29IYb9QrCL github.com/aws/aws-sdk-go-v2/internal/ini v1.3.24/go.mod h1:jULHjqqjDlbyTa7pfM7WICATnOv+iOhjletM3N0Xbu8= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.21.6 h1:Mwb2A5ygEijjkxgM3hVEiWSHwdH82nkyU2wgP4u/Hxk= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.21.6/go.mod h1:CCrqOzLQ6d1+zauyTah8o50m9dQu0NS/kaC0heWCu0c= -github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.18.19 h1:vPyIPoJUCiyUOv2TeRGWdLqf14qUp8tuTQ6bJo6ykbY= -github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.18.19/go.mod h1:tAKN3/tWkL0P+WA44wSkNyk6wWcbHUfTV2F3j3o6Yhs= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.18.20 h1:dJngzOIJ6J8lVzsEiPQwB5nTL5UjwuYjiHflORBnobE= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.18.20/go.mod h1:tAKN3/tWkL0P+WA44wSkNyk6wWcbHUfTV2F3j3o6Yhs= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17 h1:Jrd/oMh0PKQc6+BowB+pLEwLIgaQF29eYbe7E1Av9Ug= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17/go.mod h1:4nYOrY41Lrbk2170/BGkcJKBhws9Pfn8MG3aGqjjeFI= github.com/aws/aws-sdk-go-v2/service/sso v1.11.23 h1:pwvCchFUEnlceKIgPUouBJwK81aCkQ8UDMORfeFtW10= From 5b5c64706fa2aa5969f097ef0c3a7b2f00f40c1f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Oct 2022 00:49:57 +0000 Subject: [PATCH 06/68] chore(deps): bump github.com/newrelic/newrelic-client-go (#2267) Bumps [github.com/newrelic/newrelic-client-go](https://github.com/newrelic/newrelic-client-go) from 0.86.5 to 1.0.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.86.5...v1.0.0) --- updated-dependencies: - dependency-name: github.com/newrelic/newrelic-client-go dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b1b6a8d17e..9218c15c19 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/influxdata/influxdb-client-go/v2 v2.11.0 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/newrelic/newrelic-client-go v1.0.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.12.2-0.20220620141757-4ad265f1b4ee github.com/prometheus/client_model v0.2.0 diff --git a/go.sum b/go.sum index 18fd48f4a8..5441629136 100644 --- a/go.sum +++ b/go.sum @@ -804,8 +804,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.86.5 h1:RxjhA/xdjcnMTxl1oq+ms6tGTuZOOL+h8IcfBCD1PVY= -github.com/newrelic/newrelic-client-go v0.86.5/go.mod h1:RYMXt7hgYw7nzuXIGd2BH0F1AivgWw7WrBhNBQZEB4k= +github.com/newrelic/newrelic-client-go v1.0.0 h1:0ugZUujCiJg3WGDxnmOT1QRP2gDiZKIMN0Z04SvxVBc= +github.com/newrelic/newrelic-client-go v1.0.0/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/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= From ab4f1b4046b96d7d1c7194f6d7c1c8f1bd56c102 Mon Sep 17 00:00:00 2001 From: Ariel Simhon Date: Tue, 11 Oct 2022 09:42:02 +0300 Subject: [PATCH 07/68] docs: Added blog post for minimize impact in Kubernetes using Progressive Delivery and customer side impact Signed-off-by: Ariel Simhon --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f044877ab3..ff667c3f64 100644 --- a/README.md +++ b/README.md @@ -72,5 +72,5 @@ You can reach the Argo Rollouts community and developers via the following chann * [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) - +* [Minimize Impact in Kubernetes Using Argo Rollouts](https://medium.com/@arielsimhon/minimize-impact-in-kubernetes-using-argo-rollouts-992fb9519969) From 38242a37fe064b4f5947f4a0ded79864c5728a35 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Oct 2022 00:07:33 +0000 Subject: [PATCH 08/68] chore(deps): bump github.com/spf13/cobra from 1.5.0 to 1.6.0 (#2313) Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.5.0 to 1.6.0. - [Release notes](https://github.com/spf13/cobra/releases) - [Commits](https://github.com/spf13/cobra/compare/v1.5.0...v1.6.0) --- updated-dependencies: - dependency-name: github.com/spf13/cobra dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 4 ++-- go.sum | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 9218c15c19..0e2c381e5d 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ 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.5.0 + github.com/spf13/cobra v1.6.0 github.com/stretchr/testify v1.8.0 github.com/tj/assert v0.0.3 github.com/valyala/fasttemplate v1.2.1 @@ -113,7 +113,7 @@ require ( github.com/hashicorp/go-retryablehttp v0.7.1 // indirect github.com/huandu/xstrings v1.3.2 // indirect github.com/imdario/mergo v0.3.13 // indirect - github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.0.1 // 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 diff --git a/go.sum b/go.sum index 5441629136..4a5038baba 100644 --- a/go.sum +++ b/go.sum @@ -626,8 +626,9 @@ github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= 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/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/influxdb-client-go/v2 v2.11.0 h1:BrHYv38rWkAnp22gIaHFp5LpOCazOqRMRvVE1yW3ym8= github.com/influxdata/influxdb-client-go/v2 v2.11.0/go.mod h1:YteV91FiQxRdccyJ2cHvj2f/5sq4y4Njqu1fQzsQCOU= github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf h1:7JTmneyiNEwVBOHSjoMxiWAqB992atOeepeFYegn5RU= @@ -962,8 +963,9 @@ github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSW github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= 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/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI= +github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= 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= From 57356a53d068a28b6045b42b8e7157884bf486db Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Oct 2022 00:08:58 +0000 Subject: [PATCH 09/68] chore(deps): bump github.com/sirupsen/logrus from 1.8.1 to 1.9.0 (#2152) Bumps [github.com/sirupsen/logrus](https://github.com/sirupsen/logrus) from 1.8.1 to 1.9.0. - [Release notes](https://github.com/sirupsen/logrus/releases) - [Changelog](https://github.com/sirupsen/logrus/blob/master/CHANGELOG.md) - [Commits](https://github.com/sirupsen/logrus/compare/v1.8.1...v1.9.0) --- updated-dependencies: - dependency-name: github.com/sirupsen/logrus dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 4 ++-- go.sum | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 0e2c381e5d..3dcb8bfc32 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/prometheus/client_model v0.2.0 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/sirupsen/logrus v1.9.0 github.com/soheilhy/cmux v0.1.5 github.com/spaceapegames/go-wavefront v1.8.1 github.com/spf13/cobra v1.6.0 @@ -153,7 +153,7 @@ require ( golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // 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/sys v0.0.0-20220715151400-c0bba94af5f8 // 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 diff --git a/go.sum b/go.sum index 4a5038baba..0e90808809 100644 --- a/go.sum +++ b/go.sum @@ -933,8 +933,9 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB 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/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/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 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= @@ -1365,8 +1366,9 @@ 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-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/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= From 5dd3a03460ec67ac0b7e645eb48bb4ef2be27e76 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Oct 2022 00:10:19 +0000 Subject: [PATCH 10/68] chore(deps): bump github.com/prometheus/common from 0.36.0 to 0.37.0 (#2143) Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.36.0 to 0.37.0. - [Release notes](https://github.com/prometheus/common/releases) - [Commits](https://github.com/prometheus/common/compare/v0.36.0...v0.37.0) --- updated-dependencies: - dependency-name: github.com/prometheus/common dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 3dcb8bfc32..571aa6141e 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/pkg/errors v0.9.1 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/prometheus/common v0.37.0 github.com/servicemeshinterface/smi-sdk-go v0.5.0 github.com/sirupsen/logrus v1.9.0 github.com/soheilhy/cmux v0.1.5 diff --git a/go.sum b/go.sum index 0e90808809..49fe128eb1 100644 --- a/go.sum +++ b/go.sum @@ -887,8 +887,8 @@ 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.36.0 h1:78hJTing+BLYLjhXE+Z2BubeEymH5Lr0/Mt8FKkxxYo= -github.com/prometheus/common v0.36.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= +github.com/prometheus/common v0.37.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= From 27e926d88cddf3ad4698f2c528c87d65b0f39083 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Thu, 13 Oct 2022 09:31:54 -0500 Subject: [PATCH 11/68] fix(controller): leader election preventing two controllers running and gracefully shutting down (#2291) * WIP on fixing leader election fix Signed-off-by: zachaller * Start and stop informers as well Signed-off-by: zachaller * lint Signed-off-by: zachaller * Remove tests that do not test anything Signed-off-by: zachaller * fix lint Signed-off-by: zachaller * github trigger re-run Signed-off-by: zachaller * Cleanup Signed-off-by: zachaller * cleanup Signed-off-by: zachaller * Add back one test Signed-off-by: zachaller * remove secondary metric server Signed-off-by: zachaller * Remove secondary metric test Signed-off-by: zachaller * Add single instance test to catch log lines Signed-off-by: zachaller * We should shutdown if we can not sync Signed-off-by: zachaller * fix lint Signed-off-by: zachaller * Redo for loop will have another pr that stops via context Signed-off-by: zachaller * Fix comment Signed-off-by: zachaller * Add context and graceful shutdown Signed-off-by: zachaller * lint Signed-off-by: zachaller * Fix test Signed-off-by: zachaller * github trigger re-run Signed-off-by: zachaller * add more time for startup Signed-off-by: zachaller * add individual controller startup tests Signed-off-by: zachaller * standardize shutdown Signed-off-by: zachaller * Standardize leader test Signed-off-by: zachaller * fix test Signed-off-by: zachaller * We can not turn on release on cancel Signed-off-by: zachaller * fix release on cancel Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- analysis/controller.go | 19 +- analysis/controller_test.go | 21 +- cmd/rollouts-controller/main.go | 27 +- controller/controller.go | 231 ++++++++++-------- controller/controller_test.go | 185 ++++---------- controller/metrics/analysis_test.go | 2 +- controller/metrics/client_test.go | 2 +- controller/metrics/experiment_test.go | 2 +- controller/metrics/metrics.go | 15 +- controller/metrics/metrics_test.go | 13 +- controller/metrics/rollout_test.go | 4 +- experiments/controller.go | 18 +- experiments/controller_test.go | 20 +- ingress/alb_test.go | 15 +- ingress/ingress.go | 18 +- ingress/ingress_test.go | 25 +- pkg/signals/signal.go | 13 +- rollout/controller.go | 27 +- rollout/controller_test.go | 27 +- rollout/trafficrouting/istio/controller.go | 31 ++- .../trafficrouting/istio/controller_test.go | 11 +- service/service.go | 19 +- service/service_test.go | 29 ++- utils/controller/controller.go | 8 +- utils/controller/controller_test.go | 29 +-- 25 files changed, 431 insertions(+), 380 deletions(-) diff --git a/analysis/controller.go b/analysis/controller.go index 285cd1ff13..f05c955bb1 100644 --- a/analysis/controller.go +++ b/analysis/controller.go @@ -1,6 +1,8 @@ package analysis import ( + "context" + "sync" "time" unstructuredutil "github.com/argoproj/argo-rollouts/utils/unstructured" @@ -131,21 +133,26 @@ func NewController(cfg ControllerConfig) *Controller { return controller } -func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error { +func (c *Controller) Run(ctx context.Context, threadiness int) error { log.Info("Starting analysis workers") + wg := sync.WaitGroup{} for i := 0; i < threadiness; i++ { + wg.Add(1) go wait.Until(func() { - controllerutil.RunWorker(c.analysisRunWorkQueue, logutil.AnalysisRunKey, c.syncHandler, c.metricsServer) - }, time.Second, stopCh) + controllerutil.RunWorker(ctx, c.analysisRunWorkQueue, logutil.AnalysisRunKey, c.syncHandler, c.metricsServer) + log.Debug("Analysis worker has stopped") + wg.Done() + }, time.Second, ctx.Done()) } log.Infof("Started %d analysis workers", threadiness) - <-stopCh - log.Info("Shutting down analysis workers") + <-ctx.Done() + wg.Wait() + log.Info("All analysis workers have stopped") return nil } -func (c *Controller) syncHandler(key string) error { +func (c *Controller) syncHandler(ctx context.Context, key string) error { startTime := timeutil.Now() namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { diff --git a/analysis/controller_test.go b/analysis/controller_test.go index 289992ad19..a0af638c9e 100644 --- a/analysis/controller_test.go +++ b/analysis/controller_test.go @@ -1,6 +1,7 @@ package analysis import ( + "context" "encoding/json" "reflect" "testing" @@ -97,7 +98,7 @@ func (f *fixture) newController(resync resyncFunc) (*Controller, informers.Share metricsServer := metrics.NewMetricsServer(metrics.ServerConfig{ Addr: "localhost:8080", K8SRequestProvider: &metrics.K8sRequestsCountProvider{}, - }, true) + }) c := NewController(ControllerConfig{ KubeClientSet: f.kubeclient, @@ -159,7 +160,7 @@ func (f *fixture) runController(analysisRunName string, startInformers bool, exp assert.True(f.t, cache.WaitForCacheSync(stopCh, c.analysisRunSynced)) } - err := c.syncHandler(analysisRunName) + err := c.syncHandler(context.Background(), analysisRunName) if !expectError && err != nil { f.t.Errorf("error syncing experiment: %v", err) } else if expectError && err == nil { @@ -314,3 +315,19 @@ func TestNoReconcileForAnalysisRunWithDeletionTimestamp(t *testing.T) { f.run(getKey(ar, t)) } + +func TestRun(t *testing.T) { + f := newFixture(t) + defer f.Close() + + // make sure we can start and top the controller + c, _, _ := f.newController(noResyncPeriodFunc) + ctx, cancel := context.WithCancel(context.TODO()) + defer cancel() + go func() { + time.Sleep(1000 * time.Millisecond) + c.analysisRunWorkQueue.ShutDownWithDrain() + cancel() + }() + c.Run(ctx, 1) +} diff --git a/cmd/rollouts-controller/main.go b/cmd/rollouts-controller/main.go index f669a7115f..4aadf9ad82 100644 --- a/cmd/rollouts-controller/main.go +++ b/cmd/rollouts-controller/main.go @@ -88,7 +88,7 @@ func newCommand() *cobra.Command { log.WithField("version", version.GetVersion()).Info("Argo Rollouts starting") // set up signals so we handle the first shutdown signal gracefully - stopCh := signals.SetupSignalHandler() + ctx := signals.SetupSignalHandlerContext() defaults.SetVerifyTargetGroup(awsVerifyTargetGroup) defaults.SetIstioAPIVersion(istioVersion) @@ -190,23 +190,16 @@ func newCommand() *cobra.Command { healthzPort, k8sRequestProvider, nginxIngressClasses, - albIngressClasses) - // notice that there is no need to run Start methods in a separate goroutine. (i.e. go kubeInformerFactory.Start(stopCh) - // Start method is non-blocking and runs all registered informers in a dedicated goroutine. - dynamicInformerFactory.Start(stopCh) - if !namespaced { - clusterDynamicInformerFactory.Start(stopCh) - } - kubeInformerFactory.Start(stopCh) - controllerNamespaceInformerFactory.Start(stopCh) - jobInformerFactory.Start(stopCh) - - // Check if Istio installed on cluster before starting dynamicInformerFactory - if istioutil.DoesIstioExist(istioPrimaryDynamicClient, namespace) { - istioDynamicInformerFactory.Start(stopCh) - } + albIngressClasses, + dynamicInformerFactory, + clusterDynamicInformerFactory, + istioDynamicInformerFactory, + namespaced, + kubeInformerFactory, + controllerNamespaceInformerFactory, + jobInformerFactory) - if err = cm.Run(rolloutThreads, serviceThreads, ingressThreads, experimentThreads, analysisThreads, electOpts, stopCh); err != nil { + if err = cm.Run(ctx, rolloutThreads, serviceThreads, ingressThreads, experimentThreads, analysisThreads, electOpts); err != nil { log.Fatalf("Error running controller: %s", err.Error()) } return nil diff --git a/controller/controller.go b/controller/controller.go index a0efcbe55f..55ef4a45f8 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -6,8 +6,15 @@ import ( "fmt" "net/http" "os" + "sync" "time" + "k8s.io/apimachinery/pkg/util/wait" + + istioutil "github.com/argoproj/argo-rollouts/utils/istio" + "k8s.io/client-go/dynamic/dynamicinformer" + kubeinformers "k8s.io/client-go/informers" + notificationapi "github.com/argoproj/notifications-engine/pkg/api" notificationcontroller "github.com/argoproj/notifications-engine/pkg/controller" @@ -18,7 +25,6 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/uuid" - "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/discovery" "k8s.io/client-go/dynamic" appsinformers "k8s.io/client-go/informers/apps/v1" @@ -108,8 +114,8 @@ func NewLeaderElectionOptions() *LeaderElectionOptions { // Manager is the controller implementation for Argo-Rollout resources type Manager struct { + wg *sync.WaitGroup metricsServer *metrics.MetricsServer - secondaryMetricsServer *metrics.MetricsServer healthzServer *http.Server rolloutController *rollout.Controller experimentController *experiments.Controller @@ -141,6 +147,15 @@ type Manager struct { kubeClientSet kubernetes.Interface namespace string + + dynamicInformerFactory dynamicinformer.DynamicSharedInformerFactory + clusterDynamicInformerFactory dynamicinformer.DynamicSharedInformerFactory + istioDynamicInformerFactory dynamicinformer.DynamicSharedInformerFactory + namespaced bool + kubeInformerFactory kubeinformers.SharedInformerFactory + controllerNamespaceInformerFactory kubeinformers.SharedInformerFactory + jobInformerFactory kubeinformers.SharedInformerFactory + istioPrimaryDynamicClient dynamic.Interface } // NewManager returns a new manager to manage all the controllers @@ -172,6 +187,13 @@ func NewManager( k8sRequestProvider *metrics.K8sRequestsCountProvider, nginxIngressClasses []string, albIngressClasses []string, + dynamicInformerFactory dynamicinformer.DynamicSharedInformerFactory, + clusterDynamicInformerFactory dynamicinformer.DynamicSharedInformerFactory, + istioDynamicInformerFactory dynamicinformer.DynamicSharedInformerFactory, + namespaced bool, + kubeInformerFactory kubeinformers.SharedInformerFactory, + controllerNamespaceInformerFactory kubeinformers.SharedInformerFactory, + jobInformerFactory kubeinformers.SharedInformerFactory, ) *Manager { runtime.Must(rolloutscheme.AddToScheme(scheme.Scheme)) @@ -186,10 +208,9 @@ func NewManager( ClusterAnalysisTemplateLister: clusterAnalysisTemplateInformer.Lister(), ExperimentLister: experimentsInformer.Lister(), K8SRequestProvider: k8sRequestProvider, - }, true) + }) healthzServer := NewHealthzServer(fmt.Sprintf(listenAddr, healthzPort)) - rolloutWorkqueue := workqueue.NewNamedRateLimitingQueue(queue.DefaultArgoRolloutsRateLimiter(), "Rollouts") experimentWorkqueue := workqueue.NewNamedRateLimitingQueue(queue.DefaultArgoRolloutsRateLimiter(), "Experiments") analysisRunWorkqueue := workqueue.NewNamedRateLimitingQueue(queue.DefaultArgoRolloutsRateLimiter(), "AnalysisRuns") @@ -293,33 +314,42 @@ func NewManager( }) cm := &Manager{ - metricsServer: metricsServer, - healthzServer: healthzServer, - rolloutSynced: rolloutsInformer.Informer().HasSynced, - serviceSynced: servicesInformer.Informer().HasSynced, - ingressSynced: ingressWrap.HasSynced, - jobSynced: jobInformer.Informer().HasSynced, - experimentSynced: experimentsInformer.Informer().HasSynced, - analysisRunSynced: analysisRunInformer.Informer().HasSynced, - analysisTemplateSynced: analysisTemplateInformer.Informer().HasSynced, - clusterAnalysisTemplateSynced: clusterAnalysisTemplateInformer.Informer().HasSynced, - replicasSetSynced: replicaSetInformer.Informer().HasSynced, - configMapSynced: configMapInformer.Informer().HasSynced, - secretSynced: secretInformer.Informer().HasSynced, - rolloutWorkqueue: rolloutWorkqueue, - experimentWorkqueue: experimentWorkqueue, - analysisRunWorkqueue: analysisRunWorkqueue, - serviceWorkqueue: serviceWorkqueue, - ingressWorkqueue: ingressWorkqueue, - rolloutController: rolloutController, - serviceController: serviceController, - ingressController: ingressController, - experimentController: experimentController, - analysisController: analysisController, - notificationsController: notificationsController, - refResolver: refResolver, - namespace: namespace, - kubeClientSet: kubeclientset, + wg: &sync.WaitGroup{}, + metricsServer: metricsServer, + healthzServer: healthzServer, + rolloutSynced: rolloutsInformer.Informer().HasSynced, + serviceSynced: servicesInformer.Informer().HasSynced, + ingressSynced: ingressWrap.HasSynced, + jobSynced: jobInformer.Informer().HasSynced, + experimentSynced: experimentsInformer.Informer().HasSynced, + analysisRunSynced: analysisRunInformer.Informer().HasSynced, + analysisTemplateSynced: analysisTemplateInformer.Informer().HasSynced, + clusterAnalysisTemplateSynced: clusterAnalysisTemplateInformer.Informer().HasSynced, + replicasSetSynced: replicaSetInformer.Informer().HasSynced, + configMapSynced: configMapInformer.Informer().HasSynced, + secretSynced: secretInformer.Informer().HasSynced, + rolloutWorkqueue: rolloutWorkqueue, + experimentWorkqueue: experimentWorkqueue, + analysisRunWorkqueue: analysisRunWorkqueue, + serviceWorkqueue: serviceWorkqueue, + ingressWorkqueue: ingressWorkqueue, + rolloutController: rolloutController, + serviceController: serviceController, + ingressController: ingressController, + experimentController: experimentController, + analysisController: analysisController, + notificationsController: notificationsController, + refResolver: refResolver, + namespace: namespace, + kubeClientSet: kubeclientset, + dynamicInformerFactory: dynamicInformerFactory, + clusterDynamicInformerFactory: clusterDynamicInformerFactory, + istioDynamicInformerFactory: istioDynamicInformerFactory, + namespaced: namespaced, + kubeInformerFactory: kubeInformerFactory, + controllerNamespaceInformerFactory: controllerNamespaceInformerFactory, + jobInformerFactory: jobInformerFactory, + istioPrimaryDynamicClient: istioPrimaryDynamicClient, } return cm @@ -328,32 +358,32 @@ func NewManager( // Run will sync informer caches and start controllers. It will block until stopCh // is closed, at which point it will shutdown the workqueue and wait for // controllers to finish processing their current work items. -func (c *Manager) Run(rolloutThreadiness, serviceThreadiness, ingressThreadiness, experimentThreadiness, analysisThreadiness int, electOpts *LeaderElectionOptions, stopCh <-chan struct{}) error { +func (c *Manager) Run(ctx context.Context, rolloutThreadiness, serviceThreadiness, ingressThreadiness, experimentThreadiness, analysisThreadiness int, electOpts *LeaderElectionOptions) error { defer runtime.HandleCrash() - defer c.serviceWorkqueue.ShutDown() - defer c.ingressWorkqueue.ShutDown() - defer c.rolloutWorkqueue.ShutDown() - defer c.experimentWorkqueue.ShutDown() - defer c.analysisRunWorkqueue.ShutDown() + defer func() { + log.Infof("Exiting Main Run function") + }() - // Wait for the caches to be synced before starting workers - log.Info("Waiting for controller's informer caches to sync") - if ok := cache.WaitForCacheSync(stopCh, c.serviceSynced, c.ingressSynced, c.jobSynced, c.rolloutSynced, c.experimentSynced, c.analysisRunSynced, c.analysisTemplateSynced, c.replicasSetSynced, c.configMapSynced, c.secretSynced); !ok { - return fmt.Errorf("failed to wait for caches to sync") - } - // only wait for cluster scoped informers to sync if we are running in cluster-wide mode - if c.namespace == metav1.NamespaceAll { - if ok := cache.WaitForCacheSync(stopCh, c.clusterAnalysisTemplateSynced); !ok { - return fmt.Errorf("failed to wait for cluster-scoped caches to sync") + go func() { + log.Infof("Starting Healthz Server at %s", c.healthzServer.Addr) + err := c.healthzServer.ListenAndServe() + if err != nil { + err = errors.Wrap(err, "Healthz Server Error") + log.Error(err) } - } + }() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + go func() { + log.Infof("Starting Metric Server at %s", c.metricsServer.Addr) + if err := c.metricsServer.ListenAndServe(); err != nil { + log.Error(errors.Wrap(err, "Metric Server Error")) + } + }() if !electOpts.LeaderElect { log.Info("Leader election is turned off. Running in single-instance mode") go c.startLeading(ctx, rolloutThreadiness, serviceThreadiness, ingressThreadiness, experimentThreadiness, analysisThreadiness) + <-ctx.Done() } else { // id used to distinguish between multiple controller manager instances id, err := os.Hostname() @@ -368,63 +398,45 @@ func (c *Manager) Run(rolloutThreadiness, serviceThreadiness, ingressThreadiness // add a uniquifier so that two processes on the same host don't accidentally both become active id = id + "_" + string(uuid.NewUUID()) log.Infof("Leaderelection get id %s", id) - go leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ + leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ Lock: &resourcelock.LeaseLock{ LeaseMeta: metav1.ObjectMeta{Name: defaultLeaderElectionLeaseLockName, Namespace: electOpts.LeaderElectionNamespace}, Client: c.kubeClientSet.CoordinationV1(), LockConfig: resourcelock.ResourceLockConfig{Identity: id}, }, - ReleaseOnCancel: true, - LeaseDuration: electOpts.LeaderElectionLeaseDuration, - RenewDeadline: electOpts.LeaderElectionRenewDeadline, - RetryPeriod: electOpts.LeaderElectionRetryPeriod, + ReleaseOnCancel: false, // We can not set this to true because our context is sent on sig which means our code + // is still running prior to calling cancel. We would need to shut down and then call cancel in order to set this to true. + LeaseDuration: electOpts.LeaderElectionLeaseDuration, + RenewDeadline: electOpts.LeaderElectionRenewDeadline, + RetryPeriod: electOpts.LeaderElectionRetryPeriod, Callbacks: leaderelection.LeaderCallbacks{ OnStartedLeading: func(ctx context.Context) { - if c.secondaryMetricsServer != nil { - log.Warnln("Shutdown Secondary Metrics Server") - c.secondaryMetricsServer.Shutdown(ctx) - } + log.Infof("I am the new leader: %s", id) c.startLeading(ctx, rolloutThreadiness, serviceThreadiness, ingressThreadiness, experimentThreadiness, analysisThreadiness) }, OnStoppedLeading: func() { - log.Infof("Stopped leading controller: %s", id) - return + log.Infof("OnStoppedLeading called, shutting down: %s, context err: %s", id, ctx.Err()) }, OnNewLeader: func(identity string) { - if identity == id { - return - } log.Infof("New leader elected: %s", identity) - - if c.secondaryMetricsServer != nil { - log.Warn("Secondary metrics server already started") - return - } - - log.Infof("Starting Secondary Metric Server at %s", c.metricsServer.Addr) - c.secondaryMetricsServer = metrics.NewMetricsServer(metrics.ServerConfig{ - Addr: c.metricsServer.Addr, - }, false) - err = c.secondaryMetricsServer.ListenAndServe() - if err != nil { - err = errors.Wrap(err, "Starting Secondary Metric Server") - log.Warn(err) - } }, }, }) } + log.Info("Shutting down workers") - go func() { - log.Infof("Starting Healthz Server at %s", c.healthzServer.Addr) - err := c.healthzServer.ListenAndServe() - if err != nil { - err = errors.Wrap(err, "Starting Healthz Server") - log.Error(err) - } - }() + c.serviceWorkqueue.ShutDownWithDrain() + c.ingressWorkqueue.ShutDownWithDrain() + c.rolloutWorkqueue.ShutDownWithDrain() + c.experimentWorkqueue.ShutDownWithDrain() + c.analysisRunWorkqueue.ShutDownWithDrain() + c.analysisRunWorkqueue.ShutDownWithDrain() - <-stopCh - log.Info("Shutting down workers") + ctxWithTimeout, cancel := context.WithTimeout(ctx, 5*time.Second) // give max of 10 seconds for http servers to shut down + defer cancel() + c.healthzServer.Shutdown(ctxWithTimeout) + c.metricsServer.Shutdown(ctxWithTimeout) + + c.wg.Wait() return nil } @@ -433,19 +445,40 @@ func (c *Manager) startLeading(ctx context.Context, rolloutThreadiness, serviceT defer runtime.HandleCrash() // Start the informer factories to begin populating the informer caches log.Info("Starting Controllers") - go wait.Until(func() { c.rolloutController.Run(rolloutThreadiness, ctx.Done()) }, time.Second, ctx.Done()) - go wait.Until(func() { c.serviceController.Run(serviceThreadiness, ctx.Done()) }, time.Second, ctx.Done()) - go wait.Until(func() { c.ingressController.Run(ingressThreadiness, ctx.Done()) }, time.Second, ctx.Done()) - go wait.Until(func() { c.experimentController.Run(experimentThreadiness, ctx.Done()) }, time.Second, ctx.Done()) - go wait.Until(func() { c.analysisController.Run(analysisThreadiness, ctx.Done()) }, time.Second, ctx.Done()) - go wait.Until(func() { c.notificationsController.Run(rolloutThreadiness, ctx.Done()) }, time.Second, ctx.Done()) - go func() { - log.Infof("Starting Metric Server at %s", c.metricsServer.Addr) - if err := c.metricsServer.ListenAndServe(); err != nil { - log.Error(errors.Wrap(err, "Starting Metric Server")) + // notice that there is no need to run Start methods in a separate goroutine. (i.e. go kubeInformerFactory.Start(stopCh) + // Start method is non-blocking and runs all registered informers in a dedicated goroutine. + c.dynamicInformerFactory.Start(ctx.Done()) + if !c.namespaced { + c.clusterDynamicInformerFactory.Start(ctx.Done()) + } + c.kubeInformerFactory.Start(ctx.Done()) + c.controllerNamespaceInformerFactory.Start(ctx.Done()) + c.jobInformerFactory.Start(ctx.Done()) + + // Check if Istio installed on cluster before starting dynamicInformerFactory + if istioutil.DoesIstioExist(c.istioPrimaryDynamicClient, c.namespace) { + c.istioDynamicInformerFactory.Start(ctx.Done()) + } + + // Wait for the caches to be synced before starting workers + log.Info("Waiting for controller's informer caches to sync") + if ok := cache.WaitForCacheSync(ctx.Done(), c.serviceSynced, c.ingressSynced, c.jobSynced, c.rolloutSynced, c.experimentSynced, c.analysisRunSynced, c.analysisTemplateSynced, c.replicasSetSynced, c.configMapSynced, c.secretSynced); !ok { + log.Fatalf("failed to wait for caches to sync, exiting") + } + // only wait for cluster scoped informers to sync if we are running in cluster-wide mode + if c.namespace == metav1.NamespaceAll { + if ok := cache.WaitForCacheSync(ctx.Done(), c.clusterAnalysisTemplateSynced); !ok { + log.Fatalf("failed to wait for cluster-scoped caches to sync, exiting") } - }() + } + + go wait.Until(func() { c.wg.Add(1); c.rolloutController.Run(ctx, rolloutThreadiness); c.wg.Done() }, time.Second, ctx.Done()) + go wait.Until(func() { c.wg.Add(1); c.serviceController.Run(ctx, serviceThreadiness); c.wg.Done() }, time.Second, ctx.Done()) + go wait.Until(func() { c.wg.Add(1); c.ingressController.Run(ctx, ingressThreadiness); c.wg.Done() }, time.Second, ctx.Done()) + go wait.Until(func() { c.wg.Add(1); c.experimentController.Run(ctx, experimentThreadiness); c.wg.Done() }, time.Second, ctx.Done()) + go wait.Until(func() { c.wg.Add(1); c.analysisController.Run(ctx, analysisThreadiness); c.wg.Done() }, time.Second, ctx.Done()) + go wait.Until(func() { c.wg.Add(1); c.notificationsController.Run(rolloutThreadiness, ctx.Done()); c.wg.Done() }, time.Second, ctx.Done()) log.Info("Started controller") } diff --git a/controller/controller_test.go b/controller/controller_test.go index da7c22f7bc..1a601c9248 100644 --- a/controller/controller_test.go +++ b/controller/controller_test.go @@ -3,15 +3,13 @@ package controller import ( "context" "fmt" - "net/http" - "net/http/httptest" + "sync" "testing" "time" notificationapi "github.com/argoproj/notifications-engine/pkg/api" notificationcontroller "github.com/argoproj/notifications-engine/pkg/controller" smifake "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/clientset/versioned/fake" - log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -21,11 +19,8 @@ import ( "k8s.io/client-go/dynamic/dynamicinformer" dynamicfake "k8s.io/client-go/dynamic/fake" kubeinformers "k8s.io/client-go/informers" - "k8s.io/client-go/kubernetes" k8sfake "k8s.io/client-go/kubernetes/fake" - "k8s.io/client-go/tools/leaderelection" - "k8s.io/client-go/tools/leaderelection/resourcelock" "k8s.io/client-go/util/workqueue" "github.com/argoproj/argo-rollouts/analysis" @@ -72,34 +67,34 @@ func (f *fixture) newManager(t *testing.T) *Manager { analysisRunWorkqueue := workqueue.NewNamedRateLimitingQueue(queue.DefaultArgoRolloutsRateLimiter(), "AnalysisRuns") cm := &Manager{ - - kubeClientSet: f.kubeclient, - - ingressWorkqueue: ingressWorkqueue, - serviceWorkqueue: serviceWorkqueue, - rolloutWorkqueue: rolloutWorkqueue, - experimentWorkqueue: experimentWorkqueue, - analysisRunWorkqueue: analysisRunWorkqueue, - + wg: &sync.WaitGroup{}, + healthzServer: NewHealthzServer(fmt.Sprintf(listenAddr, 8080)), rolloutSynced: alwaysReady, - serviceSynced: alwaysReady, - ingressSynced: alwaysReady, - jobSynced: alwaysReady, experimentSynced: alwaysReady, analysisRunSynced: alwaysReady, analysisTemplateSynced: alwaysReady, + clusterAnalysisTemplateSynced: alwaysReady, + serviceSynced: alwaysReady, + ingressSynced: alwaysReady, + jobSynced: alwaysReady, replicasSetSynced: alwaysReady, configMapSynced: alwaysReady, secretSynced: alwaysReady, - clusterAnalysisTemplateSynced: alwaysReady, - - healthzServer: NewHealthzServer(fmt.Sprintf(listenAddr, 8080)), + rolloutWorkqueue: rolloutWorkqueue, + serviceWorkqueue: serviceWorkqueue, + ingressWorkqueue: ingressWorkqueue, + experimentWorkqueue: experimentWorkqueue, + analysisRunWorkqueue: analysisRunWorkqueue, + kubeClientSet: f.kubeclient, + namespace: "", + namespaced: false, } metricsAddr := fmt.Sprintf(listenAddr, 8090) cm.metricsServer = metrics.NewMetricsServer(metrics.ServerConfig{ - Addr: metricsAddr, - }, false) + Addr: metricsAddr, + K8SRequestProvider: &metrics.K8sRequestsCountProvider{}, + }) i := informers.NewSharedInformerFactory(f.client, noResyncPeriodFunc()) k8sI := kubeinformers.NewSharedInformerFactory(f.kubeclient, noResyncPeriodFunc()) @@ -109,16 +104,27 @@ func (f *fixture) newManager(t *testing.T) *Manager { Resource: "targetgroupbindings", } vsvcGVR := istioutil.GetIstioVirtualServiceGVR() + destGVR := istioutil.GetIstioDestinationRuleGVR() scheme := runtime.NewScheme() listMapping := map[schema.GroupVersionResource]string{ tgbGVR: "TargetGroupBindingList", vsvcGVR: vsvcGVR.Resource + "List", + destGVR: destGVR.Resource + "List", } + dynamicClient := dynamicfake.NewSimpleDynamicClientWithCustomListKinds(scheme, listMapping) dynamicInformerFactory := dynamicinformer.NewDynamicSharedInformerFactory(dynamicClient, 0) istioVirtualServiceInformer := dynamicInformerFactory.ForResource(istioutil.GetIstioVirtualServiceGVR()).Informer() istioDestinationRuleInformer := dynamicInformerFactory.ForResource(istioutil.GetIstioDestinationRuleGVR()).Informer() + cm.dynamicInformerFactory = dynamicInformerFactory + cm.clusterDynamicInformerFactory = dynamicInformerFactory + cm.kubeInformerFactory = k8sI + cm.controllerNamespaceInformerFactory = k8sI + cm.jobInformerFactory = k8sI + cm.istioPrimaryDynamicClient = dynamicClient + cm.istioDynamicInformerFactory = dynamicInformerFactory + mode, err := ingressutil.DetermineIngressMode("extensions/v1beta1", &discoveryfake.FakeDiscovery{}) assert.NoError(t, err) ingressWrapper, err := ingressutil.NewIngressWrapper(mode, f.kubeclient, k8sI) @@ -209,35 +215,6 @@ func (f *fixture) newManager(t *testing.T) *Manager { return cm } -func newElectorConfig(kubeclientset kubernetes.Interface, id string, electOpts LeaderElectionOptions) *leaderelection.LeaderElectionConfig { - lec := leaderelection.LeaderElectionConfig{ - Lock: &resourcelock.LeaseLock{ - LeaseMeta: metav1.ObjectMeta{Name: defaultLeaderElectionLeaseLockName, Namespace: electOpts.LeaderElectionNamespace}, Client: kubeclientset.CoordinationV1(), - LockConfig: resourcelock.ResourceLockConfig{Identity: id}, - }, - ReleaseOnCancel: true, - LeaseDuration: electOpts.LeaderElectionLeaseDuration, - RenewDeadline: electOpts.LeaderElectionRenewDeadline, - RetryPeriod: electOpts.LeaderElectionRetryPeriod, - Callbacks: leaderelection.LeaderCallbacks{ - OnStartedLeading: func(ctx context.Context) { - log.Info("Starting leading") - }, - OnStoppedLeading: func() { - log.Infof("Stopped leading controller: %s", id) - return - }, - OnNewLeader: func(identity string) { - if identity == id { - return - } - log.Infof("New leader elected: %s", identity) - }, - }, - } - return &lec -} - func TestNewManager(t *testing.T) { f := newFixture(t) @@ -285,6 +262,13 @@ func TestNewManager(t *testing.T) { k8sRequestProvider, nil, nil, + dynamicInformerFactory, + nil, + nil, + false, + nil, + nil, + nil, ) assert.NotNil(t, cm) @@ -293,97 +277,26 @@ func TestNewManager(t *testing.T) { func TestPrimaryController(t *testing.T) { f := newFixture(t) - stopCh := make(chan struct{}) - cm := f.newManager(t) electOpts := NewLeaderElectionOptions() - go cm.Run(1, 1, 1, 1, 1, electOpts, stopCh) - time.Sleep(2 * time.Second) - close(stopCh) - - // Test primary controller shutdown secondary metrics server - cm.secondaryMetricsServer = metrics.NewMetricsServer(metrics.ServerConfig{}, false) - time.Sleep(2 * time.Second) - stopCh = make(chan struct{}) - go cm.Run(1, 1, 1, 1, 1, electOpts, stopCh) - time.Sleep(2 * time.Second) - close(stopCh) -} - -func TestTwoControllers(t *testing.T) { - f := newFixture(t) - - stopCh := make(chan struct{}) - primary := f.newManager(t) - electOpts := NewLeaderElectionOptions() - go primary.Run(1, 1, 1, 1, 1, electOpts, stopCh) - time.Sleep(1 * time.Second) - - secondary := f.newManager(t) - secondary.healthzServer = NewHealthzServer(fmt.Sprintf(listenAddr, 8081)) - secondary.metricsServer.Addr = (fmt.Sprintf(listenAddr, 8091)) - go secondary.Run(1, 1, 1, 1, 1, electOpts, stopCh) - time.Sleep(1 * time.Second) - - var verifyEndpoints func(url string) - verifyEndpoints = func(url string) { - _, err := http.Get(url) - assert.NoErrorf(t, err, "error connecting to %s", url) - rr := httptest.NewRecorder() - assert.Equal(t, rr.Code, http.StatusOK) - } - - verifyEndpoints("http://localhost:8080/healthz") - verifyEndpoints("http://localhost:8090/metrics") - verifyEndpoints("http://localhost:8081/healthz") - verifyEndpoints("http://localhost:8091/metrics") - - // stop all controllers - time.Sleep(1 * time.Second) - close(stopCh) + ctx, cancel := context.WithCancel(context.Background()) + go func() { + time.Sleep(5 * time.Second) + cancel() + }() + cm.Run(ctx, 1, 1, 1, 1, 1, electOpts) } -func TestSecondaryController(t *testing.T) { +func TestPrimaryControllerSingleInstanceWithShutdown(t *testing.T) { f := newFixture(t) - stopCh := make(chan struct{}) - cm := f.newManager(t) - electOpts := NewLeaderElectionOptions() - lec := newElectorConfig(f.kubeclient, "holder-123-456", *electOpts) - le, err := leaderelection.NewLeaderElector(*lec) - assert.NoError(t, err) - + electOpts.LeaderElect = false ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - go le.Run(ctx) - time.Sleep(1 * time.Second) - assert.True(t, le.IsLeader()) - - go cm.Run(1, 1, 1, 1, 1, electOpts, stopCh) - time.Sleep(2 * time.Second) - assert.True(t, le.IsLeader()) - close(stopCh) - time.Sleep(1 * time.Second) - - // Test secondary metrics server has been started - stopCh = make(chan struct{}) - go cm.Run(1, 1, 1, 1, 1, electOpts, stopCh) - time.Sleep(2 * time.Second) - assert.True(t, le.IsLeader()) - close(stopCh) - time.Sleep(1 * time.Second) - - // Test secondary metrics server listen port is taken - metricsServer := metrics.NewMetricsServer(metrics.ServerConfig{ - Addr: fmt.Sprintf(listenAddr, DefaultMetricsPort), - }, false) - go metricsServer.ListenAndServe() - time.Sleep(1 * time.Second) - cm.secondaryMetricsServer = nil - stopCh = make(chan struct{}) - go cm.Run(1, 1, 1, 1, 1, electOpts, stopCh) - time.Sleep(2 * time.Second) - close(stopCh) + go func() { + time.Sleep(5 * time.Second) + cancel() + }() + cm.Run(ctx, 1, 1, 1, 1, 1, electOpts) } diff --git a/controller/metrics/analysis_test.go b/controller/metrics/analysis_test.go index 61ca87a80f..942c165209 100644 --- a/controller/metrics/analysis_test.go +++ b/controller/metrics/analysis_test.go @@ -178,7 +178,7 @@ analysis_run_reconcile_bucket{name="ar-test",namespace="ar-namespace",le="1"} 1 analysis_run_reconcile_bucket{name="ar-test",namespace="ar-namespace",le="+Inf"} 1 analysis_run_reconcile_sum{name="ar-test",namespace="ar-namespace"} 0.001 analysis_run_reconcile_count{name="ar-test",namespace="ar-namespace"} 1` - metricsServ := NewMetricsServer(newFakeServerConfig(), true) + metricsServ := NewMetricsServer(newFakeServerConfig()) ar := &v1alpha1.AnalysisRun{ ObjectMeta: metav1.ObjectMeta{ Name: "ar-test", diff --git a/controller/metrics/client_test.go b/controller/metrics/client_test.go index 0ebf470a68..b09fc6b886 100644 --- a/controller/metrics/client_test.go +++ b/controller/metrics/client_test.go @@ -14,7 +14,7 @@ controller_clientset_k8s_request_total{kind="replicasets",name="N/A",namespace=" func TestIncKubernetesRequest(t *testing.T) { config := newFakeServerConfig() - metricsServ := NewMetricsServer(config, true) + metricsServ := NewMetricsServer(config) config.K8SRequestProvider.IncKubernetesRequest(kubeclientmetrics.ResourceInfo{ Kind: "replicasets", Namespace: "default", diff --git a/controller/metrics/experiment_test.go b/controller/metrics/experiment_test.go index da050e9377..4335af6fe0 100644 --- a/controller/metrics/experiment_test.go +++ b/controller/metrics/experiment_test.go @@ -150,7 +150,7 @@ experiment_reconcile_bucket{name="ex-test",namespace="ex-namespace",le="+Inf"} 1 experiment_reconcile_sum{name="ex-test",namespace="ex-namespace"} 0.001 experiment_reconcile_count{name="ex-test",namespace="ex-namespace"} 1` - metricsServ := NewMetricsServer(newFakeServerConfig(), true) + metricsServ := NewMetricsServer(newFakeServerConfig()) ex := &v1alpha1.Experiment{ ObjectMeta: metav1.ObjectMeta{ Name: "ex-test", diff --git a/controller/metrics/metrics.go b/controller/metrics/metrics.go index 3c3bbfe246..bad18a1eb3 100644 --- a/controller/metrics/metrics.go +++ b/controller/metrics/metrics.go @@ -50,24 +50,11 @@ type ServerConfig struct { } // NewMetricsServer returns a new prometheus server which collects rollout metrics -func NewMetricsServer(cfg ServerConfig, isPrimary bool) *MetricsServer { +func NewMetricsServer(cfg ServerConfig) *MetricsServer { mux := http.NewServeMux() reg := prometheus.NewRegistry() - // secondary controller doesn't expose any metrics - if !isPrimary { - mux.Handle(MetricsPath, promhttp.HandlerFor(prometheus.Gatherers{ - reg, - }, promhttp.HandlerOpts{})) - return &MetricsServer{ - Server: &http.Server{ - Addr: cfg.Addr, - Handler: mux, - }, - } - } - reg.MustRegister(NewRolloutCollector(cfg.RolloutLister)) reg.MustRegister(NewAnalysisRunCollector(cfg.AnalysisRunLister, cfg.AnalysisTemplateLister, cfg.ClusterAnalysisTemplateLister)) reg.MustRegister(NewExperimentCollector(cfg.ExperimentLister)) diff --git a/controller/metrics/metrics_test.go b/controller/metrics/metrics_test.go index 22d671cee1..00700321fa 100644 --- a/controller/metrics/metrics_test.go +++ b/controller/metrics/metrics_test.go @@ -84,7 +84,7 @@ experiment_reconcile_error{name="name",namespace="ns"} 1 # TYPE rollout_reconcile_error counter rollout_reconcile_error{name="name",namespace="ns"} 1` - metricsServ := NewMetricsServer(newFakeServerConfig(), true) + metricsServ := NewMetricsServer(newFakeServerConfig()) metricsServ.IncError("ns", "name", logutil.AnalysisRunKey) metricsServ.IncError("ns", "name", logutil.ExperimentKey) @@ -95,14 +95,7 @@ rollout_reconcile_error{name="name",namespace="ns"} 1` 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, assert.Contains) -} - -func TestSecondaryMetricsServer(t *testing.T) { - expectedResponse := `` - - metricsServ := NewMetricsServer(newFakeServerConfig(), false) + metricsServ := NewMetricsServer(newFakeServerConfig()) testHttpResponse(t, metricsServ.Handler, expectedResponse, assert.Contains) } @@ -113,7 +106,7 @@ func TestRemove(t *testing.T) { experiment_reconcile_error{name="name1",namespace="ns"} 1 rollout_reconcile_error{name="name1",namespace="ns"} 1` - metricsServ := NewMetricsServer(newFakeServerConfig(), true) + metricsServ := NewMetricsServer(newFakeServerConfig()) metricsServ.IncError("ns", "name1", logutil.RolloutKey) metricsServ.IncError("ns", "name1", logutil.AnalysisRunKey) diff --git a/controller/metrics/rollout_test.go b/controller/metrics/rollout_test.go index b10af8b184..7c889ee09d 100644 --- a/controller/metrics/rollout_test.go +++ b/controller/metrics/rollout_test.go @@ -180,7 +180,7 @@ rollout_reconcile_sum{name="ro-test",namespace="ro-namespace"} 0.001 rollout_reconcile_count{name="ro-test",namespace="ro-namespace"} 1 ` - metricsServ := NewMetricsServer(newFakeServerConfig(), true) + metricsServ := NewMetricsServer(newFakeServerConfig()) ro := &v1alpha1.Rollout{ ObjectMeta: metav1.ObjectMeta{ Name: "ro-test", @@ -305,7 +305,7 @@ rollout_events_total{name="ro-test-1",namespace="ro-namespace",reason="FooEvent" rollout_events_total{name="ro-test-2",namespace="ro-namespace",reason="BazEvent",type="Warning"} 2 ` - metricsServ := NewMetricsServer(newFakeServerConfig(), true) + metricsServ := NewMetricsServer(newFakeServerConfig()) MetricRolloutEventsTotal.WithLabelValues("ro-namespace", "ro-test-1", corev1.EventTypeNormal, "FooEvent").Inc() MetricRolloutEventsTotal.WithLabelValues("ro-namespace", "ro-test-1", corev1.EventTypeNormal, "BarEvent").Inc() MetricRolloutEventsTotal.WithLabelValues("ro-namespace", "ro-test-2", corev1.EventTypeWarning, "BazEvent").Inc() diff --git a/experiments/controller.go b/experiments/controller.go index 2b26005971..a42821aab0 100644 --- a/experiments/controller.go +++ b/experiments/controller.go @@ -2,6 +2,7 @@ package experiments import ( "context" + "sync" "time" log "github.com/sirupsen/logrus" @@ -223,21 +224,26 @@ func NewController(cfg ControllerConfig) *Controller { } // Run starts the controller threads -func (ec *Controller) Run(threadiness int, stopCh <-chan struct{}) error { +func (ec *Controller) Run(ctx context.Context, threadiness int) error { log.Info("Starting Experiment workers") + wg := sync.WaitGroup{} for i := 0; i < threadiness; i++ { + wg.Add(1) go wait.Until(func() { - controllerutil.RunWorker(ec.experimentWorkqueue, logutil.ExperimentKey, ec.syncHandler, ec.metricsServer) - }, time.Second, stopCh) + controllerutil.RunWorker(ctx, ec.experimentWorkqueue, logutil.ExperimentKey, ec.syncHandler, ec.metricsServer) + log.Debug("Experiment worker has stopped") + wg.Done() + }, time.Second, ctx.Done()) } log.Info("Started Experiment workers") - <-stopCh - log.Info("Shutting down experiment workers") + <-ctx.Done() + wg.Wait() + log.Info("All experiment workers have stopped") return nil } -func (ec *Controller) syncHandler(key string) error { +func (ec *Controller) syncHandler(ctx context.Context, key string) error { startTime := timeutil.Now() namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { diff --git a/experiments/controller_test.go b/experiments/controller_test.go index 70fa70ca1c..1e7eb14f13 100644 --- a/experiments/controller_test.go +++ b/experiments/controller_test.go @@ -1,6 +1,7 @@ package experiments import ( + "context" "encoding/json" "fmt" "reflect" @@ -360,7 +361,7 @@ func (f *fixture) newController(resync resyncFunc) (*Controller, informers.Share metricsServer := metrics.NewMetricsServer(metrics.ServerConfig{ Addr: "localhost:8080", K8SRequestProvider: &metrics.K8sRequestsCountProvider{}, - }, true) + }) c := NewController(ControllerConfig{ KubeClientSet: f.kubeclient, @@ -445,7 +446,7 @@ func (f *fixture) runController(experimentName string, startInformers bool, expe assert.True(f.t, cache.WaitForCacheSync(stopCh, c.replicaSetSynced, c.experimentSynced, c.analysisRunSynced, c.analysisTemplateSynced, c.clusterAnalysisTemplateSynced)) } - err := c.syncHandler(experimentName) + err := c.syncHandler(context.Background(), experimentName) if !expectError && err != nil { f.t.Errorf("error syncing experiment: %v", err) } else if expectError && err == nil { @@ -893,3 +894,18 @@ func TestRemoveInvalidSpec(t *testing.T) { }`, templateStatus, cond) assert.Equal(t, expectedPatch, patch) } + +func TestRun(t *testing.T) { + f := newFixture(t, nil) + defer f.Close() + // make sure we can start and top the controller + c, _, _ := f.newController(noResyncPeriodFunc) + ctx, cancel := context.WithCancel(context.TODO()) + defer cancel() + go func() { + time.Sleep(1000 * time.Millisecond) + c.experimentWorkqueue.ShutDownWithDrain() + cancel() + }() + c.Run(ctx, 1) +} diff --git a/ingress/alb_test.go b/ingress/alb_test.go index 79a1c915a1..295f130dac 100644 --- a/ingress/alb_test.go +++ b/ingress/alb_test.go @@ -1,6 +1,7 @@ package ingress import ( + "context" "fmt" "testing" @@ -130,7 +131,7 @@ func TestInvalidManagedALBActions(t *testing.T) { ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, rollout) - err := ctrl.syncIngress("default/test-ingress") + err := ctrl.syncIngress(context.Background(), "default/test-ingress") assert.Nil(t, err) assert.Len(t, kubeclient.Actions(), 0) assert.Len(t, enqueuedObjects, 0) @@ -142,7 +143,7 @@ func TestInvalidPreviousALBActionAnnotationValue(t *testing.T) { ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, nil) - err := ctrl.syncIngress("default/test-ingress") + err := ctrl.syncIngress(context.Background(), "default/test-ingress") assert.Nil(t, err) assert.Len(t, kubeclient.Actions(), 0) assert.Len(t, enqueuedObjects, 0) @@ -153,7 +154,7 @@ func TestInvalidPreviousALBActionAnnotationKey(t *testing.T) { ing.Annotations[ingressutil.ManagedAnnotations] = "invalid-action-key" ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, nil) - err := ctrl.syncIngress("default/test-ingress") + err := ctrl.syncIngress(context.Background(), "default/test-ingress") assert.Nil(t, err) assert.Len(t, kubeclient.Actions(), 0) assert.Len(t, enqueuedObjects, 0) @@ -165,7 +166,7 @@ func TestResetActionFailureFindNoPort(t *testing.T) { ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, nil) - err := ctrl.syncIngress("default/test-ingress") + err := ctrl.syncIngress(context.Background(), "default/test-ingress") assert.Nil(t, err) assert.Len(t, kubeclient.Actions(), 0) assert.Len(t, enqueuedObjects, 0) @@ -177,7 +178,7 @@ func TestALBIngressNoModifications(t *testing.T) { ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, rollout) - err := ctrl.syncIngress("default/test-ingress") + err := ctrl.syncIngress(context.Background(), "default/test-ingress") assert.Nil(t, err) assert.Len(t, kubeclient.Actions(), 0) assert.Len(t, enqueuedObjects, 1) @@ -187,7 +188,7 @@ func TestALBIngressResetAction(t *testing.T) { ing := newALBIngress("test-ingress", 80, "stable-service", "non-existing-rollout", false) ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, nil) - err := ctrl.syncIngress("default/test-ingress") + err := ctrl.syncIngress(context.Background(), "default/test-ingress") assert.Nil(t, err) assert.Len(t, enqueuedObjects, 0) actions := kubeclient.Actions() @@ -211,7 +212,7 @@ 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") + err := ctrl.syncIngress(context.Background(), "default/test-ingress") assert.Nil(t, err) assert.Len(t, enqueuedObjects, 0) actions := kubeclient.Actions() diff --git a/ingress/ingress.go b/ingress/ingress.go index 7bbf856b89..6c4059e476 100644 --- a/ingress/ingress.go +++ b/ingress/ingress.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "strings" + "sync" "time" log "github.com/sirupsen/logrus" @@ -102,23 +103,28 @@ func NewController(cfg ControllerConfig) *Controller { } // Run starts the controller threads -func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error { +func (c *Controller) Run(ctx context.Context, threadiness int) error { log.Info("Starting Ingress workers") + wg := sync.WaitGroup{} for i := 0; i < threadiness; i++ { + wg.Add(1) go wait.Until(func() { - controllerutil.RunWorker(c.ingressWorkqueue, logutil.IngressKey, c.syncIngress, c.metricServer) - }, time.Second, stopCh) + controllerutil.RunWorker(ctx, c.ingressWorkqueue, logutil.IngressKey, c.syncIngress, c.metricServer) + wg.Done() + log.Debug("Ingress worker has stopped") + }, time.Second, ctx.Done()) } log.Info("Started Ingress workers") - <-stopCh - log.Info("Shutting down Ingress workers") + <-ctx.Done() + wg.Wait() + log.Info("All ingress workers have stopped") return nil } // syncIngress queues all rollouts referencing the Ingress for reconciliation -func (c *Controller) syncIngress(key string) error { +func (c *Controller) syncIngress(ctx context.Context, key string) error { namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { return err diff --git a/ingress/ingress_test.go b/ingress/ingress_test.go index 3db4f1bcca..e33ee29c34 100644 --- a/ingress/ingress_test.go +++ b/ingress/ingress_test.go @@ -1,8 +1,10 @@ package ingress import ( + "context" "sync" "testing" + "time" "github.com/argoproj/argo-rollouts/utils/queue" @@ -117,7 +119,7 @@ func newFakeIngressController(t *testing.T, ing *extensionsv1beta1.Ingress, roll MetricsServer: metrics.NewMetricsServer(metrics.ServerConfig{ Addr: "localhost:8080", K8SRequestProvider: &metrics.K8sRequestsCountProvider{}, - }, true), + }), }) enqueuedObjects := map[string]int{} var enqueuedObjectsLock sync.Mutex @@ -149,7 +151,7 @@ func newFakeIngressController(t *testing.T, ing *extensionsv1beta1.Ingress, roll func TestSyncMissingIngress(t *testing.T) { ctrl, _, _ := newFakeIngressController(t, nil, nil) - err := ctrl.syncIngress("default/test-ingress") + err := ctrl.syncIngress(context.Background(), "default/test-ingress") assert.NoError(t, err) } @@ -158,7 +160,7 @@ func TestSyncIngressNotReferencedByRollout(t *testing.T) { ctrl, kubeclient, _ := newFakeIngressController(t, ing, nil) - err := ctrl.syncIngress("default/test-stable-ingress") + err := ctrl.syncIngress(context.Background(), "default/test-stable-ingress") assert.NoError(t, err) actions := kubeclient.Actions() assert.Len(t, actions, 0) @@ -189,7 +191,7 @@ func TestSyncIngressReferencedByRollout(t *testing.T) { ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, rollout) - err := ctrl.syncIngress("default/test-stable-ingress") + err := ctrl.syncIngress(context.Background(), "default/test-stable-ingress") assert.NoError(t, err) actions := kubeclient.Actions() assert.Len(t, actions, 0) @@ -221,9 +223,22 @@ func TestSkipIngressWithNoClass(t *testing.T) { ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, rollout) - err := ctrl.syncIngress("default/test-stable-ingress") + err := ctrl.syncIngress(context.Background(), "default/test-stable-ingress") assert.NoError(t, err) actions := kubeclient.Actions() assert.Len(t, actions, 0) assert.Len(t, enqueuedObjects, 0) } + +func TestRun(t *testing.T) { + // make sure we can start and top the controller + c, _, _ := newFakeIngressController(t, nil, nil) + ctx, cancel := context.WithCancel(context.TODO()) + defer cancel() + go func() { + time.Sleep(1000 * time.Millisecond) + c.ingressWorkqueue.ShutDownWithDrain() + cancel() + }() + c.Run(ctx, 1) +} diff --git a/pkg/signals/signal.go b/pkg/signals/signal.go index f82aafbbd2..b5121ad885 100644 --- a/pkg/signals/signal.go +++ b/pkg/signals/signal.go @@ -1,27 +1,28 @@ package signals import ( + "context" "os" "os/signal" ) var onlyOneSignalHandler = make(chan struct{}) -// SetupSignalHandler registered for SIGTERM and SIGINT. A stop channel is returned -// which is closed on one of these signals. If a second signal is caught, the program +// SetupSignalHandlerContext registered for SIGTERM and SIGINT. A context is returned +// which is canceled on one of these signals. If a second signal is caught, the program // is terminated with exit code 1. -func SetupSignalHandler() (stopCh <-chan struct{}) { +func SetupSignalHandlerContext() (ctx context.Context) { close(onlyOneSignalHandler) // panics when called twice - stop := make(chan struct{}) + ctx, cancel := context.WithCancel(context.Background()) c := make(chan os.Signal, 2) signal.Notify(c, shutdownSignals...) go func() { <-c - close(stop) + cancel() <-c os.Exit(1) // second signal. Exit directly. }() - return stop + return ctx } diff --git a/rollout/controller.go b/rollout/controller.go index e314adf4af..5b2a4eb915 100644 --- a/rollout/controller.go +++ b/rollout/controller.go @@ -6,6 +6,7 @@ import ( "fmt" "reflect" "strconv" + "sync" "time" "k8s.io/apimachinery/pkg/runtime/schema" @@ -326,19 +327,28 @@ func removedKeys(name string, old, new *v1alpha1.Rollout, keyFunc func(ro *v1alp // as syncing informer caches and starting workers. It will block until stopCh // is closed, at which point it will shutdown the workqueue and wait for // workers to finish processing their current work items. -func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error { +func (c *Controller) Run(ctx context.Context, threadiness int) error { log.Info("Starting Rollout workers") + wg := sync.WaitGroup{} for i := 0; i < threadiness; i++ { + wg.Add(1) go wait.Until(func() { - controllerutil.RunWorker(c.rolloutWorkqueue, logutil.RolloutKey, c.syncHandler, c.metricsServer) - }, time.Second, stopCh) + controllerutil.RunWorker(ctx, c.rolloutWorkqueue, logutil.RolloutKey, c.syncHandler, c.metricsServer) + log.Debug("Rollout worker has stopped") + wg.Done() + }, time.Second, ctx.Done()) } - log.Info("Started Rollout workers") + log.Info("Started rollout workers") - go c.IstioController.Run(stopCh) + wg.Add(1) + go c.IstioController.Run(ctx) - <-stopCh - log.Info("Shutting down workers") + <-ctx.Done() + c.IstioController.ShutDownWithDrain() + wg.Done() + + wg.Wait() + log.Info("All rollout workers have stopped") return nil } @@ -346,8 +356,7 @@ func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error { // syncHandler compares the actual state with the desired, and attempts to // converge the two. It then updates the Phase block of the Rollout resource // with the current status of the resource. -func (c *Controller) syncHandler(key string) error { - ctx := context.TODO() +func (c *Controller) syncHandler(ctx context.Context, key string) error { startTime := timeutil.Now() namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { diff --git a/rollout/controller_test.go b/rollout/controller_test.go index 6738900856..7b1f9afa2d 100644 --- a/rollout/controller_test.go +++ b/rollout/controller_test.go @@ -1,6 +1,7 @@ package rollout import ( + "context" "encoding/json" "fmt" "reflect" @@ -545,9 +546,14 @@ func (f *fixture) newController(resync resyncFunc) (*Controller, informers.Share Version: "v1beta1", Resource: "targetgroupbindings", } + vsvcGVR := istioutil.GetIstioVirtualServiceGVR() + destGVR := istioutil.GetIstioDestinationRuleGVR() listMapping := map[schema.GroupVersionResource]string{ - tgbGVR: "TargetGroupBindingList", + tgbGVR: "TargetGroupBindingList", + vsvcGVR: vsvcGVR.Resource + "List", + destGVR: destGVR.Resource + "List", } + dynamicClient := dynamicfake.NewSimpleDynamicClientWithCustomListKinds(scheme, listMapping, f.objects...) dynamicInformerFactory := dynamicinformer.NewDynamicSharedInformerFactory(dynamicClient, 0) istioVirtualServiceInformer := dynamicInformerFactory.ForResource(istioutil.GetIstioVirtualServiceGVR()).Informer() @@ -560,7 +566,7 @@ func (f *fixture) newController(resync resyncFunc) (*Controller, informers.Share metricsServer := metrics.NewMetricsServer(metrics.ServerConfig{ Addr: "localhost:8080", K8SRequestProvider: &metrics.K8sRequestsCountProvider{}, - }, true) + }) ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, f.kubeclient, k8sI) if err != nil { @@ -675,7 +681,7 @@ func (f *fixture) runController(rolloutName string, startInformers bool, expectE assert.True(f.t, cache.WaitForCacheSync(stopCh, c.replicaSetSynced, c.rolloutsSynced)) } - err := c.syncHandler(rolloutName) + err := c.syncHandler(context.Background(), rolloutName) if !expectError && err != nil { f.t.Errorf("error syncing rollout: %v", err) } else if expectError && err == nil { @@ -1945,3 +1951,18 @@ func TestWriteBackToInformer(t *testing.T) { assert.NotEmpty(t, stableRS) assert.Equal(t, rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey], stableRS) } + +func TestRun(t *testing.T) { + f := newFixture(t) + defer f.Close() + // make sure we can start and top the controller + c, _, _ := f.newController(noResyncPeriodFunc) + ctx, cancel := context.WithCancel(context.TODO()) + defer cancel() + go func() { + time.Sleep(1000 * time.Millisecond) + c.rolloutWorkqueue.ShutDownWithDrain() + cancel() + }() + c.Run(ctx, 1) +} diff --git a/rollout/trafficrouting/istio/controller.go b/rollout/trafficrouting/istio/controller.go index 6b76304d79..847ae65956 100644 --- a/rollout/trafficrouting/istio/controller.go +++ b/rollout/trafficrouting/istio/controller.go @@ -3,6 +3,7 @@ package istio import ( "context" "fmt" + "sync" "time" log "github.com/sirupsen/logrus" @@ -114,7 +115,7 @@ func NewIstioController(cfg IstioControllerConfig) *IstioController { // Run starts the Istio informers. If Istio is not installed, will periodically check for presence // of Istio, then start informers once detected. This allows Argo Rollouts to be installed in any // order during cluster bootstrapping. -func (c *IstioController) Run(stopCh <-chan struct{}) { +func (c *IstioController) Run(ctx context.Context) { ns := defaults.Namespace() waitForIstioInstall := !istioutil.DoesIstioExist(c.DynamicClientSet, ns) if waitForIstioInstall { @@ -122,7 +123,7 @@ func (c *IstioController) Run(stopCh <-chan struct{}) { for !istioutil.DoesIstioExist(c.DynamicClientSet, ns) { // Should only execute if Istio is not installed on cluster select { - case <-stopCh: + case <-ctx.Done(): ticker.Stop() return case <-ticker.C: @@ -130,23 +131,29 @@ func (c *IstioController) Run(stopCh <-chan struct{}) { } ticker.Stop() log.Info("Istio install detected. Starting informers") - go c.VirtualServiceInformer.Run(stopCh) - go c.DestinationRuleInformer.Run(stopCh) + go c.VirtualServiceInformer.Run(ctx.Done()) + go c.DestinationRuleInformer.Run(ctx.Done()) } else { log.Info("Istio detected") } - cache.WaitForCacheSync(stopCh, c.VirtualServiceInformer.HasSynced, c.DestinationRuleInformer.HasSynced) + cache.WaitForCacheSync(ctx.Done(), c.VirtualServiceInformer.HasSynced, c.DestinationRuleInformer.HasSynced) + log.Info("Starting istio workers") + wg := sync.WaitGroup{} for i := 0; i < destinationRuleWorkers; i++ { + wg.Add(1) go wait.Until(func() { - controllerutil.RunWorker(c.destinationRuleWorkqueue, "destinationrule", c.syncDestinationRule, nil) - }, time.Second, stopCh) + controllerutil.RunWorker(ctx, c.destinationRuleWorkqueue, "destinationrule", c.syncDestinationRule, nil) + wg.Done() + log.Debug("Istio worker has stopped") + }, time.Second, ctx.Done()) } log.Infof("Istio workers (%d) started", destinationRuleWorkers) - <-stopCh - log.Info("Istio controller stopped") + <-ctx.Done() + wg.Wait() + log.Info("All istio workers have stopped") } // EnqueueDestinationRule examines a VirtualService, finds the Rollout referencing @@ -223,7 +230,7 @@ func (c *IstioController) GetReferencedVirtualServices(ro *v1alpha1.Rollout) (*[ // `rollouts-pod-template-hash` label and the managed-by annotation. This handles the case when a // Rollout has either been deleted, or modified such that it is longer referencing the // DestinationRule. -func (c *IstioController) syncDestinationRule(key string) error { +func (c *IstioController) syncDestinationRule(ctx context.Context, key string) error { namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { return err @@ -297,3 +304,7 @@ func getManagingRolloutName(un *unstructured.Unstructured) string { } return annots[v1alpha1.ManagedByRolloutsKey] } + +func (c *IstioController) ShutDownWithDrain() { + c.destinationRuleWorkqueue.ShutDownWithDrain() +} diff --git a/rollout/trafficrouting/istio/controller_test.go b/rollout/trafficrouting/istio/controller_test.go index 443786c010..af37f11053 100644 --- a/rollout/trafficrouting/istio/controller_test.go +++ b/rollout/trafficrouting/istio/controller_test.go @@ -182,7 +182,7 @@ spec: enqueueCalled = true } - err = c.syncDestinationRule(key) + err = c.syncDestinationRule(context.Background(), key) assert.NoError(t, err) actions := c.DynamicClientSet.(*dynamicfake.FakeDynamicClient).Actions() assert.Len(t, actions, 0) @@ -203,7 +203,7 @@ spec: enqueueCalled = true } - err = c.syncDestinationRule(key) + err = c.syncDestinationRule(context.Background(), key) assert.NoError(t, err) actions := c.DynamicClientSet.(*dynamicfake.FakeDynamicClient).Actions() assert.Len(t, actions, 1) @@ -223,7 +223,7 @@ spec: enqueueCalled = true } - err = c.syncDestinationRule(key) + err = c.syncDestinationRule(context.Background(), key) assert.NoError(t, err) actions := c.DynamicClientSet.(*dynamicfake.FakeDynamicClient).Actions() assert.Len(t, actions, 1) @@ -238,10 +238,11 @@ func TestRun(t *testing.T) { ctx, cancel := context.WithCancel(context.TODO()) defer cancel() go func() { - time.Sleep(100 * time.Millisecond) + time.Sleep(1000 * time.Millisecond) + c.destinationRuleWorkqueue.ShutDownWithDrain() cancel() }() go c.DestinationRuleInformer.Run(ctx.Done()) go c.VirtualServiceInformer.Run(ctx.Done()) - c.Run(ctx.Done()) + c.Run(ctx) } diff --git a/service/service.go b/service/service.go index 47d0ac40d9..f81c82c771 100644 --- a/service/service.go +++ b/service/service.go @@ -3,6 +3,7 @@ package service import ( "context" "fmt" + "sync" "time" log "github.com/sirupsen/logrus" @@ -129,17 +130,22 @@ func NewController(cfg ControllerConfig) *Controller { } // Run starts the controller threads -func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error { +func (c *Controller) Run(ctx context.Context, threadiness int) error { log.Info("Starting Service workers") + wg := sync.WaitGroup{} for i := 0; i < threadiness; i++ { + wg.Add(1) go wait.Until(func() { - controllerutil.RunWorker(c.serviceWorkqueue, logutil.ServiceKey, c.syncService, c.metricServer) - }, time.Second, stopCh) + controllerutil.RunWorker(ctx, c.serviceWorkqueue, logutil.ServiceKey, c.syncService, c.metricServer) + log.Debug("Service worker has stopped") + wg.Done() + }, time.Second, ctx.Done()) } log.Info("Started Service workers") - <-stopCh - log.Info("Shutting down workers") + <-ctx.Done() + wg.Wait() + log.Info("All service workers have stopped") return nil } @@ -147,8 +153,7 @@ func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error { // syncService detects a change to a Service which is managed by a Rollout, and enqueues the // related rollout for reconciliation. If no rollout is referencing the Service, then removes // any injected fields in the service (e.g. rollouts-pod-template-hash and managed-by annotation) -func (c *Controller) syncService(key string) error { - ctx := context.TODO() +func (c *Controller) syncService(ctx context.Context, key string) error { namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { return err diff --git a/service/service_test.go b/service/service_test.go index 4bcd6e8dab..69dea462da 100644 --- a/service/service_test.go +++ b/service/service_test.go @@ -1,7 +1,9 @@ package service import ( + "context" "testing" + "time" "github.com/argoproj/argo-rollouts/utils/queue" @@ -72,7 +74,7 @@ func newFakeServiceController(svc *corev1.Service, rollout *v1alpha1.Rollout) (* metricsServer := metrics.NewMetricsServer(metrics.ServerConfig{ Addr: "localhost:8080", K8SRequestProvider: &metrics.K8sRequestsCountProvider{}, - }, true) + }) c := NewController(ControllerConfig{ Kubeclientset: kubeclient, Argoprojclientset: client, @@ -110,7 +112,7 @@ func newFakeServiceController(svc *corev1.Service, rollout *v1alpha1.Rollout) (* func TestSyncMissingService(t *testing.T) { ctrl, _, _, _ := newFakeServiceController(nil, nil) - err := ctrl.syncService("default/test-service") + err := ctrl.syncService(context.Background(), "default/test-service") assert.NoError(t, err) } @@ -122,7 +124,7 @@ func TestSyncMissingServiceInCache(t *testing.T) { }) ctrl, _, _, _ := newFakeServiceController(svc, nil) ctrl.kubeclientset = k8sfake.NewSimpleClientset() - err := ctrl.syncService("default/test-service") + err := ctrl.syncService(context.Background(), "default/test-service") assert.NoError(t, err) } @@ -133,7 +135,7 @@ func TestSyncServiceNotReferencedByRollout(t *testing.T) { ctrl, kubeclient, _, _ := newFakeServiceController(svc, nil) - err := ctrl.syncService("default/test-service") + err := ctrl.syncService(context.Background(), "default/test-service") assert.NoError(t, err) actions := kubeclient.Actions() assert.Len(t, actions, 1) @@ -164,7 +166,7 @@ func TestSyncServiceWithNoManagedBy(t *testing.T) { ctrl, kubeclient, client, _ := newFakeServiceController(svc, ro) - err := ctrl.syncService("default/test-service") + err := ctrl.syncService(context.Background(), "default/test-service") assert.NoError(t, err) actions := kubeclient.Actions() assert.Len(t, actions, 0) @@ -192,7 +194,7 @@ func TestSyncServiceWithManagedByWithNoRolloutReference(t *testing.T) { ctrl, kubeclient, client, _ := newFakeServiceController(svc, ro) - err := ctrl.syncService("default/test-service") + err := ctrl.syncService(context.Background(), "default/test-service") assert.NoError(t, err) actions := kubeclient.Actions() patch, ok := actions[0].(k8stesting.PatchAction) @@ -227,9 +229,22 @@ func TestSyncServiceReferencedByRollout(t *testing.T) { ctrl, kubeclient, _, enqueuedObjects := newFakeServiceController(svc, rollout) - err := ctrl.syncService("default/test-service") + err := ctrl.syncService(context.Background(), "default/test-service") assert.NoError(t, err) actions := kubeclient.Actions() assert.Len(t, actions, 0) assert.Equal(t, 1, enqueuedObjects["default/rollout"]) } + +func TestRun(t *testing.T) { + // make sure we can start and top the controller + c, _, _, _ := newFakeServiceController(nil, nil) + ctx, cancel := context.WithCancel(context.TODO()) + defer cancel() + go func() { + time.Sleep(1000 * time.Millisecond) + c.serviceWorkqueue.ShutDownWithDrain() + cancel() + }() + c.Run(ctx, 1) +} diff --git a/utils/controller/controller.go b/utils/controller/controller.go index e3123d0f1c..63aa6f11cd 100644 --- a/utils/controller/controller.go +++ b/utils/controller/controller.go @@ -100,14 +100,14 @@ func WatchResourceWithExponentialBackoff(stopCh <-chan struct{}, client dynamic. // RunWorker is a long-running function that will continually call the // processNextWorkItem function in order to read and process a message on the // workqueue. -func RunWorker(workqueue workqueue.RateLimitingInterface, objType string, syncHandler func(string) error, metricServer *metrics.MetricsServer) { - for processNextWorkItem(workqueue, objType, syncHandler, metricServer) { +func RunWorker(ctx context.Context, workqueue workqueue.RateLimitingInterface, objType string, syncHandler func(context.Context, string) error, metricServer *metrics.MetricsServer) { + for processNextWorkItem(ctx, workqueue, objType, syncHandler, metricServer) { } } // processNextWorkItem will read a single work item off the workqueue and // attempt to process it, by calling the syncHandler. -func processNextWorkItem(workqueue workqueue.RateLimitingInterface, objType string, syncHandler func(string) error, metricsServer *metrics.MetricsServer) bool { +func processNextWorkItem(ctx context.Context, workqueue workqueue.RateLimitingInterface, objType string, syncHandler func(context.Context, string) error, metricsServer *metrics.MetricsServer) bool { obj, shutdown := workqueue.Get() if shutdown { @@ -150,7 +150,7 @@ func processNextWorkItem(workqueue workqueue.RateLimitingInterface, objType stri err = fmt.Errorf("Recovered from Panic") } }() - return syncHandler(key) + return syncHandler(ctx, key) } // Run the syncHandler, passing it the namespace/name string of the // Rollout resource to be synced. diff --git a/utils/controller/controller_test.go b/utils/controller/controller_test.go index 601a52628d..9fa54b5517 100644 --- a/utils/controller/controller_test.go +++ b/utils/controller/controller_test.go @@ -1,6 +1,7 @@ package controller import ( + "context" "fmt" "testing" "time" @@ -38,47 +39,47 @@ func TestProcessNextWorkItemHandlePanic(t *testing.T) { metricServer := metrics.NewMetricsServer(metrics.ServerConfig{ Addr: "localhost:8080", K8SRequestProvider: &metrics.K8sRequestsCountProvider{}, - }, true) - syncHandler := func(key string) error { + }) + syncHandler := func(ctx context.Context, key string) error { panic("Bad big panic :(") } - assert.True(t, processNextWorkItem(q, log.RolloutKey, syncHandler, metricServer)) + assert.True(t, processNextWorkItem(context.Background(), q, log.RolloutKey, syncHandler, metricServer)) } func TestProcessNextWorkItemShutDownQueue(t *testing.T) { q := workqueue.NewNamedRateLimitingQueue(queue.DefaultArgoRolloutsRateLimiter(), "Rollouts") - syncHandler := func(key string) error { + syncHandler := func(ctx context.Context, key string) error { return nil } q.ShutDown() - assert.False(t, processNextWorkItem(q, log.RolloutKey, syncHandler, nil)) + assert.False(t, processNextWorkItem(context.Background(), q, log.RolloutKey, syncHandler, nil)) } func TestProcessNextWorkItemNoTStringKey(t *testing.T) { q := workqueue.NewNamedRateLimitingQueue(queue.DefaultArgoRolloutsRateLimiter(), "Rollouts") q.Add(1) - syncHandler := func(key string) error { + syncHandler := func(ctx context.Context, key string) error { return nil } - assert.True(t, processNextWorkItem(q, log.RolloutKey, syncHandler, nil)) + assert.True(t, processNextWorkItem(context.Background(), q, log.RolloutKey, syncHandler, nil)) } func TestProcessNextWorkItemNoValidKey(t *testing.T) { q := workqueue.NewNamedRateLimitingQueue(queue.DefaultArgoRolloutsRateLimiter(), "Rollouts") q.Add("invalid.key") - syncHandler := func(key string) error { + syncHandler := func(ctx context.Context, key string) error { return nil } - assert.True(t, processNextWorkItem(q, log.RolloutKey, syncHandler, nil)) + assert.True(t, processNextWorkItem(context.Background(), q, log.RolloutKey, syncHandler, nil)) } func TestProcessNextWorkItemNormalSync(t *testing.T) { q := workqueue.NewNamedRateLimitingQueue(queue.DefaultArgoRolloutsRateLimiter(), "Rollouts") q.Add("valid/key") - syncHandler := func(key string) error { + syncHandler := func(ctx context.Context, key string) error { return nil } - assert.True(t, processNextWorkItem(q, log.RolloutKey, syncHandler, nil)) + assert.True(t, processNextWorkItem(context.Background(), q, log.RolloutKey, syncHandler, nil)) } func TestProcessNextWorkItemSyncHandlerReturnError(t *testing.T) { @@ -87,11 +88,11 @@ func TestProcessNextWorkItemSyncHandlerReturnError(t *testing.T) { metricServer := metrics.NewMetricsServer(metrics.ServerConfig{ Addr: "localhost:8080", K8SRequestProvider: &metrics.K8sRequestsCountProvider{}, - }, true) - syncHandler := func(key string) error { + }) + syncHandler := func(ctx context.Context, key string) error { return fmt.Errorf("error message") } - assert.True(t, processNextWorkItem(q, log.RolloutKey, syncHandler, metricServer)) + assert.True(t, processNextWorkItem(context.Background(), q, log.RolloutKey, syncHandler, metricServer)) } func TestEnqueue(t *testing.T) { From b90fff311872e3b5ead29c3fcf02f3a3cf6a0ca3 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Thu, 13 Oct 2022 16:45:32 -0500 Subject: [PATCH 12/68] fix(cli): nil pointer while linting (#2324) * fix nil pointer on lint Signed-off-by: zachaller * github trigger re-run Signed-off-by: zachaller * add test for having a virtual service but not using it in rollout Signed-off-by: zachaller * change logic Signed-off-by: zachaller * improve test cov Signed-off-by: zachaller * remove unreachable code Signed-off-by: zachaller * github trigger re-run Signed-off-by: zachaller * github trigger re-run Signed-off-by: zachaller * Add test coverage Signed-off-by: zachaller * add more test coverage Signed-off-by: zachaller * Standardize msg Signed-off-by: zachaller * lint Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- .../validation/validation_references.go | 9 +++ .../validation/validation_references_test.go | 22 +++++- pkg/kubectl-argo-rollouts/cmd/lint/lint.go | 3 + .../cmd/lint/lint_test.go | 5 ++ .../testdata/invalid-empty-rollout-vsvc.yml | 5 ++ .../testdata/valid-nginx-smi-with-vsvc.yaml | 74 +++++++++++++++++++ 6 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-empty-rollout-vsvc.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-nginx-smi-with-vsvc.yaml diff --git a/pkg/apis/rollouts/validation/validation_references.go b/pkg/apis/rollouts/validation/validation_references.go index 545b87e7af..8e3578675c 100644 --- a/pkg/apis/rollouts/validation/validation_references.go +++ b/pkg/apis/rollouts/validation/validation_references.go @@ -273,6 +273,15 @@ func ValidateVirtualService(rollout *v1alpha1.Rollout, obj unstructured.Unstruct allErrs := field.ErrorList{} newObj := obj.DeepCopy() + if rollout.Spec.Strategy.Canary == nil || + rollout.Spec.Strategy.Canary.TrafficRouting == nil || + rollout.Spec.Strategy.Canary.TrafficRouting.Istio == nil { + + msg := "Rollout object is not configured with Istio traffic routing" + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "strategy", "canary", "trafficRouting", "istio"), rollout.Name, msg)) + return allErrs + } + if istioutil.MultipleVirtualServiceConfigured(rollout) { fldPath = field.NewPath("spec", "strategy", "canary", "trafficRouting", "istio", "virtualServices", "name") virtualServices = rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualServices diff --git a/pkg/apis/rollouts/validation/validation_references_test.go b/pkg/apis/rollouts/validation/validation_references_test.go index ac8e962cf2..75e7a59c92 100644 --- a/pkg/apis/rollouts/validation/validation_references_test.go +++ b/pkg/apis/rollouts/validation/validation_references_test.go @@ -558,6 +558,18 @@ func TestValidateVirtualService(t *testing.T) { }, } + roWithoutIstio := &v1alpha1.Rollout{ + Spec: v1alpha1.RolloutSpec{ + Strategy: v1alpha1.RolloutStrategy{ + Canary: &v1alpha1.CanaryStrategy{ + StableService: "stable", + CanaryService: "canary", + TrafficRouting: &v1alpha1.RolloutTrafficRouting{}, + }, + }, + }, + } + t.Run("validate virtualService HTTP routes - success", func(t *testing.T) { vsvc := unstructured.StrToUnstructuredUnsafe(successCaseVsvc) allErrs := ValidateVirtualService(ro, *vsvc) @@ -624,13 +636,21 @@ func TestValidateVirtualService(t *testing.T) { assert.Equal(t, expectedErr.Error(), allErrs[0].Error()) }) - t.Run("validate virtualService invalid tcp routes - failure", func(t *testing.T) { + t.Run("validate virtualService invalid rollout missing istio", func(t *testing.T) { vsvc := unstructured.StrToUnstructuredUnsafe(failCaseInvalidTcpRoutesVsvc) allErrs := ValidateVirtualService(ro, *vsvc) assert.Len(t, allErrs, 1) expectedErr := field.Invalid(field.NewPath("spec", "strategy", "canary", "trafficRouting", "istio", "virtualService", "name"), "istio-vsvc", "Unable to get TCP routes for Istio VirtualService") assert.Equal(t, expectedErr.Error(), allErrs[0].Error()) }) + + t.Run("validate virtualService invalid tcp routes - failure", func(t *testing.T) { + vsvc := unstructured.StrToUnstructuredUnsafe(successCaseTcpVsvc) + allErrs := ValidateVirtualService(roWithoutIstio, *vsvc) + assert.Len(t, allErrs, 1) + expectedErr := field.Invalid(field.NewPath("spec", "strategy", "canary", "trafficRouting", "istio"), roWithoutIstio.Name, "Rollout object is not configured with Istio traffic routing") + assert.Equal(t, expectedErr.Error(), allErrs[0].Error()) + }) } func TestValidateVirtualServices(t *testing.T) { diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/lint.go b/pkg/kubectl-argo-rollouts/cmd/lint/lint.go index 66e28318eb..c7cb091a0a 100644 --- a/pkg/kubectl-argo-rollouts/cmd/lint/lint.go +++ b/pkg/kubectl-argo-rollouts/cmd/lint/lint.go @@ -294,6 +294,9 @@ func setIngressManagedAnnotation(rollouts []v1alpha1.Rollout, refResource valida func setVirtualServiceManagedAnnotation(ro []v1alpha1.Rollout, refResource validation.ReferencedResources) { for _, rollout := range ro { for i := range refResource.VirtualServices { + if rollout.Spec.Strategy.Canary == nil || rollout.Spec.Strategy.Canary.TrafficRouting == nil || rollout.Spec.Strategy.Canary.TrafficRouting.Istio == nil { + return + } 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 { diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/lint_test.go b/pkg/kubectl-argo-rollouts/cmd/lint/lint_test.go index 326015bbb3..e9b66fd2ed 100644 --- a/pkg/kubectl-argo-rollouts/cmd/lint/lint_test.go +++ b/pkg/kubectl-argo-rollouts/cmd/lint/lint_test.go @@ -29,6 +29,7 @@ func TestLintValidRollout(t *testing.T) { "testdata/valid-nginx-canary.yml", "testdata/valid-nginx-basic-canary.yml", "testdata/valid-istio-v1beta1-mulitiple-virtualsvcs.yml", + "testdata/valid-nginx-smi-with-vsvc.yaml", } for _, filename := range tests { @@ -54,6 +55,10 @@ func TestLintInvalidRollout(t *testing.T) { "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-empty-rollout-vsvc.yml", + "Error: spec.selector: Required value: Rollout has missing field '.spec.selector'\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", diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-empty-rollout-vsvc.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-empty-rollout-vsvc.yml new file mode 100644 index 0000000000..bf184253b9 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-empty-rollout-vsvc.yml @@ -0,0 +1,5 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService \ No newline at end of file diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-nginx-smi-with-vsvc.yaml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-nginx-smi-with-vsvc.yaml new file mode 100644 index 0000000000..0acb23d62f --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-nginx-smi-with-vsvc.yaml @@ -0,0 +1,74 @@ +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: 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: + smi: + trafficSplitName: rollout-smi-experiment-split + rootService: rollout-smi-experiment-root + nginx: + stableIngress: nginx-rollout-ingress + steps: + - setWeight: 10 From f4bf235e3ac93b20ef6243798db6043f26e83e1b Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Thu, 13 Oct 2022 17:32:03 -0500 Subject: [PATCH 13/68] test(controller): add extra checks to TestWriteBackToInformer (#2326) Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- rollout/controller_test.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/rollout/controller_test.go b/rollout/controller_test.go index 7b1f9afa2d..d7683fddec 100644 --- a/rollout/controller_test.go +++ b/rollout/controller_test.go @@ -1945,8 +1945,11 @@ func TestWriteBackToInformer(t *testing.T) { f.runController(roKey, true, false, c, i, k8sI) // Verify the informer was updated with the new unstructured object after reconciliation - obj, _, _ := c.rolloutsIndexer.GetByKey(roKey) - un := obj.(*unstructured.Unstructured) + obj, exists, err := c.rolloutsIndexer.GetByKey(roKey) + assert.NoError(t, err) + assert.True(t, exists) + un, ok := obj.(*unstructured.Unstructured) + assert.True(t, ok) stableRS, _, _ := unstructured.NestedString(un.Object, "status", "stableRS") assert.NotEmpty(t, stableRS) assert.Equal(t, rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey], stableRS) From a7149b6a4d7c492bbd05fcc64ea4aafbdddd694a Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Fri, 14 Oct 2022 15:32:37 -0500 Subject: [PATCH 14/68] docs: add artifact badge (#2331) Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ff667c3f64..9a88e2f492 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![codecov](https://codecov.io/gh/argoproj/argo-rollouts/branch/master/graph/badge.svg)](https://codecov.io/gh/argoproj/argo-rollouts) [![slack](https://img.shields.io/badge/slack-argoproj-brightgreen.svg?logo=slack)](https://argoproj.github.io/community/join-slack) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3834/badge)](https://bestpractices.coreinfrastructure.org/projects/3834) +[![Artifact HUB](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/argo-rollouts)](https://artifacthub.io/packages/helm/argo/argo-rollouts) ## What is Argo Rollouts? Argo Rollouts is a Kubernetes controller and set of CRDs which provide advanced deployment capabilities such as blue-green, canary, canary analysis, experimentation, and progressive delivery features to Kubernetes. From 6bdf53ad5ed30776eecc4a7570a5ade31ca20990 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Fri, 14 Oct 2022 16:03:12 -0500 Subject: [PATCH 15/68] build: add sha256 checksums for all released bins (#2332) * build: add sha256 checksums for all released bins Signed-off-by: zachaller * Add shasum Signed-off-by: zachaller * rename file Signed-off-by: zachaller * shasum is included Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- .github/workflows/release.yaml | 1 + hack/build-release-plugins.sh | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 7bb0c1dfb5..43080842a0 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -155,6 +155,7 @@ jobs: dist/kubectl-argo-rollouts-darwin-amd64 dist/kubectl-argo-rollouts-darwin-arm64 dist/kubectl-argo-rollouts-windows-amd64 + dist/argo-rollouts-checksums.txt manifests/dashboard-install.yaml manifests/install.yaml manifests/namespace-install.yaml diff --git a/hack/build-release-plugins.sh b/hack/build-release-plugins.sh index db5bcdbea7..390fbdadbc 100755 --- a/hack/build-release-plugins.sh +++ b/hack/build-release-plugins.sh @@ -14,5 +14,9 @@ container_id=$(docker create ${rollout_iid}) for plat in linux-amd64 linux-arm64 darwin-amd64 darwin-arm64 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} rm -f ${rollout_iid_file} + +cd ${SRCROOT}/dist/ +shasum -a 256 kubectl-argo-rollouts-* > argo-rollouts-checksums.txt From 6c350098dabfe5a1e9b0aede40bcf07680dddf3f Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Fri, 14 Oct 2022 17:52:24 -0500 Subject: [PATCH 16/68] ci: Add github action for PR Conventional Commits (#2320) * feat(ci): Add github action for PR Conventional Commits Signed-off-by: zachaller * add example scope Signed-off-by: zachaller * add cli as scope Signed-off-by: zachaller * Remove configuration Signed-off-by: zachaller * scopes not required Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- .github/workflows/pr-title-check.yml | 47 ++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .github/workflows/pr-title-check.yml diff --git a/.github/workflows/pr-title-check.yml b/.github/workflows/pr-title-check.yml new file mode 100644 index 0000000000..5f11c118ae --- /dev/null +++ b/.github/workflows/pr-title-check.yml @@ -0,0 +1,47 @@ +name: "Lint PR" + +on: + pull_request_target: + types: + - opened + - edited + - synchronize + +jobs: + main: + name: Validate PR title + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + # Configure which types are allowed (newline delimited). + # Default: https://github.com/commitizen/conventional-commit-types + types: | + feat + fix + docs + style + refactor + perf + test + build + ci + chore + revert + + # Configure which scopes are allowed (newline delimited). + scopes: | + controller + dashboard + trafficrouting + analysis + metricprovider + experiments + deps + example + cli + + # Configure that a scope must always be provided. + requireScope: false From ebee23715d3310ab02fecbb7ac6c34184ae7a4a0 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Sat, 15 Oct 2022 18:58:44 -0500 Subject: [PATCH 17/68] ci: add auto close to issues and prs (#2319) * add auto close issues and prs Signed-off-by: zachaller * Add awaiting-response label closer Signed-off-by: zachaller * Change name Signed-off-by: zachaller * dont close any milestones Signed-off-by: zachaller * correct label in messages Signed-off-by: zachaller * github trigger re-run Signed-off-by: zachaller * add permissions Signed-off-by: zachaller * move perms to job Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- .github/workflows/stale-issues-pr.yml | 27 ++++++++++++++++++++++++++ .github/workflows/waiting-issues.yml | 28 +++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 .github/workflows/stale-issues-pr.yml create mode 100644 .github/workflows/waiting-issues.yml diff --git a/.github/workflows/stale-issues-pr.yml b/.github/workflows/stale-issues-pr.yml new file mode 100644 index 0000000000..cbf65e7e72 --- /dev/null +++ b/.github/workflows/stale-issues-pr.yml @@ -0,0 +1,27 @@ +name: 'Close stale issues and PRs' +on: + schedule: + - cron: '30 1 * * *' + +jobs: + stale: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@v6 + with: + stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.' + stale-pr-message: 'This PR is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 14 days.' + close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.' + close-pr-message: 'This PR was closed because it has been stalled for 14 days with no activity.' + days-before-issue-stale: 60 + days-before-pr-stale: 90 + days-before-issue-close: 7 + days-before-pr-close: 14 + stale-issue-label: 'no-issue-activity' + exempt-issue-labels: 'awaiting-approval,work-in-progress' + stale-pr-label: 'no-pr-activity' + exempt-pr-labels: 'awaiting-approval,work-in-progress' + exempt-all-milestones: true \ No newline at end of file diff --git a/.github/workflows/waiting-issues.yml b/.github/workflows/waiting-issues.yml new file mode 100644 index 0000000000..7e1814e20a --- /dev/null +++ b/.github/workflows/waiting-issues.yml @@ -0,0 +1,28 @@ +name: 'Close stale issues and PRs waiting for response' +on: + schedule: + - cron: '30 1 * * *' + +jobs: + stale: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@v6 + with: + stale-issue-message: 'This issue is stale because it has awaiting-response label for 5 days with no activity. Remove stale label or comment or this will be closed in 5 days.' + stale-pr-message: 'This PR is stale because it has awaiting-response label for 10 days with no activity. Remove stale label or comment or this will be closed in 10 days.' + close-issue-message: 'This issue was closed because it has been stalled for 5 days with no activity and has the awaiting-response label.' + close-pr-message: 'This PR was closed because it has been stalled for 10 days with no activity and has the awaiting-response label.' + days-before-issue-stale: 5 + days-before-pr-stale: 10 + days-before-issue-close: 5 + days-before-pr-close: 10 + stale-issue-label: 'no-issue-activity' + exempt-issue-labels: 'awaiting-approval,work-in-progress' + stale-pr-label: 'no-pr-activity' + exempt-pr-labels: 'awaiting-approval,work-in-progress' + exempt-all-milestones: true + any-of-labels: 'awaiting-response' \ No newline at end of file From 226ff816a1fa57b2710d4bbfd2e0c87855eaf887 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Sat, 15 Oct 2022 19:03:53 -0500 Subject: [PATCH 18/68] move perms to job for clomonitor (#2333) Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- .github/workflows/dependabot_automerge.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/dependabot_automerge.yml b/.github/workflows/dependabot_automerge.yml index 961ab6da42..128e1bd8b6 100644 --- a/.github/workflows/dependabot_automerge.yml +++ b/.github/workflows/dependabot_automerge.yml @@ -2,13 +2,12 @@ name: Approve and enable auto-merge for dependabot on: pull_request -permissions: - pull-requests: write - contents: write - jobs: review: runs-on: ubuntu-latest + permissions: + pull-requests: write + contents: write if: ${{ github.actor == 'dependabot[bot]' && github.repository == 'argoproj/argo-rollouts'}} steps: - name: Dependabot metadata From 00988b8d26a8104939d14d8595ccb3e76c7e335c Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Sat, 15 Oct 2022 19:06:47 -0500 Subject: [PATCH 19/68] Move zachaller to approvers (#2311) Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- OWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OWNERS b/OWNERS index eba5228bfd..32b790229c 100644 --- a/OWNERS +++ b/OWNERS @@ -8,6 +8,7 @@ approvers: - jessesuen - khhirani - leoluz +- zachaller reviewers: - agrawroh @@ -15,4 +16,3 @@ reviewers: - harikrongali - kostis-codefresh - perenesenko -- zachaller From c073813fac0127caeaad34c717333ea77b83596a Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Sat, 15 Oct 2022 21:22:06 -0500 Subject: [PATCH 20/68] ci: fix pr lint check (#2336) Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- .github/workflows/pr-title-check.yml | 60 ++++++++++++++-------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/.github/workflows/pr-title-check.yml b/.github/workflows/pr-title-check.yml index 5f11c118ae..dd165bdf28 100644 --- a/.github/workflows/pr-title-check.yml +++ b/.github/workflows/pr-title-check.yml @@ -13,35 +13,35 @@ jobs: runs-on: ubuntu-latest steps: - uses: amannn/action-semantic-pull-request@v5 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - # Configure which types are allowed (newline delimited). - # Default: https://github.com/commitizen/conventional-commit-types - types: | - feat - fix - docs - style - refactor - perf - test - build - ci - chore - revert + with: + # Configure which types are allowed (newline delimited). + # Default: https://github.com/commitizen/conventional-commit-types + types: | + feat + fix + docs + style + refactor + perf + test + build + ci + chore + revert - # Configure which scopes are allowed (newline delimited). - scopes: | - controller - dashboard - trafficrouting - analysis - metricprovider - experiments - deps - example - cli + # Configure which scopes are allowed (newline delimited). + scopes: | + controller + dashboard + trafficrouting + analysis + metricprovider + experiments + deps + example + cli - # Configure that a scope must always be provided. - requireScope: false + # Configure that a scope must always be provided. + requireScope: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From ddbfd3060c0b681cad37339510b6d6dce3e93d8d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Oct 2022 00:07:35 +0000 Subject: [PATCH 21/68] chore(deps): bump google.golang.org/grpc from 1.50.0 to 1.50.1 (#2340) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.50.0 to 1.50.1. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.50.0...v1.50.1) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 571aa6141e..d5cc233ee2 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,7 @@ require ( github.com/tj/assert v0.0.3 github.com/valyala/fasttemplate v1.2.1 google.golang.org/genproto v0.0.0-20220712132514-bdd2acd4974d - google.golang.org/grpc v1.50.0 + google.golang.org/grpc v1.50.1 google.golang.org/protobuf v1.28.1 gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.24.2 diff --git a/go.sum b/go.sum index 49fe128eb1..e0e0151ff0 100644 --- a/go.sum +++ b/go.sum @@ -1661,8 +1661,8 @@ google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11 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/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.50.0 h1:fPVVDxY9w++VjTZsYvXWqEf9Rqar/e+9zYfxKK+W+YU= -google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= 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= From 2dbd19777a0566b135a23ab89337d2a7ccbedd0c Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Mon, 17 Oct 2022 10:49:24 -0500 Subject: [PATCH 22/68] ci: adjust settings for stale pr and issues (#2341) * adjust settings for stale pr and issues Signed-off-by: zachaller * go back to original settings Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- .github/workflows/stale-issues-pr.yml | 8 ++++---- .github/workflows/waiting-issues.yml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/stale-issues-pr.yml b/.github/workflows/stale-issues-pr.yml index cbf65e7e72..49e9590908 100644 --- a/.github/workflows/stale-issues-pr.yml +++ b/.github/workflows/stale-issues-pr.yml @@ -12,14 +12,14 @@ jobs: steps: - uses: actions/stale@v6 with: - stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.' - stale-pr-message: 'This PR is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 14 days.' + stale-issue-message: 'This issue is stale because it has been open 60 days with no activity.' + stale-pr-message: 'This PR is stale because it has been open 90 days with no activity.' close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.' close-pr-message: 'This PR was closed because it has been stalled for 14 days with no activity.' days-before-issue-stale: 60 days-before-pr-stale: 90 - days-before-issue-close: 7 - days-before-pr-close: 14 + days-before-issue-close: -1 + days-before-pr-close: -1 stale-issue-label: 'no-issue-activity' exempt-issue-labels: 'awaiting-approval,work-in-progress' stale-pr-label: 'no-pr-activity' diff --git a/.github/workflows/waiting-issues.yml b/.github/workflows/waiting-issues.yml index 7e1814e20a..4caed43734 100644 --- a/.github/workflows/waiting-issues.yml +++ b/.github/workflows/waiting-issues.yml @@ -21,7 +21,7 @@ jobs: days-before-issue-close: 5 days-before-pr-close: 10 stale-issue-label: 'no-issue-activity' - exempt-issue-labels: 'awaiting-approval,work-in-progress' + exempt-issue-labels: 'awaiting-approval,work-in-progress,enhancement' stale-pr-label: 'no-pr-activity' exempt-pr-labels: 'awaiting-approval,work-in-progress' exempt-all-milestones: true From d31eea38043d57f36cb0d053642b664c6471e1b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Oct 2022 00:03:10 +0000 Subject: [PATCH 23/68] chore(deps): bump github.com/newrelic/newrelic-client-go (#2344) Bumps [github.com/newrelic/newrelic-client-go](https://github.com/newrelic/newrelic-client-go) from 1.0.0 to 1.1.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/v1.0.0...v1.1.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] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d5cc233ee2..4f6d91e586 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/influxdata/influxdb-client-go/v2 v2.11.0 github.com/juju/ansiterm v1.0.0 github.com/mitchellh/mapstructure v1.5.0 - github.com/newrelic/newrelic-client-go v1.0.0 + github.com/newrelic/newrelic-client-go v1.1.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.12.2-0.20220620141757-4ad265f1b4ee github.com/prometheus/client_model v0.2.0 diff --git a/go.sum b/go.sum index e0e0151ff0..7e9e65ac61 100644 --- a/go.sum +++ b/go.sum @@ -805,8 +805,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 v1.0.0 h1:0ugZUujCiJg3WGDxnmOT1QRP2gDiZKIMN0Z04SvxVBc= -github.com/newrelic/newrelic-client-go v1.0.0/go.mod h1:RYMXt7hgYw7nzuXIGd2BH0F1AivgWw7WrBhNBQZEB4k= +github.com/newrelic/newrelic-client-go v1.1.0 h1:aflNjzQ21c+2GwBVh+UbAf9lznkRfCcVABoc5UM4IXw= +github.com/newrelic/newrelic-client-go v1.1.0/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/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= From 9feac908d1966f6b5a9654ba3fa4834728b4eb68 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Tue, 18 Oct 2022 12:12:14 -0500 Subject: [PATCH 24/68] ci: auto generate changelog (#2321) * Auto changelogs Signed-off-by: zachaller * change template Signed-off-by: zachaller * remove pr title check to won pr Signed-off-by: zachaller * conventionalcommits Signed-off-by: zachaller * change file name Signed-off-by: zachaller * Auto changelogs Signed-off-by: zachaller * change template Signed-off-by: zachaller * remove pr title check to won pr Signed-off-by: zachaller * conventionalcommits Signed-off-by: zachaller * change file name Signed-off-by: zachaller * fix file name when untar'ing Signed-off-by: zachaller * perms for clomonitor Signed-off-by: zachaller * sort by semver Signed-off-by: zachaller * start at v1.3.1 Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- .chglog/CHANGELOG.tpl.md | 30 ++++++++++++++++++++++++++++++ .chglog/config.yml | 28 ++++++++++++++++++++++++++++ .github/workflows/changelog.yml | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100755 .chglog/CHANGELOG.tpl.md create mode 100755 .chglog/config.yml create mode 100644 .github/workflows/changelog.yml diff --git a/.chglog/CHANGELOG.tpl.md b/.chglog/CHANGELOG.tpl.md new file mode 100755 index 0000000000..60a67d5bc2 --- /dev/null +++ b/.chglog/CHANGELOG.tpl.md @@ -0,0 +1,30 @@ +{{ range .Versions }} + +## {{ if .Tag.Previous }}[{{ .Tag.Name }}]({{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}){{ else }}{{ .Tag.Name }}{{ end }} ({{ datetime "2006-01-02" .Tag.Date }}) + +{{ range .CommitGroups -}} +### {{ .Title }} + +{{ range .Commits -}} +* {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} +{{ end }} +{{ end -}} + +{{- if .RevertCommits -}} +### Reverts + +{{ range .RevertCommits -}} +* {{ .Revert.Header }} +{{ end }} +{{ end -}} + +{{- if .NoteGroups -}} +{{ range .NoteGroups -}} +### {{ .Title }} + +{{ range .Notes }} +{{ .Body }} +{{ end }} +{{ end -}} +{{ end -}} +{{ end -}} \ No newline at end of file diff --git a/.chglog/config.yml b/.chglog/config.yml new file mode 100755 index 0000000000..0e4a037f2d --- /dev/null +++ b/.chglog/config.yml @@ -0,0 +1,28 @@ +style: github +template: CHANGELOG.tpl.md +info: + title: CHANGELOG + repository_url: https://github.com/argoproj/argo-rollouts +options: + commits: + # filters: + # Type: + # - feat + # - fix + # - perf + # - refactor + commit_groups: + # title_maps: + # feat: Features + # fix: Bug Fixes + # perf: Performance Improvements + # refactor: Code Refactoring + header: + pattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$" + pattern_maps: + - Type + - Scope + - Subject + notes: + keywords: + - BREAKING CHANGE \ No newline at end of file diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml new file mode 100644 index 0000000000..46ab0d0535 --- /dev/null +++ b/.github/workflows/changelog.yml @@ -0,0 +1,32 @@ +name: Update Changelog +on: + release: + types: [published] +permissions: + contents: read + +jobs: + updateChangelog: + permissions: + contents: write # for peter-evans/create-pull-request to create branch + pull-requests: write # for peter-evans/create-pull-request to create a PR + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Update Changelog + run: | + curl -o git-chglog.tar.gz -L https://github.com/git-chglog/git-chglog/releases/download/v0.15.1/git-chglog_0.15.1_darwin_amd64.tar.gz + tar -zxvf git-chglog.tar.gz + chmod u+x git-chglog + ./git-chglog --sort semver -o CHANGELOG-AUTO.md v1.3.1.. + rm git-chglog + - name: Create Pull Request + uses: peter-evans/create-pull-request@v4 + with: + commit-message: update changelog + title: "docs: Update Changelog" + body: Update changelog to reflect release changes + branch: update-changelog + base: master \ No newline at end of file From 60636e96de3f5835859e4b0133a691f93b7017e5 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Tue, 18 Oct 2022 12:16:35 -0500 Subject: [PATCH 25/68] docs(trafficrouting): fix docs warning to github style markdown (#2342) * fix docs warning to github style markdown Signed-off-by: zachaller * fx formating Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- docs/features/traffic-management/index.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/features/traffic-management/index.md b/docs/features/traffic-management/index.md index 8c2e97d152..1578cab580 100644 --- a/docs/features/traffic-management/index.md +++ b/docs/features/traffic-management/index.md @@ -58,7 +58,9 @@ routes we also have to set a route precedence with the upstream traffic router. 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. +!!! 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: From db61f89892f4e17b2bbcd85c480f07379694f1de Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Tue, 18 Oct 2022 13:32:42 -0500 Subject: [PATCH 26/68] fix all workflows to follow best practices of clo monitor via https://app.stepsecurity.io/ (#2343) Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- .github/workflows/codeql.yml | 63 ++++++++++++---------- .github/workflows/dependabot_automerge.yml | 3 ++ .github/workflows/docker-publish.yml | 5 +- .github/workflows/e2e.yaml | 3 ++ .github/workflows/gh-pages.yaml | 5 ++ .github/workflows/go.yml | 6 +++ .github/workflows/pr-title-check.yml | 8 ++- .github/workflows/release.yaml | 7 ++- .github/workflows/stale-issues-pr.yml | 3 ++ .github/workflows/waiting-issues.yml | 3 ++ 10 files changed, 75 insertions(+), 31 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 6af424b019..d8309ea267 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -12,38 +12,45 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +permissions: # added using https://github.com/step-security/secure-workflows + contents: read + jobs: CodeQL-Build: # CodeQL runs on ubuntu-latest and windows-latest + permissions: + actions: read # for github/codeql-action/init to get workflow details + contents: read # for actions/checkout to fetch code + security-events: write # for github/codeql-action/autobuild to send a status report runs-on: ubuntu-latest steps: - - name: Checkout repository - uses: actions/checkout@v3.1.0 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - # Override language selection by uncommenting this and choosing your languages - # with: - # languages: go, javascript, csharp, python, cpp, java - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + - name: Checkout repository + uses: actions/checkout@v3.1.0 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + # Override language selection by uncommenting this and choosing your languages + # with: + # languages: go, javascript, csharp, python, cpp, java + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/dependabot_automerge.yml b/.github/workflows/dependabot_automerge.yml index 128e1bd8b6..2bdab7b838 100644 --- a/.github/workflows/dependabot_automerge.yml +++ b/.github/workflows/dependabot_automerge.yml @@ -2,6 +2,9 @@ name: Approve and enable auto-merge for dependabot on: pull_request +permissions: + contents: read + jobs: review: runs-on: ubuntu-latest diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 6631d03342..c96f45c77f 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -9,6 +9,9 @@ on: # Run tests for any PRs. pull_request: +permissions: + contents: read + jobs: docker: runs-on: ubuntu-latest @@ -91,4 +94,4 @@ jobs: target: kubectl-argo-rollouts platforms: ${{ steps.platform-matrix.outputs.platform-matrix }} push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.plugin-meta.outputs.tags }} + tags: ${{ steps.plugin-meta.outputs.tags }} \ No newline at end of file diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index f35de3415b..7590b1c106 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -20,6 +20,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: event_file: name: "Event File" diff --git a/.github/workflows/gh-pages.yaml b/.github/workflows/gh-pages.yaml index 303d641f7f..58c87fe72a 100644 --- a/.github/workflows/gh-pages.yaml +++ b/.github/workflows/gh-pages.yaml @@ -9,8 +9,13 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: deploy: + permissions: + contents: write # for peaceiris/actions-gh-pages to push pages branch runs-on: ubuntu-latest steps: - uses: actions/checkout@v3.1.0 diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 24b18740f2..955bc796c5 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -15,6 +15,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: event_file: name: "Event File" @@ -26,6 +29,9 @@ jobs: name: Event File path: ${{ github.event_path }} lint-go: + permissions: + contents: read # for actions/checkout to fetch code + pull-requests: read # for golangci/golangci-lint-action to fetch pull requests name: Lint Go code runs-on: ubuntu-latest steps: diff --git a/.github/workflows/pr-title-check.yml b/.github/workflows/pr-title-check.yml index dd165bdf28..d24c6d268e 100644 --- a/.github/workflows/pr-title-check.yml +++ b/.github/workflows/pr-title-check.yml @@ -7,8 +7,14 @@ on: - edited - synchronize +permissions: + contents: read + jobs: main: + permissions: + pull-requests: read # for amannn/action-semantic-pull-request to analyze PRs + statuses: write # for amannn/action-semantic-pull-request to mark status of analyzed PR name: Validate PR title runs-on: ubuntu-latest steps: @@ -44,4 +50,4 @@ jobs: # Configure that a scope must always be provided. requireScope: false env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 43080842a0..f24bf75caf 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -6,6 +6,9 @@ on: tag: description: Git tag to build release from required: true +permissions: + contents: read + jobs: release-images: runs-on: ubuntu-latest @@ -94,6 +97,8 @@ jobs: release-artifacts: + permissions: + contents: write # for softprops/action-gh-release to create GitHub release runs-on: ubuntu-latest needs: release-images @@ -122,7 +127,7 @@ jobs: SIGS_BOM_VERSION: v0.2.1 # comma delimited list of project relative folders to inspect for package # managers (gomod, yarn, npm). - PROJECT_FOLDERS: ".,./ui" + PROJECT_FOLDERS: ".,./ui" # full qualified name of the docker image to be inspected DOCKER_IMAGE: quay.io/argoproj/argo-rollouts:${{ github.event.inputs.tag }} diff --git a/.github/workflows/stale-issues-pr.yml b/.github/workflows/stale-issues-pr.yml index 49e9590908..3cb789f394 100644 --- a/.github/workflows/stale-issues-pr.yml +++ b/.github/workflows/stale-issues-pr.yml @@ -3,6 +3,9 @@ on: schedule: - cron: '30 1 * * *' +permissions: + contents: read + jobs: stale: runs-on: ubuntu-latest diff --git a/.github/workflows/waiting-issues.yml b/.github/workflows/waiting-issues.yml index 4caed43734..f8c1a6cae8 100644 --- a/.github/workflows/waiting-issues.yml +++ b/.github/workflows/waiting-issues.yml @@ -3,6 +3,9 @@ on: schedule: - cron: '30 1 * * *' +permissions: + contents: read + jobs: stale: runs-on: ubuntu-latest From cf65be32312e220b76d5a236ae2c1fdb1e88c07f Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Tue, 18 Oct 2022 13:57:34 -0500 Subject: [PATCH 27/68] ci: add link to conventional pr check in pr template (#2346) Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- .github/pull_request_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 49d173bf0c..33da74335a 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,7 +1,7 @@ Checklist: * [ ] Either (a) I've created an [enhancement proposal](https://github.com/argoproj/argo-rollouts/issues/new/choose) and discussed it with the community, (b) this is a bug fix, or (c) this is a chore. -* [ ] The title of the PR is (a) [conventional](https://www.conventionalcommits.org/en/v1.0.0/), (b) states what changed, and (c) suffixes the related issues number. E.g. `"fix(controller): Updates such and such. Fixes #1234"`. +* [ ] The title of the PR is (a) [conventional](https://www.conventionalcommits.org/en/v1.0.0/) with a list of types and scopes found [here](https://github.com/argoproj/argo-rollouts/blob/master/.github/workflows/pr-title-check.yml), (b) states what changed, and (c) suffixes the related issues number. E.g. `"fix(controller): Updates such and such. Fixes #1234"`. * [ ] I've signed my commits with [DCO](https://github.com/argoproj/argoproj) * [ ] I have written unit and/or e2e tests for my change. PRs without these are unlikely to be merged. * [ ] My builds are green. Try syncing with master if they are not. From 8a7537c7346b036e5642df1904be05b43414b089 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Oct 2022 00:02:42 +0000 Subject: [PATCH 28/68] chore(deps): bump github.com/valyala/fasttemplate from 1.2.1 to 1.2.2 (#2348) Bumps [github.com/valyala/fasttemplate](https://github.com/valyala/fasttemplate) from 1.2.1 to 1.2.2. - [Release notes](https://github.com/valyala/fasttemplate/releases) - [Commits](https://github.com/valyala/fasttemplate/compare/v1.2.1...v1.2.2) --- updated-dependencies: - dependency-name: github.com/valyala/fasttemplate dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 4f6d91e586..c1d9ae838c 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,7 @@ require ( github.com/spf13/cobra v1.6.0 github.com/stretchr/testify v1.8.0 github.com/tj/assert v0.0.3 - github.com/valyala/fasttemplate v1.2.1 + github.com/valyala/fasttemplate v1.2.2 google.golang.org/genproto v0.0.0-20220712132514-bdd2acd4974d google.golang.org/grpc v1.50.1 google.golang.org/protobuf v1.28.1 diff --git a/go.sum b/go.sum index 7e9e65ac61..b79f2f2274 100644 --- a/go.sum +++ b/go.sum @@ -1017,8 +1017,9 @@ 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.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= 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= From 0d4271cb62d5a87473760ce7c07d7af1f5245daa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Oct 2022 00:02:49 +0000 Subject: [PATCH 29/68] chore(deps): bump github.com/prometheus/client_model from 0.2.0 to 0.3.0 (#2349) Bumps [github.com/prometheus/client_model](https://github.com/prometheus/client_model) from 0.2.0 to 0.3.0. - [Release notes](https://github.com/prometheus/client_model/releases) - [Commits](https://github.com/prometheus/client_model/compare/v0.2.0...v0.3.0) --- updated-dependencies: - dependency-name: github.com/prometheus/client_model dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index c1d9ae838c..10cfe102bc 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/newrelic/newrelic-client-go v1.1.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.12.2-0.20220620141757-4ad265f1b4ee - github.com/prometheus/client_model v0.2.0 + github.com/prometheus/client_model v0.3.0 github.com/prometheus/common v0.37.0 github.com/servicemeshinterface/smi-sdk-go v0.5.0 github.com/sirupsen/logrus v1.9.0 diff --git a/go.sum b/go.sum index b79f2f2274..aa02c9424d 100644 --- a/go.sum +++ b/go.sum @@ -878,8 +878,9 @@ github.com/prometheus/client_golang v1.12.2-0.20220620141757-4ad265f1b4ee/go.mod 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= -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/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= 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= From 3ad303274316d4055d3a6d4340793b6f63e7c0e2 Mon Sep 17 00:00:00 2001 From: Prema <107519450+premadk@users.noreply.github.com> Date: Wed, 19 Oct 2022 15:47:27 -0700 Subject: [PATCH 30/68] fix(metricprovider): Support jsonBody for web metric provider Fixes #2275 (#2312) * fix(issue2275): Support jsonBody for web metric provider Signed-off-by: Prema devi Kuppuswamy * fix(webmetrics): generate proto files Signed-off-by: Prema devi Kuppuswamy Signed-off-by: Prema devi Kuppuswamy Signed-off-by: Ariel Simhon --- docs/analysis/web.md | 31 +- .../features/kustomize/rollout_cr_schema.json | 12 + manifests/crds/analysis-run-crd.yaml | 3 + manifests/crds/analysis-template-crd.yaml | 3 + .../crds/cluster-analysis-template-crd.yaml | 3 + manifests/install.yaml | 9 + manifests/namespace-install.yaml | 9 + metricproviders/webmetric/webmetric.go | 29 +- metricproviders/webmetric/webmetric_test.go | 83 ++ pkg/apis/rollouts/v1alpha1/analysis_types.go | 8 +- pkg/apis/rollouts/v1alpha1/generated.pb.go | 994 +++++++++--------- pkg/apis/rollouts/v1alpha1/generated.proto | 8 +- .../rollouts/v1alpha1/openapi_generated.go | 9 +- .../v1alpha1/zz_generated.deepcopy.go | 7 + 14 files changed, 722 insertions(+), 486 deletions(-) diff --git a/docs/analysis/web.md b/docs/analysis/web.md index 285403ffe7..4572dbc4f2 100644 --- a/docs/analysis/web.md +++ b/docs/analysis/web.md @@ -50,7 +50,7 @@ to convert a result value to a numeric type so that mathematical comparison oper (e.g. >, <, >=, <=). ### Optional web methods -It is possible to use a POST or PUT requests, by specifying the `method` and `body` fields +It is possible to use a POST or PUT requests, by specifying the `method` and either `body` or `jsonBody` fields ```yaml metrics: @@ -66,9 +66,32 @@ It is possible to use a POST or PUT requests, by specifying the `method` and `bo value: "Bearer {{ args.api-token }}" - key: Content-Type # if body is a json, it is recommended to set the Content-Type value: "application/json" - body: "{\"key\": \"string value\"}" + body: "string value" jsonPath: "{$.data.ok}" ``` !!! tip - In order to send in JSON, you have to encode it yourself, and send the correct Content-Type as well. - Setting a `body` field for a `GET` request will result in an error. + In order to send in JSON, you can use jsonBody and Content-Type will be automatically set as json. + Setting a `body` or `jsonBody` field for a `GET` request will result in an error. + Set either `body` or `jsonBody` and setting both will result in an error. + +```yaml + metrics: + - name: webmetric + successCondition: result == true + provider: + web: + method: POST # valid values are GET|POST|PUT, defaults to GET + url: "http://my-server.com/api/v1/measurement?service={{ args.service-name }}" + timeoutSeconds: 20 # defaults to 10 seconds + headers: + - key: Authorization + value: "Bearer {{ args.api-token }}" + - key: Content-Type # if body is a json, it is recommended to set the Content-Type + value: "application/json" + jsonBody: # If using jsonBody Content-Type header will be automatically set to json + key1: value_1 + key2: + nestedObj: nested value + key3: "{{ args.service-name }}" + jsonPath: "{$.data.ok}" +``` \ No newline at end of file diff --git a/docs/features/kustomize/rollout_cr_schema.json b/docs/features/kustomize/rollout_cr_schema.json index 4ec83fccff..fbff809be6 100644 --- a/docs/features/kustomize/rollout_cr_schema.json +++ b/docs/features/kustomize/rollout_cr_schema.json @@ -4213,6 +4213,10 @@ "insecure": { "type": "boolean" }, + "jsonBody": { + "type": "object", + "x-kubernetes-preserve-unknown-fields": true + }, "jsonPath": { "type": "string" }, @@ -8477,6 +8481,10 @@ "insecure": { "type": "boolean" }, + "jsonBody": { + "type": "object", + "x-kubernetes-preserve-unknown-fields": true + }, "jsonPath": { "type": "string" }, @@ -12741,6 +12749,10 @@ "insecure": { "type": "boolean" }, + "jsonBody": { + "type": "object", + "x-kubernetes-preserve-unknown-fields": true + }, "jsonPath": { "type": "string" }, diff --git a/manifests/crds/analysis-run-crd.yaml b/manifests/crds/analysis-run-crd.yaml index 962db250b3..da21888bde 100644 --- a/manifests/crds/analysis-run-crd.yaml +++ b/manifests/crds/analysis-run-crd.yaml @@ -2732,6 +2732,9 @@ spec: type: array insecure: type: boolean + jsonBody: + type: object + x-kubernetes-preserve-unknown-fields: true jsonPath: type: string method: diff --git a/manifests/crds/analysis-template-crd.yaml b/manifests/crds/analysis-template-crd.yaml index 54aad4b66f..1e37db2dd0 100644 --- a/manifests/crds/analysis-template-crd.yaml +++ b/manifests/crds/analysis-template-crd.yaml @@ -2728,6 +2728,9 @@ spec: type: array insecure: type: boolean + jsonBody: + type: object + x-kubernetes-preserve-unknown-fields: true jsonPath: type: string method: diff --git a/manifests/crds/cluster-analysis-template-crd.yaml b/manifests/crds/cluster-analysis-template-crd.yaml index 1551b9d114..fb149f2fa3 100644 --- a/manifests/crds/cluster-analysis-template-crd.yaml +++ b/manifests/crds/cluster-analysis-template-crd.yaml @@ -2728,6 +2728,9 @@ spec: type: array insecure: type: boolean + jsonBody: + type: object + x-kubernetes-preserve-unknown-fields: true jsonPath: type: string method: diff --git a/manifests/install.yaml b/manifests/install.yaml index aca39e1c88..04475b6a8a 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -2733,6 +2733,9 @@ spec: type: array insecure: type: boolean + jsonBody: + type: object + x-kubernetes-preserve-unknown-fields: true jsonPath: type: string method: @@ -5607,6 +5610,9 @@ spec: type: array insecure: type: boolean + jsonBody: + type: object + x-kubernetes-preserve-unknown-fields: true jsonPath: type: string method: @@ -8367,6 +8373,9 @@ spec: type: array insecure: type: boolean + jsonBody: + type: object + x-kubernetes-preserve-unknown-fields: true jsonPath: type: string method: diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 07ffc9e787..bfca8940be 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -2733,6 +2733,9 @@ spec: type: array insecure: type: boolean + jsonBody: + type: object + x-kubernetes-preserve-unknown-fields: true jsonPath: type: string method: @@ -5607,6 +5610,9 @@ spec: type: array insecure: type: boolean + jsonBody: + type: object + x-kubernetes-preserve-unknown-fields: true jsonPath: type: string method: @@ -8367,6 +8373,9 @@ spec: type: array insecure: type: boolean + jsonBody: + type: object + x-kubernetes-preserve-unknown-fields: true jsonPath: type: string method: diff --git a/metricproviders/webmetric/webmetric.go b/metricproviders/webmetric/webmetric.go index f1b215de81..dce1865e5a 100644 --- a/metricproviders/webmetric/webmetric.go +++ b/metricproviders/webmetric/webmetric.go @@ -1,6 +1,7 @@ package webmetric import ( + "bytes" "crypto/tls" "encoding/json" "errors" @@ -23,7 +24,9 @@ import ( const ( // ProviderType indicates the provider is a web metric - ProviderType = "Web" + ProviderType = "Web" + ContentTypeKey = "Content-Type" + ContentTypeJsonValue = "application/json" ) // Provider contains all the required components to run a WebMetric query @@ -59,14 +62,25 @@ func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alph url := metric.Provider.Web.URL + stringBody := metric.Provider.Web.Body + jsonBody := metric.Provider.Web.JSONBody + var body io.Reader - if metric.Provider.Web.Body != "" { - if method == v1alpha1.WebMetricMethodGet { - return metricutil.MarkMeasurementError(measurement, fmt.Errorf("Body can only be used with POST or PUT WebMetric Method types")) - } + if stringBody != "" && jsonBody != nil { + return metricutil.MarkMeasurementError(measurement, fmt.Errorf("use either Body or JSONBody; both cannot exists for WebMetric payload")) + } else if (stringBody != "" || jsonBody != nil) && method == v1alpha1.WebMetricMethodGet { + return metricutil.MarkMeasurementError(measurement, fmt.Errorf("Body/JSONBody can only be used with POST or PUT WebMetric Method types")) + } - body = strings.NewReader(metric.Provider.Web.Body) + if stringBody != "" { + body = strings.NewReader(stringBody) + } else if jsonBody != nil { + bodyBytes, err := jsonBody.MarshalJSON() + if err != nil { + return metricutil.MarkMeasurementError(measurement, err) + } + body = bytes.NewBuffer(bodyBytes) } // Create request @@ -80,6 +94,9 @@ func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alph for _, header := range metric.Provider.Web.Headers { request.Header.Set(header.Key, header.Value) } + if jsonBody != nil { + request.Header.Set(ContentTypeKey, ContentTypeJsonValue) + } // Send Request response, err := p.client.Do(request) diff --git a/metricproviders/webmetric/webmetric_test.go b/metricproviders/webmetric/webmetric_test.go index 66861478f5..5ec0422ce1 100644 --- a/metricproviders/webmetric/webmetric_test.go +++ b/metricproviders/webmetric/webmetric_test.go @@ -2,6 +2,7 @@ package webmetric import ( "bytes" + "encoding/json" "io" "net/http" "net/http/httptest" @@ -23,6 +24,7 @@ func TestRunSuite(t *testing.T) { expectedValue string expectedPhase v1alpha1.AnalysisPhase expectedErrorMessage string + expectedJsonBody string }{ // When_noJSONPathSpecified_And_MatchesConditions_Then_Succeed { @@ -574,6 +576,81 @@ func TestRunSuite(t *testing.T) { expectedValue: "Body can only be used with POST or PUT WebMetric Method types", expectedPhase: v1alpha1.AnalysisPhaseError, }, + // When_methodPOST_Then_server_gets_jsonBody_Then_Succeed + { + webServerStatus: 200, + webServerResponse: `{"a": 1, "b": true, "c": [1, 2, 3, 4], "d": null}`, + metric: v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result.a > 0 && result.b && all(result.c, {# < 5}) && result.d == nil", + Provider: v1alpha1.MetricProvider{ + Web: &v1alpha1.WebMetric{ + Method: v1alpha1.WebMetricMethodPost, + // URL: server.URL, + Headers: []v1alpha1.WebMetricHeader{{Key: "key", Value: "value"}}, + JSONBody: json.RawMessage(`{"key1": "value1", "key2": "value2"}`), + }, + }, + }, + expectedMethod: "POST", + expectedJsonBody: `{"key1": "value1", "key2": "value2"}`, + expectedValue: `{"a":1,"b":true,"c":[1,2,3,4],"d":null}`, + expectedPhase: v1alpha1.AnalysisPhaseSuccessful, + }, + // When_methodPUT_Then_server_gets_jsonBody_Then_Succeed + { + webServerStatus: 200, + webServerResponse: `{"a": 1, "b": true, "c": [1, 2, 3, 4], "d": null}`, + metric: v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result.a > 0 && result.b && all(result.c, {# < 5}) && result.d == nil", + Provider: v1alpha1.MetricProvider{ + Web: &v1alpha1.WebMetric{ + Method: v1alpha1.WebMetricMethodPut, + // URL: server.URL, + Headers: []v1alpha1.WebMetricHeader{{Key: "key", Value: "value"}, {Key: ContentTypeKey, Value: ContentTypeJsonValue}}, + JSONBody: json.RawMessage(`{"key1": "value1", "key2": { "key3" : "value3"}}`), + }, + }, + }, + expectedMethod: "PUT", + expectedJsonBody: `{"key1": "value1", "key2": { "key3" : "value3"}}`, + expectedValue: `{"a":1,"b":true,"c":[1,2,3,4],"d":null}`, + expectedPhase: v1alpha1.AnalysisPhaseSuccessful, + }, + // When_sendingJsonBodyWithGet_Then_Failure + { + metric: v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result.a > 0 && result.b && all(result.c, {# < 5}) && result.d == nil", + Provider: v1alpha1.MetricProvider{ + Web: &v1alpha1.WebMetric{ + // URL: server.URL, + Headers: []v1alpha1.WebMetricHeader{{Key: "key", Value: "value"}}, + JSONBody: json.RawMessage(`{"key1": "value1", "key2": { "key3" : "value3"}}`), + }, + }, + }, + expectedValue: "Body/JSONBody can only be used with POST or PUT WebMetric Method types", + expectedPhase: v1alpha1.AnalysisPhaseError, + }, + // When_sending_BothBodyAndJsonBodyWithGet_Then_Failure + { + metric: v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result.a > 0 && result.b && all(result.c, {# < 5}) && result.d == nil", + Provider: v1alpha1.MetricProvider{ + Web: &v1alpha1.WebMetric{ + // URL: server.URL, + Headers: []v1alpha1.WebMetricHeader{{Key: "key", Value: "value"}}, + JSONBody: json.RawMessage(`{"key1": "value1", "key2": { "key3" : "value3"}}`), + Body: "test body", + }, + }, + }, + expectedValue: "use either Body or JSONBody; both cannot exists for WebMetric payload", + expectedPhase: v1alpha1.AnalysisPhaseError, + }, } // Run @@ -591,6 +668,12 @@ func TestRunSuite(t *testing.T) { assert.Equal(t, test.expectedBody, buf.String()) } + if test.expectedJsonBody != "" { + bodyBytes, _ := io.ReadAll(req.Body) + assert.Equal(t, test.expectedJsonBody, string(bodyBytes)) + assert.Equal(t, ContentTypeJsonValue, req.Header.Get(ContentTypeKey)) + } + if test.webServerStatus < 200 || test.webServerStatus >= 300 { http.Error(rw, http.StatusText(test.webServerStatus), test.webServerStatus) } else { diff --git a/pkg/apis/rollouts/v1alpha1/analysis_types.go b/pkg/apis/rollouts/v1alpha1/analysis_types.go index 7d5931e458..f26fc91585 100644 --- a/pkg/apis/rollouts/v1alpha1/analysis_types.go +++ b/pkg/apis/rollouts/v1alpha1/analysis_types.go @@ -1,6 +1,7 @@ package v1alpha1 import ( + "encoding/json" "time" intstrutil "k8s.io/apimachinery/pkg/util/intstr" @@ -477,7 +478,7 @@ type WebMetric struct { // +patchStrategy=merge // Headers are optional HTTP headers to use in the request Headers []WebMetricHeader `json:"headers,omitempty" patchStrategy:"merge" patchMergeKey:"key" protobuf:"bytes,3,rep,name=headers"` - // Body is the body of the we metric (must be POST/PUT) + // Body is the body of the web metric (must be POST/PUT) Body string `json:"body,omitempty" protobuf:"bytes,4,opt,name=body"` // TimeoutSeconds is the timeout for the request in seconds (default: 10) TimeoutSeconds int64 `json:"timeoutSeconds,omitempty" protobuf:"varint,5,opt,name=timeoutSeconds"` @@ -485,6 +486,11 @@ type WebMetric struct { JSONPath string `json:"jsonPath,omitempty" protobuf:"bytes,6,opt,name=jsonPath"` // Insecure skips host TLS verification Insecure bool `json:"insecure,omitempty" protobuf:"varint,7,opt,name=insecure"` + // +kubebuilder:validation:Schemaless + // +kubebuilder:pruning:PreserveUnknownFields + // +kubebuilder:validation:Type=object + // JSONBody is the body of the web metric in a json format (method must be POST/PUT) + JSONBody json.RawMessage `json:"jsonBody,omitempty" protobuf:"bytes,8,opt,name=jsonBody,casttype=encoding/json.RawMessage"` } // WebMetricMethod is the available HTTP methods diff --git a/pkg/apis/rollouts/v1alpha1/generated.pb.go b/pkg/apis/rollouts/v1alpha1/generated.pb.go index ddb670b7e1..1b57b69024 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.pb.go +++ b/pkg/apis/rollouts/v1alpha1/generated.pb.go @@ -3084,481 +3084,483 @@ func init() { } var fileDescriptor_e0e705f843545fab = []byte{ - // 7571 bytes of a gzipped FileDescriptorProto + // 7605 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, 0x48, 0xab, 0x9f, 0xbb, 0xda, 0xac, 0x2c, 0x7b, 0x97, 0xce, - 0x38, 0xf0, 0xe7, 0x7c, 0x9f, 0x23, 0x25, 0xfe, 0xf9, 0x3e, 0x27, 0x36, 0xfc, 0x95, 0x94, 0x76, - 0xbd, 0x5a, 0x4b, 0xbb, 0xdc, 0x4b, 0xed, 0x6e, 0xe2, 0xc4, 0x49, 0x46, 0xe4, 0x15, 0x35, 0xbb, - 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, 0x90, 0x22, 0x29, 0xd0, 0x26, 0x29, 0x10, 0xb6, 0x56, 0xfa, 0xd2, 0xa2, 0x45, - 0x50, 0x20, 0x45, 0x91, 0x7d, 0x2a, 0xee, 0xef, 0xdc, 0x19, 0x0e, 0x25, 0x52, 0x1c, 0x6d, 0x8c, - 0x36, 0x6f, 0xe4, 0x3d, 0xe7, 0x9e, 0x73, 0xff, 0xcf, 0xb9, 0xe7, 0x9e, 0x73, 0x06, 0xd6, 0x1b, - 0x76, 0xb0, 0xd3, 0xd9, 0x5a, 0xaa, 0xb9, 0xad, 0x65, 0xcb, 0x6b, 0xb8, 0x6d, 0xcf, 0xbd, 0xc1, - 0x7e, 0xbc, 0xcb, 0x73, 0x9b, 0x4d, 0xb7, 0x13, 0xf8, 0xcb, 0xed, 0x9b, 0x8d, 0x65, 0xab, 0x6d, - 0xfb, 0xcb, 0xaa, 0x64, 0xf7, 0x3d, 0x56, 0xb3, 0xbd, 0x63, 0xbd, 0x67, 0xb9, 0x41, 0x1c, 0xe2, - 0x59, 0x01, 0xa9, 0x2f, 0xb5, 0x3d, 0x37, 0x70, 0xd1, 0xd3, 0x21, 0xb5, 0x25, 0x49, 0x8d, 0xfd, - 0xf8, 0x88, 0xac, 0xbb, 0xd4, 0xbe, 0xd9, 0x58, 0xa2, 0xd4, 0x96, 0x54, 0x89, 0xa4, 0xb6, 0xf8, - 0x2e, 0xad, 0x2d, 0x0d, 0xb7, 0xe1, 0x2e, 0x33, 0xa2, 0x5b, 0x9d, 0x6d, 0xf6, 0x8f, 0xfd, 0x61, - 0xbf, 0x38, 0xb3, 0xc5, 0x07, 0x6f, 0x3e, 0xe9, 0x2f, 0xd9, 0x2e, 0x6d, 0xdb, 0xf2, 0x96, 0x15, - 0xd4, 0x76, 0x96, 0x77, 0x7b, 0x5a, 0xb4, 0x68, 0x6a, 0x48, 0x35, 0xd7, 0x23, 0x49, 0x38, 0x8f, - 0x87, 0x38, 0x2d, 0xab, 0xb6, 0x63, 0x3b, 0xc4, 0xdb, 0x0b, 0x7b, 0xdd, 0x22, 0x81, 0x95, 0x54, - 0x6b, 0xb9, 0x5f, 0x2d, 0xaf, 0xe3, 0x04, 0x76, 0x8b, 0xf4, 0x54, 0xf8, 0xbf, 0x87, 0x55, 0xf0, - 0x6b, 0x3b, 0xa4, 0x65, 0xf5, 0xd4, 0x7b, 0xac, 0x5f, 0xbd, 0x4e, 0x60, 0x37, 0x97, 0x6d, 0x27, - 0xf0, 0x03, 0x2f, 0x5e, 0xc9, 0xfc, 0x46, 0x16, 0x0a, 0xa5, 0xf5, 0x72, 0x35, 0xb0, 0x82, 0x8e, - 0x8f, 0x5e, 0x33, 0x60, 0xaa, 0xe9, 0x5a, 0xf5, 0xb2, 0xd5, 0xb4, 0x9c, 0x1a, 0xf1, 0x16, 0x8c, - 0x07, 0x8c, 0x87, 0x27, 0x1f, 0x5d, 0x5f, 0x1a, 0x65, 0xbe, 0x96, 0x4a, 0xb7, 0x7c, 0x4c, 0x7c, - 0xb7, 0xe3, 0xd5, 0x08, 0x26, 0xdb, 0xe5, 0xf9, 0x6f, 0x77, 0x8b, 0xf7, 0xec, 0x77, 0x8b, 0x53, - 0xeb, 0x1a, 0x27, 0x1c, 0xe1, 0x8b, 0xbe, 0x68, 0xc0, 0x5c, 0xcd, 0x72, 0x2c, 0x6f, 0x6f, 0xd3, - 0xf2, 0x1a, 0x24, 0x78, 0xd6, 0x73, 0x3b, 0xed, 0x85, 0xcc, 0x31, 0xb4, 0xe6, 0x5e, 0xd1, 0x9a, - 0xb9, 0x95, 0x38, 0x3b, 0xdc, 0xdb, 0x02, 0xd6, 0x2e, 0x3f, 0xb0, 0xb6, 0x9a, 0x44, 0x6f, 0x57, - 0xf6, 0x38, 0xdb, 0x55, 0x8d, 0xb3, 0xc3, 0xbd, 0x2d, 0x30, 0x5f, 0xcd, 0xc2, 0x5c, 0x69, 0xbd, - 0xbc, 0xe9, 0x59, 0xdb, 0xdb, 0x76, 0x0d, 0xbb, 0x9d, 0xc0, 0x76, 0x1a, 0xe8, 0x9d, 0x30, 0x61, - 0x3b, 0x0d, 0x8f, 0xf8, 0x3e, 0x9b, 0xc8, 0x42, 0x79, 0x46, 0x10, 0x9d, 0x58, 0xe3, 0xc5, 0x58, - 0xc2, 0xd1, 0x13, 0x30, 0xe9, 0x13, 0x6f, 0xd7, 0xae, 0x91, 0x8a, 0xeb, 0x05, 0x6c, 0xa4, 0x73, - 0xe5, 0x93, 0x02, 0x7d, 0xb2, 0x1a, 0x82, 0xb0, 0x8e, 0x47, 0xab, 0x79, 0xae, 0x1b, 0x08, 0x38, - 0x1b, 0x88, 0x42, 0x58, 0x0d, 0x87, 0x20, 0xac, 0xe3, 0xa1, 0xd7, 0x0d, 0x98, 0xf5, 0x03, 0xbb, - 0x76, 0xd3, 0x76, 0x88, 0xef, 0xaf, 0xb8, 0xce, 0xb6, 0xdd, 0x58, 0xc8, 0xb1, 0x51, 0xbc, 0x34, - 0xda, 0x28, 0x56, 0x63, 0x54, 0xcb, 0xf3, 0xfb, 0xdd, 0xe2, 0x6c, 0xbc, 0x14, 0xf7, 0x70, 0x47, - 0xab, 0x30, 0x6b, 0x39, 0x8e, 0x1b, 0x58, 0x81, 0xed, 0x3a, 0x15, 0x8f, 0x6c, 0xdb, 0xb7, 0x17, - 0xc6, 0x58, 0x77, 0x16, 0x44, 0x77, 0x66, 0x4b, 0x31, 0x38, 0xee, 0xa9, 0x61, 0xae, 0xc2, 0x42, - 0xa9, 0xb5, 0x65, 0xf9, 0xbe, 0x55, 0x77, 0xbd, 0xd8, 0x6c, 0x3c, 0x0c, 0xf9, 0x96, 0xd5, 0x6e, - 0xdb, 0x4e, 0x83, 0x4e, 0x47, 0xf6, 0xe1, 0x42, 0x79, 0x6a, 0xbf, 0x5b, 0xcc, 0x6f, 0x88, 0x32, - 0xac, 0xa0, 0xe6, 0x0f, 0x33, 0x30, 0x59, 0x72, 0xac, 0xe6, 0x9e, 0x6f, 0xfb, 0xb8, 0xe3, 0xa0, - 0x8f, 0x42, 0x9e, 0x9e, 0x2e, 0x75, 0x2b, 0xb0, 0xc4, 0x8e, 0x7c, 0xf7, 0x12, 0xdf, 0xec, 0x4b, - 0xfa, 0x66, 0x0f, 0xc7, 0x85, 0x62, 0x2f, 0xed, 0xbe, 0x67, 0xe9, 0xf2, 0xd6, 0x0d, 0x52, 0x0b, - 0x36, 0x48, 0x60, 0x95, 0x91, 0xe8, 0x05, 0x84, 0x65, 0x58, 0x51, 0x45, 0x2e, 0x8c, 0xf9, 0x6d, - 0x52, 0x13, 0x3b, 0x6c, 0x63, 0xc4, 0x95, 0x1c, 0x36, 0xbd, 0xda, 0x26, 0xb5, 0xf2, 0x94, 0x60, - 0x3d, 0x46, 0xff, 0x61, 0xc6, 0x08, 0xdd, 0x82, 0x71, 0x9f, 0x9d, 0x39, 0x62, 0xf3, 0x5c, 0x4e, - 0x8f, 0x25, 0x23, 0x5b, 0x9e, 0x16, 0x4c, 0xc7, 0xf9, 0x7f, 0x2c, 0xd8, 0x99, 0x7f, 0x6f, 0xc0, - 0x49, 0x0d, 0xbb, 0xe4, 0x35, 0x3a, 0x2d, 0xe2, 0x04, 0xe8, 0x01, 0x18, 0x73, 0xac, 0x16, 0x11, - 0x1b, 0x45, 0x35, 0xf9, 0x92, 0xd5, 0x22, 0x98, 0x41, 0xd0, 0x83, 0x90, 0xdb, 0xb5, 0x9a, 0x1d, - 0xc2, 0x06, 0xa9, 0x50, 0x3e, 0x21, 0x50, 0x72, 0xd7, 0x68, 0x21, 0xe6, 0x30, 0xf4, 0x12, 0x14, - 0xd8, 0x8f, 0xf3, 0x9e, 0xdb, 0x4a, 0xa9, 0x6b, 0xa2, 0x85, 0xd7, 0x24, 0xd9, 0xf2, 0x89, 0xfd, - 0x6e, 0xb1, 0xa0, 0xfe, 0xe2, 0x90, 0xa1, 0xf9, 0x0f, 0x06, 0xcc, 0x68, 0x9d, 0x5b, 0xb7, 0xfd, - 0x00, 0x7d, 0xa8, 0x67, 0xf1, 0x2c, 0x0d, 0xb6, 0x78, 0x68, 0x6d, 0xb6, 0x74, 0x66, 0x45, 0x4f, - 0xf3, 0xb2, 0x44, 0x5b, 0x38, 0x0e, 0xe4, 0xec, 0x80, 0xb4, 0xfc, 0x85, 0xcc, 0x03, 0xd9, 0x87, - 0x27, 0x1f, 0x5d, 0x4b, 0x6d, 0x1a, 0xc3, 0xf1, 0x5d, 0xa3, 0xf4, 0x31, 0x67, 0x63, 0x7e, 0x75, - 0x2c, 0xd2, 0x43, 0xba, 0xa2, 0x90, 0x0b, 0x13, 0x2d, 0x12, 0x78, 0x76, 0x8d, 0xef, 0xab, 0xc9, - 0x47, 0x57, 0x47, 0x6b, 0xc5, 0x06, 0x23, 0x16, 0x1e, 0x96, 0xfc, 0xbf, 0x8f, 0x25, 0x17, 0xb4, - 0x03, 0x63, 0x96, 0xd7, 0x90, 0x7d, 0x3e, 0x9f, 0xce, 0xfc, 0x86, 0x6b, 0xae, 0xe4, 0x35, 0x7c, - 0xcc, 0x38, 0xa0, 0x65, 0x28, 0x04, 0xc4, 0x6b, 0xd9, 0x8e, 0x15, 0xf0, 0xd3, 0x35, 0x5f, 0x9e, - 0x13, 0x68, 0x85, 0x4d, 0x09, 0xc0, 0x21, 0x0e, 0x6a, 0xc2, 0x78, 0xdd, 0xdb, 0xc3, 0x1d, 0x67, - 0x61, 0x2c, 0x8d, 0xa1, 0x58, 0x65, 0xb4, 0xc2, 0xcd, 0xc4, 0xff, 0x63, 0xc1, 0x03, 0xbd, 0x61, - 0xc0, 0x7c, 0x8b, 0x58, 0x7e, 0xc7, 0x23, 0xb4, 0x0b, 0x98, 0x04, 0xc4, 0xa1, 0xa7, 0xe1, 0x42, - 0x8e, 0x31, 0xc7, 0xa3, 0xce, 0x43, 0x2f, 0xe5, 0xf2, 0xfd, 0xa2, 0x29, 0xf3, 0x49, 0x50, 0x9c, - 0xd8, 0x1a, 0xf3, 0x87, 0x63, 0x30, 0xd7, 0x73, 0x42, 0xa0, 0xc7, 0x21, 0xd7, 0xde, 0xb1, 0x7c, - 0xb9, 0xe5, 0xcf, 0xca, 0xf5, 0x56, 0xa1, 0x85, 0x77, 0xba, 0xc5, 0x13, 0xb2, 0x0a, 0x2b, 0xc0, - 0x1c, 0x99, 0xca, 0xd4, 0x16, 0xf1, 0x7d, 0xab, 0x21, 0xcf, 0x01, 0x6d, 0x99, 0xb0, 0x62, 0x2c, - 0xe1, 0xe8, 0x57, 0x0c, 0x38, 0xc1, 0x97, 0x0c, 0x26, 0x7e, 0xa7, 0x19, 0xd0, 0xb3, 0x8e, 0x0e, - 0xcb, 0xc5, 0x34, 0x96, 0x27, 0x27, 0x59, 0x3e, 0x25, 0xb8, 0x9f, 0xd0, 0x4b, 0x7d, 0x1c, 0xe5, - 0x8b, 0xae, 0x43, 0xc1, 0x0f, 0x2c, 0x2f, 0x20, 0xf5, 0x52, 0xc0, 0xa4, 0xda, 0xe4, 0xa3, 0xff, - 0x7b, 0xb0, 0x43, 0x60, 0xd3, 0x6e, 0x11, 0x7e, 0xe0, 0x54, 0x25, 0x01, 0x1c, 0xd2, 0x42, 0x2f, - 0x01, 0x78, 0x1d, 0xa7, 0xda, 0x69, 0xb5, 0x2c, 0x6f, 0x4f, 0x48, 0xf0, 0x0b, 0xa3, 0x75, 0x0f, - 0x2b, 0x7a, 0xa1, 0xcc, 0x0a, 0xcb, 0xb0, 0xc6, 0x0f, 0xbd, 0x62, 0xc0, 0x09, 0xbe, 0x12, 0x65, - 0x0b, 0xc6, 0x53, 0x6e, 0xc1, 0x1c, 0x1d, 0xda, 0x55, 0x9d, 0x05, 0x8e, 0x72, 0x34, 0xff, 0x36, - 0x2a, 0x4f, 0xaa, 0x01, 0xd5, 0xae, 0x1b, 0x7b, 0xe8, 0x83, 0x70, 0xaf, 0xdf, 0xa9, 0xd5, 0x88, - 0xef, 0x6f, 0x77, 0x9a, 0xb8, 0xe3, 0x5c, 0xb0, 0xfd, 0xc0, 0xf5, 0xf6, 0xd6, 0xed, 0x96, 0x1d, - 0xb0, 0x15, 0x97, 0x2b, 0x9f, 0xd9, 0xef, 0x16, 0xef, 0xad, 0xf6, 0x43, 0xc2, 0xfd, 0xeb, 0x23, - 0x0b, 0xee, 0xeb, 0x38, 0xfd, 0xc9, 0x73, 0xed, 0xad, 0xb8, 0xdf, 0x2d, 0xde, 0x77, 0xb5, 0x3f, - 0x1a, 0x3e, 0x88, 0x86, 0xf9, 0x2f, 0x06, 0xcc, 0xca, 0x7e, 0x6d, 0x92, 0x56, 0xbb, 0x49, 0x4f, - 0x97, 0xe3, 0x57, 0x44, 0x82, 0x88, 0x22, 0x82, 0xd3, 0x11, 0x27, 0xb2, 0xfd, 0xfd, 0xb4, 0x11, - 0xf3, 0x9f, 0x0d, 0x98, 0x8f, 0x23, 0xdf, 0x05, 0xe1, 0xe9, 0x47, 0x85, 0xe7, 0xa5, 0x74, 0x7b, - 0xdb, 0x47, 0x82, 0xbe, 0x36, 0xd6, 0xdb, 0xd7, 0xff, 0xee, 0x62, 0x34, 0x94, 0x8a, 0xd9, 0x9f, - 0xa7, 0x54, 0x1c, 0x7b, 0x4b, 0x49, 0xc5, 0xdf, 0x1f, 0x83, 0xa9, 0x92, 0x13, 0xd8, 0xa5, 0xed, - 0x6d, 0xdb, 0xb1, 0x83, 0x3d, 0xf4, 0x99, 0x0c, 0x2c, 0xb7, 0x3d, 0xb2, 0x4d, 0x3c, 0x8f, 0xd4, - 0x57, 0x3b, 0x9e, 0xed, 0x34, 0xaa, 0xb5, 0x1d, 0x52, 0xef, 0x34, 0x6d, 0xa7, 0xb1, 0xd6, 0x70, - 0x5c, 0x55, 0x7c, 0xee, 0x36, 0xa9, 0x75, 0x58, 0x97, 0xf8, 0xa6, 0x68, 0x8d, 0xd6, 0xa5, 0xca, - 0x70, 0x4c, 0xcb, 0x8f, 0xed, 0x77, 0x8b, 0xcb, 0x43, 0x56, 0xc2, 0xc3, 0x76, 0x0d, 0x7d, 0x3a, - 0x03, 0x4b, 0x1e, 0xf9, 0x58, 0xc7, 0x1e, 0x7c, 0x34, 0xf8, 0xa9, 0xd5, 0x1c, 0x51, 0xfc, 0x0c, - 0xc5, 0xb3, 0xfc, 0xe8, 0x7e, 0xb7, 0x38, 0x64, 0x1d, 0x3c, 0x64, 0xbf, 0xcc, 0xaf, 0x67, 0xe0, - 0x54, 0xa9, 0xdd, 0xde, 0x20, 0xfe, 0x4e, 0xec, 0x52, 0xfb, 0x39, 0x03, 0xa6, 0x77, 0x6d, 0x2f, - 0xe8, 0x58, 0x4d, 0x69, 0x04, 0xe0, 0x4b, 0xa2, 0x3a, 0xe2, 0x76, 0xe6, 0xdc, 0xae, 0x45, 0x48, - 0x97, 0xd1, 0x7e, 0xb7, 0x38, 0x1d, 0x2d, 0xc3, 0x31, 0xf6, 0xe8, 0x37, 0x0d, 0x98, 0x15, 0x45, - 0x97, 0xdc, 0x3a, 0xd1, 0x2d, 0x47, 0x57, 0xd3, 0x6c, 0x93, 0x22, 0xce, 0x4d, 0x0c, 0xf1, 0x52, - 0xdc, 0xd3, 0x08, 0xf3, 0xdf, 0x32, 0x70, 0xba, 0x0f, 0x0d, 0xf4, 0x7b, 0x06, 0xcc, 0x73, 0x73, - 0x93, 0x06, 0xc2, 0x64, 0x5b, 0x8c, 0xe6, 0x07, 0xd2, 0x6e, 0x39, 0xa6, 0x7b, 0x81, 0x38, 0x35, - 0x52, 0x5e, 0xa0, 0xc7, 0xc6, 0x4a, 0x02, 0x6b, 0x9c, 0xd8, 0x20, 0xd6, 0x52, 0x6e, 0x80, 0x8a, - 0xb5, 0x34, 0x73, 0x57, 0x5a, 0x5a, 0x4d, 0x60, 0x8d, 0x13, 0x1b, 0x64, 0xfe, 0x7f, 0xb8, 0xef, - 0x00, 0x72, 0x87, 0xdf, 0xf8, 0xcd, 0x17, 0xd4, 0xaa, 0x8f, 0xae, 0xb9, 0x01, 0x8c, 0x05, 0x26, - 0x8c, 0x7b, 0x6e, 0x27, 0x20, 0x5c, 0xba, 0x15, 0xca, 0x40, 0xe5, 0x04, 0x66, 0x25, 0x58, 0x40, - 0xcc, 0xaf, 0x1b, 0x90, 0x1f, 0xc2, 0xfe, 0x50, 0x8c, 0xda, 0x1f, 0x0a, 0x3d, 0xb6, 0x87, 0xa0, - 0xd7, 0xf6, 0xf0, 0xec, 0x68, 0xb3, 0x31, 0x88, 0xcd, 0xe1, 0x27, 0x06, 0xcc, 0xf5, 0xd8, 0x28, - 0xd0, 0x0e, 0xcc, 0xb7, 0xdd, 0xba, 0xd4, 0x2f, 0x2e, 0x58, 0xfe, 0x0e, 0x83, 0x89, 0xee, 0x3d, - 0x4e, 0x67, 0xb2, 0x92, 0x00, 0xbf, 0xd3, 0x2d, 0x2e, 0x28, 0x22, 0x31, 0x04, 0x9c, 0x48, 0x11, - 0xb5, 0x21, 0xbf, 0x6d, 0x93, 0x66, 0x3d, 0x5c, 0x82, 0x23, 0x6a, 0x12, 0xe7, 0x05, 0x35, 0x6e, - 0x9e, 0x93, 0xff, 0xb0, 0xe2, 0x62, 0x5e, 0x81, 0xe9, 0xa8, 0xb1, 0x76, 0x80, 0xc9, 0x3b, 0x03, - 0x59, 0xcb, 0x73, 0xc4, 0xd4, 0x4d, 0x0a, 0x84, 0x6c, 0x09, 0x5f, 0xc2, 0xb4, 0xdc, 0xfc, 0xd9, - 0x18, 0xcc, 0x94, 0x9b, 0x1d, 0xf2, 0xac, 0x47, 0x88, 0xbc, 0x9f, 0x96, 0x60, 0xa6, 0xed, 0x91, - 0x5d, 0x9b, 0xdc, 0xaa, 0x92, 0x26, 0xa9, 0x05, 0xae, 0x27, 0xe8, 0x9f, 0x16, 0xd5, 0x67, 0x2a, - 0x51, 0x30, 0x8e, 0xe3, 0xa3, 0x67, 0x60, 0xda, 0xaa, 0x05, 0xf6, 0x2e, 0x51, 0x14, 0x78, 0x03, - 0xde, 0x26, 0x28, 0x4c, 0x97, 0x22, 0x50, 0x1c, 0xc3, 0x46, 0x1f, 0x82, 0x05, 0xbf, 0x66, 0x35, - 0xc9, 0xd5, 0xb6, 0x60, 0xb5, 0xb2, 0x43, 0x6a, 0x37, 0x2b, 0xae, 0xed, 0x04, 0xc2, 0x1a, 0xf1, - 0x80, 0xa0, 0xb4, 0x50, 0xed, 0x83, 0x87, 0xfb, 0x52, 0x40, 0x7f, 0x66, 0xc0, 0x99, 0xb6, 0x47, - 0x2a, 0x9e, 0xdb, 0x72, 0xa9, 0x98, 0xe9, 0xb9, 0xa2, 0x8b, 0xab, 0xea, 0xb5, 0x11, 0xe5, 0x29, - 0x2f, 0xe9, 0x35, 0x11, 0xbe, 0x7d, 0xbf, 0x5b, 0x3c, 0x53, 0x39, 0xa8, 0x01, 0xf8, 0xe0, 0xf6, - 0xa1, 0xbf, 0x30, 0xe0, 0x6c, 0xdb, 0xf5, 0x83, 0x03, 0xba, 0x90, 0x3b, 0xd6, 0x2e, 0x98, 0xfb, - 0xdd, 0xe2, 0xd9, 0xca, 0x81, 0x2d, 0xc0, 0x87, 0xb4, 0xd0, 0xdc, 0x9f, 0x84, 0x39, 0x6d, 0xed, - 0x89, 0xfb, 0xeb, 0x53, 0x70, 0x42, 0x2e, 0x86, 0x50, 0xac, 0x17, 0x42, 0x7b, 0x43, 0x49, 0x07, - 0xe2, 0x28, 0x2e, 0x5d, 0x77, 0x6a, 0x29, 0xf2, 0xda, 0xb1, 0x75, 0x57, 0x89, 0x40, 0x71, 0x0c, - 0x1b, 0xad, 0xc1, 0x49, 0x51, 0x82, 0x49, 0xbb, 0x69, 0xd7, 0xac, 0x15, 0xb7, 0x23, 0x96, 0x5c, - 0xae, 0x7c, 0x7a, 0xbf, 0x5b, 0x3c, 0x59, 0xe9, 0x05, 0xe3, 0xa4, 0x3a, 0x68, 0x1d, 0xe6, 0xad, - 0x4e, 0xe0, 0xaa, 0xfe, 0x9f, 0x73, 0xa8, 0xa4, 0xa8, 0xb3, 0xa5, 0x95, 0xe7, 0x22, 0xa5, 0x94, - 0x00, 0xc7, 0x89, 0xb5, 0x50, 0x25, 0x46, 0xad, 0x4a, 0x6a, 0xae, 0x53, 0xe7, 0xb3, 0x9c, 0x0b, - 0xb5, 0xf0, 0x52, 0x02, 0x0e, 0x4e, 0xac, 0x89, 0x9a, 0x30, 0xdd, 0xb2, 0x6e, 0x5f, 0x75, 0xac, - 0x5d, 0xcb, 0x6e, 0x52, 0x26, 0xc2, 0x86, 0xd1, 0xff, 0x62, 0xdd, 0x09, 0xec, 0xe6, 0x12, 0x7f, - 0xce, 0x5b, 0x5a, 0x73, 0x82, 0xcb, 0x5e, 0x35, 0xa0, 0xda, 0x1a, 0x57, 0x8e, 0x36, 0x22, 0xb4, - 0x70, 0x8c, 0x36, 0xba, 0x0c, 0xa7, 0xd8, 0x76, 0x5c, 0x75, 0x6f, 0x39, 0xab, 0xa4, 0x69, 0xed, - 0xc9, 0x0e, 0x4c, 0xb0, 0x0e, 0xdc, 0xbb, 0xdf, 0x2d, 0x9e, 0xaa, 0x26, 0x21, 0xe0, 0xe4, 0x7a, - 0xc8, 0x82, 0xfb, 0xa2, 0x00, 0x4c, 0x76, 0x6d, 0xdf, 0x76, 0x1d, 0x6e, 0x89, 0xc8, 0x87, 0x96, - 0x88, 0x6a, 0x7f, 0x34, 0x7c, 0x10, 0x0d, 0xf4, 0xdb, 0x06, 0xcc, 0x27, 0x6d, 0xc3, 0x85, 0x42, - 0x1a, 0x8f, 0x15, 0xb1, 0xad, 0xc5, 0x57, 0x44, 0xe2, 0xa1, 0x90, 0xd8, 0x08, 0xf4, 0xb2, 0x01, - 0x53, 0x96, 0x76, 0x8b, 0x5a, 0x00, 0xd6, 0xaa, 0x8b, 0xa3, 0xde, 0xe5, 0x43, 0x8a, 0xe5, 0xd9, - 0xfd, 0x6e, 0x31, 0x72, 0x53, 0xc3, 0x11, 0x8e, 0xe8, 0x77, 0x0c, 0x38, 0x95, 0xb8, 0xc7, 0x17, - 0x26, 0x8f, 0x63, 0x84, 0xd8, 0x22, 0x49, 0x3e, 0x73, 0x92, 0x9b, 0x81, 0x5e, 0x37, 0x94, 0x28, - 0xdb, 0x90, 0xd6, 0x94, 0x29, 0xd6, 0xb4, 0x2b, 0x23, 0x5e, 0x1c, 0x43, 0x85, 0x40, 0x12, 0x2e, - 0x9f, 0xd4, 0x24, 0xa3, 0x2c, 0xc4, 0x71, 0xf6, 0xe8, 0xb3, 0x86, 0x14, 0x8d, 0xaa, 0x45, 0x27, - 0x8e, 0xab, 0x45, 0x28, 0x94, 0xb4, 0xaa, 0x41, 0x31, 0xe6, 0xe8, 0xc3, 0xb0, 0x68, 0x6d, 0xb9, - 0x5e, 0x90, 0xb8, 0xf9, 0x16, 0xa6, 0xd9, 0x36, 0x3a, 0xbb, 0xdf, 0x2d, 0x2e, 0x96, 0xfa, 0x62, - 0xe1, 0x03, 0x28, 0x98, 0x7f, 0x94, 0x83, 0x29, 0xae, 0xe4, 0x0b, 0xd1, 0xf5, 0x35, 0x03, 0xee, - 0xaf, 0x75, 0x3c, 0x8f, 0x38, 0x41, 0x35, 0x20, 0xed, 0x5e, 0xc1, 0x65, 0x1c, 0xab, 0xe0, 0x7a, - 0x60, 0xbf, 0x5b, 0xbc, 0x7f, 0xe5, 0x00, 0xfe, 0xf8, 0xc0, 0xd6, 0xa1, 0xbf, 0x36, 0xc0, 0x14, - 0x08, 0x65, 0xab, 0x76, 0xb3, 0xe1, 0xb9, 0x1d, 0xa7, 0xde, 0xdb, 0x89, 0xcc, 0xb1, 0x76, 0xe2, - 0xa1, 0xfd, 0x6e, 0xd1, 0x5c, 0x39, 0xb4, 0x15, 0x78, 0x80, 0x96, 0xa2, 0x67, 0x61, 0x4e, 0x60, - 0x9d, 0xbb, 0xdd, 0x26, 0x9e, 0x4d, 0xd5, 0x69, 0xf1, 0x9e, 0x1e, 0xba, 0x28, 0xc4, 0x11, 0x70, - 0x6f, 0x1d, 0xe4, 0xc3, 0xc4, 0x2d, 0x62, 0x37, 0x76, 0x02, 0xa9, 0x3e, 0x8d, 0xe8, 0x97, 0x20, - 0x2e, 0xfc, 0xd7, 0x39, 0xcd, 0xf2, 0xe4, 0x7e, 0xb7, 0x38, 0x21, 0xfe, 0x60, 0xc9, 0x09, 0x5d, - 0x82, 0x69, 0x7e, 0x05, 0xab, 0xd8, 0x4e, 0xa3, 0xe2, 0x3a, 0xfc, 0x35, 0xbf, 0x50, 0x7e, 0x48, - 0x0a, 0xfc, 0x6a, 0x04, 0x7a, 0xa7, 0x5b, 0x9c, 0x92, 0xbf, 0x37, 0xf7, 0xda, 0x04, 0xc7, 0x6a, - 0x9b, 0xdf, 0x1a, 0x07, 0x90, 0xcb, 0x95, 0xb4, 0xd1, 0xff, 0x81, 0x82, 0x4f, 0x02, 0xce, 0x55, - 0x18, 0xcf, 0xf9, 0x9b, 0x84, 0x2c, 0xc4, 0x21, 0x1c, 0xdd, 0x84, 0x5c, 0xdb, 0xea, 0xf8, 0x44, - 0x4c, 0xfe, 0xc5, 0x54, 0x26, 0xbf, 0x42, 0x29, 0xf2, 0x3b, 0x17, 0xfb, 0x89, 0x39, 0x0f, 0xf4, - 0x29, 0x03, 0x80, 0x44, 0x27, 0x6c, 0x64, 0xdb, 0x87, 0x60, 0x19, 0xce, 0x29, 0x1d, 0x83, 0xf2, - 0xf4, 0x7e, 0xb7, 0x08, 0xda, 0xd4, 0x6b, 0x6c, 0xd1, 0x2d, 0xc8, 0x5b, 0xf2, 0xcc, 0x1f, 0x3b, - 0x8e, 0x33, 0x9f, 0x5d, 0x85, 0xd4, 0xa2, 0x55, 0xcc, 0xd0, 0xa7, 0x0d, 0x98, 0xf6, 0x49, 0x20, - 0xa6, 0x8a, 0x9e, 0x3c, 0x42, 0xe1, 0x1d, 0x71, 0xd1, 0x55, 0x23, 0x34, 0xf9, 0x09, 0x1a, 0x2d, - 0xc3, 0x31, 0xbe, 0xb2, 0x29, 0x17, 0x88, 0x55, 0x27, 0x1e, 0xbb, 0x69, 0x0b, 0x4d, 0x6a, 0xf4, - 0xa6, 0x68, 0x34, 0x55, 0x53, 0xb4, 0x32, 0x1c, 0xe3, 0x2b, 0x9b, 0xb2, 0x61, 0x7b, 0x9e, 0x2b, - 0x9a, 0x92, 0x4f, 0xa9, 0x29, 0x1a, 0x4d, 0xd5, 0x14, 0xad, 0x0c, 0xc7, 0xf8, 0x9a, 0x7f, 0x33, - 0x05, 0xd3, 0x72, 0x23, 0x85, 0x9a, 0x3d, 0x37, 0xec, 0xf4, 0xd1, 0xec, 0x57, 0x74, 0x20, 0x8e, - 0xe2, 0xd2, 0xca, 0x7c, 0xab, 0x46, 0x15, 0x7b, 0x55, 0xb9, 0xaa, 0x03, 0x71, 0x14, 0x17, 0xb5, - 0x20, 0xe7, 0x07, 0xa4, 0x2d, 0xdf, 0x41, 0x47, 0x7c, 0xa6, 0x0b, 0xcf, 0x87, 0xf0, 0xa5, 0x83, - 0xfe, 0xf3, 0x31, 0xe7, 0xc2, 0x6c, 0x93, 0x41, 0xc4, 0x5c, 0x29, 0x36, 0x47, 0x3a, 0xfb, 0x33, - 0x6a, 0x09, 0xe5, 0xb3, 0x11, 0x2d, 0xc3, 0x31, 0xf6, 0x09, 0xca, 0x7e, 0xee, 0x18, 0x95, 0xfd, - 0xe7, 0x21, 0xdf, 0xb2, 0x6e, 0x57, 0x3b, 0x5e, 0xe3, 0xe8, 0x97, 0x0a, 0xe1, 0xa2, 0xc4, 0xa9, - 0x60, 0x45, 0x0f, 0xbd, 0x62, 0x68, 0x47, 0xce, 0x04, 0x23, 0x7e, 0x3d, 0xdd, 0x23, 0x47, 0xc9, - 0xca, 0xbe, 0x87, 0x4f, 0x8f, 0xea, 0x9d, 0xbf, 0xeb, 0xaa, 0x37, 0x55, 0x23, 0xf9, 0x06, 0x51, - 0x6a, 0x64, 0xe1, 0x58, 0xd5, 0xc8, 0x95, 0x08, 0x33, 0x1c, 0x63, 0xce, 0xda, 0xc3, 0xf7, 0x9c, - 0x6a, 0x0f, 0x1c, 0x6b, 0x7b, 0xaa, 0x11, 0x66, 0x38, 0xc6, 0xbc, 0xff, 0x7d, 0x73, 0xf2, 0x78, - 0xee, 0x9b, 0x53, 0x29, 0xdc, 0x37, 0x0f, 0x56, 0xc5, 0x4f, 0x8c, 0xaa, 0x8a, 0xa3, 0x8b, 0x80, - 0xea, 0x7b, 0x8e, 0xd5, 0xb2, 0x6b, 0xe2, 0xb0, 0x64, 0x62, 0x73, 0x9a, 0xd9, 0x23, 0x16, 0xc5, - 0x41, 0x86, 0x56, 0x7b, 0x30, 0x70, 0x42, 0x2d, 0x14, 0x40, 0xbe, 0x2d, 0x35, 0xae, 0x99, 0x34, - 0x56, 0xbf, 0xd4, 0xc0, 0xf8, 0x53, 0x39, 0xdd, 0x78, 0xb2, 0x04, 0x2b, 0x4e, 0xe6, 0x7f, 0x18, - 0x30, 0xbb, 0xd2, 0x74, 0x3b, 0xf5, 0xeb, 0x56, 0x50, 0xdb, 0xe1, 0xef, 0xba, 0xe8, 0x19, 0xc8, - 0xdb, 0x4e, 0x40, 0xbc, 0x5d, 0xab, 0x29, 0x24, 0x8a, 0x29, 0x9f, 0xbe, 0xd7, 0x44, 0xf9, 0x9d, - 0x6e, 0x71, 0x7a, 0xb5, 0xe3, 0x31, 0x87, 0x49, 0x7e, 0xbe, 0x60, 0x55, 0x07, 0x7d, 0xd9, 0x80, - 0x39, 0xfe, 0x32, 0xbc, 0x6a, 0x05, 0xd6, 0x95, 0x0e, 0xf1, 0x6c, 0x22, 0xdf, 0x86, 0x47, 0x3c, - 0x5a, 0xe2, 0x6d, 0x95, 0x0c, 0xf6, 0x42, 0xd5, 0x7a, 0x23, 0xce, 0x19, 0xf7, 0x36, 0xc6, 0xfc, - 0x7c, 0x16, 0xee, 0xed, 0x4b, 0x0b, 0x2d, 0x42, 0xc6, 0xae, 0x8b, 0xae, 0x83, 0xa0, 0x9b, 0x59, - 0xab, 0xe3, 0x8c, 0x5d, 0x47, 0x4b, 0x4c, 0x4b, 0xf4, 0x88, 0xef, 0xcb, 0x67, 0xc2, 0x82, 0x52, - 0xe8, 0x44, 0x29, 0xd6, 0x30, 0x50, 0x11, 0x72, 0x4d, 0x6b, 0x8b, 0x34, 0xc5, 0x0d, 0x80, 0xe9, - 0x9d, 0xeb, 0xb4, 0x00, 0xf3, 0x72, 0xf4, 0xcb, 0x06, 0x00, 0x6f, 0x20, 0xbd, 0x3f, 0x08, 0xb9, - 0x86, 0xd3, 0x1d, 0x26, 0x4a, 0x99, 0xb7, 0x32, 0xfc, 0x8f, 0x35, 0xae, 0x68, 0x13, 0xc6, 0xa9, - 0x0a, 0xea, 0xd6, 0x8f, 0x2c, 0xc6, 0xd8, 0xb3, 0x48, 0x85, 0xd1, 0xc0, 0x82, 0x16, 0x1d, 0x2b, - 0x8f, 0x04, 0x1d, 0xcf, 0xa1, 0x43, 0xcb, 0x04, 0x57, 0x9e, 0xb7, 0x02, 0xab, 0x52, 0xac, 0x61, - 0x98, 0x7f, 0x9a, 0x81, 0xf9, 0xa4, 0xa6, 0x53, 0xf9, 0x30, 0xce, 0x5b, 0x2b, 0x2e, 0xb3, 0xef, - 0x4f, 0x7f, 0x7c, 0x84, 0x93, 0x83, 0x72, 0x05, 0x10, 0x6e, 0x58, 0x82, 0x2f, 0x7a, 0xbf, 0x1a, - 0xa1, 0xcc, 0x11, 0x47, 0x48, 0x51, 0x8e, 0x8d, 0xd2, 0x03, 0x30, 0xe6, 0xd3, 0x99, 0xcf, 0x46, - 0x9f, 0x1c, 0xd8, 0x1c, 0x31, 0x08, 0xc5, 0xe8, 0x38, 0x76, 0x20, 0xbc, 0x98, 0x15, 0xc6, 0x55, - 0xc7, 0x0e, 0x30, 0x83, 0x98, 0x5f, 0xcc, 0xc0, 0x62, 0xff, 0x4e, 0xa1, 0x2f, 0x1a, 0x00, 0x75, - 0x7a, 0xc1, 0xa0, 0x4b, 0x52, 0x3a, 0x85, 0x58, 0xc7, 0x35, 0x86, 0xab, 0x92, 0x53, 0xe8, 0x21, - 0xa4, 0x8a, 0x7c, 0xac, 0x35, 0x04, 0x3d, 0x2a, 0x97, 0xfe, 0x25, 0xab, 0x25, 0x15, 0x50, 0x55, - 0x67, 0x43, 0x41, 0xb0, 0x86, 0x45, 0x6f, 0x90, 0x8e, 0xd5, 0x22, 0x7e, 0xdb, 0x52, 0x6e, 0xea, - 0xec, 0x06, 0x79, 0x49, 0x16, 0xe2, 0x10, 0x6e, 0x36, 0xe1, 0xc1, 0x01, 0xda, 0x99, 0x92, 0xcb, - 0xb0, 0xf9, 0xef, 0x06, 0x9c, 0x5e, 0x69, 0x76, 0xfc, 0x80, 0x78, 0xff, 0x63, 0x1c, 0xae, 0xfe, - 0xd3, 0x80, 0xfb, 0xfa, 0xf4, 0xf9, 0x2e, 0xf8, 0x5d, 0xbd, 0x18, 0xf5, 0xbb, 0xba, 0x3a, 0xea, - 0x92, 0x4e, 0xec, 0x47, 0x1f, 0xf7, 0xab, 0x00, 0x4e, 0xd0, 0x53, 0xab, 0xee, 0x36, 0x52, 0x92, - 0x9b, 0x0f, 0x42, 0xee, 0x63, 0x54, 0xfe, 0xc4, 0xd7, 0x18, 0x13, 0x4a, 0x98, 0xc3, 0xcc, 0xa7, - 0x41, 0x38, 0x29, 0xc5, 0x36, 0x8f, 0x31, 0xc8, 0xe6, 0x31, 0xff, 0x2e, 0x03, 0x9a, 0xe5, 0xe1, - 0x2e, 0x2c, 0x4a, 0x27, 0xb2, 0x28, 0x47, 0xbc, 0x35, 0x6b, 0x76, 0x94, 0x7e, 0xd1, 0x08, 0xbb, - 0xb1, 0x68, 0x84, 0x4b, 0xa9, 0x71, 0x3c, 0x38, 0x18, 0xe1, 0xfb, 0x06, 0xdc, 0x17, 0x22, 0xf7, - 0x1a, 0x05, 0x0f, 0x3f, 0x61, 0x9e, 0x80, 0x49, 0x2b, 0xac, 0x26, 0xd6, 0x80, 0x0a, 0xc0, 0xd1, - 0x28, 0x62, 0x1d, 0x2f, 0xf4, 0x7d, 0xce, 0x1e, 0xd1, 0xf7, 0x79, 0xec, 0x60, 0xdf, 0x67, 0xf3, - 0xa7, 0x19, 0x38, 0xd3, 0xdb, 0x33, 0xb9, 0x37, 0x06, 0x7b, 0x33, 0x7f, 0x12, 0xa6, 0x02, 0x51, - 0x41, 0x3b, 0xe9, 0x55, 0xf8, 0xd8, 0xa6, 0x06, 0xc3, 0x11, 0x4c, 0x5a, 0xb3, 0xc6, 0x77, 0x65, - 0xb5, 0xe6, 0xb6, 0xa5, 0xe7, 0xbc, 0xaa, 0xb9, 0xa2, 0xc1, 0x70, 0x04, 0x53, 0xf9, 0x24, 0x8e, - 0x1d, 0xbb, 0x4f, 0x62, 0x15, 0x4e, 0x49, 0x2f, 0xac, 0xf3, 0xae, 0xb7, 0xe2, 0xb6, 0xda, 0x4d, - 0x22, 0x7c, 0xe7, 0x69, 0x63, 0xcf, 0x88, 0x2a, 0xa7, 0x70, 0x12, 0x12, 0x4e, 0xae, 0x6b, 0x7e, - 0x3f, 0x0b, 0x27, 0xc3, 0x61, 0x5f, 0x71, 0x9d, 0xba, 0xcd, 0x7c, 0xd9, 0x9e, 0x82, 0xb1, 0x60, - 0xaf, 0x2d, 0x07, 0xfb, 0x7f, 0xc9, 0xe6, 0x6c, 0xee, 0xb5, 0xe9, 0x6c, 0x9f, 0x4e, 0xa8, 0xc2, - 0xcc, 0xb2, 0xac, 0x12, 0x5a, 0x57, 0xbb, 0x83, 0xcf, 0xc0, 0xe3, 0xd1, 0xd5, 0x7c, 0xa7, 0x5b, - 0x4c, 0x88, 0x9e, 0x5c, 0x52, 0x94, 0xa2, 0x6b, 0x1e, 0xdd, 0x80, 0xe9, 0xa6, 0xe5, 0x07, 0x57, - 0xdb, 0x75, 0x2b, 0x20, 0x9b, 0x76, 0x8b, 0x88, 0x3d, 0x37, 0x8c, 0x43, 0xba, 0x7a, 0x47, 0x5e, - 0x8f, 0x50, 0xc2, 0x31, 0xca, 0x68, 0x17, 0x10, 0x2d, 0xd9, 0xf4, 0x2c, 0xc7, 0xe7, 0xbd, 0xa2, - 0xfc, 0x86, 0x77, 0x80, 0x57, 0xd7, 0xb2, 0xf5, 0x1e, 0x6a, 0x38, 0x81, 0x03, 0x7a, 0x08, 0xc6, - 0x3d, 0x62, 0xf9, 0x62, 0x32, 0x0b, 0xe1, 0xfe, 0xc7, 0xac, 0x14, 0x0b, 0xa8, 0xbe, 0xa1, 0xc6, - 0x0f, 0xd9, 0x50, 0x3f, 0x32, 0x60, 0x3a, 0x9c, 0xa6, 0xbb, 0x20, 0x24, 0x5b, 0x51, 0x21, 0x79, - 0x21, 0xad, 0x23, 0xb1, 0x8f, 0x5c, 0xfc, 0xcb, 0x71, 0xbd, 0x7f, 0xcc, 0x21, 0xf9, 0xe3, 0x50, - 0x90, 0xbb, 0x5a, 0x6a, 0x9f, 0x23, 0xde, 0x6e, 0x23, 0x7a, 0x89, 0x16, 0x48, 0x23, 0x98, 0xe0, - 0x90, 0x1f, 0x15, 0xcb, 0x75, 0x21, 0x72, 0xc5, 0xb2, 0x57, 0x62, 0x59, 0x8a, 0xe2, 0x24, 0xb1, - 0x2c, 0xeb, 0xa0, 0xab, 0x70, 0xba, 0xed, 0xb9, 0x2c, 0xb8, 0x72, 0x95, 0x58, 0xf5, 0xa6, 0xed, - 0x10, 0x69, 0x42, 0xe0, 0x6e, 0x0c, 0xf7, 0xed, 0x77, 0x8b, 0xa7, 0x2b, 0xc9, 0x28, 0xb8, 0x5f, - 0xdd, 0x68, 0x40, 0xd0, 0xd8, 0x00, 0x01, 0x41, 0xbf, 0xaa, 0x0c, 0x75, 0xc4, 0x17, 0x61, 0x39, - 0x1f, 0x4c, 0x6b, 0x2a, 0x13, 0x8e, 0xf5, 0x70, 0x49, 0x95, 0x04, 0x53, 0xac, 0xd8, 0xf7, 0xb7, - 0x06, 0x8d, 0x1f, 0xd1, 0x1a, 0x14, 0xfa, 0x75, 0x4f, 0xfc, 0x3c, 0xfd, 0xba, 0xf3, 0x6f, 0x29, - 0xbf, 0xee, 0x57, 0x73, 0x30, 0x1b, 0xd7, 0x40, 0x8e, 0x3f, 0xd8, 0xe9, 0x37, 0x0c, 0x98, 0x95, - 0xbb, 0x87, 0xf3, 0x24, 0xd2, 0xce, 0xbf, 0x9e, 0xd2, 0xa6, 0xe5, 0xba, 0x94, 0x0a, 0xc7, 0xdd, - 0x8c, 0x71, 0xc3, 0x3d, 0xfc, 0xd1, 0x0b, 0x30, 0xa9, 0xcc, 0xe1, 0x47, 0x8a, 0x7c, 0x9a, 0x61, - 0x5a, 0x54, 0x48, 0x02, 0xeb, 0xf4, 0xd0, 0xab, 0x06, 0x40, 0x4d, 0x8a, 0x39, 0xb9, 0xbb, 0xae, - 0xa4, 0xb5, 0xbb, 0x94, 0x00, 0x0d, 0x95, 0x65, 0x55, 0xe4, 0x63, 0x8d, 0x31, 0xfa, 0x3c, 0x33, - 0x84, 0x2b, 0xed, 0x8e, 0xee, 0xa7, 0xec, 0xe8, 0xae, 0xb8, 0x07, 0x28, 0xa6, 0xa1, 0x2a, 0xa5, - 0x81, 0x7c, 0x1c, 0x69, 0x84, 0xf9, 0x14, 0x28, 0xe7, 0x49, 0x7a, 0x6c, 0x31, 0xf7, 0xc9, 0x8a, - 0x15, 0xec, 0x88, 0x25, 0xa8, 0x8e, 0xad, 0xf3, 0x12, 0x80, 0x43, 0x1c, 0xf3, 0xa3, 0x30, 0xfd, - 0xac, 0x67, 0xb5, 0x77, 0x6c, 0x66, 0x70, 0xa6, 0xf7, 0xa4, 0x77, 0xc2, 0x84, 0x55, 0xaf, 0x27, - 0x05, 0xb3, 0x97, 0x78, 0x31, 0x96, 0xf0, 0xc1, 0xae, 0x44, 0xdf, 0x32, 0x00, 0x85, 0x8f, 0x76, - 0xb6, 0xd3, 0xd8, 0xa0, 0xb7, 0x7d, 0x7a, 0x3f, 0xda, 0x61, 0xa5, 0x49, 0xf7, 0xa3, 0x0b, 0x0a, - 0x82, 0x35, 0x2c, 0xf4, 0x12, 0x4c, 0xf2, 0x7f, 0xd7, 0xd4, 0x65, 0x7f, 0xe4, 0x50, 0x58, 0x2e, - 0x50, 0x58, 0x9b, 0xf8, 0x2a, 0xbc, 0x10, 0x72, 0xc0, 0x3a, 0x3b, 0x3a, 0x54, 0x6b, 0xce, 0x76, - 0xb3, 0x73, 0xbb, 0xbe, 0x15, 0x0e, 0x55, 0xdb, 0x73, 0xb7, 0xed, 0x26, 0x89, 0x0f, 0x55, 0x85, - 0x17, 0x63, 0x09, 0x1f, 0x6c, 0xa8, 0xbe, 0x61, 0xc0, 0xfc, 0x9a, 0x1f, 0xd8, 0xee, 0x2a, 0xf1, - 0x03, 0x2a, 0x56, 0xe8, 0xe1, 0xd3, 0x69, 0x0e, 0xe2, 0x07, 0xbd, 0x0a, 0xb3, 0xe2, 0x01, 0xb1, - 0xb3, 0xe5, 0x93, 0x40, 0xd3, 0xe3, 0xd5, 0x3e, 0x5e, 0x89, 0xc1, 0x71, 0x4f, 0x0d, 0x4a, 0x45, - 0xbc, 0x24, 0x86, 0x54, 0xb2, 0x51, 0x2a, 0xd5, 0x18, 0x1c, 0xf7, 0xd4, 0x30, 0xbf, 0x9b, 0x85, - 0x93, 0xac, 0x1b, 0xb1, 0x18, 0x86, 0xcf, 0xf6, 0x8b, 0x61, 0x18, 0x71, 0x2b, 0x33, 0x5e, 0x47, - 0x88, 0x60, 0xf8, 0x75, 0x03, 0x66, 0xea, 0xd1, 0x91, 0x4e, 0xc7, 0x3c, 0x93, 0x34, 0x87, 0xdc, - 0x5f, 0x2a, 0x56, 0x88, 0xe3, 0xfc, 0xd1, 0x17, 0x0c, 0x98, 0x89, 0x36, 0x53, 0x9e, 0xee, 0xc7, - 0x30, 0x48, 0xca, 0xc1, 0x39, 0x5a, 0xee, 0xe3, 0x78, 0x13, 0xcc, 0xef, 0x64, 0xc4, 0x94, 0x1e, - 0x87, 0x83, 0x3e, 0xba, 0x05, 0x85, 0xa0, 0xe9, 0xf3, 0x42, 0xd1, 0xdb, 0x11, 0x6f, 0x84, 0x9b, - 0xeb, 0x55, 0xfe, 0x76, 0x1f, 0x2a, 0x6d, 0xa2, 0x84, 0x2a, 0x9f, 0x92, 0x17, 0x63, 0x5c, 0x6b, - 0x0b, 0xc6, 0xa9, 0x5c, 0x45, 0x37, 0x57, 0x2a, 0x71, 0xc6, 0xa2, 0x84, 0x32, 0x96, 0xbc, 0xcc, - 0xaf, 0x18, 0x50, 0xb8, 0xe8, 0xca, 0x73, 0xe4, 0xc3, 0x29, 0x18, 0x7a, 0x94, 0x3e, 0xa8, 0xde, - 0x08, 0xc3, 0x2b, 0xc6, 0x33, 0x11, 0x33, 0xcf, 0xfd, 0x1a, 0xed, 0x25, 0x96, 0xa8, 0x87, 0x92, - 0xba, 0xe8, 0x6e, 0xf5, 0xb5, 0x22, 0xfe, 0x6e, 0x0e, 0x4e, 0x3c, 0x67, 0xed, 0x11, 0x27, 0xb0, - 0x86, 0x17, 0x12, 0x4f, 0xc0, 0xa4, 0xd5, 0x66, 0x8e, 0xc2, 0x9a, 0x8e, 0x1f, 0x5a, 0x4e, 0x42, - 0x10, 0xd6, 0xf1, 0xc2, 0x03, 0x8d, 0xe7, 0x0d, 0x49, 0x3a, 0x8a, 0x56, 0x62, 0x70, 0xdc, 0x53, - 0x03, 0x5d, 0x04, 0x24, 0xa2, 0x20, 0x4b, 0xb5, 0x9a, 0xdb, 0x71, 0xf8, 0x91, 0xc6, 0x8d, 0x2a, - 0xea, 0xb2, 0xb9, 0xd1, 0x83, 0x81, 0x13, 0x6a, 0xa1, 0x0f, 0xc1, 0x42, 0x8d, 0x51, 0x16, 0x57, - 0x0f, 0x9d, 0x22, 0xbf, 0x7e, 0x2a, 0x27, 0xfd, 0x95, 0x3e, 0x78, 0xb8, 0x2f, 0x05, 0xda, 0x52, - 0x3f, 0x70, 0x3d, 0xab, 0x41, 0x74, 0xba, 0xe3, 0xd1, 0x96, 0x56, 0x7b, 0x30, 0x70, 0x42, 0x2d, - 0xf4, 0x49, 0x28, 0x04, 0x3b, 0x1e, 0xf1, 0x77, 0xdc, 0x66, 0x5d, 0x38, 0x0d, 0x8c, 0x68, 0x69, - 0x13, 0xb3, 0xbf, 0x29, 0xa9, 0x6a, 0xcb, 0x5b, 0x16, 0xe1, 0x90, 0x27, 0xf2, 0x60, 0xdc, 0xaf, - 0xb9, 0x6d, 0xe2, 0x0b, 0x95, 0xfd, 0x62, 0x2a, 0xdc, 0x99, 0xe5, 0x48, 0xb3, 0xf1, 0x31, 0x0e, - 0x58, 0x70, 0x32, 0xbf, 0x99, 0x81, 0x29, 0x1d, 0x71, 0x80, 0xb3, 0xe9, 0x53, 0x06, 0x4c, 0xd5, - 0x5c, 0x27, 0xf0, 0xdc, 0x26, 0xb7, 0x5f, 0xa5, 0xa3, 0x51, 0x50, 0x52, 0xab, 0x24, 0xb0, 0xec, - 0xa6, 0x66, 0x0a, 0xd3, 0xd8, 0xe0, 0x08, 0x53, 0xf4, 0x19, 0x03, 0x66, 0x42, 0x1f, 0xb3, 0xd0, - 0x90, 0x96, 0x6a, 0x43, 0xd4, 0x51, 0x7f, 0x2e, 0xca, 0x09, 0xc7, 0x59, 0x9b, 0x5b, 0x30, 0x1b, - 0x9f, 0x6d, 0x3a, 0x94, 0x6d, 0x4b, 0xec, 0xf5, 0x6c, 0x38, 0x94, 0x15, 0xcb, 0xf7, 0x31, 0x83, - 0xa0, 0x47, 0x20, 0xdf, 0xb2, 0xbc, 0x86, 0xed, 0x58, 0x4d, 0x36, 0x8a, 0x59, 0xed, 0x40, 0x12, - 0xe5, 0x58, 0x61, 0x98, 0xef, 0x86, 0xa9, 0x0d, 0xcb, 0x69, 0x90, 0xba, 0x38, 0x87, 0x0f, 0x0f, - 0x11, 0xfb, 0xf1, 0x18, 0x4c, 0x6a, 0x77, 0xb3, 0xe3, 0xbf, 0x67, 0x45, 0x52, 0x39, 0x64, 0x53, - 0x4c, 0xe5, 0xf0, 0x3c, 0xc0, 0xb6, 0xed, 0xd8, 0xfe, 0xce, 0x11, 0x93, 0x44, 0xb0, 0x27, 0xda, - 0xf3, 0x8a, 0x02, 0xd6, 0xa8, 0x85, 0xef, 0x60, 0xb9, 0x03, 0x52, 0xe7, 0xbc, 0x6a, 0x68, 0xe2, - 0x66, 0x3c, 0x8d, 0x77, 0x7f, 0x6d, 0x62, 0x96, 0xa4, 0xf8, 0x39, 0xe7, 0x04, 0xde, 0xde, 0x81, - 0x52, 0x69, 0x13, 0xf2, 0x1e, 0xf1, 0x3b, 0x2d, 0x7a, 0x63, 0x9c, 0x18, 0x7a, 0x18, 0x98, 0xcf, - 0x04, 0x16, 0xf5, 0xb1, 0xa2, 0xb4, 0xf8, 0x14, 0x9c, 0x88, 0x34, 0x01, 0xcd, 0x42, 0xf6, 0x26, - 0xd9, 0xe3, 0xeb, 0x04, 0xd3, 0x9f, 0x68, 0x3e, 0xf2, 0x5a, 0x28, 0x86, 0xe5, 0x7d, 0x99, 0x27, - 0x0d, 0xd3, 0x85, 0x44, 0x03, 0xc0, 0x51, 0x1e, 0x73, 0xe8, 0x5c, 0x34, 0xb5, 0x2c, 0x11, 0x6a, - 0x2e, 0xb8, 0x67, 0x0c, 0x87, 0x99, 0x3f, 0x1d, 0x07, 0xf1, 0x94, 0x3d, 0xc0, 0x71, 0xa5, 0xbf, - 0x60, 0x65, 0x8e, 0xf0, 0x82, 0x75, 0x11, 0xa6, 0x6c, 0xc7, 0x0e, 0x6c, 0xab, 0xc9, 0x8c, 0x3b, - 0x42, 0x9c, 0x4a, 0xd7, 0xe1, 0xa9, 0x35, 0x0d, 0x96, 0x40, 0x27, 0x52, 0x17, 0x5d, 0x81, 0x1c, - 0x93, 0x37, 0x62, 0x01, 0x0f, 0xff, 0xde, 0xce, 0x5c, 0x2d, 0x78, 0x3c, 0x11, 0xa7, 0xc4, 0x2e, - 0x1f, 0x3c, 0x4d, 0x86, 0xba, 0x7e, 0x8b, 0x75, 0x1c, 0x5e, 0x3e, 0x62, 0x70, 0xdc, 0x53, 0x83, - 0x52, 0xd9, 0xb6, 0xec, 0x66, 0xc7, 0x23, 0x21, 0x95, 0xf1, 0x28, 0x95, 0xf3, 0x31, 0x38, 0xee, - 0xa9, 0x81, 0xb6, 0x61, 0x4a, 0x94, 0x71, 0x7f, 0xa7, 0x89, 0x23, 0xf6, 0x92, 0xf9, 0xb5, 0x9d, - 0xd7, 0x28, 0xe1, 0x08, 0x5d, 0xd4, 0x81, 0x39, 0xdb, 0xa9, 0xb9, 0x4e, 0xad, 0xd9, 0xf1, 0xed, - 0x5d, 0x12, 0x06, 0xf3, 0x1c, 0x85, 0xd9, 0xa9, 0xfd, 0x6e, 0x71, 0x6e, 0x2d, 0x4e, 0x0e, 0xf7, - 0x72, 0x40, 0xaf, 0x18, 0x70, 0xaa, 0xe6, 0x3a, 0x3e, 0x8b, 0x3b, 0xdf, 0x25, 0xe7, 0x3c, 0xcf, - 0xf5, 0x38, 0xef, 0xc2, 0x11, 0x79, 0x33, 0x9b, 0xe2, 0x4a, 0x12, 0x49, 0x9c, 0xcc, 0x09, 0xbd, - 0x08, 0xf9, 0xb6, 0xe7, 0xee, 0xda, 0x75, 0xe2, 0x09, 0xdf, 0xb9, 0xf5, 0x34, 0xf2, 0x60, 0x54, - 0x04, 0xcd, 0xf0, 0xe8, 0x91, 0x25, 0x58, 0xf1, 0x33, 0xdf, 0x28, 0xc0, 0x74, 0x14, 0x1d, 0x7d, - 0x02, 0xa0, 0xed, 0xb9, 0x2d, 0x12, 0xec, 0x10, 0x15, 0x94, 0x71, 0x69, 0xd4, 0x74, 0x0b, 0x92, - 0x9e, 0xf4, 0x5e, 0xa1, 0xc7, 0x45, 0x58, 0x8a, 0x35, 0x8e, 0xc8, 0x83, 0x89, 0x9b, 0x5c, 0xec, - 0x0a, 0x2d, 0xe4, 0xb9, 0x54, 0x74, 0x26, 0xc1, 0x99, 0x45, 0x13, 0x88, 0x22, 0x2c, 0x19, 0xa1, - 0x2d, 0xc8, 0xde, 0x22, 0x5b, 0xe9, 0x84, 0x30, 0x5f, 0x27, 0xe2, 0x36, 0x53, 0x9e, 0xd8, 0xef, - 0x16, 0xb3, 0xd7, 0xc9, 0x16, 0xa6, 0xc4, 0x69, 0xbf, 0xea, 0xfc, 0x1d, 0x5e, 0x1c, 0x15, 0x23, - 0xf6, 0x2b, 0xf2, 0xa8, 0xcf, 0xfb, 0x25, 0x8a, 0xb0, 0x64, 0x84, 0x5e, 0x84, 0xc2, 0x2d, 0x6b, - 0x97, 0x6c, 0x7b, 0xae, 0x13, 0x08, 0x97, 0xa9, 0x11, 0xfd, 0xf4, 0xaf, 0x4b, 0x72, 0x82, 0x2f, - 0x13, 0xef, 0xaa, 0x10, 0x87, 0xec, 0xd0, 0x2e, 0xe4, 0x1d, 0x72, 0x0b, 0x93, 0xa6, 0x5d, 0x4b, - 0xc7, 0x2f, 0xfe, 0x92, 0xa0, 0x26, 0x38, 0x33, 0xb9, 0x27, 0xcb, 0xb0, 0xe2, 0x45, 0xe7, 0xf2, - 0x86, 0xbb, 0x25, 0x0e, 0xaa, 0x11, 0xe7, 0x52, 0xdd, 0x4c, 0xf9, 0x5c, 0x5e, 0x74, 0xb7, 0x30, - 0x25, 0x4e, 0xf7, 0x48, 0x4d, 0xf9, 0xeb, 0x88, 0x63, 0xea, 0x52, 0xba, 0x7e, 0x4a, 0x7c, 0x8f, - 0x84, 0xa5, 0x58, 0xe3, 0x48, 0xc7, 0xb6, 0x21, 0x8c, 0x95, 0xe2, 0xa0, 0x1a, 0x71, 0x6c, 0xa3, - 0xa6, 0x4f, 0x3e, 0xb6, 0xb2, 0x0c, 0x2b, 0x5e, 0x94, 0xaf, 0x2d, 0x2c, 0x7f, 0xe9, 0x1c, 0x55, - 0x51, 0x3b, 0x22, 0xe7, 0x2b, 0xcb, 0xb0, 0xe2, 0x65, 0x7e, 0x65, 0x1c, 0xa6, 0xf4, 0x7c, 0x63, - 0x03, 0xe8, 0x08, 0x4a, 0x2f, 0xce, 0x0c, 0xa3, 0x17, 0xd3, 0x8b, 0x90, 0xf6, 0xc6, 0x21, 0x8d, - 0x30, 0x6b, 0xa9, 0xa9, 0x85, 0xe1, 0x45, 0x48, 0x2b, 0xf4, 0x71, 0x84, 0xe9, 0x10, 0x6e, 0x0f, - 0x54, 0xb9, 0xe2, 0xea, 0x47, 0x2e, 0xaa, 0x5c, 0x45, 0x14, 0x8a, 0x47, 0x01, 0xc2, 0xbc, 0x5b, - 0xe2, 0xed, 0x4b, 0x69, 0x6d, 0x5a, 0x3e, 0x30, 0x0d, 0x0b, 0x3d, 0x04, 0xe3, 0x54, 0x40, 0x93, - 0xba, 0x88, 0xd4, 0x55, 0xb7, 0xcd, 0xf3, 0xac, 0x14, 0x0b, 0x28, 0x7a, 0x92, 0xea, 0x52, 0xa1, - 0x58, 0x15, 0x01, 0xb8, 0xf3, 0xa1, 0x2e, 0x15, 0xc2, 0x70, 0x04, 0x93, 0x36, 0x9d, 0x50, 0x29, - 0xc8, 0x56, 0xb0, 0xd6, 0x74, 0x26, 0x1a, 0x31, 0x87, 0x31, 0xeb, 0x47, 0x4c, 0x6a, 0xb2, 0x95, - 0x97, 0xd3, 0xac, 0x1f, 0x31, 0x38, 0xee, 0xa9, 0x41, 0x3b, 0x23, 0x9e, 0xed, 0x26, 0xb9, 0x77, - 0x67, 0x9f, 0x07, 0xb7, 0xd7, 0xf4, 0x1b, 0xc1, 0x14, 0x9b, 0xfa, 0xf7, 0xa7, 0x97, 0x3b, 0x6f, - 0xf0, 0x2b, 0xc1, 0x68, 0xca, 0xfb, 0x47, 0x61, 0x3a, 0x7a, 0x56, 0xa6, 0x6e, 0x9f, 0xff, 0xab, - 0x2c, 0x9c, 0xbc, 0xd4, 0xb0, 0x9d, 0xdb, 0x31, 0xc3, 0x76, 0x52, 0x4e, 0x5b, 0x63, 0xd8, 0x9c, - 0xb6, 0x61, 0xc8, 0x8f, 0x48, 0x1a, 0x9c, 0x1c, 0xf2, 0x23, 0x33, 0x0a, 0x47, 0x71, 0xd1, 0x8f, - 0x0c, 0xb8, 0xdf, 0xaa, 0x73, 0xed, 0xd5, 0x6a, 0x8a, 0xd2, 0x90, 0xa9, 0xdc, 0xd1, 0xfe, 0x88, - 0xb2, 0xa8, 0xb7, 0xf3, 0x4b, 0xa5, 0x03, 0xb8, 0xf2, 0x19, 0x7f, 0x87, 0xe8, 0xc1, 0xfd, 0x07, - 0xa1, 0xe2, 0x03, 0x9b, 0xbf, 0x78, 0x19, 0xde, 0x7e, 0x28, 0xa3, 0xa1, 0x56, 0xcb, 0xa7, 0x0c, - 0x28, 0x70, 0xf3, 0x29, 0x26, 0xdb, 0xf4, 0xa8, 0xb0, 0xda, 0xf6, 0x35, 0xe2, 0xf9, 0x32, 0xd9, - 0x96, 0x76, 0xc1, 0x2b, 0x55, 0xd6, 0x04, 0x04, 0x6b, 0x58, 0xf4, 0x30, 0xbe, 0x69, 0x3b, 0x75, - 0x31, 0x4d, 0xea, 0x30, 0x7e, 0xce, 0x76, 0xea, 0x98, 0x41, 0xd4, 0x71, 0x9d, 0xed, 0x6b, 0xd6, - 0x78, 0xc3, 0x80, 0x69, 0x16, 0xe7, 0x18, 0x5e, 0x3d, 0x9e, 0x50, 0x3e, 0x2d, 0xbc, 0x19, 0x67, - 0xa2, 0x3e, 0x2d, 0x77, 0xba, 0xc5, 0x49, 0x1e, 0x19, 0x19, 0x75, 0x71, 0xf9, 0xa0, 0xb0, 0x57, - 0x30, 0xcf, 0x9b, 0xcc, 0xd0, 0xd7, 0x69, 0x65, 0xcf, 0xab, 0x4a, 0x22, 0x38, 0xa4, 0x67, 0xbe, - 0x04, 0x53, 0x7a, 0xc0, 0x02, 0x7a, 0x02, 0x26, 0xdb, 0xb6, 0xd3, 0x88, 0x06, 0xb6, 0x29, 0x9b, - 0x6e, 0x25, 0x04, 0x61, 0x1d, 0x8f, 0x55, 0x73, 0xc3, 0x6a, 0x31, 0x53, 0x70, 0xc5, 0xd5, 0xab, - 0x85, 0x7f, 0xcc, 0x3f, 0xce, 0xc2, 0xc9, 0x84, 0xc0, 0x18, 0xf4, 0xaa, 0x01, 0xe3, 0xcc, 0x4b, - 0x5f, 0x7a, 0xad, 0xbc, 0x90, 0x7a, 0xf0, 0xcd, 0x12, 0x0b, 0x06, 0x10, 0xeb, 0x58, 0x1d, 0x9f, - 0xbc, 0x10, 0x0b, 0xe6, 0xe8, 0xb7, 0x0c, 0x98, 0xb4, 0xb4, 0xad, 0xc6, 0x1d, 0x79, 0xb6, 0xd2, - 0x6f, 0x4c, 0xcf, 0xce, 0xd2, 0x1c, 0x10, 0xc3, 0x8d, 0xa4, 0xb7, 0x65, 0xf1, 0xbd, 0x30, 0xa9, - 0x75, 0x61, 0x98, 0x1d, 0xb2, 0xf8, 0x0c, 0xcc, 0x8e, 0xb4, 0xc3, 0x3e, 0x00, 0xc3, 0xe6, 0x8e, - 0xa3, 0x02, 0xeb, 0x96, 0x1e, 0x7c, 0xac, 0x46, 0x5c, 0x44, 0x1f, 0x0b, 0xa8, 0xb9, 0x05, 0xb3, - 0xf1, 0xcb, 0x55, 0xea, 0xef, 0xd6, 0xef, 0x86, 0x21, 0xb3, 0xbd, 0x99, 0xdf, 0xc9, 0xc0, 0x84, - 0x88, 0xae, 0xbb, 0x0b, 0xbe, 0xbb, 0x37, 0x23, 0x8f, 0x3a, 0x6b, 0xa9, 0x04, 0x05, 0xf6, 0x75, - 0xdc, 0xf5, 0x63, 0x8e, 0xbb, 0xcf, 0xa5, 0xc3, 0xee, 0x60, 0xaf, 0xdd, 0x37, 0xc6, 0x60, 0x26, - 0x16, 0xad, 0x48, 0x55, 0x95, 0x1e, 0x67, 0xb5, 0xab, 0xa9, 0x06, 0x44, 0x2a, 0xbf, 0xf2, 0x83, - 0xfd, 0xd6, 0xfc, 0x48, 0x52, 0xcd, 0x2b, 0xa9, 0xe5, 0xe3, 0xfe, 0x45, 0x7e, 0xcd, 0x61, 0xfd, - 0xb0, 0xfe, 0xc9, 0x80, 0x7b, 0xfb, 0x06, 0xb5, 0xb2, 0x9c, 0x28, 0x5e, 0x14, 0x2a, 0x36, 0x64, - 0xca, 0xa1, 0xfb, 0xea, 0x85, 0x25, 0x9e, 0xc6, 0x22, 0xce, 0x1e, 0x3d, 0x0e, 0x53, 0x4c, 0xb4, - 0xd2, 0x33, 0x25, 0x20, 0x6d, 0x61, 0x20, 0x66, 0xa6, 0xc2, 0xaa, 0x56, 0x8e, 0x23, 0x58, 0xe6, - 0x97, 0x0d, 0x58, 0xe8, 0x97, 0x21, 0x63, 0x80, 0x8b, 0xe1, 0xff, 0x8b, 0x39, 0x17, 0x17, 0x7b, - 0x9c, 0x8b, 0x63, 0x57, 0x43, 0xe9, 0x47, 0xac, 0xdd, 0xca, 0xb2, 0x87, 0xf8, 0xce, 0x7e, 0xd6, - 0x80, 0xd3, 0x7d, 0x76, 0x53, 0x8f, 0x93, 0xb9, 0x71, 0x64, 0x27, 0xf3, 0xcc, 0xa0, 0x4e, 0xe6, - 0xe6, 0xf7, 0xb2, 0x30, 0x2b, 0xda, 0x13, 0xea, 0x57, 0x4f, 0x46, 0x5c, 0xb4, 0xdf, 0x11, 0x73, - 0xd1, 0x9e, 0x8f, 0xe3, 0xff, 0xc2, 0x3f, 0xfb, 0xad, 0xe5, 0x9f, 0xfd, 0xb3, 0x0c, 0x9c, 0x4a, - 0x4c, 0xdc, 0x81, 0x3e, 0x9d, 0x20, 0x1a, 0xae, 0xa7, 0x9c, 0x21, 0x64, 0x40, 0xe1, 0x30, 0xaa, - 0x53, 0xf3, 0x17, 0x74, 0x67, 0x62, 0x7e, 0xd4, 0x6f, 0x1f, 0x43, 0xae, 0x93, 0x21, 0xfd, 0x8a, - 0xcd, 0x5f, 0xcb, 0xc2, 0xc3, 0x83, 0x12, 0x7a, 0x8b, 0xc6, 0x9d, 0xf8, 0x91, 0xb8, 0x93, 0xbb, - 0x24, 0xb6, 0x8f, 0x25, 0x04, 0xe5, 0x2b, 0x59, 0x25, 0xf6, 0x7a, 0xd7, 0xe7, 0x40, 0xaf, 0x89, - 0x13, 0x54, 0xb5, 0x93, 0xe9, 0x3c, 0xc3, 0xa3, 0x70, 0xa2, 0xca, 0x8b, 0xef, 0x74, 0x8b, 0x73, - 0x22, 0xc5, 0x5f, 0x95, 0x04, 0xa2, 0x10, 0xcb, 0x4a, 0xe8, 0x61, 0xc8, 0x7b, 0x1c, 0x2a, 0x3d, - 0xed, 0xc5, 0x93, 0x2c, 0x2f, 0xc3, 0x0a, 0x8a, 0x3e, 0xa9, 0xe9, 0xc2, 0x63, 0xc7, 0x95, 0x25, - 0xe1, 0xa0, 0x97, 0xe6, 0x17, 0x20, 0xef, 0xcb, 0xc4, 0x9c, 0xfc, 0x39, 0xe0, 0xb1, 0x01, 0x03, - 0x38, 0xe8, 0xd5, 0x49, 0x66, 0xe9, 0xe4, 0xfd, 0x53, 0x39, 0x3c, 0x15, 0x49, 0x64, 0xaa, 0x5b, - 0x0b, 0xb7, 0x31, 0x42, 0xc2, 0x8d, 0xe5, 0xfb, 0x06, 0x4c, 0x8a, 0xd9, 0xba, 0x0b, 0x31, 0x25, - 0x37, 0xa2, 0x31, 0x25, 0xe7, 0x52, 0x39, 0x3b, 0xfa, 0x04, 0x94, 0xdc, 0x80, 0x29, 0x3d, 0x77, - 0x13, 0x7a, 0x5e, 0x3b, 0xfb, 0x8c, 0x51, 0xb2, 0xa1, 0xc8, 0xd3, 0x31, 0x3c, 0x17, 0xcd, 0x2f, - 0xe5, 0xd5, 0x28, 0x32, 0x3b, 0x84, 0xbe, 0x06, 0x8d, 0x03, 0xd7, 0xa0, 0xbe, 0x04, 0x32, 0xe9, - 0x2f, 0x81, 0x2b, 0x90, 0x97, 0x07, 0x94, 0x10, 0xe3, 0x0f, 0xea, 0x5e, 0x76, 0x54, 0x17, 0xa0, - 0xc4, 0xb4, 0x85, 0xcb, 0xae, 0x5a, 0x6a, 0x0e, 0xd5, 0xc1, 0xa9, 0xc8, 0xa0, 0x17, 0x61, 0xf2, - 0x96, 0xeb, 0xdd, 0x6c, 0xba, 0x16, 0x4b, 0xb9, 0x0b, 0x69, 0x3c, 0xec, 0x28, 0x83, 0x17, 0x77, - 0x75, 0xbe, 0x1e, 0xd2, 0xc7, 0x3a, 0x33, 0x54, 0x82, 0x99, 0x96, 0xed, 0x60, 0x62, 0xd5, 0x55, - 0xe8, 0xc8, 0x18, 0xcf, 0x09, 0x2a, 0x95, 0xdc, 0x8d, 0x28, 0x18, 0xc7, 0xf1, 0xd1, 0xc7, 0x21, - 0xef, 0x8b, 0x4c, 0x48, 0xe9, 0x3c, 0xc1, 0xa9, 0x3b, 0x23, 0x27, 0x1a, 0x8e, 0x9d, 0x2c, 0xc1, - 0x8a, 0x21, 0x5a, 0x87, 0x79, 0x4f, 0xe4, 0x1a, 0x89, 0x7c, 0xb0, 0x83, 0xef, 0x4f, 0x96, 0x7a, - 0x12, 0x27, 0xc0, 0x71, 0x62, 0x2d, 0xaa, 0xc5, 0xb0, 0x24, 0x64, 0xfc, 0x4d, 0x40, 0x33, 0xa3, - 0xb3, 0x05, 0x5f, 0xc7, 0x02, 0x7a, 0x50, 0x28, 0x52, 0x7e, 0x84, 0x50, 0xa4, 0x2a, 0x9c, 0x8a, - 0x83, 0x58, 0x46, 0x14, 0x96, 0x84, 0x45, 0x93, 0x1e, 0x95, 0x24, 0x24, 0x9c, 0x5c, 0x17, 0x5d, - 0x87, 0x82, 0x47, 0xd8, 0xfd, 0xa2, 0x24, 0x1f, 0xfd, 0x87, 0x76, 0x6f, 0xc2, 0x92, 0x00, 0x0e, - 0x69, 0xd1, 0x79, 0xb7, 0xa2, 0x69, 0x31, 0xaf, 0xa4, 0xf8, 0xc9, 0x31, 0x31, 0xf7, 0x7d, 0x32, - 0x15, 0x99, 0x6f, 0x4e, 0xc3, 0x89, 0x88, 0x6d, 0x01, 0x3d, 0x08, 0x39, 0x96, 0x22, 0x86, 0x1d, - 0x0f, 0xf9, 0xf0, 0x08, 0xe3, 0x83, 0xc3, 0x61, 0xe8, 0x73, 0x06, 0xcc, 0xb4, 0x23, 0x56, 0x58, - 0x79, 0x72, 0x8e, 0xf8, 0xce, 0x17, 0x35, 0xed, 0x6a, 0x09, 0xa5, 0xa3, 0xcc, 0x70, 0x9c, 0x3b, - 0xdd, 0x80, 0xc2, 0x47, 0xb0, 0x49, 0x3c, 0x86, 0x2d, 0x74, 0x1c, 0x45, 0x62, 0x25, 0x0a, 0xc6, - 0x71, 0x7c, 0x3a, 0xc3, 0xac, 0x77, 0xa3, 0x7c, 0x8b, 0xa8, 0x24, 0x09, 0xe0, 0x90, 0x16, 0x7a, - 0x06, 0xa6, 0x45, 0x36, 0xc4, 0x8a, 0x5b, 0xbf, 0x60, 0xf9, 0x3b, 0x42, 0xb9, 0x57, 0x97, 0x91, - 0x95, 0x08, 0x14, 0xc7, 0xb0, 0x59, 0xdf, 0xc2, 0x94, 0x93, 0x8c, 0xc0, 0x78, 0x34, 0xdf, 0xf6, - 0x4a, 0x14, 0x8c, 0xe3, 0xf8, 0xe8, 0x11, 0xed, 0xdc, 0xe7, 0xef, 0x74, 0xea, 0x34, 0x48, 0x38, - 0xfb, 0x4b, 0x30, 0xd3, 0x61, 0x77, 0xa1, 0xba, 0x04, 0x8a, 0xfd, 0xa8, 0x18, 0x5e, 0x8d, 0x82, - 0x71, 0x1c, 0x1f, 0x3d, 0x05, 0x27, 0x3c, 0x7a, 0xba, 0x29, 0x02, 0xfc, 0xf1, 0x4e, 0xbd, 0xcd, - 0x60, 0x1d, 0x88, 0xa3, 0xb8, 0xe8, 0x59, 0x98, 0x0b, 0x93, 0x87, 0x49, 0x02, 0xfc, 0x35, 0x4f, - 0xe5, 0xc5, 0x29, 0xc5, 0x11, 0x70, 0x6f, 0x1d, 0xf4, 0x4b, 0x30, 0xab, 0x8d, 0xc4, 0x9a, 0x53, - 0x27, 0xb7, 0x45, 0x82, 0x27, 0xf6, 0x69, 0x84, 0x95, 0x18, 0x0c, 0xf7, 0x60, 0xa3, 0xf7, 0xc1, - 0x74, 0xcd, 0x6d, 0x36, 0xd9, 0x19, 0xc7, 0x73, 0x3d, 0xf3, 0x4c, 0x4e, 0x3c, 0xe7, 0x55, 0x04, - 0x82, 0x63, 0x98, 0xe8, 0x22, 0x20, 0x77, 0xcb, 0x27, 0xde, 0x2e, 0xa9, 0x3f, 0xcb, 0xbf, 0x6e, - 0x4a, 0x45, 0xfc, 0x89, 0xa8, 0x87, 0xf2, 0xe5, 0x1e, 0x0c, 0x9c, 0x50, 0x8b, 0xa5, 0xd5, 0xd1, - 0x22, 0xba, 0xa6, 0xd3, 0xf8, 0x2e, 0x4f, 0xfc, 0xe6, 0x7e, 0x68, 0x38, 0x97, 0x07, 0xe3, 0xdc, - 0x61, 0x3c, 0x9d, 0x94, 0x4e, 0x7a, 0xda, 0xd7, 0x50, 0x46, 0xf0, 0x52, 0x2c, 0x38, 0xa1, 0x4f, - 0x40, 0x61, 0x4b, 0xe6, 0x00, 0x5f, 0x98, 0x4d, 0x43, 0x2e, 0xc6, 0xd2, 0xd9, 0x87, 0x37, 0x53, - 0x05, 0xc0, 0x21, 0x4b, 0xf4, 0x10, 0x4c, 0x5e, 0xa8, 0x94, 0xd4, 0x2a, 0x9c, 0x63, 0xb3, 0x3f, - 0x46, 0xab, 0x60, 0x1d, 0x40, 0x77, 0x98, 0xd2, 0x97, 0x10, 0x9b, 0xe2, 0x50, 0xde, 0xf6, 0xaa, - 0x3f, 0x14, 0x9b, 0x3d, 0x47, 0xe2, 0xea, 0xc2, 0xc9, 0x18, 0xb6, 0x28, 0xc7, 0x0a, 0x03, 0xbd, - 0x00, 0x93, 0x42, 0x5e, 0xb0, 0xb3, 0x69, 0xfe, 0x68, 0xd1, 0x82, 0x38, 0x24, 0x81, 0x75, 0x7a, - 0xec, 0x95, 0x89, 0xa5, 0x46, 0x26, 0xe7, 0x3b, 0xcd, 0xe6, 0xc2, 0x29, 0x76, 0x6e, 0x86, 0xaf, - 0x4c, 0x21, 0x08, 0xeb, 0x78, 0xe8, 0x31, 0xe9, 0x39, 0xf1, 0xb6, 0xc8, 0xb3, 0x9b, 0xf2, 0x9c, - 0x50, 0x5a, 0x6e, 0x1f, 0x87, 0xe2, 0xd3, 0x87, 0xb8, 0x2c, 0x6c, 0xc1, 0xa2, 0x54, 0xb1, 0x7a, - 0x37, 0xc9, 0xc2, 0x42, 0xc4, 0x4a, 0xb0, 0x78, 0xbd, 0x2f, 0x26, 0x3e, 0x80, 0x0a, 0xda, 0x82, - 0xac, 0xd5, 0xdc, 0x5a, 0xb8, 0x37, 0x0d, 0x5d, 0x51, 0x7d, 0xad, 0x98, 0x3b, 0x01, 0x95, 0xd6, - 0xcb, 0x98, 0x12, 0x37, 0x5f, 0xc9, 0x28, 0xab, 0xbc, 0x4a, 0x75, 0xf9, 0x92, 0xbe, 0xaa, 0x8d, - 0x34, 0xbe, 0xc6, 0xd9, 0x93, 0x28, 0x9f, 0x0b, 0xa4, 0xc4, 0x35, 0xdd, 0x56, 0xfb, 0x38, 0x95, - 0x3c, 0x26, 0xd1, 0x34, 0x9e, 0xfc, 0x36, 0x17, 0xdd, 0xc5, 0xe6, 0xfe, 0x84, 0x32, 0x42, 0xc5, - 0x5c, 0x01, 0x3c, 0xc8, 0xd9, 0x7e, 0x60, 0xbb, 0x29, 0x46, 0xb6, 0xc5, 0xf2, 0x5f, 0x32, 0xc7, - 0x59, 0x06, 0xc0, 0x9c, 0x15, 0xe5, 0xe9, 0x34, 0x6c, 0xe7, 0xb6, 0xe8, 0xfe, 0x95, 0xd4, 0xdf, - 0xf8, 0x39, 0x4f, 0x06, 0xc0, 0x9c, 0x15, 0xba, 0xc1, 0x57, 0x5a, 0x3a, 0x5f, 0x5e, 0x8d, 0x7f, - 0x50, 0x39, 0xba, 0xe2, 0x28, 0x2f, 0xbf, 0x65, 0x0b, 0x1d, 0x66, 0x44, 0x5e, 0xd5, 0x8d, 0xb5, - 0x24, 0x5e, 0xd5, 0x8d, 0x35, 0x4c, 0x99, 0xa0, 0xd7, 0x0c, 0x00, 0x4b, 0x7d, 0x59, 0x38, 0x9d, - 0xaf, 0x4a, 0xf4, 0xfb, 0x52, 0x31, 0xf7, 0x75, 0x0b, 0xa1, 0x58, 0xe3, 0x8c, 0x5e, 0x84, 0x09, - 0x8b, 0x7f, 0x13, 0x47, 0xb8, 0x11, 0xa6, 0xf3, 0xa1, 0xa7, 0x58, 0x0b, 0x98, 0xff, 0xa4, 0x00, - 0x61, 0xc9, 0x90, 0xf2, 0x0e, 0x3c, 0x8b, 0x6c, 0xdb, 0x37, 0x85, 0x3f, 0x61, 0x75, 0xe4, 0xd4, - 0xd6, 0x94, 0x58, 0x12, 0x6f, 0x01, 0xc2, 0x92, 0x21, 0xff, 0x98, 0xa7, 0xe5, 0x58, 0x2a, 0x38, - 0x24, 0x9d, 0x10, 0x22, 0x3d, 0xdc, 0x44, 0xfb, 0x98, 0xa7, 0xce, 0x08, 0x47, 0xf9, 0x9a, 0x3f, - 0xc9, 0x02, 0xb0, 0x9f, 0x3c, 0x60, 0xb9, 0xc5, 0x92, 0xdc, 0xed, 0xb8, 0x75, 0xb1, 0xb5, 0x53, - 0x8c, 0x3b, 0x06, 0x91, 0xd1, 0x6e, 0xc7, 0xad, 0x63, 0xc1, 0x04, 0x35, 0x60, 0xac, 0x6d, 0x05, - 0x3b, 0xe9, 0x07, 0x39, 0xe7, 0x79, 0xe4, 0x4e, 0xb0, 0x83, 0x19, 0x03, 0xf4, 0xb2, 0x01, 0x13, - 0x3c, 0xcc, 0x59, 0x9a, 0x9a, 0x47, 0x7e, 0x4f, 0x95, 0x63, 0xb6, 0xc4, 0x63, 0xa9, 0x85, 0xb3, - 0x82, 0x12, 0x8d, 0xa2, 0x14, 0x4b, 0xb6, 0x8b, 0xaf, 0x1a, 0x30, 0xa5, 0xa3, 0x26, 0xb8, 0x19, - 0x7c, 0x44, 0x77, 0x33, 0x48, 0x73, 0x3c, 0x74, 0x8f, 0x85, 0x7f, 0x35, 0x40, 0xfb, 0x04, 0x6a, - 0xe8, 0x64, 0x68, 0x0c, 0xec, 0x64, 0x98, 0x19, 0xd2, 0xc9, 0x30, 0x3b, 0x94, 0x93, 0xe1, 0xd8, - 0xf0, 0x4e, 0x86, 0xb9, 0xfe, 0x4e, 0x86, 0xe6, 0xeb, 0x06, 0xcc, 0xf5, 0x9c, 0x87, 0xf1, 0x4f, - 0xcd, 0x1b, 0x03, 0x7e, 0x6a, 0x7e, 0x15, 0x66, 0x45, 0x12, 0xe6, 0x6a, 0xbb, 0x69, 0x27, 0x06, - 0xa0, 0x6f, 0xc6, 0xe0, 0xb8, 0xa7, 0x86, 0xf9, 0xe7, 0x06, 0x4c, 0x6a, 0x61, 0x6b, 0xb4, 0x1f, - 0x2c, 0xbc, 0x4f, 0x34, 0x23, 0xcc, 0x3f, 0xcd, 0x4c, 0xfb, 0x1c, 0xc6, 0x5f, 0x99, 0x1a, 0x5a, - 0xc2, 0xcf, 0xf0, 0x95, 0x89, 0x96, 0x62, 0x01, 0xe5, 0xa9, 0x1c, 0x49, 0x9b, 0x0d, 0x7a, 0x56, - 0x4f, 0xe5, 0x48, 0xda, 0x98, 0x41, 0x18, 0x3b, 0xaa, 0x47, 0x0a, 0xff, 0x53, 0x2d, 0xdd, 0xb5, - 0xe5, 0x05, 0x98, 0xc3, 0xd0, 0x19, 0xc8, 0x12, 0xa7, 0x2e, 0x2e, 0xbd, 0xea, 0x13, 0x53, 0xe7, - 0x9c, 0x3a, 0xa6, 0xe5, 0xe6, 0x65, 0x98, 0xaa, 0x92, 0x9a, 0x47, 0x82, 0xe7, 0xc8, 0xde, 0xc0, - 0xdf, 0xac, 0xa2, 0xab, 0x3d, 0xf6, 0xcd, 0x2a, 0x5a, 0x9d, 0x96, 0x9b, 0x7f, 0x68, 0x40, 0x2c, - 0x27, 0xbb, 0x66, 0x71, 0x36, 0xfa, 0x59, 0x9c, 0x23, 0xb6, 0xd1, 0xcc, 0x81, 0xb6, 0xd1, 0x8b, - 0x80, 0x5a, 0x74, 0x2b, 0x44, 0xbe, 0x40, 0x20, 0xec, 0x0d, 0x61, 0x90, 0x6c, 0x0f, 0x06, 0x4e, - 0xa8, 0x65, 0xfe, 0x01, 0x6f, 0xac, 0x9e, 0xa5, 0xfd, 0xf0, 0x01, 0xe8, 0x40, 0x8e, 0x91, 0x12, - 0x46, 0x97, 0xca, 0x68, 0x9b, 0xbb, 0x37, 0xd9, 0x44, 0x38, 0x91, 0x62, 0xcb, 0x33, 0x6e, 0xe6, - 0xf7, 0x78, 0x5b, 0xb5, 0x34, 0xee, 0x03, 0xb4, 0xb5, 0x15, 0x6d, 0xeb, 0x85, 0xb4, 0xce, 0xca, - 0xe4, 0x36, 0xa2, 0x25, 0x80, 0x36, 0xf1, 0x6a, 0xc4, 0x09, 0xa4, 0x5b, 0x74, 0x4e, 0x84, 0x91, - 0xa8, 0x52, 0xac, 0x61, 0x98, 0x2f, 0x1b, 0x30, 0x5b, 0x0d, 0xec, 0xda, 0x4d, 0xdb, 0xe1, 0x61, - 0x51, 0xdb, 0x76, 0x83, 0xde, 0x52, 0x88, 0xf8, 0x1c, 0x13, 0x37, 0x83, 0xa9, 0xa3, 0x58, 0x7e, - 0x85, 0x49, 0xc2, 0x51, 0x09, 0x66, 0xa4, 0xb5, 0x5d, 0xda, 0x2e, 0x79, 0x38, 0xa7, 0xb2, 0x95, - 0xac, 0x46, 0xc1, 0x38, 0x8e, 0x6f, 0x7e, 0x12, 0x26, 0xb5, 0xf3, 0x95, 0x1d, 0x45, 0xb7, 0xad, - 0x5a, 0x10, 0xdf, 0xc2, 0xe7, 0x68, 0x21, 0xe6, 0x30, 0x66, 0x62, 0xe5, 0x7e, 0xb3, 0xb1, 0x2d, - 0x2c, 0xbc, 0x65, 0x05, 0x94, 0x12, 0xf3, 0x48, 0x83, 0xdc, 0x96, 0xa9, 0x45, 0x25, 0x31, 0x4c, - 0x0b, 0x31, 0x87, 0x99, 0x8f, 0x40, 0x5e, 0x06, 0xdd, 0xb3, 0xc8, 0x55, 0x69, 0xfe, 0xd3, 0x23, - 0x57, 0x5d, 0x2f, 0xc0, 0x0c, 0x62, 0x5e, 0x83, 0xbc, 0xcc, 0x0d, 0x70, 0x38, 0x36, 0xdd, 0x55, - 0xbe, 0x63, 0x5f, 0x70, 0xfd, 0x40, 0x26, 0x34, 0xe0, 0x4f, 0x02, 0x97, 0xd6, 0x58, 0x19, 0x56, - 0x50, 0x73, 0x0e, 0x66, 0x94, 0xad, 0x5f, 0x38, 0x32, 0x7e, 0x33, 0x0b, 0x53, 0x91, 0x4f, 0x01, - 0x1f, 0xbe, 0xdc, 0x06, 0xdf, 0xc5, 0x09, 0x36, 0xfb, 0xec, 0x90, 0x36, 0x7b, 0xfd, 0x91, 0x64, - 0xec, 0x78, 0x1f, 0x49, 0x72, 0xe9, 0x3c, 0x92, 0x04, 0x30, 0xe1, 0x0b, 0x41, 0x35, 0x9e, 0x86, - 0x31, 0x25, 0x36, 0x63, 0x5c, 0x47, 0x95, 0xf2, 0x4e, 0xb2, 0x32, 0xbf, 0x96, 0x83, 0xe9, 0x68, - 0x56, 0xa4, 0x01, 0x66, 0xf2, 0x91, 0x9e, 0x99, 0x1c, 0xd2, 0x66, 0x99, 0x1d, 0xd5, 0x66, 0x39, - 0x36, 0xaa, 0xcd, 0x32, 0x77, 0x04, 0x9b, 0x65, 0xaf, 0xc5, 0x71, 0x7c, 0x60, 0x8b, 0xe3, 0xd3, - 0xca, 0xe1, 0x66, 0x22, 0xf2, 0x42, 0x1d, 0x3a, 0xdc, 0xa0, 0xe8, 0x34, 0xac, 0xb8, 0xf5, 0x44, - 0xc7, 0xa5, 0xfc, 0x21, 0xb6, 0x19, 0x2f, 0xd1, 0x3f, 0x66, 0xf8, 0x67, 0x91, 0xb7, 0x0d, 0xe1, - 0x1b, 0xf3, 0x04, 0x4c, 0x8a, 0xf5, 0xc4, 0x74, 0x25, 0x88, 0xea, 0x59, 0xd5, 0x10, 0x84, 0x75, - 0x3c, 0xf6, 0xb5, 0xca, 0xe8, 0xe7, 0x39, 0x99, 0x09, 0x58, 0xff, 0x5a, 0x65, 0xec, 0x73, 0x9e, - 0x71, 0x7c, 0xf3, 0xe3, 0x70, 0x2a, 0xf1, 0x46, 0xc6, 0x4c, 0x54, 0x4c, 0x8c, 0x93, 0xba, 0x40, - 0xd0, 0x9a, 0x11, 0x4b, 0x9a, 0xbb, 0x78, 0xbd, 0x2f, 0x26, 0x3e, 0x80, 0x8a, 0xf9, 0xd5, 0x2c, - 0x4c, 0x47, 0x3f, 0x75, 0x84, 0x6e, 0x29, 0xfb, 0x4d, 0x2a, 0xa6, 0x23, 0x4e, 0x56, 0xcb, 0xb4, - 0xd3, 0xd7, 0x18, 0x7b, 0x8b, 0xad, 0xaf, 0x2d, 0x95, 0xf6, 0xe7, 0xf8, 0x18, 0x0b, 0x2b, 0xa8, - 0x60, 0xc7, 0xbe, 0x66, 0x14, 0x86, 0x3b, 0x88, 0x6b, 0x57, 0xea, 0xdc, 0xc3, 0x00, 0x06, 0xc5, - 0x0a, 0x6b, 0x6c, 0xa9, 0x6c, 0xd9, 0x25, 0x9e, 0xbd, 0x6d, 0xab, 0xcf, 0x34, 0xb2, 0x93, 0xfb, - 0x9a, 0x28, 0xc3, 0x0a, 0x6a, 0xbe, 0x9c, 0x81, 0xf0, 0xa3, 0xb4, 0xec, 0x7b, 0x20, 0xbe, 0xa6, - 0xe2, 0x8a, 0x69, 0xbb, 0x38, 0xea, 0x47, 0x77, 0x42, 0x8a, 0xc2, 0x19, 0x52, 0x2b, 0xc1, 0x11, - 0x8e, 0x3f, 0x87, 0x8f, 0xd1, 0x5a, 0x30, 0x13, 0x0b, 0x02, 0x4d, 0xdd, 0xe3, 0xfc, 0x4b, 0x59, - 0x28, 0xa8, 0x30, 0x5a, 0xf4, 0xde, 0x88, 0xbd, 0xa1, 0x50, 0x7e, 0xbb, 0x96, 0xfa, 0x7e, 0xc7, - 0xad, 0xdf, 0xe9, 0x16, 0x67, 0x14, 0x72, 0xcc, 0x76, 0x70, 0x06, 0xb2, 0x1d, 0xaf, 0x19, 0xbf, - 0x50, 0x5c, 0xc5, 0xeb, 0x98, 0x96, 0xa3, 0xdb, 0xf1, 0x0b, 0xff, 0x46, 0x4a, 0xa1, 0xbf, 0x5c, - 0xf3, 0xee, 0x7f, 0xd1, 0xa7, 0x52, 0x72, 0xcb, 0xad, 0xef, 0xc5, 0x53, 0xe5, 0x97, 0xdd, 0xfa, - 0x1e, 0x66, 0x10, 0xf4, 0x0c, 0x4c, 0x07, 0x76, 0x8b, 0xb8, 0x9d, 0x40, 0xff, 0xe4, 0x67, 0x36, - 0x7c, 0x5c, 0xdc, 0x8c, 0x40, 0x71, 0x0c, 0x9b, 0x4a, 0xd9, 0x1b, 0xbe, 0xeb, 0xb0, 0xfc, 0x77, - 0xe3, 0xd1, 0x97, 0x88, 0x8b, 0xd5, 0xcb, 0x97, 0x98, 0xdd, 0x43, 0x61, 0x50, 0x6c, 0x9b, 0xc5, - 0xcc, 0x79, 0x44, 0xbc, 0xed, 0xcf, 0x86, 0x19, 0x15, 0x78, 0x39, 0x56, 0x18, 0xe6, 0x55, 0x98, - 0x89, 0x75, 0x55, 0x5e, 0xdd, 0x8c, 0xe4, 0xab, 0xdb, 0x60, 0x79, 0xe9, 0xff, 0xc4, 0x80, 0xb9, - 0x9e, 0xcd, 0x3b, 0x68, 0x28, 0x44, 0x5c, 0x8c, 0x64, 0x8e, 0x2e, 0x46, 0xb2, 0xc3, 0x89, 0x91, - 0xf2, 0xd6, 0xb7, 0xdf, 0x3c, 0x7b, 0xcf, 0x77, 0xdf, 0x3c, 0x7b, 0xcf, 0x0f, 0xde, 0x3c, 0x7b, - 0xcf, 0xcb, 0xfb, 0x67, 0x8d, 0x6f, 0xef, 0x9f, 0x35, 0xbe, 0xbb, 0x7f, 0xd6, 0xf8, 0xc1, 0xfe, - 0x59, 0xe3, 0x1f, 0xf7, 0xcf, 0x1a, 0xaf, 0xff, 0xf8, 0xec, 0x3d, 0xcf, 0x3f, 0x1d, 0x2e, 0xad, - 0x65, 0xb9, 0xb4, 0xd8, 0x8f, 0x77, 0xc9, 0x85, 0xb4, 0xdc, 0xbe, 0xd9, 0x58, 0xa6, 0x4b, 0x6b, - 0x59, 0x95, 0xc8, 0xa5, 0xf5, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x41, 0x02, 0xde, 0xaf, 0x0f, - 0x93, 0x00, 0x00, + 0x38, 0xf0, 0xe7, 0x7c, 0x9f, 0x23, 0x25, 0xfe, 0xf9, 0xea, 0xc4, 0x86, 0x5b, 0x52, 0xda, 0xf5, + 0x6a, 0x2d, 0xed, 0x72, 0x2f, 0xb5, 0xbb, 0x89, 0x13, 0x27, 0x19, 0x91, 0x57, 0xd4, 0xec, 0x92, + 0x33, 0xcc, 0xcc, 0x50, 0xbb, 0x72, 0x8c, 0xc4, 0x6e, 0x60, 0x37, 0x2d, 0x12, 0xc4, 0x6d, 0x12, + 0x14, 0x45, 0xd1, 0x22, 0x28, 0x0c, 0xf4, 0x27, 0x7d, 0x0a, 0x5a, 0xf4, 0x25, 0x40, 0x8b, 0xe6, + 0xa7, 0xe9, 0x43, 0x8a, 0xa4, 0x40, 0x9b, 0xa4, 0x40, 0xd8, 0x5a, 0xe9, 0x4b, 0x8b, 0x16, 0x41, + 0x81, 0x14, 0x45, 0xf6, 0xa9, 0xb8, 0xbf, 0x73, 0x67, 0x38, 0x94, 0x48, 0x71, 0xb4, 0x31, 0xda, + 0xbc, 0x91, 0xf7, 0x9c, 0x7b, 0xce, 0xb9, 0xbf, 0xe7, 0xdc, 0x73, 0xcf, 0x3d, 0x03, 0xeb, 0x0d, + 0x3b, 0xd8, 0xe9, 0x6c, 0x2d, 0xd5, 0xdc, 0xd6, 0xb2, 0xe5, 0x35, 0xdc, 0xb6, 0xe7, 0xde, 0x60, + 0x3f, 0xde, 0xe5, 0xb9, 0xcd, 0xa6, 0xdb, 0x09, 0xfc, 0xe5, 0xf6, 0xcd, 0xc6, 0xb2, 0xd5, 0xb6, + 0xfd, 0x65, 0x55, 0xb2, 0xfb, 0x1e, 0xab, 0xd9, 0xde, 0xb1, 0xde, 0xb3, 0xdc, 0x20, 0x0e, 0xf1, + 0xac, 0x80, 0xd4, 0x97, 0xda, 0x9e, 0x1b, 0xb8, 0xe8, 0xe9, 0x90, 0xda, 0x92, 0xa4, 0xc6, 0x7e, + 0x7c, 0x44, 0xd6, 0x5d, 0x6a, 0xdf, 0x6c, 0x2c, 0x51, 0x6a, 0x4b, 0xaa, 0x44, 0x52, 0x5b, 0x7c, + 0x97, 0x26, 0x4b, 0xc3, 0x6d, 0xb8, 0xcb, 0x8c, 0xe8, 0x56, 0x67, 0x9b, 0xfd, 0x63, 0x7f, 0xd8, + 0x2f, 0xce, 0x6c, 0xf1, 0xc1, 0x9b, 0x4f, 0xfa, 0x4b, 0xb6, 0x4b, 0x65, 0x5b, 0xde, 0xb2, 0x82, + 0xda, 0xce, 0xf2, 0x6e, 0x8f, 0x44, 0x8b, 0xa6, 0x86, 0x54, 0x73, 0x3d, 0x92, 0x84, 0xf3, 0x78, + 0x88, 0xd3, 0xb2, 0x6a, 0x3b, 0xb6, 0x43, 0xbc, 0xbd, 0xb0, 0xd5, 0x2d, 0x12, 0x58, 0x49, 0xb5, + 0x96, 0xfb, 0xd5, 0xf2, 0x3a, 0x4e, 0x60, 0xb7, 0x48, 0x4f, 0x85, 0xff, 0x7f, 0x58, 0x05, 0xbf, + 0xb6, 0x43, 0x5a, 0x56, 0x4f, 0xbd, 0xc7, 0xfa, 0xd5, 0xeb, 0x04, 0x76, 0x73, 0xd9, 0x76, 0x02, + 0x3f, 0xf0, 0xe2, 0x95, 0xcc, 0xaf, 0x67, 0xa1, 0x50, 0x5a, 0x2f, 0x57, 0x03, 0x2b, 0xe8, 0xf8, + 0xe8, 0x35, 0x03, 0xa6, 0x9a, 0xae, 0x55, 0x2f, 0x5b, 0x4d, 0xcb, 0xa9, 0x11, 0x6f, 0xc1, 0x78, + 0xc0, 0x78, 0x78, 0xf2, 0xd1, 0xf5, 0xa5, 0x51, 0xc6, 0x6b, 0xa9, 0x74, 0xcb, 0xc7, 0xc4, 0x77, + 0x3b, 0x5e, 0x8d, 0x60, 0xb2, 0x5d, 0x9e, 0xff, 0x56, 0xb7, 0x78, 0xcf, 0x7e, 0xb7, 0x38, 0xb5, + 0xae, 0x71, 0xc2, 0x11, 0xbe, 0xe8, 0x8b, 0x06, 0xcc, 0xd5, 0x2c, 0xc7, 0xf2, 0xf6, 0x36, 0x2d, + 0xaf, 0x41, 0x82, 0x67, 0x3d, 0xb7, 0xd3, 0x5e, 0xc8, 0x1c, 0x83, 0x34, 0xf7, 0x0a, 0x69, 0xe6, + 0x56, 0xe2, 0xec, 0x70, 0xaf, 0x04, 0x4c, 0x2e, 0x3f, 0xb0, 0xb6, 0x9a, 0x44, 0x97, 0x2b, 0x7b, + 0x9c, 0x72, 0x55, 0xe3, 0xec, 0x70, 0xaf, 0x04, 0xe6, 0xab, 0x59, 0x98, 0x2b, 0xad, 0x97, 0x37, + 0x3d, 0x6b, 0x7b, 0xdb, 0xae, 0x61, 0xb7, 0x13, 0xd8, 0x4e, 0x03, 0xbd, 0x13, 0x26, 0x6c, 0xa7, + 0xe1, 0x11, 0xdf, 0x67, 0x03, 0x59, 0x28, 0xcf, 0x08, 0xa2, 0x13, 0x6b, 0xbc, 0x18, 0x4b, 0x38, + 0x7a, 0x02, 0x26, 0x7d, 0xe2, 0xed, 0xda, 0x35, 0x52, 0x71, 0xbd, 0x80, 0xf5, 0x74, 0xae, 0x7c, + 0x52, 0xa0, 0x4f, 0x56, 0x43, 0x10, 0xd6, 0xf1, 0x68, 0x35, 0xcf, 0x75, 0x03, 0x01, 0x67, 0x1d, + 0x51, 0x08, 0xab, 0xe1, 0x10, 0x84, 0x75, 0x3c, 0xf4, 0xba, 0x01, 0xb3, 0x7e, 0x60, 0xd7, 0x6e, + 0xda, 0x0e, 0xf1, 0xfd, 0x15, 0xd7, 0xd9, 0xb6, 0x1b, 0x0b, 0x39, 0xd6, 0x8b, 0x97, 0x46, 0xeb, + 0xc5, 0x6a, 0x8c, 0x6a, 0x79, 0x7e, 0xbf, 0x5b, 0x9c, 0x8d, 0x97, 0xe2, 0x1e, 0xee, 0x68, 0x15, + 0x66, 0x2d, 0xc7, 0x71, 0x03, 0x2b, 0xb0, 0x5d, 0xa7, 0xe2, 0x91, 0x6d, 0xfb, 0xf6, 0xc2, 0x18, + 0x6b, 0xce, 0x82, 0x68, 0xce, 0x6c, 0x29, 0x06, 0xc7, 0x3d, 0x35, 0xcc, 0x55, 0x58, 0x28, 0xb5, + 0xb6, 0x2c, 0xdf, 0xb7, 0xea, 0xae, 0x17, 0x1b, 0x8d, 0x87, 0x21, 0xdf, 0xb2, 0xda, 0x6d, 0xdb, + 0x69, 0xd0, 0xe1, 0xc8, 0x3e, 0x5c, 0x28, 0x4f, 0xed, 0x77, 0x8b, 0xf9, 0x0d, 0x51, 0x86, 0x15, + 0xd4, 0xfc, 0x41, 0x06, 0x26, 0x4b, 0x8e, 0xd5, 0xdc, 0xf3, 0x6d, 0x1f, 0x77, 0x1c, 0xf4, 0x51, + 0xc8, 0xd3, 0xdd, 0xa5, 0x6e, 0x05, 0x96, 0x58, 0x91, 0xef, 0x5e, 0xe2, 0x8b, 0x7d, 0x49, 0x5f, + 0xec, 0x61, 0xbf, 0x50, 0xec, 0xa5, 0xdd, 0xf7, 0x2c, 0x5d, 0xde, 0xba, 0x41, 0x6a, 0xc1, 0x06, + 0x09, 0xac, 0x32, 0x12, 0xad, 0x80, 0xb0, 0x0c, 0x2b, 0xaa, 0xc8, 0x85, 0x31, 0xbf, 0x4d, 0x6a, + 0x62, 0x85, 0x6d, 0x8c, 0x38, 0x93, 0x43, 0xd1, 0xab, 0x6d, 0x52, 0x2b, 0x4f, 0x09, 0xd6, 0x63, + 0xf4, 0x1f, 0x66, 0x8c, 0xd0, 0x2d, 0x18, 0xf7, 0xd9, 0x9e, 0x23, 0x16, 0xcf, 0xe5, 0xf4, 0x58, + 0x32, 0xb2, 0xe5, 0x69, 0xc1, 0x74, 0x9c, 0xff, 0xc7, 0x82, 0x9d, 0xf9, 0x0f, 0x06, 0x9c, 0xd4, + 0xb0, 0x4b, 0x5e, 0xa3, 0xd3, 0x22, 0x4e, 0x80, 0x1e, 0x80, 0x31, 0xc7, 0x6a, 0x11, 0xb1, 0x50, + 0x94, 0xc8, 0x97, 0xac, 0x16, 0xc1, 0x0c, 0x82, 0x1e, 0x84, 0xdc, 0xae, 0xd5, 0xec, 0x10, 0xd6, + 0x49, 0x85, 0xf2, 0x09, 0x81, 0x92, 0xbb, 0x46, 0x0b, 0x31, 0x87, 0xa1, 0x97, 0xa0, 0xc0, 0x7e, + 0x9c, 0xf7, 0xdc, 0x56, 0x4a, 0x4d, 0x13, 0x12, 0x5e, 0x93, 0x64, 0xcb, 0x27, 0xf6, 0xbb, 0xc5, + 0x82, 0xfa, 0x8b, 0x43, 0x86, 0xe6, 0x3f, 0x1a, 0x30, 0xa3, 0x35, 0x6e, 0xdd, 0xf6, 0x03, 0xf4, + 0xa1, 0x9e, 0xc9, 0xb3, 0x34, 0xd8, 0xe4, 0xa1, 0xb5, 0xd9, 0xd4, 0x99, 0x15, 0x2d, 0xcd, 0xcb, + 0x12, 0x6d, 0xe2, 0x38, 0x90, 0xb3, 0x03, 0xd2, 0xf2, 0x17, 0x32, 0x0f, 0x64, 0x1f, 0x9e, 0x7c, + 0x74, 0x2d, 0xb5, 0x61, 0x0c, 0xfb, 0x77, 0x8d, 0xd2, 0xc7, 0x9c, 0x8d, 0xf9, 0x95, 0xb1, 0x48, + 0x0b, 0xe9, 0x8c, 0x42, 0x2e, 0x4c, 0xb4, 0x48, 0xe0, 0xd9, 0x35, 0xbe, 0xae, 0x26, 0x1f, 0x5d, + 0x1d, 0x4d, 0x8a, 0x0d, 0x46, 0x2c, 0xdc, 0x2c, 0xf9, 0x7f, 0x1f, 0x4b, 0x2e, 0x68, 0x07, 0xc6, + 0x2c, 0xaf, 0x21, 0xdb, 0x7c, 0x3e, 0x9d, 0xf1, 0x0d, 0xe7, 0x5c, 0xc9, 0x6b, 0xf8, 0x98, 0x71, + 0x40, 0xcb, 0x50, 0x08, 0x88, 0xd7, 0xb2, 0x1d, 0x2b, 0xe0, 0xbb, 0x6b, 0xbe, 0x3c, 0x27, 0xd0, + 0x0a, 0x9b, 0x12, 0x80, 0x43, 0x1c, 0xd4, 0x84, 0xf1, 0xba, 0xb7, 0x87, 0x3b, 0xce, 0xc2, 0x58, + 0x1a, 0x5d, 0xb1, 0xca, 0x68, 0x85, 0x8b, 0x89, 0xff, 0xc7, 0x82, 0x07, 0x7a, 0xc3, 0x80, 0xf9, + 0x16, 0xb1, 0xfc, 0x8e, 0x47, 0x68, 0x13, 0x30, 0x09, 0x88, 0x43, 0x77, 0xc3, 0x85, 0x1c, 0x63, + 0x8e, 0x47, 0x1d, 0x87, 0x5e, 0xca, 0xe5, 0xfb, 0x85, 0x28, 0xf3, 0x49, 0x50, 0x9c, 0x28, 0x8d, + 0xf9, 0x83, 0x31, 0x98, 0xeb, 0xd9, 0x21, 0xd0, 0xe3, 0x90, 0x6b, 0xef, 0x58, 0xbe, 0x5c, 0xf2, + 0x67, 0xe5, 0x7c, 0xab, 0xd0, 0xc2, 0x3b, 0xdd, 0xe2, 0x09, 0x59, 0x85, 0x15, 0x60, 0x8e, 0x4c, + 0x75, 0x6a, 0x8b, 0xf8, 0xbe, 0xd5, 0x90, 0xfb, 0x80, 0x36, 0x4d, 0x58, 0x31, 0x96, 0x70, 0xf4, + 0x2b, 0x06, 0x9c, 0xe0, 0x53, 0x06, 0x13, 0xbf, 0xd3, 0x0c, 0xe8, 0x5e, 0x47, 0xbb, 0xe5, 0x62, + 0x1a, 0xd3, 0x93, 0x93, 0x2c, 0x9f, 0x12, 0xdc, 0x4f, 0xe8, 0xa5, 0x3e, 0x8e, 0xf2, 0x45, 0xd7, + 0xa1, 0xe0, 0x07, 0x96, 0x17, 0x90, 0x7a, 0x29, 0x60, 0x5a, 0x6d, 0xf2, 0xd1, 0xff, 0x3b, 0xd8, + 0x26, 0xb0, 0x69, 0xb7, 0x08, 0xdf, 0x70, 0xaa, 0x92, 0x00, 0x0e, 0x69, 0xa1, 0x97, 0x00, 0xbc, + 0x8e, 0x53, 0xed, 0xb4, 0x5a, 0x96, 0xb7, 0x27, 0x34, 0xf8, 0x85, 0xd1, 0x9a, 0x87, 0x15, 0xbd, + 0x50, 0x67, 0x85, 0x65, 0x58, 0xe3, 0x87, 0x5e, 0x31, 0xe0, 0x04, 0x9f, 0x89, 0x52, 0x82, 0xf1, + 0x94, 0x25, 0x98, 0xa3, 0x5d, 0xbb, 0xaa, 0xb3, 0xc0, 0x51, 0x8e, 0xe6, 0xdf, 0x45, 0xf5, 0x49, + 0x35, 0xa0, 0xd6, 0x75, 0x63, 0x0f, 0x7d, 0x10, 0xee, 0xf5, 0x3b, 0xb5, 0x1a, 0xf1, 0xfd, 0xed, + 0x4e, 0x13, 0x77, 0x9c, 0x0b, 0xb6, 0x1f, 0xb8, 0xde, 0xde, 0xba, 0xdd, 0xb2, 0x03, 0x36, 0xe3, + 0x72, 0xe5, 0x33, 0xfb, 0xdd, 0xe2, 0xbd, 0xd5, 0x7e, 0x48, 0xb8, 0x7f, 0x7d, 0x64, 0xc1, 0x7d, + 0x1d, 0xa7, 0x3f, 0x79, 0x6e, 0xbd, 0x15, 0xf7, 0xbb, 0xc5, 0xfb, 0xae, 0xf6, 0x47, 0xc3, 0x07, + 0xd1, 0x30, 0xff, 0xd5, 0x80, 0x59, 0xd9, 0xae, 0x4d, 0xd2, 0x6a, 0x37, 0xe9, 0xee, 0x72, 0xfc, + 0x86, 0x48, 0x10, 0x31, 0x44, 0x70, 0x3a, 0xea, 0x44, 0xca, 0xdf, 0xcf, 0x1a, 0x31, 0xff, 0xc5, + 0x80, 0xf9, 0x38, 0xf2, 0x5d, 0x50, 0x9e, 0x7e, 0x54, 0x79, 0x5e, 0x4a, 0xb7, 0xb5, 0x7d, 0x34, + 0xe8, 0x6b, 0x63, 0xbd, 0x6d, 0xfd, 0x9f, 0xae, 0x46, 0x43, 0xad, 0x98, 0xfd, 0x59, 0x6a, 0xc5, + 0xb1, 0xb7, 0x94, 0x56, 0xfc, 0x83, 0x31, 0x98, 0x2a, 0x39, 0x81, 0x5d, 0xda, 0xde, 0xb6, 0x1d, + 0x3b, 0xd8, 0x43, 0x9f, 0xc9, 0xc0, 0x72, 0xdb, 0x23, 0xdb, 0xc4, 0xf3, 0x48, 0x7d, 0xb5, 0xe3, + 0xd9, 0x4e, 0xa3, 0x5a, 0xdb, 0x21, 0xf5, 0x4e, 0xd3, 0x76, 0x1a, 0x6b, 0x0d, 0xc7, 0x55, 0xc5, + 0xe7, 0x6e, 0x93, 0x5a, 0x87, 0x35, 0x89, 0x2f, 0x8a, 0xd6, 0x68, 0x4d, 0xaa, 0x0c, 0xc7, 0xb4, + 0xfc, 0xd8, 0x7e, 0xb7, 0xb8, 0x3c, 0x64, 0x25, 0x3c, 0x6c, 0xd3, 0xd0, 0xa7, 0x33, 0xb0, 0xe4, + 0x91, 0x8f, 0x75, 0xec, 0xc1, 0x7b, 0x83, 0xef, 0x5a, 0xcd, 0x11, 0xd5, 0xcf, 0x50, 0x3c, 0xcb, + 0x8f, 0xee, 0x77, 0x8b, 0x43, 0xd6, 0xc1, 0x43, 0xb6, 0xcb, 0xfc, 0x5a, 0x06, 0x4e, 0x95, 0xda, + 0xed, 0x0d, 0xe2, 0xef, 0xc4, 0x0e, 0xb5, 0x9f, 0x33, 0x60, 0x7a, 0xd7, 0xf6, 0x82, 0x8e, 0xd5, + 0x94, 0x4e, 0x00, 0x3e, 0x25, 0xaa, 0x23, 0x2e, 0x67, 0xce, 0xed, 0x5a, 0x84, 0x74, 0x19, 0xed, + 0x77, 0x8b, 0xd3, 0xd1, 0x32, 0x1c, 0x63, 0x8f, 0x7e, 0xd3, 0x80, 0x59, 0x51, 0x74, 0xc9, 0xad, + 0x13, 0xdd, 0x73, 0x74, 0x35, 0x4d, 0x99, 0x14, 0x71, 0xee, 0x62, 0x88, 0x97, 0xe2, 0x1e, 0x21, + 0xcc, 0x7f, 0xcf, 0xc0, 0xe9, 0x3e, 0x34, 0xd0, 0xef, 0x1b, 0x30, 0xcf, 0xdd, 0x4d, 0x1a, 0x08, + 0x93, 0x6d, 0xd1, 0x9b, 0x1f, 0x48, 0x5b, 0x72, 0x4c, 0xd7, 0x02, 0x71, 0x6a, 0xa4, 0xbc, 0x40, + 0xb7, 0x8d, 0x95, 0x04, 0xd6, 0x38, 0x51, 0x20, 0x26, 0x29, 0x77, 0x40, 0xc5, 0x24, 0xcd, 0xdc, + 0x15, 0x49, 0xab, 0x09, 0xac, 0x71, 0xa2, 0x40, 0xe6, 0x2f, 0xc2, 0x7d, 0x07, 0x90, 0x3b, 0xfc, + 0xc4, 0x6f, 0xbe, 0xa0, 0x66, 0x7d, 0x74, 0xce, 0x0d, 0xe0, 0x2c, 0x30, 0x61, 0xdc, 0x73, 0x3b, + 0x01, 0xe1, 0xda, 0xad, 0x50, 0x06, 0xaa, 0x27, 0x30, 0x2b, 0xc1, 0x02, 0x62, 0x7e, 0xcd, 0x80, + 0xfc, 0x10, 0xfe, 0x87, 0x62, 0xd4, 0xff, 0x50, 0xe8, 0xf1, 0x3d, 0x04, 0xbd, 0xbe, 0x87, 0x67, + 0x47, 0x1b, 0x8d, 0x41, 0x7c, 0x0e, 0x3f, 0x36, 0x60, 0xae, 0xc7, 0x47, 0x81, 0x76, 0x60, 0xbe, + 0xed, 0xd6, 0xa5, 0x7d, 0x71, 0xc1, 0xf2, 0x77, 0x18, 0x4c, 0x34, 0xef, 0x71, 0x3a, 0x92, 0x95, + 0x04, 0xf8, 0x9d, 0x6e, 0x71, 0x41, 0x11, 0x89, 0x21, 0xe0, 0x44, 0x8a, 0xa8, 0x0d, 0xf9, 0x6d, + 0x9b, 0x34, 0xeb, 0xe1, 0x14, 0x1c, 0xd1, 0x92, 0x38, 0x2f, 0xa8, 0x71, 0xf7, 0x9c, 0xfc, 0x87, + 0x15, 0x17, 0xf3, 0x0a, 0x4c, 0x47, 0x9d, 0xb5, 0x03, 0x0c, 0xde, 0x19, 0xc8, 0x5a, 0x9e, 0x23, + 0x86, 0x6e, 0x52, 0x20, 0x64, 0x4b, 0xf8, 0x12, 0xa6, 0xe5, 0xe6, 0x4f, 0xc7, 0x60, 0xa6, 0xdc, + 0xec, 0x90, 0x67, 0x3d, 0x42, 0xe4, 0xf9, 0xb4, 0x04, 0x33, 0x6d, 0x8f, 0xec, 0xda, 0xe4, 0x56, + 0x95, 0x34, 0x49, 0x2d, 0x70, 0x3d, 0x41, 0xff, 0xb4, 0xa8, 0x3e, 0x53, 0x89, 0x82, 0x71, 0x1c, + 0x1f, 0x3d, 0x03, 0xd3, 0x56, 0x2d, 0xb0, 0x77, 0x89, 0xa2, 0xc0, 0x05, 0x78, 0x9b, 0xa0, 0x30, + 0x5d, 0x8a, 0x40, 0x71, 0x0c, 0x1b, 0x7d, 0x08, 0x16, 0xfc, 0x9a, 0xd5, 0x24, 0x57, 0xdb, 0x82, + 0xd5, 0xca, 0x0e, 0xa9, 0xdd, 0xac, 0xb8, 0xb6, 0x13, 0x08, 0x6f, 0xc4, 0x03, 0x82, 0xd2, 0x42, + 0xb5, 0x0f, 0x1e, 0xee, 0x4b, 0x01, 0xfd, 0xb9, 0x01, 0x67, 0xda, 0x1e, 0xa9, 0x78, 0x6e, 0xcb, + 0xa5, 0x6a, 0xa6, 0xe7, 0x88, 0x2e, 0x8e, 0xaa, 0xd7, 0x46, 0xd4, 0xa7, 0xbc, 0xa4, 0xd7, 0x45, + 0xf8, 0xf6, 0xfd, 0x6e, 0xf1, 0x4c, 0xe5, 0x20, 0x01, 0xf0, 0xc1, 0xf2, 0xa1, 0xbf, 0x34, 0xe0, + 0x6c, 0xdb, 0xf5, 0x83, 0x03, 0x9a, 0x90, 0x3b, 0xd6, 0x26, 0x98, 0xfb, 0xdd, 0xe2, 0xd9, 0xca, + 0x81, 0x12, 0xe0, 0x43, 0x24, 0x34, 0xf7, 0x27, 0x61, 0x4e, 0x9b, 0x7b, 0xe2, 0xfc, 0xfa, 0x14, + 0x9c, 0x90, 0x93, 0x21, 0x54, 0xeb, 0x85, 0xd0, 0xdf, 0x50, 0xd2, 0x81, 0x38, 0x8a, 0x4b, 0xe7, + 0x9d, 0x9a, 0x8a, 0xbc, 0x76, 0x6c, 0xde, 0x55, 0x22, 0x50, 0x1c, 0xc3, 0x46, 0x6b, 0x70, 0x52, + 0x94, 0x60, 0xd2, 0x6e, 0xda, 0x35, 0x6b, 0xc5, 0xed, 0x88, 0x29, 0x97, 0x2b, 0x9f, 0xde, 0xef, + 0x16, 0x4f, 0x56, 0x7a, 0xc1, 0x38, 0xa9, 0x0e, 0x5a, 0x87, 0x79, 0xab, 0x13, 0xb8, 0xaa, 0xfd, + 0xe7, 0x1c, 0xaa, 0x29, 0xea, 0x6c, 0x6a, 0xe5, 0xb9, 0x4a, 0x29, 0x25, 0xc0, 0x71, 0x62, 0x2d, + 0x54, 0x89, 0x51, 0xab, 0x92, 0x9a, 0xeb, 0xd4, 0xf9, 0x28, 0xe7, 0x42, 0x2b, 0xbc, 0x94, 0x80, + 0x83, 0x13, 0x6b, 0xa2, 0x26, 0x4c, 0xb7, 0xac, 0xdb, 0x57, 0x1d, 0x6b, 0xd7, 0xb2, 0x9b, 0x94, + 0x89, 0xf0, 0x61, 0xf4, 0x3f, 0x58, 0x77, 0x02, 0xbb, 0xb9, 0xc4, 0xaf, 0xf3, 0x96, 0xd6, 0x9c, + 0xe0, 0xb2, 0x57, 0x0d, 0xa8, 0xb5, 0xc6, 0x8d, 0xa3, 0x8d, 0x08, 0x2d, 0x1c, 0xa3, 0x8d, 0x2e, + 0xc3, 0x29, 0xb6, 0x1c, 0x57, 0xdd, 0x5b, 0xce, 0x2a, 0x69, 0x5a, 0x7b, 0xb2, 0x01, 0x13, 0xac, + 0x01, 0xf7, 0xee, 0x77, 0x8b, 0xa7, 0xaa, 0x49, 0x08, 0x38, 0xb9, 0x1e, 0xb2, 0xe0, 0xbe, 0x28, + 0x00, 0x93, 0x5d, 0xdb, 0xb7, 0x5d, 0x87, 0x7b, 0x22, 0xf2, 0xa1, 0x27, 0xa2, 0xda, 0x1f, 0x0d, + 0x1f, 0x44, 0x03, 0xfd, 0xb6, 0x01, 0xf3, 0x49, 0xcb, 0x70, 0xa1, 0x90, 0xc6, 0x65, 0x45, 0x6c, + 0x69, 0xf1, 0x19, 0x91, 0xb8, 0x29, 0x24, 0x0a, 0x81, 0x5e, 0x36, 0x60, 0xca, 0xd2, 0x4e, 0x51, + 0x0b, 0xc0, 0xa4, 0xba, 0x38, 0xea, 0x59, 0x3e, 0xa4, 0x58, 0x9e, 0xdd, 0xef, 0x16, 0x23, 0x27, + 0x35, 0x1c, 0xe1, 0x88, 0x7e, 0xd7, 0x80, 0x53, 0x89, 0x6b, 0x7c, 0x61, 0xf2, 0x38, 0x7a, 0x88, + 0x4d, 0x92, 0xe4, 0x3d, 0x27, 0x59, 0x0c, 0xf4, 0xba, 0xa1, 0x54, 0xd9, 0x86, 0xf4, 0xa6, 0x4c, + 0x31, 0xd1, 0xae, 0x8c, 0x78, 0x70, 0x0c, 0x0d, 0x02, 0x49, 0xb8, 0x7c, 0x52, 0xd3, 0x8c, 0xb2, + 0x10, 0xc7, 0xd9, 0xa3, 0xcf, 0x1a, 0x52, 0x35, 0x2a, 0x89, 0x4e, 0x1c, 0x97, 0x44, 0x28, 0xd4, + 0xb4, 0x4a, 0xa0, 0x18, 0x73, 0xf4, 0x61, 0x58, 0xb4, 0xb6, 0x5c, 0x2f, 0x48, 0x5c, 0x7c, 0x0b, + 0xd3, 0x6c, 0x19, 0x9d, 0xdd, 0xef, 0x16, 0x17, 0x4b, 0x7d, 0xb1, 0xf0, 0x01, 0x14, 0xcc, 0x3f, + 0xce, 0xc1, 0x14, 0x37, 0xf2, 0x85, 0xea, 0xfa, 0xaa, 0x01, 0xf7, 0xd7, 0x3a, 0x9e, 0x47, 0x9c, + 0xa0, 0x1a, 0x90, 0x76, 0xaf, 0xe2, 0x32, 0x8e, 0x55, 0x71, 0x3d, 0xb0, 0xdf, 0x2d, 0xde, 0xbf, + 0x72, 0x00, 0x7f, 0x7c, 0xa0, 0x74, 0xe8, 0x6f, 0x0c, 0x30, 0x05, 0x42, 0xd9, 0xaa, 0xdd, 0x6c, + 0x78, 0x6e, 0xc7, 0xa9, 0xf7, 0x36, 0x22, 0x73, 0xac, 0x8d, 0x78, 0x68, 0xbf, 0x5b, 0x34, 0x57, + 0x0e, 0x95, 0x02, 0x0f, 0x20, 0x29, 0x7a, 0x16, 0xe6, 0x04, 0xd6, 0xb9, 0xdb, 0x6d, 0xe2, 0xd9, + 0xd4, 0x9c, 0x16, 0xf7, 0xe9, 0x61, 0x88, 0x42, 0x1c, 0x01, 0xf7, 0xd6, 0x41, 0x3e, 0x4c, 0xdc, + 0x22, 0x76, 0x63, 0x27, 0x90, 0xe6, 0xd3, 0x88, 0x71, 0x09, 0xe2, 0xc0, 0x7f, 0x9d, 0xd3, 0x2c, + 0x4f, 0xee, 0x77, 0x8b, 0x13, 0xe2, 0x0f, 0x96, 0x9c, 0xd0, 0x25, 0x98, 0xe6, 0x47, 0xb0, 0x8a, + 0xed, 0x34, 0x2a, 0xae, 0xc3, 0x6f, 0xf3, 0x0b, 0xe5, 0x87, 0xa4, 0xc2, 0xaf, 0x46, 0xa0, 0x77, + 0xba, 0xc5, 0x29, 0xf9, 0x7b, 0x73, 0xaf, 0x4d, 0x70, 0xac, 0xb6, 0xf9, 0xcd, 0x71, 0x00, 0x39, + 0x5d, 0x49, 0x1b, 0xfd, 0x3f, 0x28, 0xf8, 0x24, 0xe0, 0x5c, 0x85, 0xf3, 0x9c, 0xdf, 0x49, 0xc8, + 0x42, 0x1c, 0xc2, 0xd1, 0x4d, 0xc8, 0xb5, 0xad, 0x8e, 0x4f, 0xc4, 0xe0, 0x5f, 0x4c, 0x65, 0xf0, + 0x2b, 0x94, 0x22, 0x3f, 0x73, 0xb1, 0x9f, 0x98, 0xf3, 0x40, 0x9f, 0x32, 0x00, 0x48, 0x74, 0xc0, + 0x46, 0xf6, 0x7d, 0x08, 0x96, 0xe1, 0x98, 0xd2, 0x3e, 0x28, 0x4f, 0xef, 0x77, 0x8b, 0xa0, 0x0d, + 0xbd, 0xc6, 0x16, 0xdd, 0x82, 0xbc, 0x25, 0xf7, 0xfc, 0xb1, 0xe3, 0xd8, 0xf3, 0xd9, 0x51, 0x48, + 0x4d, 0x5a, 0xc5, 0x0c, 0x7d, 0xda, 0x80, 0x69, 0x9f, 0x04, 0x62, 0xa8, 0xe8, 0xce, 0x23, 0x0c, + 0xde, 0x11, 0x27, 0x5d, 0x35, 0x42, 0x93, 0xef, 0xa0, 0xd1, 0x32, 0x1c, 0xe3, 0x2b, 0x45, 0xb9, + 0x40, 0xac, 0x3a, 0xf1, 0xd8, 0x49, 0x5b, 0x58, 0x52, 0xa3, 0x8b, 0xa2, 0xd1, 0x54, 0xa2, 0x68, + 0x65, 0x38, 0xc6, 0x57, 0x8a, 0xb2, 0x61, 0x7b, 0x9e, 0x2b, 0x44, 0xc9, 0xa7, 0x24, 0x8a, 0x46, + 0x53, 0x89, 0xa2, 0x95, 0xe1, 0x18, 0x5f, 0xf3, 0x6f, 0xa7, 0x60, 0x5a, 0x2e, 0xa4, 0xd0, 0xb2, + 0xe7, 0x8e, 0x9d, 0x3e, 0x96, 0xfd, 0x8a, 0x0e, 0xc4, 0x51, 0x5c, 0x5a, 0x99, 0x2f, 0xd5, 0xa8, + 0x61, 0xaf, 0x2a, 0x57, 0x75, 0x20, 0x8e, 0xe2, 0xa2, 0x16, 0xe4, 0xfc, 0x80, 0xb4, 0xe5, 0x3d, + 0xe8, 0x88, 0xd7, 0x74, 0xe1, 0xfe, 0x10, 0xde, 0x74, 0xd0, 0x7f, 0x3e, 0xe6, 0x5c, 0x98, 0x6f, + 0x32, 0x88, 0xb8, 0x2b, 0xc5, 0xe2, 0x48, 0x67, 0x7d, 0x46, 0x3d, 0xa1, 0x7c, 0x34, 0xa2, 0x65, + 0x38, 0xc6, 0x3e, 0xc1, 0xd8, 0xcf, 0x1d, 0xa3, 0xb1, 0xff, 0x3c, 0xe4, 0x5b, 0xd6, 0xed, 0x6a, + 0xc7, 0x6b, 0x1c, 0xfd, 0x50, 0x21, 0x42, 0x94, 0x38, 0x15, 0xac, 0xe8, 0xa1, 0x57, 0x0c, 0x6d, + 0xcb, 0x99, 0x60, 0xc4, 0xaf, 0xa7, 0xbb, 0xe5, 0x28, 0x5d, 0xd9, 0x77, 0xf3, 0xe9, 0x31, 0xbd, + 0xf3, 0x77, 0xdd, 0xf4, 0xa6, 0x66, 0x24, 0x5f, 0x20, 0xca, 0x8c, 0x2c, 0x1c, 0xab, 0x19, 0xb9, + 0x12, 0x61, 0x86, 0x63, 0xcc, 0x99, 0x3c, 0x7c, 0xcd, 0x29, 0x79, 0xe0, 0x58, 0xe5, 0xa9, 0x46, + 0x98, 0xe1, 0x18, 0xf3, 0xfe, 0xe7, 0xcd, 0xc9, 0xe3, 0x39, 0x6f, 0x4e, 0xa5, 0x70, 0xde, 0x3c, + 0xd8, 0x14, 0x3f, 0x31, 0xaa, 0x29, 0x8e, 0x2e, 0x02, 0xaa, 0xef, 0x39, 0x56, 0xcb, 0xae, 0x89, + 0xcd, 0x92, 0xa9, 0xcd, 0x69, 0xe6, 0x8f, 0x58, 0x14, 0x1b, 0x19, 0x5a, 0xed, 0xc1, 0xc0, 0x09, + 0xb5, 0x50, 0x00, 0xf9, 0xb6, 0xb4, 0xb8, 0x66, 0xd2, 0x98, 0xfd, 0xd2, 0x02, 0xe3, 0x57, 0xe5, + 0x74, 0xe1, 0xc9, 0x12, 0xac, 0x38, 0x99, 0xff, 0x69, 0xc0, 0xec, 0x4a, 0xd3, 0xed, 0xd4, 0xaf, + 0x5b, 0x41, 0x6d, 0x87, 0xdf, 0xeb, 0xa2, 0x67, 0x20, 0x6f, 0x3b, 0x01, 0xf1, 0x76, 0xad, 0xa6, + 0xd0, 0x28, 0xa6, 0xbc, 0xfa, 0x5e, 0x13, 0xe5, 0x77, 0xba, 0xc5, 0xe9, 0xd5, 0x8e, 0xc7, 0x02, + 0x26, 0xf9, 0xfe, 0x82, 0x55, 0x1d, 0xf4, 0x25, 0x03, 0xe6, 0xf8, 0xcd, 0xf0, 0xaa, 0x15, 0x58, + 0x57, 0x3a, 0xc4, 0xb3, 0x89, 0xbc, 0x1b, 0x1e, 0x71, 0x6b, 0x89, 0xcb, 0x2a, 0x19, 0xec, 0x85, + 0xa6, 0xf5, 0x46, 0x9c, 0x33, 0xee, 0x15, 0xc6, 0xfc, 0x7c, 0x16, 0xee, 0xed, 0x4b, 0x0b, 0x2d, + 0x42, 0xc6, 0xae, 0x8b, 0xa6, 0x83, 0xa0, 0x9b, 0x59, 0xab, 0xe3, 0x8c, 0x5d, 0x47, 0x4b, 0xcc, + 0x4a, 0xf4, 0x88, 0xef, 0xcb, 0x6b, 0xc2, 0x82, 0x32, 0xe8, 0x44, 0x29, 0xd6, 0x30, 0x50, 0x11, + 0x72, 0x4d, 0x6b, 0x8b, 0x34, 0xc5, 0x09, 0x80, 0xd9, 0x9d, 0xeb, 0xb4, 0x00, 0xf3, 0x72, 0xf4, + 0xcb, 0x06, 0x00, 0x17, 0x90, 0x9e, 0x1f, 0x84, 0x5e, 0xc3, 0xe9, 0x76, 0x13, 0xa5, 0xcc, 0xa5, + 0x0c, 0xff, 0x63, 0x8d, 0x2b, 0xda, 0x84, 0x71, 0x6a, 0x82, 0xba, 0xf5, 0x23, 0xab, 0x31, 0x76, + 0x2d, 0x52, 0x61, 0x34, 0xb0, 0xa0, 0x45, 0xfb, 0xca, 0x23, 0x41, 0xc7, 0x73, 0x68, 0xd7, 0x32, + 0xc5, 0x95, 0xe7, 0x52, 0x60, 0x55, 0x8a, 0x35, 0x0c, 0xf3, 0xcf, 0x32, 0x30, 0x9f, 0x24, 0x3a, + 0xd5, 0x0f, 0xe3, 0x5c, 0x5a, 0x71, 0x98, 0x7d, 0x7f, 0xfa, 0xfd, 0x23, 0x82, 0x1c, 0x54, 0x28, + 0x80, 0x08, 0xc3, 0x12, 0x7c, 0xd1, 0xfb, 0x55, 0x0f, 0x65, 0x8e, 0xd8, 0x43, 0x8a, 0x72, 0xac, + 0x97, 0x1e, 0x80, 0x31, 0x9f, 0x8e, 0x7c, 0x36, 0x7a, 0xe5, 0xc0, 0xc6, 0x88, 0x41, 0x28, 0x46, + 0xc7, 0xb1, 0x03, 0x11, 0xc5, 0xac, 0x30, 0xae, 0x3a, 0x76, 0x80, 0x19, 0xc4, 0xfc, 0x62, 0x06, + 0x16, 0xfb, 0x37, 0x0a, 0x7d, 0xd1, 0x00, 0xa8, 0xd3, 0x03, 0x06, 0x9d, 0x92, 0x32, 0x28, 0xc4, + 0x3a, 0xae, 0x3e, 0x5c, 0x95, 0x9c, 0xc2, 0x08, 0x21, 0x55, 0xe4, 0x63, 0x4d, 0x10, 0xf4, 0xa8, + 0x9c, 0xfa, 0x97, 0xac, 0x96, 0x34, 0x40, 0x55, 0x9d, 0x0d, 0x05, 0xc1, 0x1a, 0x16, 0x3d, 0x41, + 0x3a, 0x56, 0x8b, 0xf8, 0x6d, 0x4b, 0x85, 0xa9, 0xb3, 0x13, 0xe4, 0x25, 0x59, 0x88, 0x43, 0xb8, + 0xd9, 0x84, 0x07, 0x07, 0x90, 0x33, 0xa5, 0x90, 0x61, 0xf3, 0x3f, 0x0c, 0x38, 0xbd, 0xd2, 0xec, + 0xf8, 0x01, 0xf1, 0xfe, 0xd7, 0x04, 0x5c, 0xfd, 0x97, 0x01, 0xf7, 0xf5, 0x69, 0xf3, 0x5d, 0x88, + 0xbb, 0x7a, 0x31, 0x1a, 0x77, 0x75, 0x75, 0xd4, 0x29, 0x9d, 0xd8, 0x8e, 0x3e, 0xe1, 0x57, 0x01, + 0x9c, 0xa0, 0xbb, 0x56, 0xdd, 0x6d, 0xa4, 0xa4, 0x37, 0x1f, 0x84, 0xdc, 0xc7, 0xa8, 0xfe, 0x89, + 0xcf, 0x31, 0xa6, 0x94, 0x30, 0x87, 0x99, 0x4f, 0x83, 0x08, 0x52, 0x8a, 0x2d, 0x1e, 0x63, 0x90, + 0xc5, 0x63, 0xfe, 0x7d, 0x06, 0x34, 0xcf, 0xc3, 0x5d, 0x98, 0x94, 0x4e, 0x64, 0x52, 0x8e, 0x78, + 0x6a, 0xd6, 0xfc, 0x28, 0xfd, 0x5e, 0x23, 0xec, 0xc6, 0x5e, 0x23, 0x5c, 0x4a, 0x8d, 0xe3, 0xc1, + 0x8f, 0x11, 0xbe, 0x67, 0xc0, 0x7d, 0x21, 0x72, 0xaf, 0x53, 0xf0, 0xf0, 0x1d, 0xe6, 0x09, 0x98, + 0xb4, 0xc2, 0x6a, 0x62, 0x0e, 0xa8, 0x07, 0x38, 0x1a, 0x45, 0xac, 0xe3, 0x85, 0xb1, 0xcf, 0xd9, + 0x23, 0xc6, 0x3e, 0x8f, 0x1d, 0x1c, 0xfb, 0x6c, 0xfe, 0x24, 0x03, 0x67, 0x7a, 0x5b, 0x26, 0xd7, + 0xc6, 0x60, 0x77, 0xe6, 0x4f, 0xc2, 0x54, 0x20, 0x2a, 0x68, 0x3b, 0xbd, 0x7a, 0x3e, 0xb6, 0xa9, + 0xc1, 0x70, 0x04, 0x93, 0xd6, 0xac, 0xf1, 0x55, 0x59, 0xad, 0xb9, 0x6d, 0x19, 0x39, 0xaf, 0x6a, + 0xae, 0x68, 0x30, 0x1c, 0xc1, 0x54, 0x31, 0x89, 0x63, 0xc7, 0x1e, 0x93, 0x58, 0x85, 0x53, 0x32, + 0x0a, 0xeb, 0xbc, 0xeb, 0xad, 0xb8, 0xad, 0x76, 0x93, 0x88, 0xd8, 0x79, 0x2a, 0xec, 0x19, 0x51, + 0xe5, 0x14, 0x4e, 0x42, 0xc2, 0xc9, 0x75, 0xcd, 0xef, 0x65, 0xe1, 0x64, 0xd8, 0xed, 0x2b, 0xae, + 0x53, 0xb7, 0x59, 0x2c, 0xdb, 0x53, 0x30, 0x16, 0xec, 0xb5, 0x65, 0x67, 0xff, 0x1f, 0x29, 0xce, + 0xe6, 0x5e, 0x9b, 0x8e, 0xf6, 0xe9, 0x84, 0x2a, 0xcc, 0x2d, 0xcb, 0x2a, 0xa1, 0x75, 0xb5, 0x3a, + 0xf8, 0x08, 0x3c, 0x1e, 0x9d, 0xcd, 0x77, 0xba, 0xc5, 0x84, 0xd7, 0x93, 0x4b, 0x8a, 0x52, 0x74, + 0xce, 0xa3, 0x1b, 0x30, 0xdd, 0xb4, 0xfc, 0xe0, 0x6a, 0xbb, 0x6e, 0x05, 0x64, 0xd3, 0x6e, 0x11, + 0xb1, 0xe6, 0x86, 0x09, 0x48, 0x57, 0xf7, 0xc8, 0xeb, 0x11, 0x4a, 0x38, 0x46, 0x19, 0xed, 0x02, + 0xa2, 0x25, 0x9b, 0x9e, 0xe5, 0xf8, 0xbc, 0x55, 0x94, 0xdf, 0xf0, 0x01, 0xf0, 0xea, 0x58, 0xb6, + 0xde, 0x43, 0x0d, 0x27, 0x70, 0x40, 0x0f, 0xc1, 0xb8, 0x47, 0x2c, 0x5f, 0x0c, 0x66, 0x21, 0x5c, + 0xff, 0x98, 0x95, 0x62, 0x01, 0xd5, 0x17, 0xd4, 0xf8, 0x21, 0x0b, 0xea, 0x87, 0x06, 0x4c, 0x87, + 0xc3, 0x74, 0x17, 0x94, 0x64, 0x2b, 0xaa, 0x24, 0x2f, 0xa4, 0xb5, 0x25, 0xf6, 0xd1, 0x8b, 0x7f, + 0x35, 0xae, 0xb7, 0x8f, 0x05, 0x24, 0x7f, 0x1c, 0x0a, 0x72, 0x55, 0x4b, 0xeb, 0x73, 0xc4, 0xd3, + 0x6d, 0xc4, 0x2e, 0xd1, 0x1e, 0xd2, 0x08, 0x26, 0x38, 0xe4, 0x47, 0xd5, 0x72, 0x5d, 0xa8, 0x5c, + 0x31, 0xed, 0x95, 0x5a, 0x96, 0xaa, 0x38, 0x49, 0x2d, 0xcb, 0x3a, 0xe8, 0x2a, 0x9c, 0x6e, 0x7b, + 0x2e, 0x7b, 0x5c, 0xb9, 0x4a, 0xac, 0x7a, 0xd3, 0x76, 0x88, 0x74, 0x21, 0xf0, 0x30, 0x86, 0xfb, + 0xf6, 0xbb, 0xc5, 0xd3, 0x95, 0x64, 0x14, 0xdc, 0xaf, 0x6e, 0xf4, 0x41, 0xd0, 0xd8, 0x00, 0x0f, + 0x82, 0x7e, 0x55, 0x39, 0xea, 0x88, 0x2f, 0x9e, 0xe5, 0x7c, 0x30, 0xad, 0xa1, 0x4c, 0xd8, 0xd6, + 0xc3, 0x29, 0x55, 0x12, 0x4c, 0xb1, 0x62, 0xdf, 0xdf, 0x1b, 0x34, 0x7e, 0x44, 0x6f, 0x50, 0x18, + 0xd7, 0x3d, 0xf1, 0xb3, 0x8c, 0xeb, 0xce, 0xbf, 0xa5, 0xe2, 0xba, 0x5f, 0xcd, 0xc1, 0x6c, 0xdc, + 0x02, 0x39, 0xfe, 0xc7, 0x4e, 0xbf, 0x61, 0xc0, 0xac, 0x5c, 0x3d, 0x9c, 0x27, 0x91, 0x7e, 0xfe, + 0xf5, 0x94, 0x16, 0x2d, 0xb7, 0xa5, 0xd4, 0x73, 0xdc, 0xcd, 0x18, 0x37, 0xdc, 0xc3, 0x1f, 0xbd, + 0x00, 0x93, 0xca, 0x1d, 0x7e, 0xa4, 0x97, 0x4f, 0x33, 0xcc, 0x8a, 0x0a, 0x49, 0x60, 0x9d, 0x1e, + 0x7a, 0xd5, 0x00, 0xa8, 0x49, 0x35, 0x27, 0x57, 0xd7, 0x95, 0xb4, 0x56, 0x97, 0x52, 0xa0, 0xa1, + 0xb1, 0xac, 0x8a, 0x7c, 0xac, 0x31, 0x46, 0x9f, 0x67, 0x8e, 0x70, 0x65, 0xdd, 0xd1, 0xf5, 0x94, + 0x1d, 0x3d, 0x14, 0xf7, 0x00, 0xc3, 0x34, 0x34, 0xa5, 0x34, 0x90, 0x8f, 0x23, 0x42, 0x98, 0x4f, + 0x81, 0x0a, 0x9e, 0xa4, 0xdb, 0x16, 0x0b, 0x9f, 0xac, 0x58, 0xc1, 0x8e, 0x98, 0x82, 0x6a, 0xdb, + 0x3a, 0x2f, 0x01, 0x38, 0xc4, 0x31, 0x3f, 0x0a, 0xd3, 0xcf, 0x7a, 0x56, 0x7b, 0xc7, 0x66, 0x0e, + 0x67, 0x7a, 0x4e, 0x7a, 0x27, 0x4c, 0x58, 0xf5, 0x7a, 0xd2, 0x63, 0xf6, 0x12, 0x2f, 0xc6, 0x12, + 0x3e, 0xd8, 0x91, 0xe8, 0x9b, 0x06, 0xa0, 0xf0, 0xd2, 0xce, 0x76, 0x1a, 0x1b, 0xf4, 0xb4, 0x4f, + 0xcf, 0x47, 0x3b, 0xac, 0x34, 0xe9, 0x7c, 0x74, 0x41, 0x41, 0xb0, 0x86, 0x85, 0x5e, 0x82, 0x49, + 0xfe, 0xef, 0x9a, 0x3a, 0xec, 0x8f, 0xfc, 0x14, 0x96, 0x2b, 0x14, 0x26, 0x13, 0x9f, 0x85, 0x17, + 0x42, 0x0e, 0x58, 0x67, 0x47, 0xbb, 0x6a, 0xcd, 0xd9, 0x6e, 0x76, 0x6e, 0xd7, 0xb7, 0xc2, 0xae, + 0x6a, 0x7b, 0xee, 0xb6, 0xdd, 0x24, 0xf1, 0xae, 0xaa, 0xf0, 0x62, 0x2c, 0xe1, 0x83, 0x75, 0xd5, + 0xd7, 0x0d, 0x98, 0x5f, 0xf3, 0x03, 0xdb, 0x5d, 0x25, 0x7e, 0x40, 0xd5, 0x0a, 0xdd, 0x7c, 0x3a, + 0xcd, 0x41, 0xe2, 0xa0, 0x57, 0x61, 0x56, 0x5c, 0x20, 0x76, 0xb6, 0x7c, 0x12, 0x68, 0x76, 0xbc, + 0x5a, 0xc7, 0x2b, 0x31, 0x38, 0xee, 0xa9, 0x41, 0xa9, 0x88, 0x9b, 0xc4, 0x90, 0x4a, 0x36, 0x4a, + 0xa5, 0x1a, 0x83, 0xe3, 0x9e, 0x1a, 0xe6, 0x77, 0xb2, 0x70, 0x92, 0x35, 0x23, 0xf6, 0x86, 0xe1, + 0xb3, 0xfd, 0xde, 0x30, 0x8c, 0xb8, 0x94, 0x19, 0xaf, 0x23, 0xbc, 0x60, 0xf8, 0x75, 0x03, 0x66, + 0xea, 0xd1, 0x9e, 0x4e, 0xc7, 0x3d, 0x93, 0x34, 0x86, 0x3c, 0x5e, 0x2a, 0x56, 0x88, 0xe3, 0xfc, + 0xd1, 0x17, 0x0c, 0x98, 0x89, 0x8a, 0x29, 0x77, 0xf7, 0x63, 0xe8, 0x24, 0x15, 0xe0, 0x1c, 0x2d, + 0xf7, 0x71, 0x5c, 0x04, 0xf3, 0xdb, 0x19, 0x31, 0xa4, 0xc7, 0x11, 0xa0, 0x8f, 0x6e, 0x41, 0x21, + 0x68, 0xfa, 0xbc, 0x50, 0xb4, 0x76, 0xc4, 0x13, 0xe1, 0xe6, 0x7a, 0x95, 0xdf, 0xdd, 0x87, 0x46, + 0x9b, 0x28, 0xa1, 0xc6, 0xa7, 0xe4, 0xc5, 0x18, 0xd7, 0xda, 0x82, 0x71, 0x2a, 0x47, 0xd1, 0xcd, + 0x95, 0x4a, 0x9c, 0xb1, 0x28, 0xa1, 0x8c, 0x25, 0x2f, 0xf3, 0xcb, 0x06, 0x14, 0x2e, 0xba, 0x72, + 0x1f, 0xf9, 0x70, 0x0a, 0x8e, 0x1e, 0x65, 0x0f, 0xaa, 0x3b, 0xc2, 0xf0, 0x88, 0xf1, 0x4c, 0xc4, + 0xcd, 0x73, 0xbf, 0x46, 0x7b, 0x89, 0x25, 0xea, 0xa1, 0xa4, 0x2e, 0xba, 0x5b, 0x7d, 0xbd, 0x88, + 0xbf, 0x97, 0x83, 0x13, 0xcf, 0x59, 0x7b, 0xc4, 0x09, 0xac, 0xe1, 0x95, 0xc4, 0x13, 0x30, 0x69, + 0xb5, 0x59, 0xa0, 0xb0, 0x66, 0xe3, 0x87, 0x9e, 0x93, 0x10, 0x84, 0x75, 0xbc, 0x70, 0x43, 0xe3, + 0x79, 0x43, 0x92, 0xb6, 0xa2, 0x95, 0x18, 0x1c, 0xf7, 0xd4, 0x40, 0x17, 0x01, 0x89, 0x57, 0x90, + 0xa5, 0x5a, 0xcd, 0xed, 0x38, 0x7c, 0x4b, 0xe3, 0x4e, 0x15, 0x75, 0xd8, 0xdc, 0xe8, 0xc1, 0xc0, + 0x09, 0xb5, 0xd0, 0x87, 0x60, 0xa1, 0xc6, 0x28, 0x8b, 0xa3, 0x87, 0x4e, 0x91, 0x1f, 0x3f, 0x55, + 0x90, 0xfe, 0x4a, 0x1f, 0x3c, 0xdc, 0x97, 0x02, 0x95, 0xd4, 0x0f, 0x5c, 0xcf, 0x6a, 0x10, 0x9d, + 0xee, 0x78, 0x54, 0xd2, 0x6a, 0x0f, 0x06, 0x4e, 0xa8, 0x85, 0x3e, 0x09, 0x85, 0x60, 0xc7, 0x23, + 0xfe, 0x8e, 0xdb, 0xac, 0x8b, 0xa0, 0x81, 0x11, 0x3d, 0x6d, 0x62, 0xf4, 0x37, 0x25, 0x55, 0x6d, + 0x7a, 0xcb, 0x22, 0x1c, 0xf2, 0x44, 0x1e, 0x8c, 0xfb, 0x35, 0xb7, 0x4d, 0x7c, 0x61, 0xb2, 0x5f, + 0x4c, 0x85, 0x3b, 0xf3, 0x1c, 0x69, 0x3e, 0x3e, 0xc6, 0x01, 0x0b, 0x4e, 0xe6, 0x37, 0x32, 0x30, + 0xa5, 0x23, 0x0e, 0xb0, 0x37, 0x7d, 0xca, 0x80, 0xa9, 0x9a, 0xeb, 0x04, 0x9e, 0xdb, 0xe4, 0xfe, + 0xab, 0x74, 0x2c, 0x0a, 0x4a, 0x6a, 0x95, 0x04, 0x96, 0xdd, 0xd4, 0x5c, 0x61, 0x1a, 0x1b, 0x1c, + 0x61, 0x8a, 0x3e, 0x63, 0xc0, 0x4c, 0x18, 0x63, 0x16, 0x3a, 0xd2, 0x52, 0x15, 0x44, 0x6d, 0xf5, + 0xe7, 0xa2, 0x9c, 0x70, 0x9c, 0xb5, 0xb9, 0x05, 0xb3, 0xf1, 0xd1, 0xa6, 0x5d, 0xd9, 0xb6, 0xc4, + 0x5a, 0xcf, 0x86, 0x5d, 0x59, 0xb1, 0x7c, 0x1f, 0x33, 0x08, 0x7a, 0x04, 0xf2, 0x2d, 0xcb, 0x6b, + 0xd8, 0x8e, 0xd5, 0x64, 0xbd, 0x98, 0xd5, 0x36, 0x24, 0x51, 0x8e, 0x15, 0x86, 0xf9, 0x6e, 0x98, + 0xda, 0xb0, 0x9c, 0x06, 0xa9, 0x8b, 0x7d, 0xf8, 0xf0, 0x27, 0x62, 0x3f, 0x1a, 0x83, 0x49, 0xed, + 0x6c, 0x76, 0xfc, 0xe7, 0xac, 0x48, 0x2a, 0x87, 0x6c, 0x8a, 0xa9, 0x1c, 0x9e, 0x07, 0xd8, 0xb6, + 0x1d, 0xdb, 0xdf, 0x39, 0x62, 0x92, 0x08, 0x76, 0x45, 0x7b, 0x5e, 0x51, 0xc0, 0x1a, 0xb5, 0xf0, + 0x1e, 0x2c, 0x77, 0x40, 0xea, 0x9c, 0x57, 0x0d, 0x4d, 0xdd, 0x8c, 0xa7, 0x71, 0xef, 0xaf, 0x0d, + 0xcc, 0x92, 0x54, 0x3f, 0xe7, 0x9c, 0xc0, 0xdb, 0x3b, 0x50, 0x2b, 0x6d, 0x42, 0xde, 0x23, 0x7e, + 0xa7, 0x45, 0x4f, 0x8c, 0x13, 0x43, 0x77, 0x03, 0x8b, 0x99, 0xc0, 0xa2, 0x3e, 0x56, 0x94, 0x16, + 0x9f, 0x82, 0x13, 0x11, 0x11, 0xd0, 0x2c, 0x64, 0x6f, 0x92, 0x3d, 0x3e, 0x4f, 0x30, 0xfd, 0x89, + 0xe6, 0x23, 0xb7, 0x85, 0xa2, 0x5b, 0xde, 0x97, 0x79, 0xd2, 0x30, 0x5d, 0x48, 0x74, 0x00, 0x1c, + 0xe5, 0x32, 0x87, 0x8e, 0x45, 0x53, 0xcb, 0x12, 0xa1, 0xc6, 0x82, 0x47, 0xc6, 0x70, 0x98, 0xf9, + 0x93, 0x71, 0x10, 0x57, 0xd9, 0x03, 0x6c, 0x57, 0xfa, 0x0d, 0x56, 0xe6, 0x08, 0x37, 0x58, 0x17, + 0x61, 0xca, 0x76, 0xec, 0xc0, 0xb6, 0x9a, 0xcc, 0xb9, 0x23, 0xd4, 0xa9, 0x0c, 0x1d, 0x9e, 0x5a, + 0xd3, 0x60, 0x09, 0x74, 0x22, 0x75, 0xd1, 0x15, 0xc8, 0x31, 0x7d, 0x23, 0x26, 0xf0, 0xf0, 0xf7, + 0xed, 0x2c, 0xd4, 0x82, 0xbf, 0x27, 0xe2, 0x94, 0xd8, 0xe1, 0x83, 0xa7, 0xc9, 0x50, 0xc7, 0x6f, + 0x31, 0x8f, 0xc3, 0xc3, 0x47, 0x0c, 0x8e, 0x7b, 0x6a, 0x50, 0x2a, 0xdb, 0x96, 0xdd, 0xec, 0x78, + 0x24, 0xa4, 0x32, 0x1e, 0xa5, 0x72, 0x3e, 0x06, 0xc7, 0x3d, 0x35, 0xd0, 0x36, 0x4c, 0x89, 0x32, + 0x1e, 0xef, 0x34, 0x71, 0xc4, 0x56, 0xb2, 0xb8, 0xb6, 0xf3, 0x1a, 0x25, 0x1c, 0xa1, 0x8b, 0x3a, + 0x30, 0x67, 0x3b, 0x35, 0xd7, 0xa9, 0x35, 0x3b, 0xbe, 0xbd, 0x4b, 0xc2, 0xc7, 0x3c, 0x47, 0x61, + 0x76, 0x6a, 0xbf, 0x5b, 0x9c, 0x5b, 0x8b, 0x93, 0xc3, 0xbd, 0x1c, 0xd0, 0x2b, 0x06, 0x9c, 0xaa, + 0xb9, 0x8e, 0xcf, 0xde, 0x9d, 0xef, 0x92, 0x73, 0x9e, 0xe7, 0x7a, 0x9c, 0x77, 0xe1, 0x88, 0xbc, + 0x99, 0x4f, 0x71, 0x25, 0x89, 0x24, 0x4e, 0xe6, 0x84, 0x5e, 0x84, 0x7c, 0xdb, 0x73, 0x77, 0xed, + 0x3a, 0xf1, 0x44, 0xec, 0xdc, 0x7a, 0x1a, 0x79, 0x30, 0x2a, 0x82, 0x66, 0xb8, 0xf5, 0xc8, 0x12, + 0xac, 0xf8, 0x99, 0x6f, 0x14, 0x60, 0x3a, 0x8a, 0x8e, 0x3e, 0x01, 0xd0, 0xf6, 0xdc, 0x16, 0x09, + 0x76, 0x88, 0x7a, 0x94, 0x71, 0x69, 0xd4, 0x74, 0x0b, 0x92, 0x9e, 0x8c, 0x5e, 0xa1, 0xdb, 0x45, + 0x58, 0x8a, 0x35, 0x8e, 0xc8, 0x83, 0x89, 0x9b, 0x5c, 0xed, 0x0a, 0x2b, 0xe4, 0xb9, 0x54, 0x6c, + 0x26, 0xc1, 0x99, 0xbd, 0x26, 0x10, 0x45, 0x58, 0x32, 0x42, 0x5b, 0x90, 0xbd, 0x45, 0xb6, 0xd2, + 0x79, 0xc2, 0x7c, 0x9d, 0x88, 0xd3, 0x4c, 0x79, 0x62, 0xbf, 0x5b, 0xcc, 0x5e, 0x27, 0x5b, 0x98, + 0x12, 0xa7, 0xed, 0xaa, 0xf3, 0x7b, 0x78, 0xb1, 0x55, 0x8c, 0xd8, 0xae, 0xc8, 0xa5, 0x3e, 0x6f, + 0x97, 0x28, 0xc2, 0x92, 0x11, 0x7a, 0x11, 0x0a, 0xb7, 0xac, 0x5d, 0xb2, 0xed, 0xb9, 0x4e, 0x20, + 0x42, 0xa6, 0x46, 0x8c, 0xd3, 0xbf, 0x2e, 0xc9, 0x09, 0xbe, 0x4c, 0xbd, 0xab, 0x42, 0x1c, 0xb2, + 0x43, 0xbb, 0x90, 0x77, 0xc8, 0x2d, 0x4c, 0x9a, 0x76, 0x2d, 0x9d, 0xb8, 0xf8, 0x4b, 0x82, 0x9a, + 0xe0, 0xcc, 0xf4, 0x9e, 0x2c, 0xc3, 0x8a, 0x17, 0x1d, 0xcb, 0x1b, 0xee, 0x96, 0xd8, 0xa8, 0x46, + 0x1c, 0x4b, 0x75, 0x32, 0xe5, 0x63, 0x79, 0xd1, 0xdd, 0xc2, 0x94, 0x38, 0x5d, 0x23, 0x35, 0x15, + 0xaf, 0x23, 0xb6, 0xa9, 0x4b, 0xe9, 0xc6, 0x29, 0xf1, 0x35, 0x12, 0x96, 0x62, 0x8d, 0x23, 0xed, + 0xdb, 0x86, 0x70, 0x56, 0x8a, 0x8d, 0x6a, 0xc4, 0xbe, 0x8d, 0xba, 0x3e, 0x79, 0xdf, 0xca, 0x32, + 0xac, 0x78, 0x51, 0xbe, 0xb6, 0xf0, 0xfc, 0xa5, 0xb3, 0x55, 0x45, 0xfd, 0x88, 0x9c, 0xaf, 0x2c, + 0xc3, 0x8a, 0x97, 0xf9, 0xe5, 0x71, 0x98, 0xd2, 0xf3, 0x8d, 0x0d, 0x60, 0x23, 0x28, 0xbb, 0x38, + 0x33, 0x8c, 0x5d, 0x4c, 0x0f, 0x42, 0xda, 0x1d, 0x87, 0x74, 0xc2, 0xac, 0xa5, 0x66, 0x16, 0x86, + 0x07, 0x21, 0xad, 0xd0, 0xc7, 0x11, 0xa6, 0x43, 0x84, 0x3d, 0x50, 0xe3, 0x8a, 0x9b, 0x1f, 0xb9, + 0xa8, 0x71, 0x15, 0x31, 0x28, 0x1e, 0x05, 0x08, 0xf3, 0x6e, 0x89, 0xbb, 0x2f, 0x65, 0xb5, 0x69, + 0xf9, 0xc0, 0x34, 0x2c, 0xf4, 0x10, 0x8c, 0x53, 0x05, 0x4d, 0xea, 0xe2, 0xa5, 0xae, 0x3a, 0x6d, + 0x9e, 0x67, 0xa5, 0x58, 0x40, 0xd1, 0x93, 0xd4, 0x96, 0x0a, 0xd5, 0xaa, 0x78, 0x80, 0x3b, 0x1f, + 0xda, 0x52, 0x21, 0x0c, 0x47, 0x30, 0xa9, 0xe8, 0x84, 0x6a, 0x41, 0x36, 0x83, 0x35, 0xd1, 0x99, + 0x6a, 0xc4, 0x1c, 0xc6, 0xbc, 0x1f, 0x31, 0xad, 0xc9, 0x66, 0x5e, 0x4e, 0xf3, 0x7e, 0xc4, 0xe0, + 0xb8, 0xa7, 0x06, 0x6d, 0x8c, 0xb8, 0xb6, 0x9b, 0xe4, 0xd1, 0x9d, 0x7d, 0x2e, 0xdc, 0x5e, 0xd3, + 0x4f, 0x04, 0x53, 0x6c, 0xe8, 0xdf, 0x9f, 0x5e, 0xee, 0xbc, 0xc1, 0x8f, 0x04, 0xa3, 0x19, 0xef, + 0x1f, 0x85, 0xe9, 0xe8, 0x5e, 0x99, 0xba, 0x7f, 0xfe, 0xaf, 0xb3, 0x70, 0xf2, 0x52, 0xc3, 0x76, + 0x6e, 0xc7, 0x1c, 0xdb, 0x49, 0x39, 0x6d, 0x8d, 0x61, 0x73, 0xda, 0x86, 0x4f, 0x7e, 0x44, 0xd2, + 0xe0, 0xe4, 0x27, 0x3f, 0x32, 0xa3, 0x70, 0x14, 0x17, 0xfd, 0xd0, 0x80, 0xfb, 0xad, 0x3a, 0xb7, + 0x5e, 0xad, 0xa6, 0x28, 0x0d, 0x99, 0xca, 0x15, 0xed, 0x8f, 0xa8, 0x8b, 0x7a, 0x1b, 0xbf, 0x54, + 0x3a, 0x80, 0x2b, 0x1f, 0xf1, 0x77, 0x88, 0x16, 0xdc, 0x7f, 0x10, 0x2a, 0x3e, 0x50, 0xfc, 0xc5, + 0xcb, 0xf0, 0xf6, 0x43, 0x19, 0x0d, 0x35, 0x5b, 0x3e, 0x65, 0x40, 0x81, 0xbb, 0x4f, 0x31, 0xd9, + 0xa6, 0x5b, 0x85, 0xd5, 0xb6, 0xaf, 0x11, 0xcf, 0x97, 0xc9, 0xb6, 0xb4, 0x03, 0x5e, 0xa9, 0xb2, + 0x26, 0x20, 0x58, 0xc3, 0xa2, 0x9b, 0xf1, 0x4d, 0xdb, 0xa9, 0x8b, 0x61, 0x52, 0x9b, 0xf1, 0x73, + 0xb6, 0x53, 0xc7, 0x0c, 0xa2, 0xb6, 0xeb, 0x6c, 0x5f, 0xb7, 0xc6, 0x1b, 0x06, 0x4c, 0xb3, 0x77, + 0x8e, 0xe1, 0xd1, 0xe3, 0x09, 0x15, 0xd3, 0xc2, 0xc5, 0x38, 0x13, 0x8d, 0x69, 0xb9, 0xd3, 0x2d, + 0x4e, 0xf2, 0x97, 0x91, 0xd1, 0x10, 0x97, 0x0f, 0x0a, 0x7f, 0x05, 0x8b, 0xbc, 0xc9, 0x0c, 0x7d, + 0x9c, 0x56, 0xfe, 0xbc, 0xaa, 0x24, 0x82, 0x43, 0x7a, 0xe6, 0x4b, 0x30, 0xa5, 0x3f, 0x58, 0x40, + 0x4f, 0xc0, 0x64, 0xdb, 0x76, 0x1a, 0xd1, 0x87, 0x6d, 0xca, 0xa7, 0x5b, 0x09, 0x41, 0x58, 0xc7, + 0x63, 0xd5, 0xdc, 0xb0, 0x5a, 0xcc, 0x15, 0x5c, 0x71, 0xf5, 0x6a, 0xe1, 0x1f, 0xf3, 0x4f, 0xb2, + 0x70, 0x32, 0xe1, 0x61, 0x0c, 0x7a, 0xd5, 0x80, 0x71, 0x16, 0xa5, 0x2f, 0xa3, 0x56, 0x5e, 0x48, + 0xfd, 0xf1, 0xcd, 0x12, 0x7b, 0x0c, 0x20, 0xe6, 0xb1, 0xda, 0x3e, 0x79, 0x21, 0x16, 0xcc, 0xd1, + 0x6f, 0x19, 0x30, 0x69, 0x69, 0x4b, 0x8d, 0x07, 0xf2, 0x6c, 0xa5, 0x2f, 0x4c, 0xcf, 0xca, 0xd2, + 0x02, 0x10, 0xc3, 0x85, 0xa4, 0xcb, 0xb2, 0xf8, 0x5e, 0x98, 0xd4, 0x9a, 0x30, 0xcc, 0x0a, 0x59, + 0x7c, 0x06, 0x66, 0x47, 0x5a, 0x61, 0x1f, 0x80, 0x61, 0x73, 0xc7, 0x51, 0x85, 0x75, 0x4b, 0x7f, + 0x7c, 0xac, 0x7a, 0x5c, 0xbc, 0x3e, 0x16, 0x50, 0x73, 0x0b, 0x66, 0xe3, 0x87, 0xab, 0xd4, 0xef, + 0xad, 0xdf, 0x0d, 0x43, 0x66, 0x7b, 0x33, 0xbf, 0x9d, 0x81, 0x09, 0xf1, 0xba, 0xee, 0x2e, 0xc4, + 0xee, 0xde, 0x8c, 0x5c, 0xea, 0xac, 0xa5, 0xf2, 0x28, 0xb0, 0x6f, 0xe0, 0xae, 0x1f, 0x0b, 0xdc, + 0x7d, 0x2e, 0x1d, 0x76, 0x07, 0x47, 0xed, 0xbe, 0x31, 0x06, 0x33, 0xb1, 0xd7, 0x8a, 0xd4, 0x54, + 0xe9, 0x09, 0x56, 0xbb, 0x9a, 0xea, 0x83, 0x48, 0x15, 0x57, 0x7e, 0x70, 0xdc, 0x9a, 0x1f, 0x49, + 0xaa, 0x79, 0x25, 0xb5, 0x7c, 0xdc, 0x3f, 0xcf, 0xaf, 0x39, 0x6c, 0x1c, 0xd6, 0x3f, 0x1b, 0x70, + 0x6f, 0xdf, 0x47, 0xad, 0x2c, 0x27, 0x8a, 0x17, 0x85, 0x8a, 0x05, 0x99, 0xf2, 0xd3, 0x7d, 0x75, + 0xc3, 0x12, 0x4f, 0x63, 0x11, 0x67, 0x8f, 0x1e, 0x87, 0x29, 0xa6, 0x5a, 0xe9, 0x9e, 0x12, 0x90, + 0xb6, 0x70, 0x10, 0x33, 0x57, 0x61, 0x55, 0x2b, 0xc7, 0x11, 0x2c, 0xf3, 0x4b, 0x06, 0x2c, 0xf4, + 0xcb, 0x90, 0x31, 0xc0, 0xc1, 0xf0, 0x17, 0x62, 0xc1, 0xc5, 0xc5, 0x9e, 0xe0, 0xe2, 0xd8, 0xd1, + 0x50, 0xc6, 0x11, 0x6b, 0xa7, 0xb2, 0xec, 0x21, 0xb1, 0xb3, 0x9f, 0x35, 0xe0, 0x74, 0x9f, 0xd5, + 0xd4, 0x13, 0x64, 0x6e, 0x1c, 0x39, 0xc8, 0x3c, 0x33, 0x68, 0x90, 0xb9, 0xf9, 0xdd, 0x2c, 0xcc, + 0x0a, 0x79, 0x42, 0xfb, 0xea, 0xc9, 0x48, 0x88, 0xf6, 0x3b, 0x62, 0x21, 0xda, 0xf3, 0x71, 0xfc, + 0x9f, 0xc7, 0x67, 0xbf, 0xb5, 0xe2, 0xb3, 0x7f, 0x9a, 0x81, 0x53, 0x89, 0x89, 0x3b, 0xd0, 0xa7, + 0x13, 0x54, 0xc3, 0xf5, 0x94, 0x33, 0x84, 0x0c, 0xa8, 0x1c, 0x46, 0x0d, 0x6a, 0xfe, 0x82, 0x1e, + 0x4c, 0xcc, 0xb7, 0xfa, 0xed, 0x63, 0xc8, 0x75, 0x32, 0x64, 0x5c, 0xb1, 0xf9, 0x6b, 0x59, 0x78, + 0x78, 0x50, 0x42, 0x6f, 0xd1, 0x77, 0x27, 0x7e, 0xe4, 0xdd, 0xc9, 0x5d, 0x52, 0xdb, 0xc7, 0xf2, + 0x04, 0xe5, 0xcb, 0x59, 0xa5, 0xf6, 0x7a, 0xe7, 0xe7, 0x40, 0xb7, 0x89, 0x13, 0xd4, 0xb4, 0x93, + 0xe9, 0x3c, 0xc3, 0xad, 0x70, 0xa2, 0xca, 0x8b, 0xef, 0x74, 0x8b, 0x73, 0x22, 0xc5, 0x5f, 0x95, + 0x04, 0xa2, 0x10, 0xcb, 0x4a, 0xe8, 0x61, 0xc8, 0x7b, 0x1c, 0x2a, 0x23, 0xed, 0xc5, 0x95, 0x2c, + 0x2f, 0xc3, 0x0a, 0x8a, 0x3e, 0xa9, 0xd9, 0xc2, 0x63, 0xc7, 0x95, 0x25, 0xe1, 0xa0, 0x9b, 0xe6, + 0x17, 0x20, 0xef, 0xcb, 0xc4, 0x9c, 0xfc, 0x3a, 0xe0, 0xb1, 0x01, 0x1f, 0x70, 0xd0, 0xa3, 0x93, + 0xcc, 0xd2, 0xc9, 0xdb, 0xa7, 0x72, 0x78, 0x2a, 0x92, 0xc8, 0x54, 0xa7, 0x16, 0xee, 0x63, 0x84, + 0x84, 0x13, 0xcb, 0xf7, 0x0c, 0x98, 0x14, 0xa3, 0x75, 0x17, 0xde, 0x94, 0xdc, 0x88, 0xbe, 0x29, + 0x39, 0x97, 0xca, 0xde, 0xd1, 0xe7, 0x41, 0xc9, 0x0d, 0x98, 0xd2, 0x73, 0x37, 0xa1, 0xe7, 0xb5, + 0xbd, 0xcf, 0x18, 0x25, 0x1b, 0x8a, 0xdc, 0x1d, 0xc3, 0x7d, 0xd1, 0xfc, 0x9d, 0xbc, 0xea, 0x45, + 0xe6, 0x87, 0xd0, 0xe7, 0xa0, 0x71, 0xe0, 0x1c, 0xd4, 0xa7, 0x40, 0x26, 0xfd, 0x29, 0x70, 0x05, + 0xf2, 0x72, 0x83, 0x12, 0x6a, 0xfc, 0x41, 0x3d, 0xca, 0x8e, 0xda, 0x02, 0x94, 0x98, 0x36, 0x71, + 0xd9, 0x51, 0x4b, 0x8d, 0xa1, 0xda, 0x38, 0x15, 0x19, 0xf4, 0x22, 0x4c, 0xde, 0x72, 0xbd, 0x9b, + 0x4d, 0xd7, 0x62, 0x29, 0x77, 0x21, 0x8d, 0x8b, 0x1d, 0xe5, 0xf0, 0xe2, 0xa1, 0xce, 0xd7, 0x43, + 0xfa, 0x58, 0x67, 0x86, 0x4a, 0x30, 0xd3, 0xb2, 0x1d, 0x4c, 0xac, 0xba, 0x7a, 0x3a, 0x32, 0xc6, + 0x73, 0x82, 0x4a, 0x23, 0x77, 0x23, 0x0a, 0xc6, 0x71, 0x7c, 0xf4, 0x71, 0xc8, 0xfb, 0x22, 0x13, + 0x52, 0x3a, 0x57, 0x70, 0xea, 0xcc, 0xc8, 0x89, 0x86, 0x7d, 0x27, 0x4b, 0xb0, 0x62, 0x88, 0xd6, + 0x61, 0xde, 0x13, 0xb9, 0x46, 0x22, 0x1f, 0xec, 0xe0, 0xeb, 0x93, 0xa5, 0x9e, 0xc4, 0x09, 0x70, + 0x9c, 0x58, 0x8b, 0x5a, 0x31, 0x2c, 0x09, 0x19, 0xbf, 0x13, 0xd0, 0xdc, 0xe8, 0x6c, 0xc2, 0xd7, + 0xb1, 0x80, 0x1e, 0xf4, 0x14, 0x29, 0x3f, 0xc2, 0x53, 0xa4, 0x2a, 0x9c, 0x8a, 0x83, 0x58, 0x46, + 0x14, 0x96, 0x84, 0x45, 0xd3, 0x1e, 0x95, 0x24, 0x24, 0x9c, 0x5c, 0x17, 0x5d, 0x87, 0x82, 0x47, + 0xd8, 0xf9, 0xa2, 0x24, 0x2f, 0xfd, 0x87, 0x0e, 0x6f, 0xc2, 0x92, 0x00, 0x0e, 0x69, 0xd1, 0x71, + 0xb7, 0xa2, 0x69, 0x31, 0xaf, 0xa4, 0xf8, 0xc9, 0x31, 0x31, 0xf6, 0x7d, 0x32, 0x15, 0x99, 0x6f, + 0x4e, 0xc3, 0x89, 0x88, 0x6f, 0x01, 0x3d, 0x08, 0x39, 0x96, 0x22, 0x86, 0x6d, 0x0f, 0xf9, 0x70, + 0x0b, 0xe3, 0x9d, 0xc3, 0x61, 0xe8, 0x73, 0x06, 0xcc, 0xb4, 0x23, 0x5e, 0x58, 0xb9, 0x73, 0x8e, + 0x78, 0xcf, 0x17, 0x75, 0xed, 0x6a, 0x09, 0xa5, 0xa3, 0xcc, 0x70, 0x9c, 0x3b, 0x5d, 0x80, 0x22, + 0x46, 0xb0, 0x49, 0x3c, 0x86, 0x2d, 0x6c, 0x1c, 0x45, 0x62, 0x25, 0x0a, 0xc6, 0x71, 0x7c, 0x3a, + 0xc2, 0xac, 0x75, 0xa3, 0x7c, 0x8b, 0xa8, 0x24, 0x09, 0xe0, 0x90, 0x16, 0x7a, 0x06, 0xa6, 0x45, + 0x36, 0xc4, 0x8a, 0x5b, 0xbf, 0x60, 0xf9, 0x3b, 0xc2, 0xb8, 0x57, 0x87, 0x91, 0x95, 0x08, 0x14, + 0xc7, 0xb0, 0x59, 0xdb, 0xc2, 0x94, 0x93, 0x8c, 0xc0, 0x78, 0x34, 0xdf, 0xf6, 0x4a, 0x14, 0x8c, + 0xe3, 0xf8, 0xe8, 0x11, 0x6d, 0xdf, 0xe7, 0xf7, 0x74, 0x6a, 0x37, 0x48, 0xd8, 0xfb, 0x4b, 0x30, + 0xd3, 0x61, 0x67, 0xa1, 0xba, 0x04, 0x8a, 0xf5, 0xa8, 0x18, 0x5e, 0x8d, 0x82, 0x71, 0x1c, 0x1f, + 0x3d, 0x05, 0x27, 0x3c, 0xba, 0xbb, 0x29, 0x02, 0xfc, 0xf2, 0x4e, 0xdd, 0xcd, 0x60, 0x1d, 0x88, + 0xa3, 0xb8, 0xe8, 0x59, 0x98, 0x0b, 0x93, 0x87, 0x49, 0x02, 0xfc, 0x36, 0x4f, 0xe5, 0xc5, 0x29, + 0xc5, 0x11, 0x70, 0x6f, 0x1d, 0xf4, 0x4b, 0x30, 0xab, 0xf5, 0xc4, 0x9a, 0x53, 0x27, 0xb7, 0x45, + 0x82, 0x27, 0xf6, 0x69, 0x84, 0x95, 0x18, 0x0c, 0xf7, 0x60, 0xa3, 0xf7, 0xc1, 0x74, 0xcd, 0x6d, + 0x36, 0xd9, 0x1e, 0xc7, 0x73, 0x3d, 0xf3, 0x4c, 0x4e, 0x3c, 0xe7, 0x55, 0x04, 0x82, 0x63, 0x98, + 0xe8, 0x22, 0x20, 0x77, 0xcb, 0x27, 0xde, 0x2e, 0xa9, 0x3f, 0xcb, 0xbf, 0x6e, 0x4a, 0x55, 0xfc, + 0x89, 0x68, 0x84, 0xf2, 0xe5, 0x1e, 0x0c, 0x9c, 0x50, 0x8b, 0xa5, 0xd5, 0xd1, 0x5e, 0x74, 0x4d, + 0xa7, 0xf1, 0x5d, 0x9e, 0xf8, 0xc9, 0xfd, 0xd0, 0xe7, 0x5c, 0x1e, 0x8c, 0xf3, 0x80, 0xf1, 0x74, + 0x52, 0x3a, 0xe9, 0x69, 0x5f, 0x43, 0x1d, 0xc1, 0x4b, 0xb1, 0xe0, 0x84, 0x3e, 0x01, 0x85, 0x2d, + 0x99, 0x03, 0x7c, 0x61, 0x36, 0x0d, 0xbd, 0x18, 0x4b, 0x67, 0x1f, 0x9e, 0x4c, 0x15, 0x00, 0x87, + 0x2c, 0xd1, 0x43, 0x30, 0x79, 0xa1, 0x52, 0x52, 0xb3, 0x70, 0x8e, 0x8d, 0xfe, 0x18, 0xad, 0x82, + 0x75, 0x00, 0x5d, 0x61, 0xca, 0x5e, 0x42, 0x6c, 0x88, 0x43, 0x7d, 0xdb, 0x6b, 0xfe, 0x50, 0x6c, + 0x76, 0x1d, 0x89, 0xab, 0x0b, 0x27, 0x63, 0xd8, 0xa2, 0x1c, 0x2b, 0x0c, 0xf4, 0x02, 0x4c, 0x0a, + 0x7d, 0xc1, 0xf6, 0xa6, 0xf9, 0xa3, 0xbd, 0x16, 0xc4, 0x21, 0x09, 0xac, 0xd3, 0x63, 0xb7, 0x4c, + 0x2c, 0x35, 0x32, 0x39, 0xdf, 0x69, 0x36, 0x17, 0x4e, 0xb1, 0x7d, 0x33, 0xbc, 0x65, 0x0a, 0x41, + 0x58, 0xc7, 0x43, 0x8f, 0xc9, 0xc8, 0x89, 0xb7, 0x45, 0xae, 0xdd, 0x54, 0xe4, 0x84, 0xb2, 0x72, + 0xfb, 0x04, 0x14, 0x9f, 0x3e, 0x24, 0x64, 0x61, 0x0b, 0x16, 0xa5, 0x89, 0xd5, 0xbb, 0x48, 0x16, + 0x16, 0x22, 0x5e, 0x82, 0xc5, 0xeb, 0x7d, 0x31, 0xf1, 0x01, 0x54, 0xd0, 0x16, 0x64, 0xad, 0xe6, + 0xd6, 0xc2, 0xbd, 0x69, 0xd8, 0x8a, 0xea, 0x6b, 0xc5, 0x3c, 0x08, 0xa8, 0xb4, 0x5e, 0xc6, 0x94, + 0xb8, 0xf9, 0x4a, 0x46, 0x79, 0xe5, 0x55, 0xaa, 0xcb, 0x97, 0xf4, 0x59, 0x6d, 0xa4, 0xf1, 0x35, + 0xce, 0x9e, 0x44, 0xf9, 0x5c, 0x21, 0x25, 0xce, 0xe9, 0xb6, 0x5a, 0xc7, 0xa9, 0xe4, 0x31, 0x89, + 0xa6, 0xf1, 0xe4, 0xa7, 0xb9, 0xe8, 0x2a, 0x36, 0xf7, 0x27, 0x94, 0x13, 0x2a, 0x16, 0x0a, 0xe0, + 0x41, 0xce, 0xf6, 0x03, 0xdb, 0x4d, 0xf1, 0x65, 0x5b, 0x2c, 0xff, 0x25, 0x0b, 0x9c, 0x65, 0x00, + 0xcc, 0x59, 0x51, 0x9e, 0x4e, 0xc3, 0x76, 0x6e, 0x8b, 0xe6, 0x5f, 0x49, 0xfd, 0x8e, 0x9f, 0xf3, + 0x64, 0x00, 0xcc, 0x59, 0xa1, 0x1b, 0x7c, 0xa6, 0xa5, 0xf3, 0xe5, 0xd5, 0xf8, 0x07, 0x95, 0xa3, + 0x33, 0x8e, 0xf2, 0xf2, 0x5b, 0xb6, 0xb0, 0x61, 0x46, 0xe4, 0x55, 0xdd, 0x58, 0x4b, 0xe2, 0x55, + 0xdd, 0x58, 0xc3, 0x94, 0x09, 0x7a, 0xcd, 0x00, 0xb0, 0xd4, 0x97, 0x85, 0xd3, 0xf9, 0xaa, 0x44, + 0xbf, 0x2f, 0x15, 0xf3, 0x58, 0xb7, 0x10, 0x8a, 0x35, 0xce, 0xe8, 0x45, 0x98, 0xb0, 0xf8, 0x37, + 0x71, 0x44, 0x18, 0x61, 0x3a, 0x1f, 0x7a, 0x8a, 0x49, 0xc0, 0xe2, 0x27, 0x05, 0x08, 0x4b, 0x86, + 0x94, 0x77, 0xe0, 0x59, 0x64, 0xdb, 0xbe, 0x29, 0xe2, 0x09, 0xab, 0x23, 0xa7, 0xb6, 0xa6, 0xc4, + 0x92, 0x78, 0x0b, 0x10, 0x96, 0x0c, 0xf9, 0xc7, 0x3c, 0x2d, 0xc7, 0x52, 0x8f, 0x43, 0xd2, 0x79, + 0x42, 0xa4, 0x3f, 0x37, 0xd1, 0x3e, 0xe6, 0xa9, 0x33, 0xc2, 0x51, 0xbe, 0xe6, 0x8f, 0xb3, 0x00, + 0xec, 0x27, 0x7f, 0xb0, 0xdc, 0x62, 0x49, 0xee, 0x76, 0xdc, 0xba, 0x58, 0xda, 0x29, 0xbe, 0x3b, + 0x06, 0x91, 0xd1, 0x6e, 0xc7, 0xad, 0x63, 0xc1, 0x04, 0x35, 0x60, 0xac, 0x6d, 0x05, 0x3b, 0xe9, + 0x3f, 0x72, 0xce, 0xf3, 0x97, 0x3b, 0xc1, 0x0e, 0x66, 0x0c, 0xd0, 0xcb, 0x06, 0x4c, 0xf0, 0x67, + 0xce, 0xd2, 0xd5, 0x3c, 0xf2, 0x7d, 0xaa, 0xec, 0xb3, 0x25, 0xfe, 0x96, 0x5a, 0x04, 0x2b, 0x28, + 0xd5, 0x28, 0x4a, 0xb1, 0x64, 0xbb, 0xf8, 0xaa, 0x01, 0x53, 0x3a, 0x6a, 0x42, 0x98, 0xc1, 0x47, + 0xf4, 0x30, 0x83, 0x34, 0xfb, 0x43, 0x8f, 0x58, 0xf8, 0x37, 0x03, 0xb4, 0x4f, 0xa0, 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, 0x6e, 0xc0, 0x5c, 0xcf, 0x7e, 0x18, 0xff, 0xd4, 0xbc, + 0x31, 0xe0, 0xa7, 0xe6, 0x57, 0x61, 0x56, 0x24, 0x61, 0xae, 0xb6, 0x9b, 0x76, 0xe2, 0x03, 0xf4, + 0xcd, 0x18, 0x1c, 0xf7, 0xd4, 0x30, 0xff, 0xc2, 0x80, 0x49, 0xed, 0xd9, 0x1a, 0x6d, 0x07, 0x7b, + 0xde, 0x27, 0xc4, 0x08, 0xf3, 0x4f, 0x33, 0xd7, 0x3e, 0x87, 0xf1, 0x5b, 0xa6, 0x86, 0x96, 0xf0, + 0x33, 0xbc, 0x65, 0xa2, 0xa5, 0x58, 0x40, 0x79, 0x2a, 0x47, 0xd2, 0x66, 0x9d, 0x9e, 0xd5, 0x53, + 0x39, 0x92, 0x36, 0x66, 0x10, 0xc6, 0x8e, 0xda, 0x91, 0x22, 0xfe, 0x54, 0x4b, 0x77, 0x6d, 0x79, + 0x01, 0xe6, 0x30, 0x74, 0x06, 0xb2, 0xc4, 0xa9, 0x8b, 0x43, 0xaf, 0xfa, 0xc4, 0xd4, 0x39, 0xa7, + 0x8e, 0x69, 0xb9, 0x79, 0x19, 0xa6, 0xaa, 0xa4, 0xe6, 0x91, 0xe0, 0x39, 0xb2, 0x37, 0xf0, 0x37, + 0xab, 0xe8, 0x6c, 0x8f, 0x7d, 0xb3, 0x8a, 0x56, 0xa7, 0xe5, 0xe6, 0x1f, 0x19, 0x10, 0xcb, 0xc9, + 0xae, 0x79, 0x9c, 0x8d, 0x7e, 0x1e, 0xe7, 0x88, 0x6f, 0x34, 0x73, 0xa0, 0x6f, 0xf4, 0x22, 0xa0, + 0x16, 0x5d, 0x0a, 0x91, 0x2f, 0x10, 0x08, 0x7f, 0x43, 0xf8, 0x48, 0xb6, 0x07, 0x03, 0x27, 0xd4, + 0x32, 0xff, 0x90, 0x0b, 0xab, 0x67, 0x69, 0x3f, 0xbc, 0x03, 0x3a, 0x90, 0x63, 0xa4, 0x84, 0xd3, + 0xa5, 0x32, 0xda, 0xe2, 0xee, 0x4d, 0x36, 0x11, 0x0e, 0xa4, 0x58, 0xf2, 0x8c, 0x9b, 0xf9, 0x5d, + 0x2e, 0xab, 0x96, 0xc6, 0x7d, 0x00, 0x59, 0x5b, 0x51, 0x59, 0x2f, 0xa4, 0xb5, 0x57, 0x26, 0xcb, + 0x88, 0x96, 0x00, 0xda, 0xc4, 0xab, 0x11, 0x27, 0x90, 0x61, 0xd1, 0x39, 0xf1, 0x8c, 0x44, 0x95, + 0x62, 0x0d, 0xc3, 0x7c, 0xd9, 0x80, 0xd9, 0x6a, 0x60, 0xd7, 0x6e, 0xda, 0x0e, 0x7f, 0x16, 0xb5, + 0x6d, 0x37, 0xe8, 0x29, 0x85, 0x88, 0xcf, 0x31, 0x71, 0x37, 0x98, 0xda, 0x8a, 0xe5, 0x57, 0x98, + 0x24, 0x1c, 0x95, 0x60, 0x46, 0x7a, 0xdb, 0xa5, 0xef, 0x92, 0x3f, 0xe7, 0x54, 0xbe, 0x92, 0xd5, + 0x28, 0x18, 0xc7, 0xf1, 0xcd, 0x4f, 0xc2, 0xa4, 0xb6, 0xbf, 0xb2, 0xad, 0xe8, 0xb6, 0x55, 0x0b, + 0xe2, 0x4b, 0xf8, 0x1c, 0x2d, 0xc4, 0x1c, 0xc6, 0x5c, 0xac, 0x3c, 0x6e, 0x36, 0xb6, 0x84, 0x45, + 0xb4, 0xac, 0x80, 0x52, 0x62, 0x1e, 0x69, 0x90, 0xdb, 0x32, 0xb5, 0xa8, 0x24, 0x86, 0x69, 0x21, + 0xe6, 0x30, 0xf3, 0x11, 0xc8, 0xcb, 0x47, 0xf7, 0xec, 0xe5, 0xaa, 0x74, 0xff, 0xe9, 0x2f, 0x57, + 0x5d, 0x2f, 0xc0, 0x0c, 0x62, 0x5e, 0x83, 0xbc, 0xcc, 0x0d, 0x70, 0x38, 0x36, 0x5d, 0x55, 0xbe, + 0x63, 0x5f, 0x70, 0xfd, 0x40, 0x26, 0x34, 0xe0, 0x57, 0x02, 0x97, 0xd6, 0x58, 0x19, 0x56, 0x50, + 0x73, 0x0e, 0x66, 0x94, 0xaf, 0x5f, 0x04, 0x32, 0x7e, 0x23, 0x0b, 0x53, 0x91, 0x4f, 0x01, 0x1f, + 0x3e, 0xdd, 0x06, 0x5f, 0xc5, 0x09, 0x3e, 0xfb, 0xec, 0x90, 0x3e, 0x7b, 0xfd, 0x92, 0x64, 0xec, + 0x78, 0x2f, 0x49, 0x72, 0xe9, 0x5c, 0x92, 0x04, 0x30, 0xe1, 0x0b, 0x45, 0x35, 0x9e, 0x86, 0x33, + 0x25, 0x36, 0x62, 0xdc, 0x46, 0x95, 0xfa, 0x4e, 0xb2, 0x32, 0xbf, 0x9a, 0x83, 0xe9, 0x68, 0x56, + 0xa4, 0x01, 0x46, 0xf2, 0x91, 0x9e, 0x91, 0x1c, 0xd2, 0x67, 0x99, 0x1d, 0xd5, 0x67, 0x39, 0x36, + 0xaa, 0xcf, 0x32, 0x77, 0x04, 0x9f, 0x65, 0xaf, 0xc7, 0x71, 0x7c, 0x60, 0x8f, 0xe3, 0xd3, 0x2a, + 0xe0, 0x66, 0x22, 0x72, 0x43, 0x1d, 0x06, 0xdc, 0xa0, 0xe8, 0x30, 0xac, 0xb8, 0xf5, 0xc4, 0xc0, + 0xa5, 0xfc, 0x21, 0xbe, 0x19, 0x2f, 0x31, 0x3e, 0x66, 0xf8, 0x6b, 0x91, 0xb7, 0x0d, 0x11, 0x1b, + 0xf3, 0x04, 0x4c, 0x8a, 0xf9, 0xc4, 0x6c, 0x25, 0x88, 0xda, 0x59, 0xd5, 0x10, 0x84, 0x75, 0x3c, + 0xf6, 0xb5, 0xca, 0xe8, 0xe7, 0x39, 0x99, 0x0b, 0x58, 0xff, 0x5a, 0x65, 0xec, 0x73, 0x9e, 0x71, + 0x7c, 0xf3, 0xe3, 0x70, 0x2a, 0xf1, 0x44, 0xc6, 0x5c, 0x54, 0x4c, 0x8d, 0x93, 0xba, 0x40, 0xd0, + 0xc4, 0x88, 0x25, 0xcd, 0x5d, 0xbc, 0xde, 0x17, 0x13, 0x1f, 0x40, 0xc5, 0xfc, 0x4a, 0x16, 0xa6, + 0xa3, 0x9f, 0x3a, 0x42, 0xb7, 0x94, 0xff, 0x26, 0x15, 0xd7, 0x11, 0x27, 0xab, 0x65, 0xda, 0xe9, + 0xeb, 0x8c, 0xbd, 0xc5, 0xe6, 0xd7, 0x96, 0x4a, 0xfb, 0x73, 0x7c, 0x8c, 0x85, 0x17, 0x54, 0xb0, + 0x63, 0x5f, 0x33, 0x0a, 0x9f, 0x3b, 0x88, 0x63, 0x57, 0xea, 0xdc, 0xc3, 0x07, 0x0c, 0x8a, 0x15, + 0xd6, 0xd8, 0x52, 0xdd, 0xb2, 0x4b, 0x3c, 0x7b, 0xdb, 0x56, 0x9f, 0x69, 0x64, 0x3b, 0xf7, 0x35, + 0x51, 0x86, 0x15, 0xd4, 0x7c, 0x39, 0x03, 0xe1, 0x47, 0x69, 0xd9, 0xf7, 0x40, 0x7c, 0xcd, 0xc4, + 0x15, 0xc3, 0x76, 0x71, 0xd4, 0x8f, 0xee, 0x84, 0x14, 0x45, 0x30, 0xa4, 0x56, 0x82, 0x23, 0x1c, + 0x7f, 0x06, 0x1f, 0xa3, 0xb5, 0x60, 0x26, 0xf6, 0x08, 0x34, 0xf5, 0x88, 0xf3, 0x1f, 0x65, 0xa1, + 0xa0, 0x9e, 0xd1, 0xa2, 0xf7, 0x46, 0xfc, 0x0d, 0x85, 0xf2, 0xdb, 0xb5, 0xd4, 0xf7, 0x3b, 0x6e, + 0xfd, 0x4e, 0xb7, 0x38, 0xa3, 0x90, 0x63, 0xbe, 0x83, 0x33, 0x90, 0xed, 0x78, 0xcd, 0xf8, 0x81, + 0xe2, 0x2a, 0x5e, 0xc7, 0xb4, 0x1c, 0xdd, 0x8e, 0x1f, 0xf8, 0x37, 0x52, 0x7a, 0xfa, 0xcb, 0x2d, + 0xef, 0xfe, 0x07, 0x7d, 0xaa, 0x25, 0xb7, 0xdc, 0xfa, 0x5e, 0x3c, 0x55, 0x7e, 0xd9, 0xad, 0xef, + 0x61, 0x06, 0x41, 0xcf, 0xc0, 0x74, 0x60, 0xb7, 0x88, 0xdb, 0x09, 0xf4, 0x4f, 0x7e, 0x66, 0xc3, + 0xcb, 0xc5, 0xcd, 0x08, 0x14, 0xc7, 0xb0, 0xa9, 0x96, 0xbd, 0xe1, 0xbb, 0x0e, 0xcb, 0x7f, 0x37, + 0x1e, 0xbd, 0x89, 0xb8, 0x58, 0xbd, 0x7c, 0x89, 0xf9, 0x3d, 0x14, 0x06, 0xc5, 0xb6, 0xd9, 0x9b, + 0x39, 0x8f, 0x88, 0xbb, 0xfd, 0xd9, 0x30, 0xa3, 0x02, 0x2f, 0xc7, 0x0a, 0x03, 0xad, 0x72, 0xda, + 0x54, 0x5a, 0xa6, 0x51, 0xa6, 0xca, 0x0f, 0x4b, 0xba, 0xb4, 0xec, 0x4e, 0xb7, 0xb8, 0x40, 0x9c, + 0x9a, 0x5b, 0xb7, 0x9d, 0xc6, 0x32, 0x45, 0x5c, 0xc2, 0xd6, 0x2d, 0xa9, 0x6a, 0x54, 0x4d, 0xf3, + 0x2a, 0xcc, 0xc4, 0x3a, 0x4c, 0x1e, 0x00, 0x8d, 0xe4, 0x03, 0xe0, 0x60, 0xd9, 0xed, 0xff, 0xd4, + 0x80, 0xb9, 0x9e, 0x2d, 0x60, 0xd0, 0x07, 0x15, 0x71, 0x65, 0x94, 0x39, 0xba, 0x32, 0xca, 0x0e, + 0xa7, 0x8c, 0xca, 0x5b, 0xdf, 0x7a, 0xf3, 0xec, 0x3d, 0xdf, 0x79, 0xf3, 0xec, 0x3d, 0xdf, 0x7f, + 0xf3, 0xec, 0x3d, 0x2f, 0xef, 0x9f, 0x35, 0xbe, 0xb5, 0x7f, 0xd6, 0xf8, 0xce, 0xfe, 0x59, 0xe3, + 0xfb, 0xfb, 0x67, 0x8d, 0x7f, 0xda, 0x3f, 0x6b, 0xbc, 0xfe, 0xa3, 0xb3, 0xf7, 0x3c, 0xff, 0x74, + 0x38, 0x41, 0x97, 0xe5, 0x04, 0x65, 0x3f, 0xde, 0x25, 0xa7, 0xe3, 0x72, 0xfb, 0x66, 0x63, 0x99, + 0x4e, 0xd0, 0x65, 0x55, 0x22, 0x27, 0xe8, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0xf8, 0x2a, 0x23, + 0xab, 0x55, 0x93, 0x00, 0x00, } func (m *ALBStatus) Marshal() (dAtA []byte, err error) { @@ -9233,6 +9235,13 @@ func (m *WebMetric) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.JSONBody != nil { + i -= len(m.JSONBody) + copy(dAtA[i:], m.JSONBody) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.JSONBody))) + i-- + dAtA[i] = 0x42 + } i-- if m.Insecure { dAtA[i] = 1 @@ -11460,6 +11469,10 @@ func (m *WebMetric) Size() (n int) { l = len(m.JSONPath) n += 1 + l + sovGenerated(uint64(l)) n += 2 + if m.JSONBody != nil { + l = len(m.JSONBody) + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -13089,6 +13102,7 @@ func (this *WebMetric) String() string { `TimeoutSeconds:` + fmt.Sprintf("%v", this.TimeoutSeconds) + `,`, `JSONPath:` + fmt.Sprintf("%v", this.JSONPath) + `,`, `Insecure:` + fmt.Sprintf("%v", this.Insecure) + `,`, + `JSONBody:` + valueToStringGenerated(this.JSONBody) + `,`, `}`, }, "") return s @@ -31042,6 +31056,40 @@ func (m *WebMetric) Unmarshal(dAtA []byte) error { } } m.Insecure = bool(v != 0) + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field JSONBody", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.JSONBody = append(m.JSONBody[:0], dAtA[iNdEx:postIndex]...) + if m.JSONBody == nil { + m.JSONBody = []byte{} + } + 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 490aad9581..c90faf3a42 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.proto +++ b/pkg/apis/rollouts/v1alpha1/generated.proto @@ -1701,7 +1701,7 @@ message WebMetric { // Headers are optional HTTP headers to use in the request repeated WebMetricHeader headers = 3; - // Body is the body of the we metric (must be POST/PUT) + // Body is the body of the web metric (must be POST/PUT) optional string body = 4; // TimeoutSeconds is the timeout for the request in seconds (default: 10) @@ -1712,6 +1712,12 @@ message WebMetric { // Insecure skips host TLS verification optional bool insecure = 7; + + // +kubebuilder:validation:Schemaless + // +kubebuilder:pruning:PreserveUnknownFields + // +kubebuilder:validation:Type=object + // JSONBody is the body of the web metric in a json format (method must be POST/PUT) + optional bytes jsonBody = 8; } message WebMetricHeader { diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index 222b2fc46f..ac729e0107 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -5012,7 +5012,7 @@ func schema_pkg_apis_rollouts_v1alpha1_WebMetric(ref common.ReferenceCallback) c }, "body": { SchemaProps: spec.SchemaProps{ - Description: "Body is the body of the we metric (must be POST/PUT)", + Description: "Body is the body of the web metric (must be POST/PUT)", Type: []string{"string"}, Format: "", }, @@ -5038,6 +5038,13 @@ func schema_pkg_apis_rollouts_v1alpha1_WebMetric(ref common.ReferenceCallback) c Format: "", }, }, + "jsonBody": { + SchemaProps: spec.SchemaProps{ + Description: "JSONBody is the body of the web metric in a json format (method must be POST/PUT)", + Type: []string{"string"}, + Format: "byte", + }, + }, }, Required: []string{"url"}, }, diff --git a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go index 58d6135a98..1a64ef2cca 100644 --- a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go @@ -22,6 +22,8 @@ limitations under the License. package v1alpha1 import ( + json "encoding/json" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" intstr "k8s.io/apimachinery/pkg/util/intstr" @@ -2699,6 +2701,11 @@ func (in *WebMetric) DeepCopyInto(out *WebMetric) { *out = make([]WebMetricHeader, len(*in)) copy(*out, *in) } + if in.JSONBody != nil { + in, out := &in.JSONBody, &out.JSONBody + *out = make(json.RawMessage, len(*in)) + copy(*out, *in) + } return } From 51ed2d456e32d1ec33e3457fcf1c78359b6804d6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 7 Oct 2022 00:09:48 +0000 Subject: [PATCH 31/68] chore(deps): bump google.golang.org/protobuf from 1.28.0 to 1.28.1 (#2296) Bumps [google.golang.org/protobuf](https://github.com/protocolbuffers/protobuf-go) from 1.28.0 to 1.28.1. - [Release notes](https://github.com/protocolbuffers/protobuf-go/releases) - [Changelog](https://github.com/protocolbuffers/protobuf-go/blob/master/release.bash) - [Commits](https://github.com/protocolbuffers/protobuf-go/compare/v1.28.0...v1.28.1) --- updated-dependencies: - dependency-name: google.golang.org/protobuf dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index d7d8d6e71e..276a6e9afd 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,7 @@ require ( github.com/valyala/fasttemplate v1.2.1 google.golang.org/genproto v0.0.0-20220712132514-bdd2acd4974d google.golang.org/grpc v1.50.0 - google.golang.org/protobuf v1.28.0 + google.golang.org/protobuf v1.28.1 gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.24.2 k8s.io/apiextensions-apiserver v0.24.2 diff --git a/go.sum b/go.sum index 5c4365e2b3..541a6d0f1d 100644 --- a/go.sum +++ b/go.sum @@ -1677,8 +1677,9 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba 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/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= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/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= From c40b72aef178bf737c57262a89e4ceca80d46bb4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 7 Oct 2022 00:11:54 +0000 Subject: [PATCH 32/68] chore(deps): bump github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 (#2295) Bumps [github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2](https://github.com/aws/aws-sdk-go-v2) from 1.18.8 to 1.18.19. - [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/service/ecs/v1.18.8...service/ecs/v1.18.19) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 2 +- go.sum | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 276a6e9afd..e651da60d2 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/aws/aws-sdk-go-v2 v1.16.16 github.com/aws/aws-sdk-go-v2/config v1.17.8 github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.21.6 - github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.18.8 + github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.18.19 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 541a6d0f1d..be8967b6dd 100644 --- a/go.sum +++ b/go.sum @@ -152,7 +152,6 @@ github.com/auth0/go-jwt-middleware v1.0.1/go.mod h1:YSeUX3z6+TF2H+7padiEqNJ73Zy9 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 v1.44.39/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= -github.com/aws/aws-sdk-go-v2 v1.16.7/go.mod h1:6CpKuLXg2w7If3ABZCl/qZ6rEgwtjZTn4eAf4RcEyuw= github.com/aws/aws-sdk-go-v2 v1.16.16 h1:M1fj4FE2lB4NzRb9Y0xdWsn2P0+2UHVxwKyOa4YJNjk= github.com/aws/aws-sdk-go-v2 v1.16.16/go.mod h1:SwiyXi/1zTUZ6KIAmLK5V5ll8SiURNUYOqTerZPaF9k= github.com/aws/aws-sdk-go-v2/config v1.17.8 h1:b9LGqNnOdg9vR4Q43tBTVWk4J6F+W774MSchvKJsqnE= @@ -161,18 +160,16 @@ github.com/aws/aws-sdk-go-v2/credentials v1.12.21 h1:4tjlyCD0hRGNQivh5dN8hbP30qQ github.com/aws/aws-sdk-go-v2/credentials v1.12.21/go.mod h1:O+4XyAt4e+oBAoIwNUYkRg3CVMscaIJdmZBOcPgJ8D8= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.17 h1:r08j4sbZu/RVi+BNxkBJwPMUYY3P8mgSDuKkZ/ZN1lE= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.17/go.mod h1:yIkQcCDYNsZfXpd5UX2Cy+sWA1jPgIhGTw9cOBzfVnQ= -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/configsources v1.1.23 h1:s4g/wnzMf+qepSNgTvaQQHNxyMLKSawNhKCPNy++2xY= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23/go.mod h1:2DFxAQ9pfIRy0imBCJv+vZ2X6RKxves6fbnEuSry6b4= -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/endpoints/v2 v2.4.17 h1:/K482T5A3623WJgWT8w1yRAFK4RzGzEl7y39yhtn9eA= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17/go.mod h1:pRwaTYCJemADaqCbUAxltMoHKata7hmB5PjEXeu0kfg= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.24 h1:wj5Rwc05hvUSvKuOF29IYb9QrCLjU+rHAy/x/o0DK2c= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.24/go.mod h1:jULHjqqjDlbyTa7pfM7WICATnOv+iOhjletM3N0Xbu8= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.21.6 h1:Mwb2A5ygEijjkxgM3hVEiWSHwdH82nkyU2wgP4u/Hxk= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.21.6/go.mod h1:CCrqOzLQ6d1+zauyTah8o50m9dQu0NS/kaC0heWCu0c= -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/elasticloadbalancingv2 v1.18.19 h1:vPyIPoJUCiyUOv2TeRGWdLqf14qUp8tuTQ6bJo6ykbY= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.18.19/go.mod h1:tAKN3/tWkL0P+WA44wSkNyk6wWcbHUfTV2F3j3o6Yhs= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17 h1:Jrd/oMh0PKQc6+BowB+pLEwLIgaQF29eYbe7E1Av9Ug= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17/go.mod h1:4nYOrY41Lrbk2170/BGkcJKBhws9Pfn8MG3aGqjjeFI= github.com/aws/aws-sdk-go-v2/service/sso v1.11.23 h1:pwvCchFUEnlceKIgPUouBJwK81aCkQ8UDMORfeFtW10= @@ -181,7 +178,6 @@ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.6 h1:OwhhKc1P9ElfWbMKPIbMMZBV github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.6/go.mod h1:csZuQY65DAdFBt1oIjO5hhBR49kQqop4+lcuCjf2arA= github.com/aws/aws-sdk-go-v2/service/sts v1.16.19 h1:9pPi0PsFNAGILFfPCk8Y0iyEBGc6lu6OQ97U7hmdesg= github.com/aws/aws-sdk-go-v2/service/sts v1.16.19/go.mod h1:h4J3oPZQbxLhzGnk+j9dfYHi5qIOVJ5kczZd658/ydM= -github.com/aws/smithy-go v1.12.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/aws/smithy-go v1.13.3 h1:l7LYxGuzK6/K+NzJ2mC+VvLUbae0sL3bXU//04MkmnA= github.com/aws/smithy-go v1.13.3/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= From 9a6349ba7c584e8f3fe61f841eefb9ac522e113b Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Fri, 7 Oct 2022 14:53:01 -0400 Subject: [PATCH 33/68] docs: Use new Google Analytics 4 site tag (#2299) Signed-off-by: Patrice Chalin Signed-off-by: Patrice Chalin Signed-off-by: Ariel Simhon --- mkdocs.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mkdocs.yml b/mkdocs.yml index a84ef3a807..9dbb3c80fe 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,3 +1,7 @@ +extra: + analytics: + property: G-5Z1VTPDL73 + provider: google extra_css: - assets/versions.css extra_javascript: From d38111dfbe2548b8e7fdf0575c90cb8539b9b828 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Oct 2022 00:10:46 +0000 Subject: [PATCH 34/68] chore(deps): bump github.com/influxdata/influxdb-client-go/v2 (#2304) Bumps [github.com/influxdata/influxdb-client-go/v2](https://github.com/influxdata/influxdb-client-go) from 2.9.1 to 2.11.0. - [Release notes](https://github.com/influxdata/influxdb-client-go/releases) - [Changelog](https://github.com/influxdata/influxdb-client-go/blob/master/CHANGELOG.md) - [Commits](https://github.com/influxdata/influxdb-client-go/compare/v2.9.1...v2.11.0) --- updated-dependencies: - dependency-name: github.com/influxdata/influxdb-client-go/v2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index e651da60d2..208ba4d61e 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,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.9.1 + github.com/influxdata/influxdb-client-go/v2 v2.11.0 github.com/juju/ansiterm v1.0.0 github.com/mitchellh/mapstructure v1.5.0 github.com/newrelic/newrelic-client-go v0.86.5 diff --git a/go.sum b/go.sum index be8967b6dd..8b0b0affe0 100644 --- a/go.sum +++ b/go.sum @@ -628,8 +628,8 @@ 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/influxdb-client-go/v2 v2.11.0 h1:BrHYv38rWkAnp22gIaHFp5LpOCazOqRMRvVE1yW3ym8= +github.com/influxdata/influxdb-client-go/v2 v2.11.0/go.mod h1:YteV91FiQxRdccyJ2cHvj2f/5sq4y4Njqu1fQzsQCOU= 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= From f4c3bf59894c0adf121a3a57cccd09adf4c652ac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Oct 2022 00:10:57 +0000 Subject: [PATCH 35/68] chore(deps): bump docker/setup-buildx-action from 1 to 2 (#2305) Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 1 to 2. - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](https://github.com/docker/setup-buildx-action/compare/v1...v2) --- updated-dependencies: - dependency-name: docker/setup-buildx-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- .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 99067bb8e4..6786339c54 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -24,7 +24,7 @@ jobs: uses: docker/setup-qemu-action@v2 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2 with: config-inline: | [worker.oci] From d9bf71998984923e93ae124d4f62b9a4193fa637 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Oct 2022 00:11:21 +0000 Subject: [PATCH 36/68] chore(deps): bump docker/build-push-action from 2 to 3 (#2306) Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 2 to 3. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v2...v3) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- .github/workflows/release.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 6786339c54..7bb0c1dfb5 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -76,7 +76,7 @@ jobs: password: ${{ secrets.QUAY_ROBOT_TOKEN }} - name: Build and push (controller-image) - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v3 with: context: . platforms: linux/amd64,linux/arm64 @@ -84,7 +84,7 @@ jobs: 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: context: . target: kubectl-argo-rollouts From 8a00abff77abde52d73bf8f06a9a1f4d2481ba29 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Oct 2022 00:11:58 +0000 Subject: [PATCH 37/68] chore(deps): bump github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 (#2307) Bumps [github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2](https://github.com/aws/aws-sdk-go-v2) from 1.18.19 to 1.18.20. - [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/service/ecs/v1.18.19...service/ecs/v1.18.20) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 208ba4d61e..b1b6a8d17e 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/aws/aws-sdk-go-v2 v1.16.16 github.com/aws/aws-sdk-go-v2/config v1.17.8 github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.21.6 - github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.18.19 + github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.18.20 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 8b0b0affe0..18fd48f4a8 100644 --- a/go.sum +++ b/go.sum @@ -168,8 +168,8 @@ github.com/aws/aws-sdk-go-v2/internal/ini v1.3.24 h1:wj5Rwc05hvUSvKuOF29IYb9QrCL github.com/aws/aws-sdk-go-v2/internal/ini v1.3.24/go.mod h1:jULHjqqjDlbyTa7pfM7WICATnOv+iOhjletM3N0Xbu8= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.21.6 h1:Mwb2A5ygEijjkxgM3hVEiWSHwdH82nkyU2wgP4u/Hxk= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.21.6/go.mod h1:CCrqOzLQ6d1+zauyTah8o50m9dQu0NS/kaC0heWCu0c= -github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.18.19 h1:vPyIPoJUCiyUOv2TeRGWdLqf14qUp8tuTQ6bJo6ykbY= -github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.18.19/go.mod h1:tAKN3/tWkL0P+WA44wSkNyk6wWcbHUfTV2F3j3o6Yhs= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.18.20 h1:dJngzOIJ6J8lVzsEiPQwB5nTL5UjwuYjiHflORBnobE= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.18.20/go.mod h1:tAKN3/tWkL0P+WA44wSkNyk6wWcbHUfTV2F3j3o6Yhs= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17 h1:Jrd/oMh0PKQc6+BowB+pLEwLIgaQF29eYbe7E1Av9Ug= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17/go.mod h1:4nYOrY41Lrbk2170/BGkcJKBhws9Pfn8MG3aGqjjeFI= github.com/aws/aws-sdk-go-v2/service/sso v1.11.23 h1:pwvCchFUEnlceKIgPUouBJwK81aCkQ8UDMORfeFtW10= From d41c40aa3273124178a3a728a30b0e7de8b57f86 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Oct 2022 00:49:57 +0000 Subject: [PATCH 38/68] chore(deps): bump github.com/newrelic/newrelic-client-go (#2267) Bumps [github.com/newrelic/newrelic-client-go](https://github.com/newrelic/newrelic-client-go) from 0.86.5 to 1.0.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.86.5...v1.0.0) --- updated-dependencies: - dependency-name: github.com/newrelic/newrelic-client-go dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b1b6a8d17e..9218c15c19 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/influxdata/influxdb-client-go/v2 v2.11.0 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/newrelic/newrelic-client-go v1.0.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.12.2-0.20220620141757-4ad265f1b4ee github.com/prometheus/client_model v0.2.0 diff --git a/go.sum b/go.sum index 18fd48f4a8..5441629136 100644 --- a/go.sum +++ b/go.sum @@ -804,8 +804,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.86.5 h1:RxjhA/xdjcnMTxl1oq+ms6tGTuZOOL+h8IcfBCD1PVY= -github.com/newrelic/newrelic-client-go v0.86.5/go.mod h1:RYMXt7hgYw7nzuXIGd2BH0F1AivgWw7WrBhNBQZEB4k= +github.com/newrelic/newrelic-client-go v1.0.0 h1:0ugZUujCiJg3WGDxnmOT1QRP2gDiZKIMN0Z04SvxVBc= +github.com/newrelic/newrelic-client-go v1.0.0/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/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= From 4d1a2df0c16591308a94baf6c970eed110e2c4de Mon Sep 17 00:00:00 2001 From: Ariel Simhon Date: Tue, 11 Oct 2022 09:42:02 +0300 Subject: [PATCH 39/68] docs: Added blog post for minimize impact in Kubernetes using Progressive Delivery and customer side impact Signed-off-by: Ariel Simhon --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f044877ab3..ff667c3f64 100644 --- a/README.md +++ b/README.md @@ -72,5 +72,5 @@ You can reach the Argo Rollouts community and developers via the following chann * [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) - +* [Minimize Impact in Kubernetes Using Argo Rollouts](https://medium.com/@arielsimhon/minimize-impact-in-kubernetes-using-argo-rollouts-992fb9519969) From 7cbbd31d6d9a97666f4acd5e06e1021421c08895 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Oct 2022 00:07:33 +0000 Subject: [PATCH 40/68] chore(deps): bump github.com/spf13/cobra from 1.5.0 to 1.6.0 (#2313) Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.5.0 to 1.6.0. - [Release notes](https://github.com/spf13/cobra/releases) - [Commits](https://github.com/spf13/cobra/compare/v1.5.0...v1.6.0) --- updated-dependencies: - dependency-name: github.com/spf13/cobra dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 4 ++-- go.sum | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 9218c15c19..0e2c381e5d 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ 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.5.0 + github.com/spf13/cobra v1.6.0 github.com/stretchr/testify v1.8.0 github.com/tj/assert v0.0.3 github.com/valyala/fasttemplate v1.2.1 @@ -113,7 +113,7 @@ require ( github.com/hashicorp/go-retryablehttp v0.7.1 // indirect github.com/huandu/xstrings v1.3.2 // indirect github.com/imdario/mergo v0.3.13 // indirect - github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.0.1 // 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 diff --git a/go.sum b/go.sum index 5441629136..4a5038baba 100644 --- a/go.sum +++ b/go.sum @@ -626,8 +626,9 @@ github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= 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/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/influxdb-client-go/v2 v2.11.0 h1:BrHYv38rWkAnp22gIaHFp5LpOCazOqRMRvVE1yW3ym8= github.com/influxdata/influxdb-client-go/v2 v2.11.0/go.mod h1:YteV91FiQxRdccyJ2cHvj2f/5sq4y4Njqu1fQzsQCOU= github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf h1:7JTmneyiNEwVBOHSjoMxiWAqB992atOeepeFYegn5RU= @@ -962,8 +963,9 @@ github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSW github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= 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/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI= +github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= 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= From a13002741f953e6c21bc9626c7fa1e6e3087de0b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Oct 2022 00:08:58 +0000 Subject: [PATCH 41/68] chore(deps): bump github.com/sirupsen/logrus from 1.8.1 to 1.9.0 (#2152) Bumps [github.com/sirupsen/logrus](https://github.com/sirupsen/logrus) from 1.8.1 to 1.9.0. - [Release notes](https://github.com/sirupsen/logrus/releases) - [Changelog](https://github.com/sirupsen/logrus/blob/master/CHANGELOG.md) - [Commits](https://github.com/sirupsen/logrus/compare/v1.8.1...v1.9.0) --- updated-dependencies: - dependency-name: github.com/sirupsen/logrus dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 4 ++-- go.sum | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 0e2c381e5d..3dcb8bfc32 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/prometheus/client_model v0.2.0 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/sirupsen/logrus v1.9.0 github.com/soheilhy/cmux v0.1.5 github.com/spaceapegames/go-wavefront v1.8.1 github.com/spf13/cobra v1.6.0 @@ -153,7 +153,7 @@ require ( golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // 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/sys v0.0.0-20220715151400-c0bba94af5f8 // 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 diff --git a/go.sum b/go.sum index 4a5038baba..0e90808809 100644 --- a/go.sum +++ b/go.sum @@ -933,8 +933,9 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB 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/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/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 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= @@ -1365,8 +1366,9 @@ 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-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/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= From 431875228d5633825a485c2f291d6327792bdb47 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Oct 2022 00:10:19 +0000 Subject: [PATCH 42/68] chore(deps): bump github.com/prometheus/common from 0.36.0 to 0.37.0 (#2143) Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.36.0 to 0.37.0. - [Release notes](https://github.com/prometheus/common/releases) - [Commits](https://github.com/prometheus/common/compare/v0.36.0...v0.37.0) --- updated-dependencies: - dependency-name: github.com/prometheus/common dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 3dcb8bfc32..571aa6141e 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/pkg/errors v0.9.1 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/prometheus/common v0.37.0 github.com/servicemeshinterface/smi-sdk-go v0.5.0 github.com/sirupsen/logrus v1.9.0 github.com/soheilhy/cmux v0.1.5 diff --git a/go.sum b/go.sum index 0e90808809..49fe128eb1 100644 --- a/go.sum +++ b/go.sum @@ -887,8 +887,8 @@ 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.36.0 h1:78hJTing+BLYLjhXE+Z2BubeEymH5Lr0/Mt8FKkxxYo= -github.com/prometheus/common v0.36.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= +github.com/prometheus/common v0.37.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= From 6fa349a31aae66cfe0456e5e1360664ef3f9e20a Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Thu, 13 Oct 2022 09:31:54 -0500 Subject: [PATCH 43/68] fix(controller): leader election preventing two controllers running and gracefully shutting down (#2291) * WIP on fixing leader election fix Signed-off-by: zachaller * Start and stop informers as well Signed-off-by: zachaller * lint Signed-off-by: zachaller * Remove tests that do not test anything Signed-off-by: zachaller * fix lint Signed-off-by: zachaller * github trigger re-run Signed-off-by: zachaller * Cleanup Signed-off-by: zachaller * cleanup Signed-off-by: zachaller * Add back one test Signed-off-by: zachaller * remove secondary metric server Signed-off-by: zachaller * Remove secondary metric test Signed-off-by: zachaller * Add single instance test to catch log lines Signed-off-by: zachaller * We should shutdown if we can not sync Signed-off-by: zachaller * fix lint Signed-off-by: zachaller * Redo for loop will have another pr that stops via context Signed-off-by: zachaller * Fix comment Signed-off-by: zachaller * Add context and graceful shutdown Signed-off-by: zachaller * lint Signed-off-by: zachaller * Fix test Signed-off-by: zachaller * github trigger re-run Signed-off-by: zachaller * add more time for startup Signed-off-by: zachaller * add individual controller startup tests Signed-off-by: zachaller * standardize shutdown Signed-off-by: zachaller * Standardize leader test Signed-off-by: zachaller * fix test Signed-off-by: zachaller * We can not turn on release on cancel Signed-off-by: zachaller * fix release on cancel Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- analysis/controller.go | 19 +- analysis/controller_test.go | 21 +- cmd/rollouts-controller/main.go | 27 +- controller/controller.go | 231 ++++++++++-------- controller/controller_test.go | 185 ++++---------- controller/metrics/analysis_test.go | 2 +- controller/metrics/client_test.go | 2 +- controller/metrics/experiment_test.go | 2 +- controller/metrics/metrics.go | 15 +- controller/metrics/metrics_test.go | 13 +- controller/metrics/rollout_test.go | 4 +- experiments/controller.go | 18 +- experiments/controller_test.go | 20 +- ingress/alb_test.go | 15 +- ingress/ingress.go | 18 +- ingress/ingress_test.go | 25 +- pkg/signals/signal.go | 13 +- rollout/controller.go | 27 +- rollout/controller_test.go | 27 +- rollout/trafficrouting/istio/controller.go | 31 ++- .../trafficrouting/istio/controller_test.go | 11 +- service/service.go | 19 +- service/service_test.go | 29 ++- utils/controller/controller.go | 8 +- utils/controller/controller_test.go | 29 +-- 25 files changed, 431 insertions(+), 380 deletions(-) diff --git a/analysis/controller.go b/analysis/controller.go index 285cd1ff13..f05c955bb1 100644 --- a/analysis/controller.go +++ b/analysis/controller.go @@ -1,6 +1,8 @@ package analysis import ( + "context" + "sync" "time" unstructuredutil "github.com/argoproj/argo-rollouts/utils/unstructured" @@ -131,21 +133,26 @@ func NewController(cfg ControllerConfig) *Controller { return controller } -func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error { +func (c *Controller) Run(ctx context.Context, threadiness int) error { log.Info("Starting analysis workers") + wg := sync.WaitGroup{} for i := 0; i < threadiness; i++ { + wg.Add(1) go wait.Until(func() { - controllerutil.RunWorker(c.analysisRunWorkQueue, logutil.AnalysisRunKey, c.syncHandler, c.metricsServer) - }, time.Second, stopCh) + controllerutil.RunWorker(ctx, c.analysisRunWorkQueue, logutil.AnalysisRunKey, c.syncHandler, c.metricsServer) + log.Debug("Analysis worker has stopped") + wg.Done() + }, time.Second, ctx.Done()) } log.Infof("Started %d analysis workers", threadiness) - <-stopCh - log.Info("Shutting down analysis workers") + <-ctx.Done() + wg.Wait() + log.Info("All analysis workers have stopped") return nil } -func (c *Controller) syncHandler(key string) error { +func (c *Controller) syncHandler(ctx context.Context, key string) error { startTime := timeutil.Now() namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { diff --git a/analysis/controller_test.go b/analysis/controller_test.go index 289992ad19..a0af638c9e 100644 --- a/analysis/controller_test.go +++ b/analysis/controller_test.go @@ -1,6 +1,7 @@ package analysis import ( + "context" "encoding/json" "reflect" "testing" @@ -97,7 +98,7 @@ func (f *fixture) newController(resync resyncFunc) (*Controller, informers.Share metricsServer := metrics.NewMetricsServer(metrics.ServerConfig{ Addr: "localhost:8080", K8SRequestProvider: &metrics.K8sRequestsCountProvider{}, - }, true) + }) c := NewController(ControllerConfig{ KubeClientSet: f.kubeclient, @@ -159,7 +160,7 @@ func (f *fixture) runController(analysisRunName string, startInformers bool, exp assert.True(f.t, cache.WaitForCacheSync(stopCh, c.analysisRunSynced)) } - err := c.syncHandler(analysisRunName) + err := c.syncHandler(context.Background(), analysisRunName) if !expectError && err != nil { f.t.Errorf("error syncing experiment: %v", err) } else if expectError && err == nil { @@ -314,3 +315,19 @@ func TestNoReconcileForAnalysisRunWithDeletionTimestamp(t *testing.T) { f.run(getKey(ar, t)) } + +func TestRun(t *testing.T) { + f := newFixture(t) + defer f.Close() + + // make sure we can start and top the controller + c, _, _ := f.newController(noResyncPeriodFunc) + ctx, cancel := context.WithCancel(context.TODO()) + defer cancel() + go func() { + time.Sleep(1000 * time.Millisecond) + c.analysisRunWorkQueue.ShutDownWithDrain() + cancel() + }() + c.Run(ctx, 1) +} diff --git a/cmd/rollouts-controller/main.go b/cmd/rollouts-controller/main.go index f669a7115f..4aadf9ad82 100644 --- a/cmd/rollouts-controller/main.go +++ b/cmd/rollouts-controller/main.go @@ -88,7 +88,7 @@ func newCommand() *cobra.Command { log.WithField("version", version.GetVersion()).Info("Argo Rollouts starting") // set up signals so we handle the first shutdown signal gracefully - stopCh := signals.SetupSignalHandler() + ctx := signals.SetupSignalHandlerContext() defaults.SetVerifyTargetGroup(awsVerifyTargetGroup) defaults.SetIstioAPIVersion(istioVersion) @@ -190,23 +190,16 @@ func newCommand() *cobra.Command { healthzPort, k8sRequestProvider, nginxIngressClasses, - albIngressClasses) - // notice that there is no need to run Start methods in a separate goroutine. (i.e. go kubeInformerFactory.Start(stopCh) - // Start method is non-blocking and runs all registered informers in a dedicated goroutine. - dynamicInformerFactory.Start(stopCh) - if !namespaced { - clusterDynamicInformerFactory.Start(stopCh) - } - kubeInformerFactory.Start(stopCh) - controllerNamespaceInformerFactory.Start(stopCh) - jobInformerFactory.Start(stopCh) - - // Check if Istio installed on cluster before starting dynamicInformerFactory - if istioutil.DoesIstioExist(istioPrimaryDynamicClient, namespace) { - istioDynamicInformerFactory.Start(stopCh) - } + albIngressClasses, + dynamicInformerFactory, + clusterDynamicInformerFactory, + istioDynamicInformerFactory, + namespaced, + kubeInformerFactory, + controllerNamespaceInformerFactory, + jobInformerFactory) - if err = cm.Run(rolloutThreads, serviceThreads, ingressThreads, experimentThreads, analysisThreads, electOpts, stopCh); err != nil { + if err = cm.Run(ctx, rolloutThreads, serviceThreads, ingressThreads, experimentThreads, analysisThreads, electOpts); err != nil { log.Fatalf("Error running controller: %s", err.Error()) } return nil diff --git a/controller/controller.go b/controller/controller.go index a0efcbe55f..55ef4a45f8 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -6,8 +6,15 @@ import ( "fmt" "net/http" "os" + "sync" "time" + "k8s.io/apimachinery/pkg/util/wait" + + istioutil "github.com/argoproj/argo-rollouts/utils/istio" + "k8s.io/client-go/dynamic/dynamicinformer" + kubeinformers "k8s.io/client-go/informers" + notificationapi "github.com/argoproj/notifications-engine/pkg/api" notificationcontroller "github.com/argoproj/notifications-engine/pkg/controller" @@ -18,7 +25,6 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/uuid" - "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/discovery" "k8s.io/client-go/dynamic" appsinformers "k8s.io/client-go/informers/apps/v1" @@ -108,8 +114,8 @@ func NewLeaderElectionOptions() *LeaderElectionOptions { // Manager is the controller implementation for Argo-Rollout resources type Manager struct { + wg *sync.WaitGroup metricsServer *metrics.MetricsServer - secondaryMetricsServer *metrics.MetricsServer healthzServer *http.Server rolloutController *rollout.Controller experimentController *experiments.Controller @@ -141,6 +147,15 @@ type Manager struct { kubeClientSet kubernetes.Interface namespace string + + dynamicInformerFactory dynamicinformer.DynamicSharedInformerFactory + clusterDynamicInformerFactory dynamicinformer.DynamicSharedInformerFactory + istioDynamicInformerFactory dynamicinformer.DynamicSharedInformerFactory + namespaced bool + kubeInformerFactory kubeinformers.SharedInformerFactory + controllerNamespaceInformerFactory kubeinformers.SharedInformerFactory + jobInformerFactory kubeinformers.SharedInformerFactory + istioPrimaryDynamicClient dynamic.Interface } // NewManager returns a new manager to manage all the controllers @@ -172,6 +187,13 @@ func NewManager( k8sRequestProvider *metrics.K8sRequestsCountProvider, nginxIngressClasses []string, albIngressClasses []string, + dynamicInformerFactory dynamicinformer.DynamicSharedInformerFactory, + clusterDynamicInformerFactory dynamicinformer.DynamicSharedInformerFactory, + istioDynamicInformerFactory dynamicinformer.DynamicSharedInformerFactory, + namespaced bool, + kubeInformerFactory kubeinformers.SharedInformerFactory, + controllerNamespaceInformerFactory kubeinformers.SharedInformerFactory, + jobInformerFactory kubeinformers.SharedInformerFactory, ) *Manager { runtime.Must(rolloutscheme.AddToScheme(scheme.Scheme)) @@ -186,10 +208,9 @@ func NewManager( ClusterAnalysisTemplateLister: clusterAnalysisTemplateInformer.Lister(), ExperimentLister: experimentsInformer.Lister(), K8SRequestProvider: k8sRequestProvider, - }, true) + }) healthzServer := NewHealthzServer(fmt.Sprintf(listenAddr, healthzPort)) - rolloutWorkqueue := workqueue.NewNamedRateLimitingQueue(queue.DefaultArgoRolloutsRateLimiter(), "Rollouts") experimentWorkqueue := workqueue.NewNamedRateLimitingQueue(queue.DefaultArgoRolloutsRateLimiter(), "Experiments") analysisRunWorkqueue := workqueue.NewNamedRateLimitingQueue(queue.DefaultArgoRolloutsRateLimiter(), "AnalysisRuns") @@ -293,33 +314,42 @@ func NewManager( }) cm := &Manager{ - metricsServer: metricsServer, - healthzServer: healthzServer, - rolloutSynced: rolloutsInformer.Informer().HasSynced, - serviceSynced: servicesInformer.Informer().HasSynced, - ingressSynced: ingressWrap.HasSynced, - jobSynced: jobInformer.Informer().HasSynced, - experimentSynced: experimentsInformer.Informer().HasSynced, - analysisRunSynced: analysisRunInformer.Informer().HasSynced, - analysisTemplateSynced: analysisTemplateInformer.Informer().HasSynced, - clusterAnalysisTemplateSynced: clusterAnalysisTemplateInformer.Informer().HasSynced, - replicasSetSynced: replicaSetInformer.Informer().HasSynced, - configMapSynced: configMapInformer.Informer().HasSynced, - secretSynced: secretInformer.Informer().HasSynced, - rolloutWorkqueue: rolloutWorkqueue, - experimentWorkqueue: experimentWorkqueue, - analysisRunWorkqueue: analysisRunWorkqueue, - serviceWorkqueue: serviceWorkqueue, - ingressWorkqueue: ingressWorkqueue, - rolloutController: rolloutController, - serviceController: serviceController, - ingressController: ingressController, - experimentController: experimentController, - analysisController: analysisController, - notificationsController: notificationsController, - refResolver: refResolver, - namespace: namespace, - kubeClientSet: kubeclientset, + wg: &sync.WaitGroup{}, + metricsServer: metricsServer, + healthzServer: healthzServer, + rolloutSynced: rolloutsInformer.Informer().HasSynced, + serviceSynced: servicesInformer.Informer().HasSynced, + ingressSynced: ingressWrap.HasSynced, + jobSynced: jobInformer.Informer().HasSynced, + experimentSynced: experimentsInformer.Informer().HasSynced, + analysisRunSynced: analysisRunInformer.Informer().HasSynced, + analysisTemplateSynced: analysisTemplateInformer.Informer().HasSynced, + clusterAnalysisTemplateSynced: clusterAnalysisTemplateInformer.Informer().HasSynced, + replicasSetSynced: replicaSetInformer.Informer().HasSynced, + configMapSynced: configMapInformer.Informer().HasSynced, + secretSynced: secretInformer.Informer().HasSynced, + rolloutWorkqueue: rolloutWorkqueue, + experimentWorkqueue: experimentWorkqueue, + analysisRunWorkqueue: analysisRunWorkqueue, + serviceWorkqueue: serviceWorkqueue, + ingressWorkqueue: ingressWorkqueue, + rolloutController: rolloutController, + serviceController: serviceController, + ingressController: ingressController, + experimentController: experimentController, + analysisController: analysisController, + notificationsController: notificationsController, + refResolver: refResolver, + namespace: namespace, + kubeClientSet: kubeclientset, + dynamicInformerFactory: dynamicInformerFactory, + clusterDynamicInformerFactory: clusterDynamicInformerFactory, + istioDynamicInformerFactory: istioDynamicInformerFactory, + namespaced: namespaced, + kubeInformerFactory: kubeInformerFactory, + controllerNamespaceInformerFactory: controllerNamespaceInformerFactory, + jobInformerFactory: jobInformerFactory, + istioPrimaryDynamicClient: istioPrimaryDynamicClient, } return cm @@ -328,32 +358,32 @@ func NewManager( // Run will sync informer caches and start controllers. It will block until stopCh // is closed, at which point it will shutdown the workqueue and wait for // controllers to finish processing their current work items. -func (c *Manager) Run(rolloutThreadiness, serviceThreadiness, ingressThreadiness, experimentThreadiness, analysisThreadiness int, electOpts *LeaderElectionOptions, stopCh <-chan struct{}) error { +func (c *Manager) Run(ctx context.Context, rolloutThreadiness, serviceThreadiness, ingressThreadiness, experimentThreadiness, analysisThreadiness int, electOpts *LeaderElectionOptions) error { defer runtime.HandleCrash() - defer c.serviceWorkqueue.ShutDown() - defer c.ingressWorkqueue.ShutDown() - defer c.rolloutWorkqueue.ShutDown() - defer c.experimentWorkqueue.ShutDown() - defer c.analysisRunWorkqueue.ShutDown() + defer func() { + log.Infof("Exiting Main Run function") + }() - // Wait for the caches to be synced before starting workers - log.Info("Waiting for controller's informer caches to sync") - if ok := cache.WaitForCacheSync(stopCh, c.serviceSynced, c.ingressSynced, c.jobSynced, c.rolloutSynced, c.experimentSynced, c.analysisRunSynced, c.analysisTemplateSynced, c.replicasSetSynced, c.configMapSynced, c.secretSynced); !ok { - return fmt.Errorf("failed to wait for caches to sync") - } - // only wait for cluster scoped informers to sync if we are running in cluster-wide mode - if c.namespace == metav1.NamespaceAll { - if ok := cache.WaitForCacheSync(stopCh, c.clusterAnalysisTemplateSynced); !ok { - return fmt.Errorf("failed to wait for cluster-scoped caches to sync") + go func() { + log.Infof("Starting Healthz Server at %s", c.healthzServer.Addr) + err := c.healthzServer.ListenAndServe() + if err != nil { + err = errors.Wrap(err, "Healthz Server Error") + log.Error(err) } - } + }() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + go func() { + log.Infof("Starting Metric Server at %s", c.metricsServer.Addr) + if err := c.metricsServer.ListenAndServe(); err != nil { + log.Error(errors.Wrap(err, "Metric Server Error")) + } + }() if !electOpts.LeaderElect { log.Info("Leader election is turned off. Running in single-instance mode") go c.startLeading(ctx, rolloutThreadiness, serviceThreadiness, ingressThreadiness, experimentThreadiness, analysisThreadiness) + <-ctx.Done() } else { // id used to distinguish between multiple controller manager instances id, err := os.Hostname() @@ -368,63 +398,45 @@ func (c *Manager) Run(rolloutThreadiness, serviceThreadiness, ingressThreadiness // add a uniquifier so that two processes on the same host don't accidentally both become active id = id + "_" + string(uuid.NewUUID()) log.Infof("Leaderelection get id %s", id) - go leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ + leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ Lock: &resourcelock.LeaseLock{ LeaseMeta: metav1.ObjectMeta{Name: defaultLeaderElectionLeaseLockName, Namespace: electOpts.LeaderElectionNamespace}, Client: c.kubeClientSet.CoordinationV1(), LockConfig: resourcelock.ResourceLockConfig{Identity: id}, }, - ReleaseOnCancel: true, - LeaseDuration: electOpts.LeaderElectionLeaseDuration, - RenewDeadline: electOpts.LeaderElectionRenewDeadline, - RetryPeriod: electOpts.LeaderElectionRetryPeriod, + ReleaseOnCancel: false, // We can not set this to true because our context is sent on sig which means our code + // is still running prior to calling cancel. We would need to shut down and then call cancel in order to set this to true. + LeaseDuration: electOpts.LeaderElectionLeaseDuration, + RenewDeadline: electOpts.LeaderElectionRenewDeadline, + RetryPeriod: electOpts.LeaderElectionRetryPeriod, Callbacks: leaderelection.LeaderCallbacks{ OnStartedLeading: func(ctx context.Context) { - if c.secondaryMetricsServer != nil { - log.Warnln("Shutdown Secondary Metrics Server") - c.secondaryMetricsServer.Shutdown(ctx) - } + log.Infof("I am the new leader: %s", id) c.startLeading(ctx, rolloutThreadiness, serviceThreadiness, ingressThreadiness, experimentThreadiness, analysisThreadiness) }, OnStoppedLeading: func() { - log.Infof("Stopped leading controller: %s", id) - return + log.Infof("OnStoppedLeading called, shutting down: %s, context err: %s", id, ctx.Err()) }, OnNewLeader: func(identity string) { - if identity == id { - return - } log.Infof("New leader elected: %s", identity) - - if c.secondaryMetricsServer != nil { - log.Warn("Secondary metrics server already started") - return - } - - log.Infof("Starting Secondary Metric Server at %s", c.metricsServer.Addr) - c.secondaryMetricsServer = metrics.NewMetricsServer(metrics.ServerConfig{ - Addr: c.metricsServer.Addr, - }, false) - err = c.secondaryMetricsServer.ListenAndServe() - if err != nil { - err = errors.Wrap(err, "Starting Secondary Metric Server") - log.Warn(err) - } }, }, }) } + log.Info("Shutting down workers") - go func() { - log.Infof("Starting Healthz Server at %s", c.healthzServer.Addr) - err := c.healthzServer.ListenAndServe() - if err != nil { - err = errors.Wrap(err, "Starting Healthz Server") - log.Error(err) - } - }() + c.serviceWorkqueue.ShutDownWithDrain() + c.ingressWorkqueue.ShutDownWithDrain() + c.rolloutWorkqueue.ShutDownWithDrain() + c.experimentWorkqueue.ShutDownWithDrain() + c.analysisRunWorkqueue.ShutDownWithDrain() + c.analysisRunWorkqueue.ShutDownWithDrain() - <-stopCh - log.Info("Shutting down workers") + ctxWithTimeout, cancel := context.WithTimeout(ctx, 5*time.Second) // give max of 10 seconds for http servers to shut down + defer cancel() + c.healthzServer.Shutdown(ctxWithTimeout) + c.metricsServer.Shutdown(ctxWithTimeout) + + c.wg.Wait() return nil } @@ -433,19 +445,40 @@ func (c *Manager) startLeading(ctx context.Context, rolloutThreadiness, serviceT defer runtime.HandleCrash() // Start the informer factories to begin populating the informer caches log.Info("Starting Controllers") - go wait.Until(func() { c.rolloutController.Run(rolloutThreadiness, ctx.Done()) }, time.Second, ctx.Done()) - go wait.Until(func() { c.serviceController.Run(serviceThreadiness, ctx.Done()) }, time.Second, ctx.Done()) - go wait.Until(func() { c.ingressController.Run(ingressThreadiness, ctx.Done()) }, time.Second, ctx.Done()) - go wait.Until(func() { c.experimentController.Run(experimentThreadiness, ctx.Done()) }, time.Second, ctx.Done()) - go wait.Until(func() { c.analysisController.Run(analysisThreadiness, ctx.Done()) }, time.Second, ctx.Done()) - go wait.Until(func() { c.notificationsController.Run(rolloutThreadiness, ctx.Done()) }, time.Second, ctx.Done()) - go func() { - log.Infof("Starting Metric Server at %s", c.metricsServer.Addr) - if err := c.metricsServer.ListenAndServe(); err != nil { - log.Error(errors.Wrap(err, "Starting Metric Server")) + // notice that there is no need to run Start methods in a separate goroutine. (i.e. go kubeInformerFactory.Start(stopCh) + // Start method is non-blocking and runs all registered informers in a dedicated goroutine. + c.dynamicInformerFactory.Start(ctx.Done()) + if !c.namespaced { + c.clusterDynamicInformerFactory.Start(ctx.Done()) + } + c.kubeInformerFactory.Start(ctx.Done()) + c.controllerNamespaceInformerFactory.Start(ctx.Done()) + c.jobInformerFactory.Start(ctx.Done()) + + // Check if Istio installed on cluster before starting dynamicInformerFactory + if istioutil.DoesIstioExist(c.istioPrimaryDynamicClient, c.namespace) { + c.istioDynamicInformerFactory.Start(ctx.Done()) + } + + // Wait for the caches to be synced before starting workers + log.Info("Waiting for controller's informer caches to sync") + if ok := cache.WaitForCacheSync(ctx.Done(), c.serviceSynced, c.ingressSynced, c.jobSynced, c.rolloutSynced, c.experimentSynced, c.analysisRunSynced, c.analysisTemplateSynced, c.replicasSetSynced, c.configMapSynced, c.secretSynced); !ok { + log.Fatalf("failed to wait for caches to sync, exiting") + } + // only wait for cluster scoped informers to sync if we are running in cluster-wide mode + if c.namespace == metav1.NamespaceAll { + if ok := cache.WaitForCacheSync(ctx.Done(), c.clusterAnalysisTemplateSynced); !ok { + log.Fatalf("failed to wait for cluster-scoped caches to sync, exiting") } - }() + } + + go wait.Until(func() { c.wg.Add(1); c.rolloutController.Run(ctx, rolloutThreadiness); c.wg.Done() }, time.Second, ctx.Done()) + go wait.Until(func() { c.wg.Add(1); c.serviceController.Run(ctx, serviceThreadiness); c.wg.Done() }, time.Second, ctx.Done()) + go wait.Until(func() { c.wg.Add(1); c.ingressController.Run(ctx, ingressThreadiness); c.wg.Done() }, time.Second, ctx.Done()) + go wait.Until(func() { c.wg.Add(1); c.experimentController.Run(ctx, experimentThreadiness); c.wg.Done() }, time.Second, ctx.Done()) + go wait.Until(func() { c.wg.Add(1); c.analysisController.Run(ctx, analysisThreadiness); c.wg.Done() }, time.Second, ctx.Done()) + go wait.Until(func() { c.wg.Add(1); c.notificationsController.Run(rolloutThreadiness, ctx.Done()); c.wg.Done() }, time.Second, ctx.Done()) log.Info("Started controller") } diff --git a/controller/controller_test.go b/controller/controller_test.go index da7c22f7bc..1a601c9248 100644 --- a/controller/controller_test.go +++ b/controller/controller_test.go @@ -3,15 +3,13 @@ package controller import ( "context" "fmt" - "net/http" - "net/http/httptest" + "sync" "testing" "time" notificationapi "github.com/argoproj/notifications-engine/pkg/api" notificationcontroller "github.com/argoproj/notifications-engine/pkg/controller" smifake "github.com/servicemeshinterface/smi-sdk-go/pkg/gen/client/split/clientset/versioned/fake" - log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -21,11 +19,8 @@ import ( "k8s.io/client-go/dynamic/dynamicinformer" dynamicfake "k8s.io/client-go/dynamic/fake" kubeinformers "k8s.io/client-go/informers" - "k8s.io/client-go/kubernetes" k8sfake "k8s.io/client-go/kubernetes/fake" - "k8s.io/client-go/tools/leaderelection" - "k8s.io/client-go/tools/leaderelection/resourcelock" "k8s.io/client-go/util/workqueue" "github.com/argoproj/argo-rollouts/analysis" @@ -72,34 +67,34 @@ func (f *fixture) newManager(t *testing.T) *Manager { analysisRunWorkqueue := workqueue.NewNamedRateLimitingQueue(queue.DefaultArgoRolloutsRateLimiter(), "AnalysisRuns") cm := &Manager{ - - kubeClientSet: f.kubeclient, - - ingressWorkqueue: ingressWorkqueue, - serviceWorkqueue: serviceWorkqueue, - rolloutWorkqueue: rolloutWorkqueue, - experimentWorkqueue: experimentWorkqueue, - analysisRunWorkqueue: analysisRunWorkqueue, - + wg: &sync.WaitGroup{}, + healthzServer: NewHealthzServer(fmt.Sprintf(listenAddr, 8080)), rolloutSynced: alwaysReady, - serviceSynced: alwaysReady, - ingressSynced: alwaysReady, - jobSynced: alwaysReady, experimentSynced: alwaysReady, analysisRunSynced: alwaysReady, analysisTemplateSynced: alwaysReady, + clusterAnalysisTemplateSynced: alwaysReady, + serviceSynced: alwaysReady, + ingressSynced: alwaysReady, + jobSynced: alwaysReady, replicasSetSynced: alwaysReady, configMapSynced: alwaysReady, secretSynced: alwaysReady, - clusterAnalysisTemplateSynced: alwaysReady, - - healthzServer: NewHealthzServer(fmt.Sprintf(listenAddr, 8080)), + rolloutWorkqueue: rolloutWorkqueue, + serviceWorkqueue: serviceWorkqueue, + ingressWorkqueue: ingressWorkqueue, + experimentWorkqueue: experimentWorkqueue, + analysisRunWorkqueue: analysisRunWorkqueue, + kubeClientSet: f.kubeclient, + namespace: "", + namespaced: false, } metricsAddr := fmt.Sprintf(listenAddr, 8090) cm.metricsServer = metrics.NewMetricsServer(metrics.ServerConfig{ - Addr: metricsAddr, - }, false) + Addr: metricsAddr, + K8SRequestProvider: &metrics.K8sRequestsCountProvider{}, + }) i := informers.NewSharedInformerFactory(f.client, noResyncPeriodFunc()) k8sI := kubeinformers.NewSharedInformerFactory(f.kubeclient, noResyncPeriodFunc()) @@ -109,16 +104,27 @@ func (f *fixture) newManager(t *testing.T) *Manager { Resource: "targetgroupbindings", } vsvcGVR := istioutil.GetIstioVirtualServiceGVR() + destGVR := istioutil.GetIstioDestinationRuleGVR() scheme := runtime.NewScheme() listMapping := map[schema.GroupVersionResource]string{ tgbGVR: "TargetGroupBindingList", vsvcGVR: vsvcGVR.Resource + "List", + destGVR: destGVR.Resource + "List", } + dynamicClient := dynamicfake.NewSimpleDynamicClientWithCustomListKinds(scheme, listMapping) dynamicInformerFactory := dynamicinformer.NewDynamicSharedInformerFactory(dynamicClient, 0) istioVirtualServiceInformer := dynamicInformerFactory.ForResource(istioutil.GetIstioVirtualServiceGVR()).Informer() istioDestinationRuleInformer := dynamicInformerFactory.ForResource(istioutil.GetIstioDestinationRuleGVR()).Informer() + cm.dynamicInformerFactory = dynamicInformerFactory + cm.clusterDynamicInformerFactory = dynamicInformerFactory + cm.kubeInformerFactory = k8sI + cm.controllerNamespaceInformerFactory = k8sI + cm.jobInformerFactory = k8sI + cm.istioPrimaryDynamicClient = dynamicClient + cm.istioDynamicInformerFactory = dynamicInformerFactory + mode, err := ingressutil.DetermineIngressMode("extensions/v1beta1", &discoveryfake.FakeDiscovery{}) assert.NoError(t, err) ingressWrapper, err := ingressutil.NewIngressWrapper(mode, f.kubeclient, k8sI) @@ -209,35 +215,6 @@ func (f *fixture) newManager(t *testing.T) *Manager { return cm } -func newElectorConfig(kubeclientset kubernetes.Interface, id string, electOpts LeaderElectionOptions) *leaderelection.LeaderElectionConfig { - lec := leaderelection.LeaderElectionConfig{ - Lock: &resourcelock.LeaseLock{ - LeaseMeta: metav1.ObjectMeta{Name: defaultLeaderElectionLeaseLockName, Namespace: electOpts.LeaderElectionNamespace}, Client: kubeclientset.CoordinationV1(), - LockConfig: resourcelock.ResourceLockConfig{Identity: id}, - }, - ReleaseOnCancel: true, - LeaseDuration: electOpts.LeaderElectionLeaseDuration, - RenewDeadline: electOpts.LeaderElectionRenewDeadline, - RetryPeriod: electOpts.LeaderElectionRetryPeriod, - Callbacks: leaderelection.LeaderCallbacks{ - OnStartedLeading: func(ctx context.Context) { - log.Info("Starting leading") - }, - OnStoppedLeading: func() { - log.Infof("Stopped leading controller: %s", id) - return - }, - OnNewLeader: func(identity string) { - if identity == id { - return - } - log.Infof("New leader elected: %s", identity) - }, - }, - } - return &lec -} - func TestNewManager(t *testing.T) { f := newFixture(t) @@ -285,6 +262,13 @@ func TestNewManager(t *testing.T) { k8sRequestProvider, nil, nil, + dynamicInformerFactory, + nil, + nil, + false, + nil, + nil, + nil, ) assert.NotNil(t, cm) @@ -293,97 +277,26 @@ func TestNewManager(t *testing.T) { func TestPrimaryController(t *testing.T) { f := newFixture(t) - stopCh := make(chan struct{}) - cm := f.newManager(t) electOpts := NewLeaderElectionOptions() - go cm.Run(1, 1, 1, 1, 1, electOpts, stopCh) - time.Sleep(2 * time.Second) - close(stopCh) - - // Test primary controller shutdown secondary metrics server - cm.secondaryMetricsServer = metrics.NewMetricsServer(metrics.ServerConfig{}, false) - time.Sleep(2 * time.Second) - stopCh = make(chan struct{}) - go cm.Run(1, 1, 1, 1, 1, electOpts, stopCh) - time.Sleep(2 * time.Second) - close(stopCh) -} - -func TestTwoControllers(t *testing.T) { - f := newFixture(t) - - stopCh := make(chan struct{}) - primary := f.newManager(t) - electOpts := NewLeaderElectionOptions() - go primary.Run(1, 1, 1, 1, 1, electOpts, stopCh) - time.Sleep(1 * time.Second) - - secondary := f.newManager(t) - secondary.healthzServer = NewHealthzServer(fmt.Sprintf(listenAddr, 8081)) - secondary.metricsServer.Addr = (fmt.Sprintf(listenAddr, 8091)) - go secondary.Run(1, 1, 1, 1, 1, electOpts, stopCh) - time.Sleep(1 * time.Second) - - var verifyEndpoints func(url string) - verifyEndpoints = func(url string) { - _, err := http.Get(url) - assert.NoErrorf(t, err, "error connecting to %s", url) - rr := httptest.NewRecorder() - assert.Equal(t, rr.Code, http.StatusOK) - } - - verifyEndpoints("http://localhost:8080/healthz") - verifyEndpoints("http://localhost:8090/metrics") - verifyEndpoints("http://localhost:8081/healthz") - verifyEndpoints("http://localhost:8091/metrics") - - // stop all controllers - time.Sleep(1 * time.Second) - close(stopCh) + ctx, cancel := context.WithCancel(context.Background()) + go func() { + time.Sleep(5 * time.Second) + cancel() + }() + cm.Run(ctx, 1, 1, 1, 1, 1, electOpts) } -func TestSecondaryController(t *testing.T) { +func TestPrimaryControllerSingleInstanceWithShutdown(t *testing.T) { f := newFixture(t) - stopCh := make(chan struct{}) - cm := f.newManager(t) - electOpts := NewLeaderElectionOptions() - lec := newElectorConfig(f.kubeclient, "holder-123-456", *electOpts) - le, err := leaderelection.NewLeaderElector(*lec) - assert.NoError(t, err) - + electOpts.LeaderElect = false ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - go le.Run(ctx) - time.Sleep(1 * time.Second) - assert.True(t, le.IsLeader()) - - go cm.Run(1, 1, 1, 1, 1, electOpts, stopCh) - time.Sleep(2 * time.Second) - assert.True(t, le.IsLeader()) - close(stopCh) - time.Sleep(1 * time.Second) - - // Test secondary metrics server has been started - stopCh = make(chan struct{}) - go cm.Run(1, 1, 1, 1, 1, electOpts, stopCh) - time.Sleep(2 * time.Second) - assert.True(t, le.IsLeader()) - close(stopCh) - time.Sleep(1 * time.Second) - - // Test secondary metrics server listen port is taken - metricsServer := metrics.NewMetricsServer(metrics.ServerConfig{ - Addr: fmt.Sprintf(listenAddr, DefaultMetricsPort), - }, false) - go metricsServer.ListenAndServe() - time.Sleep(1 * time.Second) - cm.secondaryMetricsServer = nil - stopCh = make(chan struct{}) - go cm.Run(1, 1, 1, 1, 1, electOpts, stopCh) - time.Sleep(2 * time.Second) - close(stopCh) + go func() { + time.Sleep(5 * time.Second) + cancel() + }() + cm.Run(ctx, 1, 1, 1, 1, 1, electOpts) } diff --git a/controller/metrics/analysis_test.go b/controller/metrics/analysis_test.go index 61ca87a80f..942c165209 100644 --- a/controller/metrics/analysis_test.go +++ b/controller/metrics/analysis_test.go @@ -178,7 +178,7 @@ analysis_run_reconcile_bucket{name="ar-test",namespace="ar-namespace",le="1"} 1 analysis_run_reconcile_bucket{name="ar-test",namespace="ar-namespace",le="+Inf"} 1 analysis_run_reconcile_sum{name="ar-test",namespace="ar-namespace"} 0.001 analysis_run_reconcile_count{name="ar-test",namespace="ar-namespace"} 1` - metricsServ := NewMetricsServer(newFakeServerConfig(), true) + metricsServ := NewMetricsServer(newFakeServerConfig()) ar := &v1alpha1.AnalysisRun{ ObjectMeta: metav1.ObjectMeta{ Name: "ar-test", diff --git a/controller/metrics/client_test.go b/controller/metrics/client_test.go index 0ebf470a68..b09fc6b886 100644 --- a/controller/metrics/client_test.go +++ b/controller/metrics/client_test.go @@ -14,7 +14,7 @@ controller_clientset_k8s_request_total{kind="replicasets",name="N/A",namespace=" func TestIncKubernetesRequest(t *testing.T) { config := newFakeServerConfig() - metricsServ := NewMetricsServer(config, true) + metricsServ := NewMetricsServer(config) config.K8SRequestProvider.IncKubernetesRequest(kubeclientmetrics.ResourceInfo{ Kind: "replicasets", Namespace: "default", diff --git a/controller/metrics/experiment_test.go b/controller/metrics/experiment_test.go index da050e9377..4335af6fe0 100644 --- a/controller/metrics/experiment_test.go +++ b/controller/metrics/experiment_test.go @@ -150,7 +150,7 @@ experiment_reconcile_bucket{name="ex-test",namespace="ex-namespace",le="+Inf"} 1 experiment_reconcile_sum{name="ex-test",namespace="ex-namespace"} 0.001 experiment_reconcile_count{name="ex-test",namespace="ex-namespace"} 1` - metricsServ := NewMetricsServer(newFakeServerConfig(), true) + metricsServ := NewMetricsServer(newFakeServerConfig()) ex := &v1alpha1.Experiment{ ObjectMeta: metav1.ObjectMeta{ Name: "ex-test", diff --git a/controller/metrics/metrics.go b/controller/metrics/metrics.go index 3c3bbfe246..bad18a1eb3 100644 --- a/controller/metrics/metrics.go +++ b/controller/metrics/metrics.go @@ -50,24 +50,11 @@ type ServerConfig struct { } // NewMetricsServer returns a new prometheus server which collects rollout metrics -func NewMetricsServer(cfg ServerConfig, isPrimary bool) *MetricsServer { +func NewMetricsServer(cfg ServerConfig) *MetricsServer { mux := http.NewServeMux() reg := prometheus.NewRegistry() - // secondary controller doesn't expose any metrics - if !isPrimary { - mux.Handle(MetricsPath, promhttp.HandlerFor(prometheus.Gatherers{ - reg, - }, promhttp.HandlerOpts{})) - return &MetricsServer{ - Server: &http.Server{ - Addr: cfg.Addr, - Handler: mux, - }, - } - } - reg.MustRegister(NewRolloutCollector(cfg.RolloutLister)) reg.MustRegister(NewAnalysisRunCollector(cfg.AnalysisRunLister, cfg.AnalysisTemplateLister, cfg.ClusterAnalysisTemplateLister)) reg.MustRegister(NewExperimentCollector(cfg.ExperimentLister)) diff --git a/controller/metrics/metrics_test.go b/controller/metrics/metrics_test.go index 22d671cee1..00700321fa 100644 --- a/controller/metrics/metrics_test.go +++ b/controller/metrics/metrics_test.go @@ -84,7 +84,7 @@ experiment_reconcile_error{name="name",namespace="ns"} 1 # TYPE rollout_reconcile_error counter rollout_reconcile_error{name="name",namespace="ns"} 1` - metricsServ := NewMetricsServer(newFakeServerConfig(), true) + metricsServ := NewMetricsServer(newFakeServerConfig()) metricsServ.IncError("ns", "name", logutil.AnalysisRunKey) metricsServ.IncError("ns", "name", logutil.ExperimentKey) @@ -95,14 +95,7 @@ rollout_reconcile_error{name="name",namespace="ns"} 1` 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, assert.Contains) -} - -func TestSecondaryMetricsServer(t *testing.T) { - expectedResponse := `` - - metricsServ := NewMetricsServer(newFakeServerConfig(), false) + metricsServ := NewMetricsServer(newFakeServerConfig()) testHttpResponse(t, metricsServ.Handler, expectedResponse, assert.Contains) } @@ -113,7 +106,7 @@ func TestRemove(t *testing.T) { experiment_reconcile_error{name="name1",namespace="ns"} 1 rollout_reconcile_error{name="name1",namespace="ns"} 1` - metricsServ := NewMetricsServer(newFakeServerConfig(), true) + metricsServ := NewMetricsServer(newFakeServerConfig()) metricsServ.IncError("ns", "name1", logutil.RolloutKey) metricsServ.IncError("ns", "name1", logutil.AnalysisRunKey) diff --git a/controller/metrics/rollout_test.go b/controller/metrics/rollout_test.go index b10af8b184..7c889ee09d 100644 --- a/controller/metrics/rollout_test.go +++ b/controller/metrics/rollout_test.go @@ -180,7 +180,7 @@ rollout_reconcile_sum{name="ro-test",namespace="ro-namespace"} 0.001 rollout_reconcile_count{name="ro-test",namespace="ro-namespace"} 1 ` - metricsServ := NewMetricsServer(newFakeServerConfig(), true) + metricsServ := NewMetricsServer(newFakeServerConfig()) ro := &v1alpha1.Rollout{ ObjectMeta: metav1.ObjectMeta{ Name: "ro-test", @@ -305,7 +305,7 @@ rollout_events_total{name="ro-test-1",namespace="ro-namespace",reason="FooEvent" rollout_events_total{name="ro-test-2",namespace="ro-namespace",reason="BazEvent",type="Warning"} 2 ` - metricsServ := NewMetricsServer(newFakeServerConfig(), true) + metricsServ := NewMetricsServer(newFakeServerConfig()) MetricRolloutEventsTotal.WithLabelValues("ro-namespace", "ro-test-1", corev1.EventTypeNormal, "FooEvent").Inc() MetricRolloutEventsTotal.WithLabelValues("ro-namespace", "ro-test-1", corev1.EventTypeNormal, "BarEvent").Inc() MetricRolloutEventsTotal.WithLabelValues("ro-namespace", "ro-test-2", corev1.EventTypeWarning, "BazEvent").Inc() diff --git a/experiments/controller.go b/experiments/controller.go index 2b26005971..a42821aab0 100644 --- a/experiments/controller.go +++ b/experiments/controller.go @@ -2,6 +2,7 @@ package experiments import ( "context" + "sync" "time" log "github.com/sirupsen/logrus" @@ -223,21 +224,26 @@ func NewController(cfg ControllerConfig) *Controller { } // Run starts the controller threads -func (ec *Controller) Run(threadiness int, stopCh <-chan struct{}) error { +func (ec *Controller) Run(ctx context.Context, threadiness int) error { log.Info("Starting Experiment workers") + wg := sync.WaitGroup{} for i := 0; i < threadiness; i++ { + wg.Add(1) go wait.Until(func() { - controllerutil.RunWorker(ec.experimentWorkqueue, logutil.ExperimentKey, ec.syncHandler, ec.metricsServer) - }, time.Second, stopCh) + controllerutil.RunWorker(ctx, ec.experimentWorkqueue, logutil.ExperimentKey, ec.syncHandler, ec.metricsServer) + log.Debug("Experiment worker has stopped") + wg.Done() + }, time.Second, ctx.Done()) } log.Info("Started Experiment workers") - <-stopCh - log.Info("Shutting down experiment workers") + <-ctx.Done() + wg.Wait() + log.Info("All experiment workers have stopped") return nil } -func (ec *Controller) syncHandler(key string) error { +func (ec *Controller) syncHandler(ctx context.Context, key string) error { startTime := timeutil.Now() namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { diff --git a/experiments/controller_test.go b/experiments/controller_test.go index 70fa70ca1c..1e7eb14f13 100644 --- a/experiments/controller_test.go +++ b/experiments/controller_test.go @@ -1,6 +1,7 @@ package experiments import ( + "context" "encoding/json" "fmt" "reflect" @@ -360,7 +361,7 @@ func (f *fixture) newController(resync resyncFunc) (*Controller, informers.Share metricsServer := metrics.NewMetricsServer(metrics.ServerConfig{ Addr: "localhost:8080", K8SRequestProvider: &metrics.K8sRequestsCountProvider{}, - }, true) + }) c := NewController(ControllerConfig{ KubeClientSet: f.kubeclient, @@ -445,7 +446,7 @@ func (f *fixture) runController(experimentName string, startInformers bool, expe assert.True(f.t, cache.WaitForCacheSync(stopCh, c.replicaSetSynced, c.experimentSynced, c.analysisRunSynced, c.analysisTemplateSynced, c.clusterAnalysisTemplateSynced)) } - err := c.syncHandler(experimentName) + err := c.syncHandler(context.Background(), experimentName) if !expectError && err != nil { f.t.Errorf("error syncing experiment: %v", err) } else if expectError && err == nil { @@ -893,3 +894,18 @@ func TestRemoveInvalidSpec(t *testing.T) { }`, templateStatus, cond) assert.Equal(t, expectedPatch, patch) } + +func TestRun(t *testing.T) { + f := newFixture(t, nil) + defer f.Close() + // make sure we can start and top the controller + c, _, _ := f.newController(noResyncPeriodFunc) + ctx, cancel := context.WithCancel(context.TODO()) + defer cancel() + go func() { + time.Sleep(1000 * time.Millisecond) + c.experimentWorkqueue.ShutDownWithDrain() + cancel() + }() + c.Run(ctx, 1) +} diff --git a/ingress/alb_test.go b/ingress/alb_test.go index 79a1c915a1..295f130dac 100644 --- a/ingress/alb_test.go +++ b/ingress/alb_test.go @@ -1,6 +1,7 @@ package ingress import ( + "context" "fmt" "testing" @@ -130,7 +131,7 @@ func TestInvalidManagedALBActions(t *testing.T) { ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, rollout) - err := ctrl.syncIngress("default/test-ingress") + err := ctrl.syncIngress(context.Background(), "default/test-ingress") assert.Nil(t, err) assert.Len(t, kubeclient.Actions(), 0) assert.Len(t, enqueuedObjects, 0) @@ -142,7 +143,7 @@ func TestInvalidPreviousALBActionAnnotationValue(t *testing.T) { ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, nil) - err := ctrl.syncIngress("default/test-ingress") + err := ctrl.syncIngress(context.Background(), "default/test-ingress") assert.Nil(t, err) assert.Len(t, kubeclient.Actions(), 0) assert.Len(t, enqueuedObjects, 0) @@ -153,7 +154,7 @@ func TestInvalidPreviousALBActionAnnotationKey(t *testing.T) { ing.Annotations[ingressutil.ManagedAnnotations] = "invalid-action-key" ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, nil) - err := ctrl.syncIngress("default/test-ingress") + err := ctrl.syncIngress(context.Background(), "default/test-ingress") assert.Nil(t, err) assert.Len(t, kubeclient.Actions(), 0) assert.Len(t, enqueuedObjects, 0) @@ -165,7 +166,7 @@ func TestResetActionFailureFindNoPort(t *testing.T) { ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, nil) - err := ctrl.syncIngress("default/test-ingress") + err := ctrl.syncIngress(context.Background(), "default/test-ingress") assert.Nil(t, err) assert.Len(t, kubeclient.Actions(), 0) assert.Len(t, enqueuedObjects, 0) @@ -177,7 +178,7 @@ func TestALBIngressNoModifications(t *testing.T) { ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, rollout) - err := ctrl.syncIngress("default/test-ingress") + err := ctrl.syncIngress(context.Background(), "default/test-ingress") assert.Nil(t, err) assert.Len(t, kubeclient.Actions(), 0) assert.Len(t, enqueuedObjects, 1) @@ -187,7 +188,7 @@ func TestALBIngressResetAction(t *testing.T) { ing := newALBIngress("test-ingress", 80, "stable-service", "non-existing-rollout", false) ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, nil) - err := ctrl.syncIngress("default/test-ingress") + err := ctrl.syncIngress(context.Background(), "default/test-ingress") assert.Nil(t, err) assert.Len(t, enqueuedObjects, 0) actions := kubeclient.Actions() @@ -211,7 +212,7 @@ 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") + err := ctrl.syncIngress(context.Background(), "default/test-ingress") assert.Nil(t, err) assert.Len(t, enqueuedObjects, 0) actions := kubeclient.Actions() diff --git a/ingress/ingress.go b/ingress/ingress.go index 7bbf856b89..6c4059e476 100644 --- a/ingress/ingress.go +++ b/ingress/ingress.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "strings" + "sync" "time" log "github.com/sirupsen/logrus" @@ -102,23 +103,28 @@ func NewController(cfg ControllerConfig) *Controller { } // Run starts the controller threads -func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error { +func (c *Controller) Run(ctx context.Context, threadiness int) error { log.Info("Starting Ingress workers") + wg := sync.WaitGroup{} for i := 0; i < threadiness; i++ { + wg.Add(1) go wait.Until(func() { - controllerutil.RunWorker(c.ingressWorkqueue, logutil.IngressKey, c.syncIngress, c.metricServer) - }, time.Second, stopCh) + controllerutil.RunWorker(ctx, c.ingressWorkqueue, logutil.IngressKey, c.syncIngress, c.metricServer) + wg.Done() + log.Debug("Ingress worker has stopped") + }, time.Second, ctx.Done()) } log.Info("Started Ingress workers") - <-stopCh - log.Info("Shutting down Ingress workers") + <-ctx.Done() + wg.Wait() + log.Info("All ingress workers have stopped") return nil } // syncIngress queues all rollouts referencing the Ingress for reconciliation -func (c *Controller) syncIngress(key string) error { +func (c *Controller) syncIngress(ctx context.Context, key string) error { namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { return err diff --git a/ingress/ingress_test.go b/ingress/ingress_test.go index 3db4f1bcca..e33ee29c34 100644 --- a/ingress/ingress_test.go +++ b/ingress/ingress_test.go @@ -1,8 +1,10 @@ package ingress import ( + "context" "sync" "testing" + "time" "github.com/argoproj/argo-rollouts/utils/queue" @@ -117,7 +119,7 @@ func newFakeIngressController(t *testing.T, ing *extensionsv1beta1.Ingress, roll MetricsServer: metrics.NewMetricsServer(metrics.ServerConfig{ Addr: "localhost:8080", K8SRequestProvider: &metrics.K8sRequestsCountProvider{}, - }, true), + }), }) enqueuedObjects := map[string]int{} var enqueuedObjectsLock sync.Mutex @@ -149,7 +151,7 @@ func newFakeIngressController(t *testing.T, ing *extensionsv1beta1.Ingress, roll func TestSyncMissingIngress(t *testing.T) { ctrl, _, _ := newFakeIngressController(t, nil, nil) - err := ctrl.syncIngress("default/test-ingress") + err := ctrl.syncIngress(context.Background(), "default/test-ingress") assert.NoError(t, err) } @@ -158,7 +160,7 @@ func TestSyncIngressNotReferencedByRollout(t *testing.T) { ctrl, kubeclient, _ := newFakeIngressController(t, ing, nil) - err := ctrl.syncIngress("default/test-stable-ingress") + err := ctrl.syncIngress(context.Background(), "default/test-stable-ingress") assert.NoError(t, err) actions := kubeclient.Actions() assert.Len(t, actions, 0) @@ -189,7 +191,7 @@ func TestSyncIngressReferencedByRollout(t *testing.T) { ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, rollout) - err := ctrl.syncIngress("default/test-stable-ingress") + err := ctrl.syncIngress(context.Background(), "default/test-stable-ingress") assert.NoError(t, err) actions := kubeclient.Actions() assert.Len(t, actions, 0) @@ -221,9 +223,22 @@ func TestSkipIngressWithNoClass(t *testing.T) { ctrl, kubeclient, enqueuedObjects := newFakeIngressController(t, ing, rollout) - err := ctrl.syncIngress("default/test-stable-ingress") + err := ctrl.syncIngress(context.Background(), "default/test-stable-ingress") assert.NoError(t, err) actions := kubeclient.Actions() assert.Len(t, actions, 0) assert.Len(t, enqueuedObjects, 0) } + +func TestRun(t *testing.T) { + // make sure we can start and top the controller + c, _, _ := newFakeIngressController(t, nil, nil) + ctx, cancel := context.WithCancel(context.TODO()) + defer cancel() + go func() { + time.Sleep(1000 * time.Millisecond) + c.ingressWorkqueue.ShutDownWithDrain() + cancel() + }() + c.Run(ctx, 1) +} diff --git a/pkg/signals/signal.go b/pkg/signals/signal.go index f82aafbbd2..b5121ad885 100644 --- a/pkg/signals/signal.go +++ b/pkg/signals/signal.go @@ -1,27 +1,28 @@ package signals import ( + "context" "os" "os/signal" ) var onlyOneSignalHandler = make(chan struct{}) -// SetupSignalHandler registered for SIGTERM and SIGINT. A stop channel is returned -// which is closed on one of these signals. If a second signal is caught, the program +// SetupSignalHandlerContext registered for SIGTERM and SIGINT. A context is returned +// which is canceled on one of these signals. If a second signal is caught, the program // is terminated with exit code 1. -func SetupSignalHandler() (stopCh <-chan struct{}) { +func SetupSignalHandlerContext() (ctx context.Context) { close(onlyOneSignalHandler) // panics when called twice - stop := make(chan struct{}) + ctx, cancel := context.WithCancel(context.Background()) c := make(chan os.Signal, 2) signal.Notify(c, shutdownSignals...) go func() { <-c - close(stop) + cancel() <-c os.Exit(1) // second signal. Exit directly. }() - return stop + return ctx } diff --git a/rollout/controller.go b/rollout/controller.go index e314adf4af..5b2a4eb915 100644 --- a/rollout/controller.go +++ b/rollout/controller.go @@ -6,6 +6,7 @@ import ( "fmt" "reflect" "strconv" + "sync" "time" "k8s.io/apimachinery/pkg/runtime/schema" @@ -326,19 +327,28 @@ func removedKeys(name string, old, new *v1alpha1.Rollout, keyFunc func(ro *v1alp // as syncing informer caches and starting workers. It will block until stopCh // is closed, at which point it will shutdown the workqueue and wait for // workers to finish processing their current work items. -func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error { +func (c *Controller) Run(ctx context.Context, threadiness int) error { log.Info("Starting Rollout workers") + wg := sync.WaitGroup{} for i := 0; i < threadiness; i++ { + wg.Add(1) go wait.Until(func() { - controllerutil.RunWorker(c.rolloutWorkqueue, logutil.RolloutKey, c.syncHandler, c.metricsServer) - }, time.Second, stopCh) + controllerutil.RunWorker(ctx, c.rolloutWorkqueue, logutil.RolloutKey, c.syncHandler, c.metricsServer) + log.Debug("Rollout worker has stopped") + wg.Done() + }, time.Second, ctx.Done()) } - log.Info("Started Rollout workers") + log.Info("Started rollout workers") - go c.IstioController.Run(stopCh) + wg.Add(1) + go c.IstioController.Run(ctx) - <-stopCh - log.Info("Shutting down workers") + <-ctx.Done() + c.IstioController.ShutDownWithDrain() + wg.Done() + + wg.Wait() + log.Info("All rollout workers have stopped") return nil } @@ -346,8 +356,7 @@ func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error { // syncHandler compares the actual state with the desired, and attempts to // converge the two. It then updates the Phase block of the Rollout resource // with the current status of the resource. -func (c *Controller) syncHandler(key string) error { - ctx := context.TODO() +func (c *Controller) syncHandler(ctx context.Context, key string) error { startTime := timeutil.Now() namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { diff --git a/rollout/controller_test.go b/rollout/controller_test.go index 6738900856..7b1f9afa2d 100644 --- a/rollout/controller_test.go +++ b/rollout/controller_test.go @@ -1,6 +1,7 @@ package rollout import ( + "context" "encoding/json" "fmt" "reflect" @@ -545,9 +546,14 @@ func (f *fixture) newController(resync resyncFunc) (*Controller, informers.Share Version: "v1beta1", Resource: "targetgroupbindings", } + vsvcGVR := istioutil.GetIstioVirtualServiceGVR() + destGVR := istioutil.GetIstioDestinationRuleGVR() listMapping := map[schema.GroupVersionResource]string{ - tgbGVR: "TargetGroupBindingList", + tgbGVR: "TargetGroupBindingList", + vsvcGVR: vsvcGVR.Resource + "List", + destGVR: destGVR.Resource + "List", } + dynamicClient := dynamicfake.NewSimpleDynamicClientWithCustomListKinds(scheme, listMapping, f.objects...) dynamicInformerFactory := dynamicinformer.NewDynamicSharedInformerFactory(dynamicClient, 0) istioVirtualServiceInformer := dynamicInformerFactory.ForResource(istioutil.GetIstioVirtualServiceGVR()).Informer() @@ -560,7 +566,7 @@ func (f *fixture) newController(resync resyncFunc) (*Controller, informers.Share metricsServer := metrics.NewMetricsServer(metrics.ServerConfig{ Addr: "localhost:8080", K8SRequestProvider: &metrics.K8sRequestsCountProvider{}, - }, true) + }) ingressWrapper, err := ingressutil.NewIngressWrapper(ingressutil.IngressModeExtensions, f.kubeclient, k8sI) if err != nil { @@ -675,7 +681,7 @@ func (f *fixture) runController(rolloutName string, startInformers bool, expectE assert.True(f.t, cache.WaitForCacheSync(stopCh, c.replicaSetSynced, c.rolloutsSynced)) } - err := c.syncHandler(rolloutName) + err := c.syncHandler(context.Background(), rolloutName) if !expectError && err != nil { f.t.Errorf("error syncing rollout: %v", err) } else if expectError && err == nil { @@ -1945,3 +1951,18 @@ func TestWriteBackToInformer(t *testing.T) { assert.NotEmpty(t, stableRS) assert.Equal(t, rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey], stableRS) } + +func TestRun(t *testing.T) { + f := newFixture(t) + defer f.Close() + // make sure we can start and top the controller + c, _, _ := f.newController(noResyncPeriodFunc) + ctx, cancel := context.WithCancel(context.TODO()) + defer cancel() + go func() { + time.Sleep(1000 * time.Millisecond) + c.rolloutWorkqueue.ShutDownWithDrain() + cancel() + }() + c.Run(ctx, 1) +} diff --git a/rollout/trafficrouting/istio/controller.go b/rollout/trafficrouting/istio/controller.go index 6b76304d79..847ae65956 100644 --- a/rollout/trafficrouting/istio/controller.go +++ b/rollout/trafficrouting/istio/controller.go @@ -3,6 +3,7 @@ package istio import ( "context" "fmt" + "sync" "time" log "github.com/sirupsen/logrus" @@ -114,7 +115,7 @@ func NewIstioController(cfg IstioControllerConfig) *IstioController { // Run starts the Istio informers. If Istio is not installed, will periodically check for presence // of Istio, then start informers once detected. This allows Argo Rollouts to be installed in any // order during cluster bootstrapping. -func (c *IstioController) Run(stopCh <-chan struct{}) { +func (c *IstioController) Run(ctx context.Context) { ns := defaults.Namespace() waitForIstioInstall := !istioutil.DoesIstioExist(c.DynamicClientSet, ns) if waitForIstioInstall { @@ -122,7 +123,7 @@ func (c *IstioController) Run(stopCh <-chan struct{}) { for !istioutil.DoesIstioExist(c.DynamicClientSet, ns) { // Should only execute if Istio is not installed on cluster select { - case <-stopCh: + case <-ctx.Done(): ticker.Stop() return case <-ticker.C: @@ -130,23 +131,29 @@ func (c *IstioController) Run(stopCh <-chan struct{}) { } ticker.Stop() log.Info("Istio install detected. Starting informers") - go c.VirtualServiceInformer.Run(stopCh) - go c.DestinationRuleInformer.Run(stopCh) + go c.VirtualServiceInformer.Run(ctx.Done()) + go c.DestinationRuleInformer.Run(ctx.Done()) } else { log.Info("Istio detected") } - cache.WaitForCacheSync(stopCh, c.VirtualServiceInformer.HasSynced, c.DestinationRuleInformer.HasSynced) + cache.WaitForCacheSync(ctx.Done(), c.VirtualServiceInformer.HasSynced, c.DestinationRuleInformer.HasSynced) + log.Info("Starting istio workers") + wg := sync.WaitGroup{} for i := 0; i < destinationRuleWorkers; i++ { + wg.Add(1) go wait.Until(func() { - controllerutil.RunWorker(c.destinationRuleWorkqueue, "destinationrule", c.syncDestinationRule, nil) - }, time.Second, stopCh) + controllerutil.RunWorker(ctx, c.destinationRuleWorkqueue, "destinationrule", c.syncDestinationRule, nil) + wg.Done() + log.Debug("Istio worker has stopped") + }, time.Second, ctx.Done()) } log.Infof("Istio workers (%d) started", destinationRuleWorkers) - <-stopCh - log.Info("Istio controller stopped") + <-ctx.Done() + wg.Wait() + log.Info("All istio workers have stopped") } // EnqueueDestinationRule examines a VirtualService, finds the Rollout referencing @@ -223,7 +230,7 @@ func (c *IstioController) GetReferencedVirtualServices(ro *v1alpha1.Rollout) (*[ // `rollouts-pod-template-hash` label and the managed-by annotation. This handles the case when a // Rollout has either been deleted, or modified such that it is longer referencing the // DestinationRule. -func (c *IstioController) syncDestinationRule(key string) error { +func (c *IstioController) syncDestinationRule(ctx context.Context, key string) error { namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { return err @@ -297,3 +304,7 @@ func getManagingRolloutName(un *unstructured.Unstructured) string { } return annots[v1alpha1.ManagedByRolloutsKey] } + +func (c *IstioController) ShutDownWithDrain() { + c.destinationRuleWorkqueue.ShutDownWithDrain() +} diff --git a/rollout/trafficrouting/istio/controller_test.go b/rollout/trafficrouting/istio/controller_test.go index 443786c010..af37f11053 100644 --- a/rollout/trafficrouting/istio/controller_test.go +++ b/rollout/trafficrouting/istio/controller_test.go @@ -182,7 +182,7 @@ spec: enqueueCalled = true } - err = c.syncDestinationRule(key) + err = c.syncDestinationRule(context.Background(), key) assert.NoError(t, err) actions := c.DynamicClientSet.(*dynamicfake.FakeDynamicClient).Actions() assert.Len(t, actions, 0) @@ -203,7 +203,7 @@ spec: enqueueCalled = true } - err = c.syncDestinationRule(key) + err = c.syncDestinationRule(context.Background(), key) assert.NoError(t, err) actions := c.DynamicClientSet.(*dynamicfake.FakeDynamicClient).Actions() assert.Len(t, actions, 1) @@ -223,7 +223,7 @@ spec: enqueueCalled = true } - err = c.syncDestinationRule(key) + err = c.syncDestinationRule(context.Background(), key) assert.NoError(t, err) actions := c.DynamicClientSet.(*dynamicfake.FakeDynamicClient).Actions() assert.Len(t, actions, 1) @@ -238,10 +238,11 @@ func TestRun(t *testing.T) { ctx, cancel := context.WithCancel(context.TODO()) defer cancel() go func() { - time.Sleep(100 * time.Millisecond) + time.Sleep(1000 * time.Millisecond) + c.destinationRuleWorkqueue.ShutDownWithDrain() cancel() }() go c.DestinationRuleInformer.Run(ctx.Done()) go c.VirtualServiceInformer.Run(ctx.Done()) - c.Run(ctx.Done()) + c.Run(ctx) } diff --git a/service/service.go b/service/service.go index 47d0ac40d9..f81c82c771 100644 --- a/service/service.go +++ b/service/service.go @@ -3,6 +3,7 @@ package service import ( "context" "fmt" + "sync" "time" log "github.com/sirupsen/logrus" @@ -129,17 +130,22 @@ func NewController(cfg ControllerConfig) *Controller { } // Run starts the controller threads -func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error { +func (c *Controller) Run(ctx context.Context, threadiness int) error { log.Info("Starting Service workers") + wg := sync.WaitGroup{} for i := 0; i < threadiness; i++ { + wg.Add(1) go wait.Until(func() { - controllerutil.RunWorker(c.serviceWorkqueue, logutil.ServiceKey, c.syncService, c.metricServer) - }, time.Second, stopCh) + controllerutil.RunWorker(ctx, c.serviceWorkqueue, logutil.ServiceKey, c.syncService, c.metricServer) + log.Debug("Service worker has stopped") + wg.Done() + }, time.Second, ctx.Done()) } log.Info("Started Service workers") - <-stopCh - log.Info("Shutting down workers") + <-ctx.Done() + wg.Wait() + log.Info("All service workers have stopped") return nil } @@ -147,8 +153,7 @@ func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error { // syncService detects a change to a Service which is managed by a Rollout, and enqueues the // related rollout for reconciliation. If no rollout is referencing the Service, then removes // any injected fields in the service (e.g. rollouts-pod-template-hash and managed-by annotation) -func (c *Controller) syncService(key string) error { - ctx := context.TODO() +func (c *Controller) syncService(ctx context.Context, key string) error { namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { return err diff --git a/service/service_test.go b/service/service_test.go index 4bcd6e8dab..69dea462da 100644 --- a/service/service_test.go +++ b/service/service_test.go @@ -1,7 +1,9 @@ package service import ( + "context" "testing" + "time" "github.com/argoproj/argo-rollouts/utils/queue" @@ -72,7 +74,7 @@ func newFakeServiceController(svc *corev1.Service, rollout *v1alpha1.Rollout) (* metricsServer := metrics.NewMetricsServer(metrics.ServerConfig{ Addr: "localhost:8080", K8SRequestProvider: &metrics.K8sRequestsCountProvider{}, - }, true) + }) c := NewController(ControllerConfig{ Kubeclientset: kubeclient, Argoprojclientset: client, @@ -110,7 +112,7 @@ func newFakeServiceController(svc *corev1.Service, rollout *v1alpha1.Rollout) (* func TestSyncMissingService(t *testing.T) { ctrl, _, _, _ := newFakeServiceController(nil, nil) - err := ctrl.syncService("default/test-service") + err := ctrl.syncService(context.Background(), "default/test-service") assert.NoError(t, err) } @@ -122,7 +124,7 @@ func TestSyncMissingServiceInCache(t *testing.T) { }) ctrl, _, _, _ := newFakeServiceController(svc, nil) ctrl.kubeclientset = k8sfake.NewSimpleClientset() - err := ctrl.syncService("default/test-service") + err := ctrl.syncService(context.Background(), "default/test-service") assert.NoError(t, err) } @@ -133,7 +135,7 @@ func TestSyncServiceNotReferencedByRollout(t *testing.T) { ctrl, kubeclient, _, _ := newFakeServiceController(svc, nil) - err := ctrl.syncService("default/test-service") + err := ctrl.syncService(context.Background(), "default/test-service") assert.NoError(t, err) actions := kubeclient.Actions() assert.Len(t, actions, 1) @@ -164,7 +166,7 @@ func TestSyncServiceWithNoManagedBy(t *testing.T) { ctrl, kubeclient, client, _ := newFakeServiceController(svc, ro) - err := ctrl.syncService("default/test-service") + err := ctrl.syncService(context.Background(), "default/test-service") assert.NoError(t, err) actions := kubeclient.Actions() assert.Len(t, actions, 0) @@ -192,7 +194,7 @@ func TestSyncServiceWithManagedByWithNoRolloutReference(t *testing.T) { ctrl, kubeclient, client, _ := newFakeServiceController(svc, ro) - err := ctrl.syncService("default/test-service") + err := ctrl.syncService(context.Background(), "default/test-service") assert.NoError(t, err) actions := kubeclient.Actions() patch, ok := actions[0].(k8stesting.PatchAction) @@ -227,9 +229,22 @@ func TestSyncServiceReferencedByRollout(t *testing.T) { ctrl, kubeclient, _, enqueuedObjects := newFakeServiceController(svc, rollout) - err := ctrl.syncService("default/test-service") + err := ctrl.syncService(context.Background(), "default/test-service") assert.NoError(t, err) actions := kubeclient.Actions() assert.Len(t, actions, 0) assert.Equal(t, 1, enqueuedObjects["default/rollout"]) } + +func TestRun(t *testing.T) { + // make sure we can start and top the controller + c, _, _, _ := newFakeServiceController(nil, nil) + ctx, cancel := context.WithCancel(context.TODO()) + defer cancel() + go func() { + time.Sleep(1000 * time.Millisecond) + c.serviceWorkqueue.ShutDownWithDrain() + cancel() + }() + c.Run(ctx, 1) +} diff --git a/utils/controller/controller.go b/utils/controller/controller.go index e3123d0f1c..63aa6f11cd 100644 --- a/utils/controller/controller.go +++ b/utils/controller/controller.go @@ -100,14 +100,14 @@ func WatchResourceWithExponentialBackoff(stopCh <-chan struct{}, client dynamic. // RunWorker is a long-running function that will continually call the // processNextWorkItem function in order to read and process a message on the // workqueue. -func RunWorker(workqueue workqueue.RateLimitingInterface, objType string, syncHandler func(string) error, metricServer *metrics.MetricsServer) { - for processNextWorkItem(workqueue, objType, syncHandler, metricServer) { +func RunWorker(ctx context.Context, workqueue workqueue.RateLimitingInterface, objType string, syncHandler func(context.Context, string) error, metricServer *metrics.MetricsServer) { + for processNextWorkItem(ctx, workqueue, objType, syncHandler, metricServer) { } } // processNextWorkItem will read a single work item off the workqueue and // attempt to process it, by calling the syncHandler. -func processNextWorkItem(workqueue workqueue.RateLimitingInterface, objType string, syncHandler func(string) error, metricsServer *metrics.MetricsServer) bool { +func processNextWorkItem(ctx context.Context, workqueue workqueue.RateLimitingInterface, objType string, syncHandler func(context.Context, string) error, metricsServer *metrics.MetricsServer) bool { obj, shutdown := workqueue.Get() if shutdown { @@ -150,7 +150,7 @@ func processNextWorkItem(workqueue workqueue.RateLimitingInterface, objType stri err = fmt.Errorf("Recovered from Panic") } }() - return syncHandler(key) + return syncHandler(ctx, key) } // Run the syncHandler, passing it the namespace/name string of the // Rollout resource to be synced. diff --git a/utils/controller/controller_test.go b/utils/controller/controller_test.go index 601a52628d..9fa54b5517 100644 --- a/utils/controller/controller_test.go +++ b/utils/controller/controller_test.go @@ -1,6 +1,7 @@ package controller import ( + "context" "fmt" "testing" "time" @@ -38,47 +39,47 @@ func TestProcessNextWorkItemHandlePanic(t *testing.T) { metricServer := metrics.NewMetricsServer(metrics.ServerConfig{ Addr: "localhost:8080", K8SRequestProvider: &metrics.K8sRequestsCountProvider{}, - }, true) - syncHandler := func(key string) error { + }) + syncHandler := func(ctx context.Context, key string) error { panic("Bad big panic :(") } - assert.True(t, processNextWorkItem(q, log.RolloutKey, syncHandler, metricServer)) + assert.True(t, processNextWorkItem(context.Background(), q, log.RolloutKey, syncHandler, metricServer)) } func TestProcessNextWorkItemShutDownQueue(t *testing.T) { q := workqueue.NewNamedRateLimitingQueue(queue.DefaultArgoRolloutsRateLimiter(), "Rollouts") - syncHandler := func(key string) error { + syncHandler := func(ctx context.Context, key string) error { return nil } q.ShutDown() - assert.False(t, processNextWorkItem(q, log.RolloutKey, syncHandler, nil)) + assert.False(t, processNextWorkItem(context.Background(), q, log.RolloutKey, syncHandler, nil)) } func TestProcessNextWorkItemNoTStringKey(t *testing.T) { q := workqueue.NewNamedRateLimitingQueue(queue.DefaultArgoRolloutsRateLimiter(), "Rollouts") q.Add(1) - syncHandler := func(key string) error { + syncHandler := func(ctx context.Context, key string) error { return nil } - assert.True(t, processNextWorkItem(q, log.RolloutKey, syncHandler, nil)) + assert.True(t, processNextWorkItem(context.Background(), q, log.RolloutKey, syncHandler, nil)) } func TestProcessNextWorkItemNoValidKey(t *testing.T) { q := workqueue.NewNamedRateLimitingQueue(queue.DefaultArgoRolloutsRateLimiter(), "Rollouts") q.Add("invalid.key") - syncHandler := func(key string) error { + syncHandler := func(ctx context.Context, key string) error { return nil } - assert.True(t, processNextWorkItem(q, log.RolloutKey, syncHandler, nil)) + assert.True(t, processNextWorkItem(context.Background(), q, log.RolloutKey, syncHandler, nil)) } func TestProcessNextWorkItemNormalSync(t *testing.T) { q := workqueue.NewNamedRateLimitingQueue(queue.DefaultArgoRolloutsRateLimiter(), "Rollouts") q.Add("valid/key") - syncHandler := func(key string) error { + syncHandler := func(ctx context.Context, key string) error { return nil } - assert.True(t, processNextWorkItem(q, log.RolloutKey, syncHandler, nil)) + assert.True(t, processNextWorkItem(context.Background(), q, log.RolloutKey, syncHandler, nil)) } func TestProcessNextWorkItemSyncHandlerReturnError(t *testing.T) { @@ -87,11 +88,11 @@ func TestProcessNextWorkItemSyncHandlerReturnError(t *testing.T) { metricServer := metrics.NewMetricsServer(metrics.ServerConfig{ Addr: "localhost:8080", K8SRequestProvider: &metrics.K8sRequestsCountProvider{}, - }, true) - syncHandler := func(key string) error { + }) + syncHandler := func(ctx context.Context, key string) error { return fmt.Errorf("error message") } - assert.True(t, processNextWorkItem(q, log.RolloutKey, syncHandler, metricServer)) + assert.True(t, processNextWorkItem(context.Background(), q, log.RolloutKey, syncHandler, metricServer)) } func TestEnqueue(t *testing.T) { From 300332579d2877d92081ac1a873eb79e956bd978 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Thu, 13 Oct 2022 16:45:32 -0500 Subject: [PATCH 44/68] fix(cli): nil pointer while linting (#2324) * fix nil pointer on lint Signed-off-by: zachaller * github trigger re-run Signed-off-by: zachaller * add test for having a virtual service but not using it in rollout Signed-off-by: zachaller * change logic Signed-off-by: zachaller * improve test cov Signed-off-by: zachaller * remove unreachable code Signed-off-by: zachaller * github trigger re-run Signed-off-by: zachaller * github trigger re-run Signed-off-by: zachaller * Add test coverage Signed-off-by: zachaller * add more test coverage Signed-off-by: zachaller * Standardize msg Signed-off-by: zachaller * lint Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- .../validation/validation_references.go | 9 +++ .../validation/validation_references_test.go | 22 +++++- pkg/kubectl-argo-rollouts/cmd/lint/lint.go | 3 + .../cmd/lint/lint_test.go | 5 ++ .../testdata/invalid-empty-rollout-vsvc.yml | 5 ++ .../testdata/valid-nginx-smi-with-vsvc.yaml | 74 +++++++++++++++++++ 6 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-empty-rollout-vsvc.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-nginx-smi-with-vsvc.yaml diff --git a/pkg/apis/rollouts/validation/validation_references.go b/pkg/apis/rollouts/validation/validation_references.go index 545b87e7af..8e3578675c 100644 --- a/pkg/apis/rollouts/validation/validation_references.go +++ b/pkg/apis/rollouts/validation/validation_references.go @@ -273,6 +273,15 @@ func ValidateVirtualService(rollout *v1alpha1.Rollout, obj unstructured.Unstruct allErrs := field.ErrorList{} newObj := obj.DeepCopy() + if rollout.Spec.Strategy.Canary == nil || + rollout.Spec.Strategy.Canary.TrafficRouting == nil || + rollout.Spec.Strategy.Canary.TrafficRouting.Istio == nil { + + msg := "Rollout object is not configured with Istio traffic routing" + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "strategy", "canary", "trafficRouting", "istio"), rollout.Name, msg)) + return allErrs + } + if istioutil.MultipleVirtualServiceConfigured(rollout) { fldPath = field.NewPath("spec", "strategy", "canary", "trafficRouting", "istio", "virtualServices", "name") virtualServices = rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualServices diff --git a/pkg/apis/rollouts/validation/validation_references_test.go b/pkg/apis/rollouts/validation/validation_references_test.go index ac8e962cf2..75e7a59c92 100644 --- a/pkg/apis/rollouts/validation/validation_references_test.go +++ b/pkg/apis/rollouts/validation/validation_references_test.go @@ -558,6 +558,18 @@ func TestValidateVirtualService(t *testing.T) { }, } + roWithoutIstio := &v1alpha1.Rollout{ + Spec: v1alpha1.RolloutSpec{ + Strategy: v1alpha1.RolloutStrategy{ + Canary: &v1alpha1.CanaryStrategy{ + StableService: "stable", + CanaryService: "canary", + TrafficRouting: &v1alpha1.RolloutTrafficRouting{}, + }, + }, + }, + } + t.Run("validate virtualService HTTP routes - success", func(t *testing.T) { vsvc := unstructured.StrToUnstructuredUnsafe(successCaseVsvc) allErrs := ValidateVirtualService(ro, *vsvc) @@ -624,13 +636,21 @@ func TestValidateVirtualService(t *testing.T) { assert.Equal(t, expectedErr.Error(), allErrs[0].Error()) }) - t.Run("validate virtualService invalid tcp routes - failure", func(t *testing.T) { + t.Run("validate virtualService invalid rollout missing istio", func(t *testing.T) { vsvc := unstructured.StrToUnstructuredUnsafe(failCaseInvalidTcpRoutesVsvc) allErrs := ValidateVirtualService(ro, *vsvc) assert.Len(t, allErrs, 1) expectedErr := field.Invalid(field.NewPath("spec", "strategy", "canary", "trafficRouting", "istio", "virtualService", "name"), "istio-vsvc", "Unable to get TCP routes for Istio VirtualService") assert.Equal(t, expectedErr.Error(), allErrs[0].Error()) }) + + t.Run("validate virtualService invalid tcp routes - failure", func(t *testing.T) { + vsvc := unstructured.StrToUnstructuredUnsafe(successCaseTcpVsvc) + allErrs := ValidateVirtualService(roWithoutIstio, *vsvc) + assert.Len(t, allErrs, 1) + expectedErr := field.Invalid(field.NewPath("spec", "strategy", "canary", "trafficRouting", "istio"), roWithoutIstio.Name, "Rollout object is not configured with Istio traffic routing") + assert.Equal(t, expectedErr.Error(), allErrs[0].Error()) + }) } func TestValidateVirtualServices(t *testing.T) { diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/lint.go b/pkg/kubectl-argo-rollouts/cmd/lint/lint.go index 66e28318eb..c7cb091a0a 100644 --- a/pkg/kubectl-argo-rollouts/cmd/lint/lint.go +++ b/pkg/kubectl-argo-rollouts/cmd/lint/lint.go @@ -294,6 +294,9 @@ func setIngressManagedAnnotation(rollouts []v1alpha1.Rollout, refResource valida func setVirtualServiceManagedAnnotation(ro []v1alpha1.Rollout, refResource validation.ReferencedResources) { for _, rollout := range ro { for i := range refResource.VirtualServices { + if rollout.Spec.Strategy.Canary == nil || rollout.Spec.Strategy.Canary.TrafficRouting == nil || rollout.Spec.Strategy.Canary.TrafficRouting.Istio == nil { + return + } 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 { diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/lint_test.go b/pkg/kubectl-argo-rollouts/cmd/lint/lint_test.go index 326015bbb3..e9b66fd2ed 100644 --- a/pkg/kubectl-argo-rollouts/cmd/lint/lint_test.go +++ b/pkg/kubectl-argo-rollouts/cmd/lint/lint_test.go @@ -29,6 +29,7 @@ func TestLintValidRollout(t *testing.T) { "testdata/valid-nginx-canary.yml", "testdata/valid-nginx-basic-canary.yml", "testdata/valid-istio-v1beta1-mulitiple-virtualsvcs.yml", + "testdata/valid-nginx-smi-with-vsvc.yaml", } for _, filename := range tests { @@ -54,6 +55,10 @@ func TestLintInvalidRollout(t *testing.T) { "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-empty-rollout-vsvc.yml", + "Error: spec.selector: Required value: Rollout has missing field '.spec.selector'\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", diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-empty-rollout-vsvc.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-empty-rollout-vsvc.yml new file mode 100644 index 0000000000..bf184253b9 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-empty-rollout-vsvc.yml @@ -0,0 +1,5 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService \ No newline at end of file diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-nginx-smi-with-vsvc.yaml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-nginx-smi-with-vsvc.yaml new file mode 100644 index 0000000000..0acb23d62f --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-nginx-smi-with-vsvc.yaml @@ -0,0 +1,74 @@ +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: 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: + smi: + trafficSplitName: rollout-smi-experiment-split + rootService: rollout-smi-experiment-root + nginx: + stableIngress: nginx-rollout-ingress + steps: + - setWeight: 10 From e4c94dcba19e5fdbcced978972c7bbf01ddd01ae Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Thu, 13 Oct 2022 17:32:03 -0500 Subject: [PATCH 45/68] test(controller): add extra checks to TestWriteBackToInformer (#2326) Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- rollout/controller_test.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/rollout/controller_test.go b/rollout/controller_test.go index 7b1f9afa2d..d7683fddec 100644 --- a/rollout/controller_test.go +++ b/rollout/controller_test.go @@ -1945,8 +1945,11 @@ func TestWriteBackToInformer(t *testing.T) { f.runController(roKey, true, false, c, i, k8sI) // Verify the informer was updated with the new unstructured object after reconciliation - obj, _, _ := c.rolloutsIndexer.GetByKey(roKey) - un := obj.(*unstructured.Unstructured) + obj, exists, err := c.rolloutsIndexer.GetByKey(roKey) + assert.NoError(t, err) + assert.True(t, exists) + un, ok := obj.(*unstructured.Unstructured) + assert.True(t, ok) stableRS, _, _ := unstructured.NestedString(un.Object, "status", "stableRS") assert.NotEmpty(t, stableRS) assert.Equal(t, rs1.Labels[v1alpha1.DefaultRolloutUniqueLabelKey], stableRS) From 152918526279297fe72e58c498760a6b9a2a84da Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Fri, 14 Oct 2022 15:32:37 -0500 Subject: [PATCH 46/68] docs: add artifact badge (#2331) Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ff667c3f64..9a88e2f492 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![codecov](https://codecov.io/gh/argoproj/argo-rollouts/branch/master/graph/badge.svg)](https://codecov.io/gh/argoproj/argo-rollouts) [![slack](https://img.shields.io/badge/slack-argoproj-brightgreen.svg?logo=slack)](https://argoproj.github.io/community/join-slack) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3834/badge)](https://bestpractices.coreinfrastructure.org/projects/3834) +[![Artifact HUB](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/argo-rollouts)](https://artifacthub.io/packages/helm/argo/argo-rollouts) ## What is Argo Rollouts? Argo Rollouts is a Kubernetes controller and set of CRDs which provide advanced deployment capabilities such as blue-green, canary, canary analysis, experimentation, and progressive delivery features to Kubernetes. From 23ce2f779944a80a6a17057d6bf7953802a4480a Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Fri, 14 Oct 2022 16:03:12 -0500 Subject: [PATCH 47/68] build: add sha256 checksums for all released bins (#2332) * build: add sha256 checksums for all released bins Signed-off-by: zachaller * Add shasum Signed-off-by: zachaller * rename file Signed-off-by: zachaller * shasum is included Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- .github/workflows/release.yaml | 1 + hack/build-release-plugins.sh | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 7bb0c1dfb5..43080842a0 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -155,6 +155,7 @@ jobs: dist/kubectl-argo-rollouts-darwin-amd64 dist/kubectl-argo-rollouts-darwin-arm64 dist/kubectl-argo-rollouts-windows-amd64 + dist/argo-rollouts-checksums.txt manifests/dashboard-install.yaml manifests/install.yaml manifests/namespace-install.yaml diff --git a/hack/build-release-plugins.sh b/hack/build-release-plugins.sh index db5bcdbea7..390fbdadbc 100755 --- a/hack/build-release-plugins.sh +++ b/hack/build-release-plugins.sh @@ -14,5 +14,9 @@ container_id=$(docker create ${rollout_iid}) for plat in linux-amd64 linux-arm64 darwin-amd64 darwin-arm64 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} rm -f ${rollout_iid_file} + +cd ${SRCROOT}/dist/ +shasum -a 256 kubectl-argo-rollouts-* > argo-rollouts-checksums.txt From 8d06499705e7e34e824716a354bdcaa37e67995a Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Fri, 14 Oct 2022 17:52:24 -0500 Subject: [PATCH 48/68] ci: Add github action for PR Conventional Commits (#2320) * feat(ci): Add github action for PR Conventional Commits Signed-off-by: zachaller * add example scope Signed-off-by: zachaller * add cli as scope Signed-off-by: zachaller * Remove configuration Signed-off-by: zachaller * scopes not required Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- .github/workflows/pr-title-check.yml | 47 ++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .github/workflows/pr-title-check.yml diff --git a/.github/workflows/pr-title-check.yml b/.github/workflows/pr-title-check.yml new file mode 100644 index 0000000000..5f11c118ae --- /dev/null +++ b/.github/workflows/pr-title-check.yml @@ -0,0 +1,47 @@ +name: "Lint PR" + +on: + pull_request_target: + types: + - opened + - edited + - synchronize + +jobs: + main: + name: Validate PR title + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + # Configure which types are allowed (newline delimited). + # Default: https://github.com/commitizen/conventional-commit-types + types: | + feat + fix + docs + style + refactor + perf + test + build + ci + chore + revert + + # Configure which scopes are allowed (newline delimited). + scopes: | + controller + dashboard + trafficrouting + analysis + metricprovider + experiments + deps + example + cli + + # Configure that a scope must always be provided. + requireScope: false From 5552b2ade894dd11de02b3c194dcdd8c8a77fe2b Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Sat, 15 Oct 2022 18:58:44 -0500 Subject: [PATCH 49/68] ci: add auto close to issues and prs (#2319) * add auto close issues and prs Signed-off-by: zachaller * Add awaiting-response label closer Signed-off-by: zachaller * Change name Signed-off-by: zachaller * dont close any milestones Signed-off-by: zachaller * correct label in messages Signed-off-by: zachaller * github trigger re-run Signed-off-by: zachaller * add permissions Signed-off-by: zachaller * move perms to job Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- .github/workflows/stale-issues-pr.yml | 27 ++++++++++++++++++++++++++ .github/workflows/waiting-issues.yml | 28 +++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 .github/workflows/stale-issues-pr.yml create mode 100644 .github/workflows/waiting-issues.yml diff --git a/.github/workflows/stale-issues-pr.yml b/.github/workflows/stale-issues-pr.yml new file mode 100644 index 0000000000..cbf65e7e72 --- /dev/null +++ b/.github/workflows/stale-issues-pr.yml @@ -0,0 +1,27 @@ +name: 'Close stale issues and PRs' +on: + schedule: + - cron: '30 1 * * *' + +jobs: + stale: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@v6 + with: + stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.' + stale-pr-message: 'This PR is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 14 days.' + close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.' + close-pr-message: 'This PR was closed because it has been stalled for 14 days with no activity.' + days-before-issue-stale: 60 + days-before-pr-stale: 90 + days-before-issue-close: 7 + days-before-pr-close: 14 + stale-issue-label: 'no-issue-activity' + exempt-issue-labels: 'awaiting-approval,work-in-progress' + stale-pr-label: 'no-pr-activity' + exempt-pr-labels: 'awaiting-approval,work-in-progress' + exempt-all-milestones: true \ No newline at end of file diff --git a/.github/workflows/waiting-issues.yml b/.github/workflows/waiting-issues.yml new file mode 100644 index 0000000000..7e1814e20a --- /dev/null +++ b/.github/workflows/waiting-issues.yml @@ -0,0 +1,28 @@ +name: 'Close stale issues and PRs waiting for response' +on: + schedule: + - cron: '30 1 * * *' + +jobs: + stale: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@v6 + with: + stale-issue-message: 'This issue is stale because it has awaiting-response label for 5 days with no activity. Remove stale label or comment or this will be closed in 5 days.' + stale-pr-message: 'This PR is stale because it has awaiting-response label for 10 days with no activity. Remove stale label or comment or this will be closed in 10 days.' + close-issue-message: 'This issue was closed because it has been stalled for 5 days with no activity and has the awaiting-response label.' + close-pr-message: 'This PR was closed because it has been stalled for 10 days with no activity and has the awaiting-response label.' + days-before-issue-stale: 5 + days-before-pr-stale: 10 + days-before-issue-close: 5 + days-before-pr-close: 10 + stale-issue-label: 'no-issue-activity' + exempt-issue-labels: 'awaiting-approval,work-in-progress' + stale-pr-label: 'no-pr-activity' + exempt-pr-labels: 'awaiting-approval,work-in-progress' + exempt-all-milestones: true + any-of-labels: 'awaiting-response' \ No newline at end of file From a8bccfe801938db9d6abbe94b73708c5ea7641e5 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Sat, 15 Oct 2022 19:03:53 -0500 Subject: [PATCH 50/68] move perms to job for clomonitor (#2333) Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- .github/workflows/dependabot_automerge.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/dependabot_automerge.yml b/.github/workflows/dependabot_automerge.yml index 961ab6da42..128e1bd8b6 100644 --- a/.github/workflows/dependabot_automerge.yml +++ b/.github/workflows/dependabot_automerge.yml @@ -2,13 +2,12 @@ name: Approve and enable auto-merge for dependabot on: pull_request -permissions: - pull-requests: write - contents: write - jobs: review: runs-on: ubuntu-latest + permissions: + pull-requests: write + contents: write if: ${{ github.actor == 'dependabot[bot]' && github.repository == 'argoproj/argo-rollouts'}} steps: - name: Dependabot metadata From 375d7950d24478e9cdbaa02ca15d0bc077a4153e Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Sat, 15 Oct 2022 19:06:47 -0500 Subject: [PATCH 51/68] Move zachaller to approvers (#2311) Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- OWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OWNERS b/OWNERS index eba5228bfd..32b790229c 100644 --- a/OWNERS +++ b/OWNERS @@ -8,6 +8,7 @@ approvers: - jessesuen - khhirani - leoluz +- zachaller reviewers: - agrawroh @@ -15,4 +16,3 @@ reviewers: - harikrongali - kostis-codefresh - perenesenko -- zachaller From 50d0e8718494b16ab57e1e3a8ed26833cf14ade2 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Sat, 15 Oct 2022 21:22:06 -0500 Subject: [PATCH 52/68] ci: fix pr lint check (#2336) Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- .github/workflows/pr-title-check.yml | 60 ++++++++++++++-------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/.github/workflows/pr-title-check.yml b/.github/workflows/pr-title-check.yml index 5f11c118ae..dd165bdf28 100644 --- a/.github/workflows/pr-title-check.yml +++ b/.github/workflows/pr-title-check.yml @@ -13,35 +13,35 @@ jobs: runs-on: ubuntu-latest steps: - uses: amannn/action-semantic-pull-request@v5 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - # Configure which types are allowed (newline delimited). - # Default: https://github.com/commitizen/conventional-commit-types - types: | - feat - fix - docs - style - refactor - perf - test - build - ci - chore - revert + with: + # Configure which types are allowed (newline delimited). + # Default: https://github.com/commitizen/conventional-commit-types + types: | + feat + fix + docs + style + refactor + perf + test + build + ci + chore + revert - # Configure which scopes are allowed (newline delimited). - scopes: | - controller - dashboard - trafficrouting - analysis - metricprovider - experiments - deps - example - cli + # Configure which scopes are allowed (newline delimited). + scopes: | + controller + dashboard + trafficrouting + analysis + metricprovider + experiments + deps + example + cli - # Configure that a scope must always be provided. - requireScope: false + # Configure that a scope must always be provided. + requireScope: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From f636734d224b27041dcdbc759cf29c83713e67a8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Oct 2022 00:07:35 +0000 Subject: [PATCH 53/68] chore(deps): bump google.golang.org/grpc from 1.50.0 to 1.50.1 (#2340) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.50.0 to 1.50.1. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.50.0...v1.50.1) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 571aa6141e..d5cc233ee2 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,7 @@ require ( github.com/tj/assert v0.0.3 github.com/valyala/fasttemplate v1.2.1 google.golang.org/genproto v0.0.0-20220712132514-bdd2acd4974d - google.golang.org/grpc v1.50.0 + google.golang.org/grpc v1.50.1 google.golang.org/protobuf v1.28.1 gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.24.2 diff --git a/go.sum b/go.sum index 49fe128eb1..e0e0151ff0 100644 --- a/go.sum +++ b/go.sum @@ -1661,8 +1661,8 @@ google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11 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/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.50.0 h1:fPVVDxY9w++VjTZsYvXWqEf9Rqar/e+9zYfxKK+W+YU= -google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= 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= From c99ac35965dc8873afaeb05e86ec411231fa6720 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Mon, 17 Oct 2022 10:49:24 -0500 Subject: [PATCH 54/68] ci: adjust settings for stale pr and issues (#2341) * adjust settings for stale pr and issues Signed-off-by: zachaller * go back to original settings Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- .github/workflows/stale-issues-pr.yml | 8 ++++---- .github/workflows/waiting-issues.yml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/stale-issues-pr.yml b/.github/workflows/stale-issues-pr.yml index cbf65e7e72..49e9590908 100644 --- a/.github/workflows/stale-issues-pr.yml +++ b/.github/workflows/stale-issues-pr.yml @@ -12,14 +12,14 @@ jobs: steps: - uses: actions/stale@v6 with: - stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.' - stale-pr-message: 'This PR is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 14 days.' + stale-issue-message: 'This issue is stale because it has been open 60 days with no activity.' + stale-pr-message: 'This PR is stale because it has been open 90 days with no activity.' close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.' close-pr-message: 'This PR was closed because it has been stalled for 14 days with no activity.' days-before-issue-stale: 60 days-before-pr-stale: 90 - days-before-issue-close: 7 - days-before-pr-close: 14 + days-before-issue-close: -1 + days-before-pr-close: -1 stale-issue-label: 'no-issue-activity' exempt-issue-labels: 'awaiting-approval,work-in-progress' stale-pr-label: 'no-pr-activity' diff --git a/.github/workflows/waiting-issues.yml b/.github/workflows/waiting-issues.yml index 7e1814e20a..4caed43734 100644 --- a/.github/workflows/waiting-issues.yml +++ b/.github/workflows/waiting-issues.yml @@ -21,7 +21,7 @@ jobs: days-before-issue-close: 5 days-before-pr-close: 10 stale-issue-label: 'no-issue-activity' - exempt-issue-labels: 'awaiting-approval,work-in-progress' + exempt-issue-labels: 'awaiting-approval,work-in-progress,enhancement' stale-pr-label: 'no-pr-activity' exempt-pr-labels: 'awaiting-approval,work-in-progress' exempt-all-milestones: true From d67b23bbe1b3a86e3fa20f826c2da034a935d1a2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Oct 2022 00:03:10 +0000 Subject: [PATCH 55/68] chore(deps): bump github.com/newrelic/newrelic-client-go (#2344) Bumps [github.com/newrelic/newrelic-client-go](https://github.com/newrelic/newrelic-client-go) from 1.0.0 to 1.1.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/v1.0.0...v1.1.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] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d5cc233ee2..4f6d91e586 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/influxdata/influxdb-client-go/v2 v2.11.0 github.com/juju/ansiterm v1.0.0 github.com/mitchellh/mapstructure v1.5.0 - github.com/newrelic/newrelic-client-go v1.0.0 + github.com/newrelic/newrelic-client-go v1.1.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.12.2-0.20220620141757-4ad265f1b4ee github.com/prometheus/client_model v0.2.0 diff --git a/go.sum b/go.sum index e0e0151ff0..7e9e65ac61 100644 --- a/go.sum +++ b/go.sum @@ -805,8 +805,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 v1.0.0 h1:0ugZUujCiJg3WGDxnmOT1QRP2gDiZKIMN0Z04SvxVBc= -github.com/newrelic/newrelic-client-go v1.0.0/go.mod h1:RYMXt7hgYw7nzuXIGd2BH0F1AivgWw7WrBhNBQZEB4k= +github.com/newrelic/newrelic-client-go v1.1.0 h1:aflNjzQ21c+2GwBVh+UbAf9lznkRfCcVABoc5UM4IXw= +github.com/newrelic/newrelic-client-go v1.1.0/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/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= From 5fb075e131c6ad9c6a38c5c18be937d06fb9aba3 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Tue, 18 Oct 2022 12:12:14 -0500 Subject: [PATCH 56/68] ci: auto generate changelog (#2321) * Auto changelogs Signed-off-by: zachaller * change template Signed-off-by: zachaller * remove pr title check to won pr Signed-off-by: zachaller * conventionalcommits Signed-off-by: zachaller * change file name Signed-off-by: zachaller * Auto changelogs Signed-off-by: zachaller * change template Signed-off-by: zachaller * remove pr title check to won pr Signed-off-by: zachaller * conventionalcommits Signed-off-by: zachaller * change file name Signed-off-by: zachaller * fix file name when untar'ing Signed-off-by: zachaller * perms for clomonitor Signed-off-by: zachaller * sort by semver Signed-off-by: zachaller * start at v1.3.1 Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- .chglog/CHANGELOG.tpl.md | 30 ++++++++++++++++++++++++++++++ .chglog/config.yml | 28 ++++++++++++++++++++++++++++ .github/workflows/changelog.yml | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100755 .chglog/CHANGELOG.tpl.md create mode 100755 .chglog/config.yml create mode 100644 .github/workflows/changelog.yml diff --git a/.chglog/CHANGELOG.tpl.md b/.chglog/CHANGELOG.tpl.md new file mode 100755 index 0000000000..60a67d5bc2 --- /dev/null +++ b/.chglog/CHANGELOG.tpl.md @@ -0,0 +1,30 @@ +{{ range .Versions }} + +## {{ if .Tag.Previous }}[{{ .Tag.Name }}]({{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}){{ else }}{{ .Tag.Name }}{{ end }} ({{ datetime "2006-01-02" .Tag.Date }}) + +{{ range .CommitGroups -}} +### {{ .Title }} + +{{ range .Commits -}} +* {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} +{{ end }} +{{ end -}} + +{{- if .RevertCommits -}} +### Reverts + +{{ range .RevertCommits -}} +* {{ .Revert.Header }} +{{ end }} +{{ end -}} + +{{- if .NoteGroups -}} +{{ range .NoteGroups -}} +### {{ .Title }} + +{{ range .Notes }} +{{ .Body }} +{{ end }} +{{ end -}} +{{ end -}} +{{ end -}} \ No newline at end of file diff --git a/.chglog/config.yml b/.chglog/config.yml new file mode 100755 index 0000000000..0e4a037f2d --- /dev/null +++ b/.chglog/config.yml @@ -0,0 +1,28 @@ +style: github +template: CHANGELOG.tpl.md +info: + title: CHANGELOG + repository_url: https://github.com/argoproj/argo-rollouts +options: + commits: + # filters: + # Type: + # - feat + # - fix + # - perf + # - refactor + commit_groups: + # title_maps: + # feat: Features + # fix: Bug Fixes + # perf: Performance Improvements + # refactor: Code Refactoring + header: + pattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$" + pattern_maps: + - Type + - Scope + - Subject + notes: + keywords: + - BREAKING CHANGE \ No newline at end of file diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml new file mode 100644 index 0000000000..46ab0d0535 --- /dev/null +++ b/.github/workflows/changelog.yml @@ -0,0 +1,32 @@ +name: Update Changelog +on: + release: + types: [published] +permissions: + contents: read + +jobs: + updateChangelog: + permissions: + contents: write # for peter-evans/create-pull-request to create branch + pull-requests: write # for peter-evans/create-pull-request to create a PR + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Update Changelog + run: | + curl -o git-chglog.tar.gz -L https://github.com/git-chglog/git-chglog/releases/download/v0.15.1/git-chglog_0.15.1_darwin_amd64.tar.gz + tar -zxvf git-chglog.tar.gz + chmod u+x git-chglog + ./git-chglog --sort semver -o CHANGELOG-AUTO.md v1.3.1.. + rm git-chglog + - name: Create Pull Request + uses: peter-evans/create-pull-request@v4 + with: + commit-message: update changelog + title: "docs: Update Changelog" + body: Update changelog to reflect release changes + branch: update-changelog + base: master \ No newline at end of file From a7721dcc2e63e79cd60f1c41b5ced65e3bfe1f60 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Tue, 18 Oct 2022 12:16:35 -0500 Subject: [PATCH 57/68] docs(trafficrouting): fix docs warning to github style markdown (#2342) * fix docs warning to github style markdown Signed-off-by: zachaller * fx formating Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- docs/features/traffic-management/index.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/features/traffic-management/index.md b/docs/features/traffic-management/index.md index 8c2e97d152..1578cab580 100644 --- a/docs/features/traffic-management/index.md +++ b/docs/features/traffic-management/index.md @@ -58,7 +58,9 @@ routes we also have to set a route precedence with the upstream traffic router. 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. +!!! 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: From ee3cc0b50b0f32a9e1f690e04453d09acb6d46fb Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Tue, 18 Oct 2022 13:32:42 -0500 Subject: [PATCH 58/68] fix all workflows to follow best practices of clo monitor via https://app.stepsecurity.io/ (#2343) Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- .github/workflows/codeql.yml | 63 ++++++++++++---------- .github/workflows/dependabot_automerge.yml | 3 ++ .github/workflows/docker-publish.yml | 5 +- .github/workflows/e2e.yaml | 3 ++ .github/workflows/gh-pages.yaml | 5 ++ .github/workflows/go.yml | 6 +++ .github/workflows/pr-title-check.yml | 8 ++- .github/workflows/release.yaml | 7 ++- .github/workflows/stale-issues-pr.yml | 3 ++ .github/workflows/waiting-issues.yml | 3 ++ 10 files changed, 75 insertions(+), 31 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 6af424b019..d8309ea267 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -12,38 +12,45 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +permissions: # added using https://github.com/step-security/secure-workflows + contents: read + jobs: CodeQL-Build: # CodeQL runs on ubuntu-latest and windows-latest + permissions: + actions: read # for github/codeql-action/init to get workflow details + contents: read # for actions/checkout to fetch code + security-events: write # for github/codeql-action/autobuild to send a status report runs-on: ubuntu-latest steps: - - name: Checkout repository - uses: actions/checkout@v3.1.0 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - # Override language selection by uncommenting this and choosing your languages - # with: - # languages: go, javascript, csharp, python, cpp, java - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + - name: Checkout repository + uses: actions/checkout@v3.1.0 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + # Override language selection by uncommenting this and choosing your languages + # with: + # languages: go, javascript, csharp, python, cpp, java + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/dependabot_automerge.yml b/.github/workflows/dependabot_automerge.yml index 128e1bd8b6..2bdab7b838 100644 --- a/.github/workflows/dependabot_automerge.yml +++ b/.github/workflows/dependabot_automerge.yml @@ -2,6 +2,9 @@ name: Approve and enable auto-merge for dependabot on: pull_request +permissions: + contents: read + jobs: review: runs-on: ubuntu-latest diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 6631d03342..c96f45c77f 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -9,6 +9,9 @@ on: # Run tests for any PRs. pull_request: +permissions: + contents: read + jobs: docker: runs-on: ubuntu-latest @@ -91,4 +94,4 @@ jobs: target: kubectl-argo-rollouts platforms: ${{ steps.platform-matrix.outputs.platform-matrix }} push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.plugin-meta.outputs.tags }} + tags: ${{ steps.plugin-meta.outputs.tags }} \ No newline at end of file diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index f35de3415b..7590b1c106 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -20,6 +20,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: event_file: name: "Event File" diff --git a/.github/workflows/gh-pages.yaml b/.github/workflows/gh-pages.yaml index 303d641f7f..58c87fe72a 100644 --- a/.github/workflows/gh-pages.yaml +++ b/.github/workflows/gh-pages.yaml @@ -9,8 +9,13 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: deploy: + permissions: + contents: write # for peaceiris/actions-gh-pages to push pages branch runs-on: ubuntu-latest steps: - uses: actions/checkout@v3.1.0 diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 24b18740f2..955bc796c5 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -15,6 +15,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: event_file: name: "Event File" @@ -26,6 +29,9 @@ jobs: name: Event File path: ${{ github.event_path }} lint-go: + permissions: + contents: read # for actions/checkout to fetch code + pull-requests: read # for golangci/golangci-lint-action to fetch pull requests name: Lint Go code runs-on: ubuntu-latest steps: diff --git a/.github/workflows/pr-title-check.yml b/.github/workflows/pr-title-check.yml index dd165bdf28..d24c6d268e 100644 --- a/.github/workflows/pr-title-check.yml +++ b/.github/workflows/pr-title-check.yml @@ -7,8 +7,14 @@ on: - edited - synchronize +permissions: + contents: read + jobs: main: + permissions: + pull-requests: read # for amannn/action-semantic-pull-request to analyze PRs + statuses: write # for amannn/action-semantic-pull-request to mark status of analyzed PR name: Validate PR title runs-on: ubuntu-latest steps: @@ -44,4 +50,4 @@ jobs: # Configure that a scope must always be provided. requireScope: false env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 43080842a0..f24bf75caf 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -6,6 +6,9 @@ on: tag: description: Git tag to build release from required: true +permissions: + contents: read + jobs: release-images: runs-on: ubuntu-latest @@ -94,6 +97,8 @@ jobs: release-artifacts: + permissions: + contents: write # for softprops/action-gh-release to create GitHub release runs-on: ubuntu-latest needs: release-images @@ -122,7 +127,7 @@ jobs: SIGS_BOM_VERSION: v0.2.1 # comma delimited list of project relative folders to inspect for package # managers (gomod, yarn, npm). - PROJECT_FOLDERS: ".,./ui" + PROJECT_FOLDERS: ".,./ui" # full qualified name of the docker image to be inspected DOCKER_IMAGE: quay.io/argoproj/argo-rollouts:${{ github.event.inputs.tag }} diff --git a/.github/workflows/stale-issues-pr.yml b/.github/workflows/stale-issues-pr.yml index 49e9590908..3cb789f394 100644 --- a/.github/workflows/stale-issues-pr.yml +++ b/.github/workflows/stale-issues-pr.yml @@ -3,6 +3,9 @@ on: schedule: - cron: '30 1 * * *' +permissions: + contents: read + jobs: stale: runs-on: ubuntu-latest diff --git a/.github/workflows/waiting-issues.yml b/.github/workflows/waiting-issues.yml index 4caed43734..f8c1a6cae8 100644 --- a/.github/workflows/waiting-issues.yml +++ b/.github/workflows/waiting-issues.yml @@ -3,6 +3,9 @@ on: schedule: - cron: '30 1 * * *' +permissions: + contents: read + jobs: stale: runs-on: ubuntu-latest From 08d1ef931ae35c6f0484c5dee5897c7bfe3a14b3 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Tue, 18 Oct 2022 13:57:34 -0500 Subject: [PATCH 59/68] ci: add link to conventional pr check in pr template (#2346) Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- .github/pull_request_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 49d173bf0c..33da74335a 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,7 +1,7 @@ Checklist: * [ ] Either (a) I've created an [enhancement proposal](https://github.com/argoproj/argo-rollouts/issues/new/choose) and discussed it with the community, (b) this is a bug fix, or (c) this is a chore. -* [ ] The title of the PR is (a) [conventional](https://www.conventionalcommits.org/en/v1.0.0/), (b) states what changed, and (c) suffixes the related issues number. E.g. `"fix(controller): Updates such and such. Fixes #1234"`. +* [ ] The title of the PR is (a) [conventional](https://www.conventionalcommits.org/en/v1.0.0/) with a list of types and scopes found [here](https://github.com/argoproj/argo-rollouts/blob/master/.github/workflows/pr-title-check.yml), (b) states what changed, and (c) suffixes the related issues number. E.g. `"fix(controller): Updates such and such. Fixes #1234"`. * [ ] I've signed my commits with [DCO](https://github.com/argoproj/argoproj) * [ ] I have written unit and/or e2e tests for my change. PRs without these are unlikely to be merged. * [ ] My builds are green. Try syncing with master if they are not. From 4598be3a64d1a1b41f04eefa1e3ffee2e0d439b4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Oct 2022 00:02:42 +0000 Subject: [PATCH 60/68] chore(deps): bump github.com/valyala/fasttemplate from 1.2.1 to 1.2.2 (#2348) Bumps [github.com/valyala/fasttemplate](https://github.com/valyala/fasttemplate) from 1.2.1 to 1.2.2. - [Release notes](https://github.com/valyala/fasttemplate/releases) - [Commits](https://github.com/valyala/fasttemplate/compare/v1.2.1...v1.2.2) --- updated-dependencies: - dependency-name: github.com/valyala/fasttemplate dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 4f6d91e586..c1d9ae838c 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,7 @@ require ( github.com/spf13/cobra v1.6.0 github.com/stretchr/testify v1.8.0 github.com/tj/assert v0.0.3 - github.com/valyala/fasttemplate v1.2.1 + github.com/valyala/fasttemplate v1.2.2 google.golang.org/genproto v0.0.0-20220712132514-bdd2acd4974d google.golang.org/grpc v1.50.1 google.golang.org/protobuf v1.28.1 diff --git a/go.sum b/go.sum index 7e9e65ac61..b79f2f2274 100644 --- a/go.sum +++ b/go.sum @@ -1017,8 +1017,9 @@ 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.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= 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= From 927d5c4e8a3ba959f976bad8567f6b4a2e4978d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Oct 2022 00:02:49 +0000 Subject: [PATCH 61/68] chore(deps): bump github.com/prometheus/client_model from 0.2.0 to 0.3.0 (#2349) Bumps [github.com/prometheus/client_model](https://github.com/prometheus/client_model) from 0.2.0 to 0.3.0. - [Release notes](https://github.com/prometheus/client_model/releases) - [Commits](https://github.com/prometheus/client_model/compare/v0.2.0...v0.3.0) --- updated-dependencies: - dependency-name: github.com/prometheus/client_model dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: Ariel Simhon --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index c1d9ae838c..10cfe102bc 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/newrelic/newrelic-client-go v1.1.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.12.2-0.20220620141757-4ad265f1b4ee - github.com/prometheus/client_model v0.2.0 + github.com/prometheus/client_model v0.3.0 github.com/prometheus/common v0.37.0 github.com/servicemeshinterface/smi-sdk-go v0.5.0 github.com/sirupsen/logrus v1.9.0 diff --git a/go.sum b/go.sum index b79f2f2274..aa02c9424d 100644 --- a/go.sum +++ b/go.sum @@ -878,8 +878,9 @@ github.com/prometheus/client_golang v1.12.2-0.20220620141757-4ad265f1b4ee/go.mod 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= -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/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= 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= From 7c67a2f4c0315a5adb43c43f5b5543dcaf6ee2b0 Mon Sep 17 00:00:00 2001 From: Prema <107519450+premadk@users.noreply.github.com> Date: Wed, 19 Oct 2022 15:47:27 -0700 Subject: [PATCH 62/68] fix(metricprovider): Support jsonBody for web metric provider Fixes #2275 (#2312) * fix(issue2275): Support jsonBody for web metric provider Signed-off-by: Prema devi Kuppuswamy * fix(webmetrics): generate proto files Signed-off-by: Prema devi Kuppuswamy Signed-off-by: Prema devi Kuppuswamy Signed-off-by: Ariel Simhon --- docs/analysis/web.md | 31 +- .../features/kustomize/rollout_cr_schema.json | 12 + manifests/crds/analysis-run-crd.yaml | 3 + manifests/crds/analysis-template-crd.yaml | 3 + .../crds/cluster-analysis-template-crd.yaml | 3 + manifests/install.yaml | 9 + manifests/namespace-install.yaml | 9 + metricproviders/webmetric/webmetric.go | 29 +- metricproviders/webmetric/webmetric_test.go | 83 ++ pkg/apis/rollouts/v1alpha1/analysis_types.go | 8 +- pkg/apis/rollouts/v1alpha1/generated.pb.go | 994 +++++++++--------- pkg/apis/rollouts/v1alpha1/generated.proto | 8 +- .../rollouts/v1alpha1/openapi_generated.go | 9 +- .../v1alpha1/zz_generated.deepcopy.go | 7 + 14 files changed, 722 insertions(+), 486 deletions(-) diff --git a/docs/analysis/web.md b/docs/analysis/web.md index 285403ffe7..4572dbc4f2 100644 --- a/docs/analysis/web.md +++ b/docs/analysis/web.md @@ -50,7 +50,7 @@ to convert a result value to a numeric type so that mathematical comparison oper (e.g. >, <, >=, <=). ### Optional web methods -It is possible to use a POST or PUT requests, by specifying the `method` and `body` fields +It is possible to use a POST or PUT requests, by specifying the `method` and either `body` or `jsonBody` fields ```yaml metrics: @@ -66,9 +66,32 @@ It is possible to use a POST or PUT requests, by specifying the `method` and `bo value: "Bearer {{ args.api-token }}" - key: Content-Type # if body is a json, it is recommended to set the Content-Type value: "application/json" - body: "{\"key\": \"string value\"}" + body: "string value" jsonPath: "{$.data.ok}" ``` !!! tip - In order to send in JSON, you have to encode it yourself, and send the correct Content-Type as well. - Setting a `body` field for a `GET` request will result in an error. + In order to send in JSON, you can use jsonBody and Content-Type will be automatically set as json. + Setting a `body` or `jsonBody` field for a `GET` request will result in an error. + Set either `body` or `jsonBody` and setting both will result in an error. + +```yaml + metrics: + - name: webmetric + successCondition: result == true + provider: + web: + method: POST # valid values are GET|POST|PUT, defaults to GET + url: "http://my-server.com/api/v1/measurement?service={{ args.service-name }}" + timeoutSeconds: 20 # defaults to 10 seconds + headers: + - key: Authorization + value: "Bearer {{ args.api-token }}" + - key: Content-Type # if body is a json, it is recommended to set the Content-Type + value: "application/json" + jsonBody: # If using jsonBody Content-Type header will be automatically set to json + key1: value_1 + key2: + nestedObj: nested value + key3: "{{ args.service-name }}" + jsonPath: "{$.data.ok}" +``` \ No newline at end of file diff --git a/docs/features/kustomize/rollout_cr_schema.json b/docs/features/kustomize/rollout_cr_schema.json index 4ec83fccff..fbff809be6 100644 --- a/docs/features/kustomize/rollout_cr_schema.json +++ b/docs/features/kustomize/rollout_cr_schema.json @@ -4213,6 +4213,10 @@ "insecure": { "type": "boolean" }, + "jsonBody": { + "type": "object", + "x-kubernetes-preserve-unknown-fields": true + }, "jsonPath": { "type": "string" }, @@ -8477,6 +8481,10 @@ "insecure": { "type": "boolean" }, + "jsonBody": { + "type": "object", + "x-kubernetes-preserve-unknown-fields": true + }, "jsonPath": { "type": "string" }, @@ -12741,6 +12749,10 @@ "insecure": { "type": "boolean" }, + "jsonBody": { + "type": "object", + "x-kubernetes-preserve-unknown-fields": true + }, "jsonPath": { "type": "string" }, diff --git a/manifests/crds/analysis-run-crd.yaml b/manifests/crds/analysis-run-crd.yaml index 962db250b3..da21888bde 100644 --- a/manifests/crds/analysis-run-crd.yaml +++ b/manifests/crds/analysis-run-crd.yaml @@ -2732,6 +2732,9 @@ spec: type: array insecure: type: boolean + jsonBody: + type: object + x-kubernetes-preserve-unknown-fields: true jsonPath: type: string method: diff --git a/manifests/crds/analysis-template-crd.yaml b/manifests/crds/analysis-template-crd.yaml index 54aad4b66f..1e37db2dd0 100644 --- a/manifests/crds/analysis-template-crd.yaml +++ b/manifests/crds/analysis-template-crd.yaml @@ -2728,6 +2728,9 @@ spec: type: array insecure: type: boolean + jsonBody: + type: object + x-kubernetes-preserve-unknown-fields: true jsonPath: type: string method: diff --git a/manifests/crds/cluster-analysis-template-crd.yaml b/manifests/crds/cluster-analysis-template-crd.yaml index 1551b9d114..fb149f2fa3 100644 --- a/manifests/crds/cluster-analysis-template-crd.yaml +++ b/manifests/crds/cluster-analysis-template-crd.yaml @@ -2728,6 +2728,9 @@ spec: type: array insecure: type: boolean + jsonBody: + type: object + x-kubernetes-preserve-unknown-fields: true jsonPath: type: string method: diff --git a/manifests/install.yaml b/manifests/install.yaml index aca39e1c88..04475b6a8a 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -2733,6 +2733,9 @@ spec: type: array insecure: type: boolean + jsonBody: + type: object + x-kubernetes-preserve-unknown-fields: true jsonPath: type: string method: @@ -5607,6 +5610,9 @@ spec: type: array insecure: type: boolean + jsonBody: + type: object + x-kubernetes-preserve-unknown-fields: true jsonPath: type: string method: @@ -8367,6 +8373,9 @@ spec: type: array insecure: type: boolean + jsonBody: + type: object + x-kubernetes-preserve-unknown-fields: true jsonPath: type: string method: diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 07ffc9e787..bfca8940be 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -2733,6 +2733,9 @@ spec: type: array insecure: type: boolean + jsonBody: + type: object + x-kubernetes-preserve-unknown-fields: true jsonPath: type: string method: @@ -5607,6 +5610,9 @@ spec: type: array insecure: type: boolean + jsonBody: + type: object + x-kubernetes-preserve-unknown-fields: true jsonPath: type: string method: @@ -8367,6 +8373,9 @@ spec: type: array insecure: type: boolean + jsonBody: + type: object + x-kubernetes-preserve-unknown-fields: true jsonPath: type: string method: diff --git a/metricproviders/webmetric/webmetric.go b/metricproviders/webmetric/webmetric.go index f1b215de81..dce1865e5a 100644 --- a/metricproviders/webmetric/webmetric.go +++ b/metricproviders/webmetric/webmetric.go @@ -1,6 +1,7 @@ package webmetric import ( + "bytes" "crypto/tls" "encoding/json" "errors" @@ -23,7 +24,9 @@ import ( const ( // ProviderType indicates the provider is a web metric - ProviderType = "Web" + ProviderType = "Web" + ContentTypeKey = "Content-Type" + ContentTypeJsonValue = "application/json" ) // Provider contains all the required components to run a WebMetric query @@ -59,14 +62,25 @@ func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alph url := metric.Provider.Web.URL + stringBody := metric.Provider.Web.Body + jsonBody := metric.Provider.Web.JSONBody + var body io.Reader - if metric.Provider.Web.Body != "" { - if method == v1alpha1.WebMetricMethodGet { - return metricutil.MarkMeasurementError(measurement, fmt.Errorf("Body can only be used with POST or PUT WebMetric Method types")) - } + if stringBody != "" && jsonBody != nil { + return metricutil.MarkMeasurementError(measurement, fmt.Errorf("use either Body or JSONBody; both cannot exists for WebMetric payload")) + } else if (stringBody != "" || jsonBody != nil) && method == v1alpha1.WebMetricMethodGet { + return metricutil.MarkMeasurementError(measurement, fmt.Errorf("Body/JSONBody can only be used with POST or PUT WebMetric Method types")) + } - body = strings.NewReader(metric.Provider.Web.Body) + if stringBody != "" { + body = strings.NewReader(stringBody) + } else if jsonBody != nil { + bodyBytes, err := jsonBody.MarshalJSON() + if err != nil { + return metricutil.MarkMeasurementError(measurement, err) + } + body = bytes.NewBuffer(bodyBytes) } // Create request @@ -80,6 +94,9 @@ func (p *Provider) Run(run *v1alpha1.AnalysisRun, metric v1alpha1.Metric) v1alph for _, header := range metric.Provider.Web.Headers { request.Header.Set(header.Key, header.Value) } + if jsonBody != nil { + request.Header.Set(ContentTypeKey, ContentTypeJsonValue) + } // Send Request response, err := p.client.Do(request) diff --git a/metricproviders/webmetric/webmetric_test.go b/metricproviders/webmetric/webmetric_test.go index 66861478f5..5ec0422ce1 100644 --- a/metricproviders/webmetric/webmetric_test.go +++ b/metricproviders/webmetric/webmetric_test.go @@ -2,6 +2,7 @@ package webmetric import ( "bytes" + "encoding/json" "io" "net/http" "net/http/httptest" @@ -23,6 +24,7 @@ func TestRunSuite(t *testing.T) { expectedValue string expectedPhase v1alpha1.AnalysisPhase expectedErrorMessage string + expectedJsonBody string }{ // When_noJSONPathSpecified_And_MatchesConditions_Then_Succeed { @@ -574,6 +576,81 @@ func TestRunSuite(t *testing.T) { expectedValue: "Body can only be used with POST or PUT WebMetric Method types", expectedPhase: v1alpha1.AnalysisPhaseError, }, + // When_methodPOST_Then_server_gets_jsonBody_Then_Succeed + { + webServerStatus: 200, + webServerResponse: `{"a": 1, "b": true, "c": [1, 2, 3, 4], "d": null}`, + metric: v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result.a > 0 && result.b && all(result.c, {# < 5}) && result.d == nil", + Provider: v1alpha1.MetricProvider{ + Web: &v1alpha1.WebMetric{ + Method: v1alpha1.WebMetricMethodPost, + // URL: server.URL, + Headers: []v1alpha1.WebMetricHeader{{Key: "key", Value: "value"}}, + JSONBody: json.RawMessage(`{"key1": "value1", "key2": "value2"}`), + }, + }, + }, + expectedMethod: "POST", + expectedJsonBody: `{"key1": "value1", "key2": "value2"}`, + expectedValue: `{"a":1,"b":true,"c":[1,2,3,4],"d":null}`, + expectedPhase: v1alpha1.AnalysisPhaseSuccessful, + }, + // When_methodPUT_Then_server_gets_jsonBody_Then_Succeed + { + webServerStatus: 200, + webServerResponse: `{"a": 1, "b": true, "c": [1, 2, 3, 4], "d": null}`, + metric: v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result.a > 0 && result.b && all(result.c, {# < 5}) && result.d == nil", + Provider: v1alpha1.MetricProvider{ + Web: &v1alpha1.WebMetric{ + Method: v1alpha1.WebMetricMethodPut, + // URL: server.URL, + Headers: []v1alpha1.WebMetricHeader{{Key: "key", Value: "value"}, {Key: ContentTypeKey, Value: ContentTypeJsonValue}}, + JSONBody: json.RawMessage(`{"key1": "value1", "key2": { "key3" : "value3"}}`), + }, + }, + }, + expectedMethod: "PUT", + expectedJsonBody: `{"key1": "value1", "key2": { "key3" : "value3"}}`, + expectedValue: `{"a":1,"b":true,"c":[1,2,3,4],"d":null}`, + expectedPhase: v1alpha1.AnalysisPhaseSuccessful, + }, + // When_sendingJsonBodyWithGet_Then_Failure + { + metric: v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result.a > 0 && result.b && all(result.c, {# < 5}) && result.d == nil", + Provider: v1alpha1.MetricProvider{ + Web: &v1alpha1.WebMetric{ + // URL: server.URL, + Headers: []v1alpha1.WebMetricHeader{{Key: "key", Value: "value"}}, + JSONBody: json.RawMessage(`{"key1": "value1", "key2": { "key3" : "value3"}}`), + }, + }, + }, + expectedValue: "Body/JSONBody can only be used with POST or PUT WebMetric Method types", + expectedPhase: v1alpha1.AnalysisPhaseError, + }, + // When_sending_BothBodyAndJsonBodyWithGet_Then_Failure + { + metric: v1alpha1.Metric{ + Name: "foo", + SuccessCondition: "result.a > 0 && result.b && all(result.c, {# < 5}) && result.d == nil", + Provider: v1alpha1.MetricProvider{ + Web: &v1alpha1.WebMetric{ + // URL: server.URL, + Headers: []v1alpha1.WebMetricHeader{{Key: "key", Value: "value"}}, + JSONBody: json.RawMessage(`{"key1": "value1", "key2": { "key3" : "value3"}}`), + Body: "test body", + }, + }, + }, + expectedValue: "use either Body or JSONBody; both cannot exists for WebMetric payload", + expectedPhase: v1alpha1.AnalysisPhaseError, + }, } // Run @@ -591,6 +668,12 @@ func TestRunSuite(t *testing.T) { assert.Equal(t, test.expectedBody, buf.String()) } + if test.expectedJsonBody != "" { + bodyBytes, _ := io.ReadAll(req.Body) + assert.Equal(t, test.expectedJsonBody, string(bodyBytes)) + assert.Equal(t, ContentTypeJsonValue, req.Header.Get(ContentTypeKey)) + } + if test.webServerStatus < 200 || test.webServerStatus >= 300 { http.Error(rw, http.StatusText(test.webServerStatus), test.webServerStatus) } else { diff --git a/pkg/apis/rollouts/v1alpha1/analysis_types.go b/pkg/apis/rollouts/v1alpha1/analysis_types.go index 7d5931e458..f26fc91585 100644 --- a/pkg/apis/rollouts/v1alpha1/analysis_types.go +++ b/pkg/apis/rollouts/v1alpha1/analysis_types.go @@ -1,6 +1,7 @@ package v1alpha1 import ( + "encoding/json" "time" intstrutil "k8s.io/apimachinery/pkg/util/intstr" @@ -477,7 +478,7 @@ type WebMetric struct { // +patchStrategy=merge // Headers are optional HTTP headers to use in the request Headers []WebMetricHeader `json:"headers,omitempty" patchStrategy:"merge" patchMergeKey:"key" protobuf:"bytes,3,rep,name=headers"` - // Body is the body of the we metric (must be POST/PUT) + // Body is the body of the web metric (must be POST/PUT) Body string `json:"body,omitempty" protobuf:"bytes,4,opt,name=body"` // TimeoutSeconds is the timeout for the request in seconds (default: 10) TimeoutSeconds int64 `json:"timeoutSeconds,omitempty" protobuf:"varint,5,opt,name=timeoutSeconds"` @@ -485,6 +486,11 @@ type WebMetric struct { JSONPath string `json:"jsonPath,omitempty" protobuf:"bytes,6,opt,name=jsonPath"` // Insecure skips host TLS verification Insecure bool `json:"insecure,omitempty" protobuf:"varint,7,opt,name=insecure"` + // +kubebuilder:validation:Schemaless + // +kubebuilder:pruning:PreserveUnknownFields + // +kubebuilder:validation:Type=object + // JSONBody is the body of the web metric in a json format (method must be POST/PUT) + JSONBody json.RawMessage `json:"jsonBody,omitempty" protobuf:"bytes,8,opt,name=jsonBody,casttype=encoding/json.RawMessage"` } // WebMetricMethod is the available HTTP methods diff --git a/pkg/apis/rollouts/v1alpha1/generated.pb.go b/pkg/apis/rollouts/v1alpha1/generated.pb.go index ddb670b7e1..1b57b69024 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.pb.go +++ b/pkg/apis/rollouts/v1alpha1/generated.pb.go @@ -3084,481 +3084,483 @@ func init() { } var fileDescriptor_e0e705f843545fab = []byte{ - // 7571 bytes of a gzipped FileDescriptorProto + // 7605 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, 0x48, 0xab, 0x9f, 0xbb, 0xda, 0xac, 0x2c, 0x7b, 0x97, 0xce, - 0x38, 0xf0, 0xe7, 0x7c, 0x9f, 0x23, 0x25, 0xfe, 0xf9, 0x3e, 0x27, 0x36, 0xfc, 0x95, 0x94, 0x76, - 0xbd, 0x5a, 0x4b, 0xbb, 0xdc, 0x4b, 0xed, 0x6e, 0xe2, 0xc4, 0x49, 0x46, 0xe4, 0x15, 0x35, 0xbb, - 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, 0x90, 0x22, 0x29, 0xd0, 0x26, 0x29, 0x10, 0xb6, 0x56, 0xfa, 0xd2, 0xa2, 0x45, - 0x50, 0x20, 0x45, 0x91, 0x7d, 0x2a, 0xee, 0xef, 0xdc, 0x19, 0x0e, 0x25, 0x52, 0x1c, 0x6d, 0x8c, - 0x36, 0x6f, 0xe4, 0x3d, 0xe7, 0x9e, 0x73, 0xff, 0xcf, 0xb9, 0xe7, 0x9e, 0x73, 0x06, 0xd6, 0x1b, - 0x76, 0xb0, 0xd3, 0xd9, 0x5a, 0xaa, 0xb9, 0xad, 0x65, 0xcb, 0x6b, 0xb8, 0x6d, 0xcf, 0xbd, 0xc1, - 0x7e, 0xbc, 0xcb, 0x73, 0x9b, 0x4d, 0xb7, 0x13, 0xf8, 0xcb, 0xed, 0x9b, 0x8d, 0x65, 0xab, 0x6d, - 0xfb, 0xcb, 0xaa, 0x64, 0xf7, 0x3d, 0x56, 0xb3, 0xbd, 0x63, 0xbd, 0x67, 0xb9, 0x41, 0x1c, 0xe2, - 0x59, 0x01, 0xa9, 0x2f, 0xb5, 0x3d, 0x37, 0x70, 0xd1, 0xd3, 0x21, 0xb5, 0x25, 0x49, 0x8d, 0xfd, - 0xf8, 0x88, 0xac, 0xbb, 0xd4, 0xbe, 0xd9, 0x58, 0xa2, 0xd4, 0x96, 0x54, 0x89, 0xa4, 0xb6, 0xf8, - 0x2e, 0xad, 0x2d, 0x0d, 0xb7, 0xe1, 0x2e, 0x33, 0xa2, 0x5b, 0x9d, 0x6d, 0xf6, 0x8f, 0xfd, 0x61, - 0xbf, 0x38, 0xb3, 0xc5, 0x07, 0x6f, 0x3e, 0xe9, 0x2f, 0xd9, 0x2e, 0x6d, 0xdb, 0xf2, 0x96, 0x15, - 0xd4, 0x76, 0x96, 0x77, 0x7b, 0x5a, 0xb4, 0x68, 0x6a, 0x48, 0x35, 0xd7, 0x23, 0x49, 0x38, 0x8f, - 0x87, 0x38, 0x2d, 0xab, 0xb6, 0x63, 0x3b, 0xc4, 0xdb, 0x0b, 0x7b, 0xdd, 0x22, 0x81, 0x95, 0x54, - 0x6b, 0xb9, 0x5f, 0x2d, 0xaf, 0xe3, 0x04, 0x76, 0x8b, 0xf4, 0x54, 0xf8, 0xbf, 0x87, 0x55, 0xf0, - 0x6b, 0x3b, 0xa4, 0x65, 0xf5, 0xd4, 0x7b, 0xac, 0x5f, 0xbd, 0x4e, 0x60, 0x37, 0x97, 0x6d, 0x27, - 0xf0, 0x03, 0x2f, 0x5e, 0xc9, 0xfc, 0x46, 0x16, 0x0a, 0xa5, 0xf5, 0x72, 0x35, 0xb0, 0x82, 0x8e, - 0x8f, 0x5e, 0x33, 0x60, 0xaa, 0xe9, 0x5a, 0xf5, 0xb2, 0xd5, 0xb4, 0x9c, 0x1a, 0xf1, 0x16, 0x8c, - 0x07, 0x8c, 0x87, 0x27, 0x1f, 0x5d, 0x5f, 0x1a, 0x65, 0xbe, 0x96, 0x4a, 0xb7, 0x7c, 0x4c, 0x7c, - 0xb7, 0xe3, 0xd5, 0x08, 0x26, 0xdb, 0xe5, 0xf9, 0x6f, 0x77, 0x8b, 0xf7, 0xec, 0x77, 0x8b, 0x53, - 0xeb, 0x1a, 0x27, 0x1c, 0xe1, 0x8b, 0xbe, 0x68, 0xc0, 0x5c, 0xcd, 0x72, 0x2c, 0x6f, 0x6f, 0xd3, - 0xf2, 0x1a, 0x24, 0x78, 0xd6, 0x73, 0x3b, 0xed, 0x85, 0xcc, 0x31, 0xb4, 0xe6, 0x5e, 0xd1, 0x9a, - 0xb9, 0x95, 0x38, 0x3b, 0xdc, 0xdb, 0x02, 0xd6, 0x2e, 0x3f, 0xb0, 0xb6, 0x9a, 0x44, 0x6f, 0x57, - 0xf6, 0x38, 0xdb, 0x55, 0x8d, 0xb3, 0xc3, 0xbd, 0x2d, 0x30, 0x5f, 0xcd, 0xc2, 0x5c, 0x69, 0xbd, - 0xbc, 0xe9, 0x59, 0xdb, 0xdb, 0x76, 0x0d, 0xbb, 0x9d, 0xc0, 0x76, 0x1a, 0xe8, 0x9d, 0x30, 0x61, - 0x3b, 0x0d, 0x8f, 0xf8, 0x3e, 0x9b, 0xc8, 0x42, 0x79, 0x46, 0x10, 0x9d, 0x58, 0xe3, 0xc5, 0x58, - 0xc2, 0xd1, 0x13, 0x30, 0xe9, 0x13, 0x6f, 0xd7, 0xae, 0x91, 0x8a, 0xeb, 0x05, 0x6c, 0xa4, 0x73, - 0xe5, 0x93, 0x02, 0x7d, 0xb2, 0x1a, 0x82, 0xb0, 0x8e, 0x47, 0xab, 0x79, 0xae, 0x1b, 0x08, 0x38, - 0x1b, 0x88, 0x42, 0x58, 0x0d, 0x87, 0x20, 0xac, 0xe3, 0xa1, 0xd7, 0x0d, 0x98, 0xf5, 0x03, 0xbb, - 0x76, 0xd3, 0x76, 0x88, 0xef, 0xaf, 0xb8, 0xce, 0xb6, 0xdd, 0x58, 0xc8, 0xb1, 0x51, 0xbc, 0x34, - 0xda, 0x28, 0x56, 0x63, 0x54, 0xcb, 0xf3, 0xfb, 0xdd, 0xe2, 0x6c, 0xbc, 0x14, 0xf7, 0x70, 0x47, - 0xab, 0x30, 0x6b, 0x39, 0x8e, 0x1b, 0x58, 0x81, 0xed, 0x3a, 0x15, 0x8f, 0x6c, 0xdb, 0xb7, 0x17, - 0xc6, 0x58, 0x77, 0x16, 0x44, 0x77, 0x66, 0x4b, 0x31, 0x38, 0xee, 0xa9, 0x61, 0xae, 0xc2, 0x42, - 0xa9, 0xb5, 0x65, 0xf9, 0xbe, 0x55, 0x77, 0xbd, 0xd8, 0x6c, 0x3c, 0x0c, 0xf9, 0x96, 0xd5, 0x6e, - 0xdb, 0x4e, 0x83, 0x4e, 0x47, 0xf6, 0xe1, 0x42, 0x79, 0x6a, 0xbf, 0x5b, 0xcc, 0x6f, 0x88, 0x32, - 0xac, 0xa0, 0xe6, 0x0f, 0x33, 0x30, 0x59, 0x72, 0xac, 0xe6, 0x9e, 0x6f, 0xfb, 0xb8, 0xe3, 0xa0, - 0x8f, 0x42, 0x9e, 0x9e, 0x2e, 0x75, 0x2b, 0xb0, 0xc4, 0x8e, 0x7c, 0xf7, 0x12, 0xdf, 0xec, 0x4b, - 0xfa, 0x66, 0x0f, 0xc7, 0x85, 0x62, 0x2f, 0xed, 0xbe, 0x67, 0xe9, 0xf2, 0xd6, 0x0d, 0x52, 0x0b, - 0x36, 0x48, 0x60, 0x95, 0x91, 0xe8, 0x05, 0x84, 0x65, 0x58, 0x51, 0x45, 0x2e, 0x8c, 0xf9, 0x6d, - 0x52, 0x13, 0x3b, 0x6c, 0x63, 0xc4, 0x95, 0x1c, 0x36, 0xbd, 0xda, 0x26, 0xb5, 0xf2, 0x94, 0x60, - 0x3d, 0x46, 0xff, 0x61, 0xc6, 0x08, 0xdd, 0x82, 0x71, 0x9f, 0x9d, 0x39, 0x62, 0xf3, 0x5c, 0x4e, - 0x8f, 0x25, 0x23, 0x5b, 0x9e, 0x16, 0x4c, 0xc7, 0xf9, 0x7f, 0x2c, 0xd8, 0x99, 0x7f, 0x6f, 0xc0, - 0x49, 0x0d, 0xbb, 0xe4, 0x35, 0x3a, 0x2d, 0xe2, 0x04, 0xe8, 0x01, 0x18, 0x73, 0xac, 0x16, 0x11, - 0x1b, 0x45, 0x35, 0xf9, 0x92, 0xd5, 0x22, 0x98, 0x41, 0xd0, 0x83, 0x90, 0xdb, 0xb5, 0x9a, 0x1d, - 0xc2, 0x06, 0xa9, 0x50, 0x3e, 0x21, 0x50, 0x72, 0xd7, 0x68, 0x21, 0xe6, 0x30, 0xf4, 0x12, 0x14, - 0xd8, 0x8f, 0xf3, 0x9e, 0xdb, 0x4a, 0xa9, 0x6b, 0xa2, 0x85, 0xd7, 0x24, 0xd9, 0xf2, 0x89, 0xfd, - 0x6e, 0xb1, 0xa0, 0xfe, 0xe2, 0x90, 0xa1, 0xf9, 0x0f, 0x06, 0xcc, 0x68, 0x9d, 0x5b, 0xb7, 0xfd, - 0x00, 0x7d, 0xa8, 0x67, 0xf1, 0x2c, 0x0d, 0xb6, 0x78, 0x68, 0x6d, 0xb6, 0x74, 0x66, 0x45, 0x4f, - 0xf3, 0xb2, 0x44, 0x5b, 0x38, 0x0e, 0xe4, 0xec, 0x80, 0xb4, 0xfc, 0x85, 0xcc, 0x03, 0xd9, 0x87, - 0x27, 0x1f, 0x5d, 0x4b, 0x6d, 0x1a, 0xc3, 0xf1, 0x5d, 0xa3, 0xf4, 0x31, 0x67, 0x63, 0x7e, 0x75, - 0x2c, 0xd2, 0x43, 0xba, 0xa2, 0x90, 0x0b, 0x13, 0x2d, 0x12, 0x78, 0x76, 0x8d, 0xef, 0xab, 0xc9, - 0x47, 0x57, 0x47, 0x6b, 0xc5, 0x06, 0x23, 0x16, 0x1e, 0x96, 0xfc, 0xbf, 0x8f, 0x25, 0x17, 0xb4, - 0x03, 0x63, 0x96, 0xd7, 0x90, 0x7d, 0x3e, 0x9f, 0xce, 0xfc, 0x86, 0x6b, 0xae, 0xe4, 0x35, 0x7c, - 0xcc, 0x38, 0xa0, 0x65, 0x28, 0x04, 0xc4, 0x6b, 0xd9, 0x8e, 0x15, 0xf0, 0xd3, 0x35, 0x5f, 0x9e, - 0x13, 0x68, 0x85, 0x4d, 0x09, 0xc0, 0x21, 0x0e, 0x6a, 0xc2, 0x78, 0xdd, 0xdb, 0xc3, 0x1d, 0x67, - 0x61, 0x2c, 0x8d, 0xa1, 0x58, 0x65, 0xb4, 0xc2, 0xcd, 0xc4, 0xff, 0x63, 0xc1, 0x03, 0xbd, 0x61, - 0xc0, 0x7c, 0x8b, 0x58, 0x7e, 0xc7, 0x23, 0xb4, 0x0b, 0x98, 0x04, 0xc4, 0xa1, 0xa7, 0xe1, 0x42, - 0x8e, 0x31, 0xc7, 0xa3, 0xce, 0x43, 0x2f, 0xe5, 0xf2, 0xfd, 0xa2, 0x29, 0xf3, 0x49, 0x50, 0x9c, - 0xd8, 0x1a, 0xf3, 0x87, 0x63, 0x30, 0xd7, 0x73, 0x42, 0xa0, 0xc7, 0x21, 0xd7, 0xde, 0xb1, 0x7c, - 0xb9, 0xe5, 0xcf, 0xca, 0xf5, 0x56, 0xa1, 0x85, 0x77, 0xba, 0xc5, 0x13, 0xb2, 0x0a, 0x2b, 0xc0, - 0x1c, 0x99, 0xca, 0xd4, 0x16, 0xf1, 0x7d, 0xab, 0x21, 0xcf, 0x01, 0x6d, 0x99, 0xb0, 0x62, 0x2c, - 0xe1, 0xe8, 0x57, 0x0c, 0x38, 0xc1, 0x97, 0x0c, 0x26, 0x7e, 0xa7, 0x19, 0xd0, 0xb3, 0x8e, 0x0e, - 0xcb, 0xc5, 0x34, 0x96, 0x27, 0x27, 0x59, 0x3e, 0x25, 0xb8, 0x9f, 0xd0, 0x4b, 0x7d, 0x1c, 0xe5, - 0x8b, 0xae, 0x43, 0xc1, 0x0f, 0x2c, 0x2f, 0x20, 0xf5, 0x52, 0xc0, 0xa4, 0xda, 0xe4, 0xa3, 0xff, - 0x7b, 0xb0, 0x43, 0x60, 0xd3, 0x6e, 0x11, 0x7e, 0xe0, 0x54, 0x25, 0x01, 0x1c, 0xd2, 0x42, 0x2f, - 0x01, 0x78, 0x1d, 0xa7, 0xda, 0x69, 0xb5, 0x2c, 0x6f, 0x4f, 0x48, 0xf0, 0x0b, 0xa3, 0x75, 0x0f, - 0x2b, 0x7a, 0xa1, 0xcc, 0x0a, 0xcb, 0xb0, 0xc6, 0x0f, 0xbd, 0x62, 0xc0, 0x09, 0xbe, 0x12, 0x65, - 0x0b, 0xc6, 0x53, 0x6e, 0xc1, 0x1c, 0x1d, 0xda, 0x55, 0x9d, 0x05, 0x8e, 0x72, 0x34, 0xff, 0x36, - 0x2a, 0x4f, 0xaa, 0x01, 0xd5, 0xae, 0x1b, 0x7b, 0xe8, 0x83, 0x70, 0xaf, 0xdf, 0xa9, 0xd5, 0x88, - 0xef, 0x6f, 0x77, 0x9a, 0xb8, 0xe3, 0x5c, 0xb0, 0xfd, 0xc0, 0xf5, 0xf6, 0xd6, 0xed, 0x96, 0x1d, - 0xb0, 0x15, 0x97, 0x2b, 0x9f, 0xd9, 0xef, 0x16, 0xef, 0xad, 0xf6, 0x43, 0xc2, 0xfd, 0xeb, 0x23, - 0x0b, 0xee, 0xeb, 0x38, 0xfd, 0xc9, 0x73, 0xed, 0xad, 0xb8, 0xdf, 0x2d, 0xde, 0x77, 0xb5, 0x3f, - 0x1a, 0x3e, 0x88, 0x86, 0xf9, 0x2f, 0x06, 0xcc, 0xca, 0x7e, 0x6d, 0x92, 0x56, 0xbb, 0x49, 0x4f, - 0x97, 0xe3, 0x57, 0x44, 0x82, 0x88, 0x22, 0x82, 0xd3, 0x11, 0x27, 0xb2, 0xfd, 0xfd, 0xb4, 0x11, - 0xf3, 0x9f, 0x0d, 0x98, 0x8f, 0x23, 0xdf, 0x05, 0xe1, 0xe9, 0x47, 0x85, 0xe7, 0xa5, 0x74, 0x7b, - 0xdb, 0x47, 0x82, 0xbe, 0x36, 0xd6, 0xdb, 0xd7, 0xff, 0xee, 0x62, 0x34, 0x94, 0x8a, 0xd9, 0x9f, - 0xa7, 0x54, 0x1c, 0x7b, 0x4b, 0x49, 0xc5, 0xdf, 0x1f, 0x83, 0xa9, 0x92, 0x13, 0xd8, 0xa5, 0xed, - 0x6d, 0xdb, 0xb1, 0x83, 0x3d, 0xf4, 0x99, 0x0c, 0x2c, 0xb7, 0x3d, 0xb2, 0x4d, 0x3c, 0x8f, 0xd4, - 0x57, 0x3b, 0x9e, 0xed, 0x34, 0xaa, 0xb5, 0x1d, 0x52, 0xef, 0x34, 0x6d, 0xa7, 0xb1, 0xd6, 0x70, - 0x5c, 0x55, 0x7c, 0xee, 0x36, 0xa9, 0x75, 0x58, 0x97, 0xf8, 0xa6, 0x68, 0x8d, 0xd6, 0xa5, 0xca, - 0x70, 0x4c, 0xcb, 0x8f, 0xed, 0x77, 0x8b, 0xcb, 0x43, 0x56, 0xc2, 0xc3, 0x76, 0x0d, 0x7d, 0x3a, - 0x03, 0x4b, 0x1e, 0xf9, 0x58, 0xc7, 0x1e, 0x7c, 0x34, 0xf8, 0xa9, 0xd5, 0x1c, 0x51, 0xfc, 0x0c, - 0xc5, 0xb3, 0xfc, 0xe8, 0x7e, 0xb7, 0x38, 0x64, 0x1d, 0x3c, 0x64, 0xbf, 0xcc, 0xaf, 0x67, 0xe0, - 0x54, 0xa9, 0xdd, 0xde, 0x20, 0xfe, 0x4e, 0xec, 0x52, 0xfb, 0x39, 0x03, 0xa6, 0x77, 0x6d, 0x2f, - 0xe8, 0x58, 0x4d, 0x69, 0x04, 0xe0, 0x4b, 0xa2, 0x3a, 0xe2, 0x76, 0xe6, 0xdc, 0xae, 0x45, 0x48, - 0x97, 0xd1, 0x7e, 0xb7, 0x38, 0x1d, 0x2d, 0xc3, 0x31, 0xf6, 0xe8, 0x37, 0x0d, 0x98, 0x15, 0x45, - 0x97, 0xdc, 0x3a, 0xd1, 0x2d, 0x47, 0x57, 0xd3, 0x6c, 0x93, 0x22, 0xce, 0x4d, 0x0c, 0xf1, 0x52, - 0xdc, 0xd3, 0x08, 0xf3, 0xdf, 0x32, 0x70, 0xba, 0x0f, 0x0d, 0xf4, 0x7b, 0x06, 0xcc, 0x73, 0x73, - 0x93, 0x06, 0xc2, 0x64, 0x5b, 0x8c, 0xe6, 0x07, 0xd2, 0x6e, 0x39, 0xa6, 0x7b, 0x81, 0x38, 0x35, - 0x52, 0x5e, 0xa0, 0xc7, 0xc6, 0x4a, 0x02, 0x6b, 0x9c, 0xd8, 0x20, 0xd6, 0x52, 0x6e, 0x80, 0x8a, - 0xb5, 0x34, 0x73, 0x57, 0x5a, 0x5a, 0x4d, 0x60, 0x8d, 0x13, 0x1b, 0x64, 0xfe, 0x7f, 0xb8, 0xef, - 0x00, 0x72, 0x87, 0xdf, 0xf8, 0xcd, 0x17, 0xd4, 0xaa, 0x8f, 0xae, 0xb9, 0x01, 0x8c, 0x05, 0x26, - 0x8c, 0x7b, 0x6e, 0x27, 0x20, 0x5c, 0xba, 0x15, 0xca, 0x40, 0xe5, 0x04, 0x66, 0x25, 0x58, 0x40, - 0xcc, 0xaf, 0x1b, 0x90, 0x1f, 0xc2, 0xfe, 0x50, 0x8c, 0xda, 0x1f, 0x0a, 0x3d, 0xb6, 0x87, 0xa0, - 0xd7, 0xf6, 0xf0, 0xec, 0x68, 0xb3, 0x31, 0x88, 0xcd, 0xe1, 0x27, 0x06, 0xcc, 0xf5, 0xd8, 0x28, - 0xd0, 0x0e, 0xcc, 0xb7, 0xdd, 0xba, 0xd4, 0x2f, 0x2e, 0x58, 0xfe, 0x0e, 0x83, 0x89, 0xee, 0x3d, - 0x4e, 0x67, 0xb2, 0x92, 0x00, 0xbf, 0xd3, 0x2d, 0x2e, 0x28, 0x22, 0x31, 0x04, 0x9c, 0x48, 0x11, - 0xb5, 0x21, 0xbf, 0x6d, 0x93, 0x66, 0x3d, 0x5c, 0x82, 0x23, 0x6a, 0x12, 0xe7, 0x05, 0x35, 0x6e, - 0x9e, 0x93, 0xff, 0xb0, 0xe2, 0x62, 0x5e, 0x81, 0xe9, 0xa8, 0xb1, 0x76, 0x80, 0xc9, 0x3b, 0x03, - 0x59, 0xcb, 0x73, 0xc4, 0xd4, 0x4d, 0x0a, 0x84, 0x6c, 0x09, 0x5f, 0xc2, 0xb4, 0xdc, 0xfc, 0xd9, - 0x18, 0xcc, 0x94, 0x9b, 0x1d, 0xf2, 0xac, 0x47, 0x88, 0xbc, 0x9f, 0x96, 0x60, 0xa6, 0xed, 0x91, - 0x5d, 0x9b, 0xdc, 0xaa, 0x92, 0x26, 0xa9, 0x05, 0xae, 0x27, 0xe8, 0x9f, 0x16, 0xd5, 0x67, 0x2a, - 0x51, 0x30, 0x8e, 0xe3, 0xa3, 0x67, 0x60, 0xda, 0xaa, 0x05, 0xf6, 0x2e, 0x51, 0x14, 0x78, 0x03, - 0xde, 0x26, 0x28, 0x4c, 0x97, 0x22, 0x50, 0x1c, 0xc3, 0x46, 0x1f, 0x82, 0x05, 0xbf, 0x66, 0x35, - 0xc9, 0xd5, 0xb6, 0x60, 0xb5, 0xb2, 0x43, 0x6a, 0x37, 0x2b, 0xae, 0xed, 0x04, 0xc2, 0x1a, 0xf1, - 0x80, 0xa0, 0xb4, 0x50, 0xed, 0x83, 0x87, 0xfb, 0x52, 0x40, 0x7f, 0x66, 0xc0, 0x99, 0xb6, 0x47, - 0x2a, 0x9e, 0xdb, 0x72, 0xa9, 0x98, 0xe9, 0xb9, 0xa2, 0x8b, 0xab, 0xea, 0xb5, 0x11, 0xe5, 0x29, - 0x2f, 0xe9, 0x35, 0x11, 0xbe, 0x7d, 0xbf, 0x5b, 0x3c, 0x53, 0x39, 0xa8, 0x01, 0xf8, 0xe0, 0xf6, - 0xa1, 0xbf, 0x30, 0xe0, 0x6c, 0xdb, 0xf5, 0x83, 0x03, 0xba, 0x90, 0x3b, 0xd6, 0x2e, 0x98, 0xfb, - 0xdd, 0xe2, 0xd9, 0xca, 0x81, 0x2d, 0xc0, 0x87, 0xb4, 0xd0, 0xdc, 0x9f, 0x84, 0x39, 0x6d, 0xed, - 0x89, 0xfb, 0xeb, 0x53, 0x70, 0x42, 0x2e, 0x86, 0x50, 0xac, 0x17, 0x42, 0x7b, 0x43, 0x49, 0x07, - 0xe2, 0x28, 0x2e, 0x5d, 0x77, 0x6a, 0x29, 0xf2, 0xda, 0xb1, 0x75, 0x57, 0x89, 0x40, 0x71, 0x0c, - 0x1b, 0xad, 0xc1, 0x49, 0x51, 0x82, 0x49, 0xbb, 0x69, 0xd7, 0xac, 0x15, 0xb7, 0x23, 0x96, 0x5c, - 0xae, 0x7c, 0x7a, 0xbf, 0x5b, 0x3c, 0x59, 0xe9, 0x05, 0xe3, 0xa4, 0x3a, 0x68, 0x1d, 0xe6, 0xad, - 0x4e, 0xe0, 0xaa, 0xfe, 0x9f, 0x73, 0xa8, 0xa4, 0xa8, 0xb3, 0xa5, 0x95, 0xe7, 0x22, 0xa5, 0x94, - 0x00, 0xc7, 0x89, 0xb5, 0x50, 0x25, 0x46, 0xad, 0x4a, 0x6a, 0xae, 0x53, 0xe7, 0xb3, 0x9c, 0x0b, - 0xb5, 0xf0, 0x52, 0x02, 0x0e, 0x4e, 0xac, 0x89, 0x9a, 0x30, 0xdd, 0xb2, 0x6e, 0x5f, 0x75, 0xac, - 0x5d, 0xcb, 0x6e, 0x52, 0x26, 0xc2, 0x86, 0xd1, 0xff, 0x62, 0xdd, 0x09, 0xec, 0xe6, 0x12, 0x7f, - 0xce, 0x5b, 0x5a, 0x73, 0x82, 0xcb, 0x5e, 0x35, 0xa0, 0xda, 0x1a, 0x57, 0x8e, 0x36, 0x22, 0xb4, - 0x70, 0x8c, 0x36, 0xba, 0x0c, 0xa7, 0xd8, 0x76, 0x5c, 0x75, 0x6f, 0x39, 0xab, 0xa4, 0x69, 0xed, - 0xc9, 0x0e, 0x4c, 0xb0, 0x0e, 0xdc, 0xbb, 0xdf, 0x2d, 0x9e, 0xaa, 0x26, 0x21, 0xe0, 0xe4, 0x7a, - 0xc8, 0x82, 0xfb, 0xa2, 0x00, 0x4c, 0x76, 0x6d, 0xdf, 0x76, 0x1d, 0x6e, 0x89, 0xc8, 0x87, 0x96, - 0x88, 0x6a, 0x7f, 0x34, 0x7c, 0x10, 0x0d, 0xf4, 0xdb, 0x06, 0xcc, 0x27, 0x6d, 0xc3, 0x85, 0x42, - 0x1a, 0x8f, 0x15, 0xb1, 0xad, 0xc5, 0x57, 0x44, 0xe2, 0xa1, 0x90, 0xd8, 0x08, 0xf4, 0xb2, 0x01, - 0x53, 0x96, 0x76, 0x8b, 0x5a, 0x00, 0xd6, 0xaa, 0x8b, 0xa3, 0xde, 0xe5, 0x43, 0x8a, 0xe5, 0xd9, - 0xfd, 0x6e, 0x31, 0x72, 0x53, 0xc3, 0x11, 0x8e, 0xe8, 0x77, 0x0c, 0x38, 0x95, 0xb8, 0xc7, 0x17, - 0x26, 0x8f, 0x63, 0x84, 0xd8, 0x22, 0x49, 0x3e, 0x73, 0x92, 0x9b, 0x81, 0x5e, 0x37, 0x94, 0x28, - 0xdb, 0x90, 0xd6, 0x94, 0x29, 0xd6, 0xb4, 0x2b, 0x23, 0x5e, 0x1c, 0x43, 0x85, 0x40, 0x12, 0x2e, - 0x9f, 0xd4, 0x24, 0xa3, 0x2c, 0xc4, 0x71, 0xf6, 0xe8, 0xb3, 0x86, 0x14, 0x8d, 0xaa, 0x45, 0x27, - 0x8e, 0xab, 0x45, 0x28, 0x94, 0xb4, 0xaa, 0x41, 0x31, 0xe6, 0xe8, 0xc3, 0xb0, 0x68, 0x6d, 0xb9, - 0x5e, 0x90, 0xb8, 0xf9, 0x16, 0xa6, 0xd9, 0x36, 0x3a, 0xbb, 0xdf, 0x2d, 0x2e, 0x96, 0xfa, 0x62, - 0xe1, 0x03, 0x28, 0x98, 0x7f, 0x94, 0x83, 0x29, 0xae, 0xe4, 0x0b, 0xd1, 0xf5, 0x35, 0x03, 0xee, - 0xaf, 0x75, 0x3c, 0x8f, 0x38, 0x41, 0x35, 0x20, 0xed, 0x5e, 0xc1, 0x65, 0x1c, 0xab, 0xe0, 0x7a, - 0x60, 0xbf, 0x5b, 0xbc, 0x7f, 0xe5, 0x00, 0xfe, 0xf8, 0xc0, 0xd6, 0xa1, 0xbf, 0x36, 0xc0, 0x14, - 0x08, 0x65, 0xab, 0x76, 0xb3, 0xe1, 0xb9, 0x1d, 0xa7, 0xde, 0xdb, 0x89, 0xcc, 0xb1, 0x76, 0xe2, - 0xa1, 0xfd, 0x6e, 0xd1, 0x5c, 0x39, 0xb4, 0x15, 0x78, 0x80, 0x96, 0xa2, 0x67, 0x61, 0x4e, 0x60, - 0x9d, 0xbb, 0xdd, 0x26, 0x9e, 0x4d, 0xd5, 0x69, 0xf1, 0x9e, 0x1e, 0xba, 0x28, 0xc4, 0x11, 0x70, - 0x6f, 0x1d, 0xe4, 0xc3, 0xc4, 0x2d, 0x62, 0x37, 0x76, 0x02, 0xa9, 0x3e, 0x8d, 0xe8, 0x97, 0x20, - 0x2e, 0xfc, 0xd7, 0x39, 0xcd, 0xf2, 0xe4, 0x7e, 0xb7, 0x38, 0x21, 0xfe, 0x60, 0xc9, 0x09, 0x5d, - 0x82, 0x69, 0x7e, 0x05, 0xab, 0xd8, 0x4e, 0xa3, 0xe2, 0x3a, 0xfc, 0x35, 0xbf, 0x50, 0x7e, 0x48, - 0x0a, 0xfc, 0x6a, 0x04, 0x7a, 0xa7, 0x5b, 0x9c, 0x92, 0xbf, 0x37, 0xf7, 0xda, 0x04, 0xc7, 0x6a, - 0x9b, 0xdf, 0x1a, 0x07, 0x90, 0xcb, 0x95, 0xb4, 0xd1, 0xff, 0x81, 0x82, 0x4f, 0x02, 0xce, 0x55, - 0x18, 0xcf, 0xf9, 0x9b, 0x84, 0x2c, 0xc4, 0x21, 0x1c, 0xdd, 0x84, 0x5c, 0xdb, 0xea, 0xf8, 0x44, - 0x4c, 0xfe, 0xc5, 0x54, 0x26, 0xbf, 0x42, 0x29, 0xf2, 0x3b, 0x17, 0xfb, 0x89, 0x39, 0x0f, 0xf4, - 0x29, 0x03, 0x80, 0x44, 0x27, 0x6c, 0x64, 0xdb, 0x87, 0x60, 0x19, 0xce, 0x29, 0x1d, 0x83, 0xf2, - 0xf4, 0x7e, 0xb7, 0x08, 0xda, 0xd4, 0x6b, 0x6c, 0xd1, 0x2d, 0xc8, 0x5b, 0xf2, 0xcc, 0x1f, 0x3b, - 0x8e, 0x33, 0x9f, 0x5d, 0x85, 0xd4, 0xa2, 0x55, 0xcc, 0xd0, 0xa7, 0x0d, 0x98, 0xf6, 0x49, 0x20, - 0xa6, 0x8a, 0x9e, 0x3c, 0x42, 0xe1, 0x1d, 0x71, 0xd1, 0x55, 0x23, 0x34, 0xf9, 0x09, 0x1a, 0x2d, - 0xc3, 0x31, 0xbe, 0xb2, 0x29, 0x17, 0x88, 0x55, 0x27, 0x1e, 0xbb, 0x69, 0x0b, 0x4d, 0x6a, 0xf4, - 0xa6, 0x68, 0x34, 0x55, 0x53, 0xb4, 0x32, 0x1c, 0xe3, 0x2b, 0x9b, 0xb2, 0x61, 0x7b, 0x9e, 0x2b, - 0x9a, 0x92, 0x4f, 0xa9, 0x29, 0x1a, 0x4d, 0xd5, 0x14, 0xad, 0x0c, 0xc7, 0xf8, 0x9a, 0x7f, 0x33, - 0x05, 0xd3, 0x72, 0x23, 0x85, 0x9a, 0x3d, 0x37, 0xec, 0xf4, 0xd1, 0xec, 0x57, 0x74, 0x20, 0x8e, - 0xe2, 0xd2, 0xca, 0x7c, 0xab, 0x46, 0x15, 0x7b, 0x55, 0xb9, 0xaa, 0x03, 0x71, 0x14, 0x17, 0xb5, - 0x20, 0xe7, 0x07, 0xa4, 0x2d, 0xdf, 0x41, 0x47, 0x7c, 0xa6, 0x0b, 0xcf, 0x87, 0xf0, 0xa5, 0x83, - 0xfe, 0xf3, 0x31, 0xe7, 0xc2, 0x6c, 0x93, 0x41, 0xc4, 0x5c, 0x29, 0x36, 0x47, 0x3a, 0xfb, 0x33, - 0x6a, 0x09, 0xe5, 0xb3, 0x11, 0x2d, 0xc3, 0x31, 0xf6, 0x09, 0xca, 0x7e, 0xee, 0x18, 0x95, 0xfd, - 0xe7, 0x21, 0xdf, 0xb2, 0x6e, 0x57, 0x3b, 0x5e, 0xe3, 0xe8, 0x97, 0x0a, 0xe1, 0xa2, 0xc4, 0xa9, - 0x60, 0x45, 0x0f, 0xbd, 0x62, 0x68, 0x47, 0xce, 0x04, 0x23, 0x7e, 0x3d, 0xdd, 0x23, 0x47, 0xc9, - 0xca, 0xbe, 0x87, 0x4f, 0x8f, 0xea, 0x9d, 0xbf, 0xeb, 0xaa, 0x37, 0x55, 0x23, 0xf9, 0x06, 0x51, - 0x6a, 0x64, 0xe1, 0x58, 0xd5, 0xc8, 0x95, 0x08, 0x33, 0x1c, 0x63, 0xce, 0xda, 0xc3, 0xf7, 0x9c, - 0x6a, 0x0f, 0x1c, 0x6b, 0x7b, 0xaa, 0x11, 0x66, 0x38, 0xc6, 0xbc, 0xff, 0x7d, 0x73, 0xf2, 0x78, - 0xee, 0x9b, 0x53, 0x29, 0xdc, 0x37, 0x0f, 0x56, 0xc5, 0x4f, 0x8c, 0xaa, 0x8a, 0xa3, 0x8b, 0x80, - 0xea, 0x7b, 0x8e, 0xd5, 0xb2, 0x6b, 0xe2, 0xb0, 0x64, 0x62, 0x73, 0x9a, 0xd9, 0x23, 0x16, 0xc5, - 0x41, 0x86, 0x56, 0x7b, 0x30, 0x70, 0x42, 0x2d, 0x14, 0x40, 0xbe, 0x2d, 0x35, 0xae, 0x99, 0x34, - 0x56, 0xbf, 0xd4, 0xc0, 0xf8, 0x53, 0x39, 0xdd, 0x78, 0xb2, 0x04, 0x2b, 0x4e, 0xe6, 0x7f, 0x18, - 0x30, 0xbb, 0xd2, 0x74, 0x3b, 0xf5, 0xeb, 0x56, 0x50, 0xdb, 0xe1, 0xef, 0xba, 0xe8, 0x19, 0xc8, - 0xdb, 0x4e, 0x40, 0xbc, 0x5d, 0xab, 0x29, 0x24, 0x8a, 0x29, 0x9f, 0xbe, 0xd7, 0x44, 0xf9, 0x9d, - 0x6e, 0x71, 0x7a, 0xb5, 0xe3, 0x31, 0x87, 0x49, 0x7e, 0xbe, 0x60, 0x55, 0x07, 0x7d, 0xd9, 0x80, - 0x39, 0xfe, 0x32, 0xbc, 0x6a, 0x05, 0xd6, 0x95, 0x0e, 0xf1, 0x6c, 0x22, 0xdf, 0x86, 0x47, 0x3c, - 0x5a, 0xe2, 0x6d, 0x95, 0x0c, 0xf6, 0x42, 0xd5, 0x7a, 0x23, 0xce, 0x19, 0xf7, 0x36, 0xc6, 0xfc, - 0x7c, 0x16, 0xee, 0xed, 0x4b, 0x0b, 0x2d, 0x42, 0xc6, 0xae, 0x8b, 0xae, 0x83, 0xa0, 0x9b, 0x59, - 0xab, 0xe3, 0x8c, 0x5d, 0x47, 0x4b, 0x4c, 0x4b, 0xf4, 0x88, 0xef, 0xcb, 0x67, 0xc2, 0x82, 0x52, - 0xe8, 0x44, 0x29, 0xd6, 0x30, 0x50, 0x11, 0x72, 0x4d, 0x6b, 0x8b, 0x34, 0xc5, 0x0d, 0x80, 0xe9, - 0x9d, 0xeb, 0xb4, 0x00, 0xf3, 0x72, 0xf4, 0xcb, 0x06, 0x00, 0x6f, 0x20, 0xbd, 0x3f, 0x08, 0xb9, - 0x86, 0xd3, 0x1d, 0x26, 0x4a, 0x99, 0xb7, 0x32, 0xfc, 0x8f, 0x35, 0xae, 0x68, 0x13, 0xc6, 0xa9, - 0x0a, 0xea, 0xd6, 0x8f, 0x2c, 0xc6, 0xd8, 0xb3, 0x48, 0x85, 0xd1, 0xc0, 0x82, 0x16, 0x1d, 0x2b, - 0x8f, 0x04, 0x1d, 0xcf, 0xa1, 0x43, 0xcb, 0x04, 0x57, 0x9e, 0xb7, 0x02, 0xab, 0x52, 0xac, 0x61, - 0x98, 0x7f, 0x9a, 0x81, 0xf9, 0xa4, 0xa6, 0x53, 0xf9, 0x30, 0xce, 0x5b, 0x2b, 0x2e, 0xb3, 0xef, - 0x4f, 0x7f, 0x7c, 0x84, 0x93, 0x83, 0x72, 0x05, 0x10, 0x6e, 0x58, 0x82, 0x2f, 0x7a, 0xbf, 0x1a, - 0xa1, 0xcc, 0x11, 0x47, 0x48, 0x51, 0x8e, 0x8d, 0xd2, 0x03, 0x30, 0xe6, 0xd3, 0x99, 0xcf, 0x46, - 0x9f, 0x1c, 0xd8, 0x1c, 0x31, 0x08, 0xc5, 0xe8, 0x38, 0x76, 0x20, 0xbc, 0x98, 0x15, 0xc6, 0x55, - 0xc7, 0x0e, 0x30, 0x83, 0x98, 0x5f, 0xcc, 0xc0, 0x62, 0xff, 0x4e, 0xa1, 0x2f, 0x1a, 0x00, 0x75, - 0x7a, 0xc1, 0xa0, 0x4b, 0x52, 0x3a, 0x85, 0x58, 0xc7, 0x35, 0x86, 0xab, 0x92, 0x53, 0xe8, 0x21, - 0xa4, 0x8a, 0x7c, 0xac, 0x35, 0x04, 0x3d, 0x2a, 0x97, 0xfe, 0x25, 0xab, 0x25, 0x15, 0x50, 0x55, - 0x67, 0x43, 0x41, 0xb0, 0x86, 0x45, 0x6f, 0x90, 0x8e, 0xd5, 0x22, 0x7e, 0xdb, 0x52, 0x6e, 0xea, - 0xec, 0x06, 0x79, 0x49, 0x16, 0xe2, 0x10, 0x6e, 0x36, 0xe1, 0xc1, 0x01, 0xda, 0x99, 0x92, 0xcb, - 0xb0, 0xf9, 0xef, 0x06, 0x9c, 0x5e, 0x69, 0x76, 0xfc, 0x80, 0x78, 0xff, 0x63, 0x1c, 0xae, 0xfe, - 0xd3, 0x80, 0xfb, 0xfa, 0xf4, 0xf9, 0x2e, 0xf8, 0x5d, 0xbd, 0x18, 0xf5, 0xbb, 0xba, 0x3a, 0xea, - 0x92, 0x4e, 0xec, 0x47, 0x1f, 0xf7, 0xab, 0x00, 0x4e, 0xd0, 0x53, 0xab, 0xee, 0x36, 0x52, 0x92, - 0x9b, 0x0f, 0x42, 0xee, 0x63, 0x54, 0xfe, 0xc4, 0xd7, 0x18, 0x13, 0x4a, 0x98, 0xc3, 0xcc, 0xa7, - 0x41, 0x38, 0x29, 0xc5, 0x36, 0x8f, 0x31, 0xc8, 0xe6, 0x31, 0xff, 0x2e, 0x03, 0x9a, 0xe5, 0xe1, - 0x2e, 0x2c, 0x4a, 0x27, 0xb2, 0x28, 0x47, 0xbc, 0x35, 0x6b, 0x76, 0x94, 0x7e, 0xd1, 0x08, 0xbb, - 0xb1, 0x68, 0x84, 0x4b, 0xa9, 0x71, 0x3c, 0x38, 0x18, 0xe1, 0xfb, 0x06, 0xdc, 0x17, 0x22, 0xf7, - 0x1a, 0x05, 0x0f, 0x3f, 0x61, 0x9e, 0x80, 0x49, 0x2b, 0xac, 0x26, 0xd6, 0x80, 0x0a, 0xc0, 0xd1, - 0x28, 0x62, 0x1d, 0x2f, 0xf4, 0x7d, 0xce, 0x1e, 0xd1, 0xf7, 0x79, 0xec, 0x60, 0xdf, 0x67, 0xf3, - 0xa7, 0x19, 0x38, 0xd3, 0xdb, 0x33, 0xb9, 0x37, 0x06, 0x7b, 0x33, 0x7f, 0x12, 0xa6, 0x02, 0x51, - 0x41, 0x3b, 0xe9, 0x55, 0xf8, 0xd8, 0xa6, 0x06, 0xc3, 0x11, 0x4c, 0x5a, 0xb3, 0xc6, 0x77, 0x65, - 0xb5, 0xe6, 0xb6, 0xa5, 0xe7, 0xbc, 0xaa, 0xb9, 0xa2, 0xc1, 0x70, 0x04, 0x53, 0xf9, 0x24, 0x8e, - 0x1d, 0xbb, 0x4f, 0x62, 0x15, 0x4e, 0x49, 0x2f, 0xac, 0xf3, 0xae, 0xb7, 0xe2, 0xb6, 0xda, 0x4d, - 0x22, 0x7c, 0xe7, 0x69, 0x63, 0xcf, 0x88, 0x2a, 0xa7, 0x70, 0x12, 0x12, 0x4e, 0xae, 0x6b, 0x7e, - 0x3f, 0x0b, 0x27, 0xc3, 0x61, 0x5f, 0x71, 0x9d, 0xba, 0xcd, 0x7c, 0xd9, 0x9e, 0x82, 0xb1, 0x60, - 0xaf, 0x2d, 0x07, 0xfb, 0x7f, 0xc9, 0xe6, 0x6c, 0xee, 0xb5, 0xe9, 0x6c, 0x9f, 0x4e, 0xa8, 0xc2, - 0xcc, 0xb2, 0xac, 0x12, 0x5a, 0x57, 0xbb, 0x83, 0xcf, 0xc0, 0xe3, 0xd1, 0xd5, 0x7c, 0xa7, 0x5b, - 0x4c, 0x88, 0x9e, 0x5c, 0x52, 0x94, 0xa2, 0x6b, 0x1e, 0xdd, 0x80, 0xe9, 0xa6, 0xe5, 0x07, 0x57, - 0xdb, 0x75, 0x2b, 0x20, 0x9b, 0x76, 0x8b, 0x88, 0x3d, 0x37, 0x8c, 0x43, 0xba, 0x7a, 0x47, 0x5e, - 0x8f, 0x50, 0xc2, 0x31, 0xca, 0x68, 0x17, 0x10, 0x2d, 0xd9, 0xf4, 0x2c, 0xc7, 0xe7, 0xbd, 0xa2, - 0xfc, 0x86, 0x77, 0x80, 0x57, 0xd7, 0xb2, 0xf5, 0x1e, 0x6a, 0x38, 0x81, 0x03, 0x7a, 0x08, 0xc6, - 0x3d, 0x62, 0xf9, 0x62, 0x32, 0x0b, 0xe1, 0xfe, 0xc7, 0xac, 0x14, 0x0b, 0xa8, 0xbe, 0xa1, 0xc6, - 0x0f, 0xd9, 0x50, 0x3f, 0x32, 0x60, 0x3a, 0x9c, 0xa6, 0xbb, 0x20, 0x24, 0x5b, 0x51, 0x21, 0x79, - 0x21, 0xad, 0x23, 0xb1, 0x8f, 0x5c, 0xfc, 0xcb, 0x71, 0xbd, 0x7f, 0xcc, 0x21, 0xf9, 0xe3, 0x50, - 0x90, 0xbb, 0x5a, 0x6a, 0x9f, 0x23, 0xde, 0x6e, 0x23, 0x7a, 0x89, 0x16, 0x48, 0x23, 0x98, 0xe0, - 0x90, 0x1f, 0x15, 0xcb, 0x75, 0x21, 0x72, 0xc5, 0xb2, 0x57, 0x62, 0x59, 0x8a, 0xe2, 0x24, 0xb1, - 0x2c, 0xeb, 0xa0, 0xab, 0x70, 0xba, 0xed, 0xb9, 0x2c, 0xb8, 0x72, 0x95, 0x58, 0xf5, 0xa6, 0xed, - 0x10, 0x69, 0x42, 0xe0, 0x6e, 0x0c, 0xf7, 0xed, 0x77, 0x8b, 0xa7, 0x2b, 0xc9, 0x28, 0xb8, 0x5f, - 0xdd, 0x68, 0x40, 0xd0, 0xd8, 0x00, 0x01, 0x41, 0xbf, 0xaa, 0x0c, 0x75, 0xc4, 0x17, 0x61, 0x39, - 0x1f, 0x4c, 0x6b, 0x2a, 0x13, 0x8e, 0xf5, 0x70, 0x49, 0x95, 0x04, 0x53, 0xac, 0xd8, 0xf7, 0xb7, - 0x06, 0x8d, 0x1f, 0xd1, 0x1a, 0x14, 0xfa, 0x75, 0x4f, 0xfc, 0x3c, 0xfd, 0xba, 0xf3, 0x6f, 0x29, - 0xbf, 0xee, 0x57, 0x73, 0x30, 0x1b, 0xd7, 0x40, 0x8e, 0x3f, 0xd8, 0xe9, 0x37, 0x0c, 0x98, 0x95, - 0xbb, 0x87, 0xf3, 0x24, 0xd2, 0xce, 0xbf, 0x9e, 0xd2, 0xa6, 0xe5, 0xba, 0x94, 0x0a, 0xc7, 0xdd, - 0x8c, 0x71, 0xc3, 0x3d, 0xfc, 0xd1, 0x0b, 0x30, 0xa9, 0xcc, 0xe1, 0x47, 0x8a, 0x7c, 0x9a, 0x61, - 0x5a, 0x54, 0x48, 0x02, 0xeb, 0xf4, 0xd0, 0xab, 0x06, 0x40, 0x4d, 0x8a, 0x39, 0xb9, 0xbb, 0xae, - 0xa4, 0xb5, 0xbb, 0x94, 0x00, 0x0d, 0x95, 0x65, 0x55, 0xe4, 0x63, 0x8d, 0x31, 0xfa, 0x3c, 0x33, - 0x84, 0x2b, 0xed, 0x8e, 0xee, 0xa7, 0xec, 0xe8, 0xae, 0xb8, 0x07, 0x28, 0xa6, 0xa1, 0x2a, 0xa5, - 0x81, 0x7c, 0x1c, 0x69, 0x84, 0xf9, 0x14, 0x28, 0xe7, 0x49, 0x7a, 0x6c, 0x31, 0xf7, 0xc9, 0x8a, - 0x15, 0xec, 0x88, 0x25, 0xa8, 0x8e, 0xad, 0xf3, 0x12, 0x80, 0x43, 0x1c, 0xf3, 0xa3, 0x30, 0xfd, - 0xac, 0x67, 0xb5, 0x77, 0x6c, 0x66, 0x70, 0xa6, 0xf7, 0xa4, 0x77, 0xc2, 0x84, 0x55, 0xaf, 0x27, - 0x05, 0xb3, 0x97, 0x78, 0x31, 0x96, 0xf0, 0xc1, 0xae, 0x44, 0xdf, 0x32, 0x00, 0x85, 0x8f, 0x76, - 0xb6, 0xd3, 0xd8, 0xa0, 0xb7, 0x7d, 0x7a, 0x3f, 0xda, 0x61, 0xa5, 0x49, 0xf7, 0xa3, 0x0b, 0x0a, - 0x82, 0x35, 0x2c, 0xf4, 0x12, 0x4c, 0xf2, 0x7f, 0xd7, 0xd4, 0x65, 0x7f, 0xe4, 0x50, 0x58, 0x2e, - 0x50, 0x58, 0x9b, 0xf8, 0x2a, 0xbc, 0x10, 0x72, 0xc0, 0x3a, 0x3b, 0x3a, 0x54, 0x6b, 0xce, 0x76, - 0xb3, 0x73, 0xbb, 0xbe, 0x15, 0x0e, 0x55, 0xdb, 0x73, 0xb7, 0xed, 0x26, 0x89, 0x0f, 0x55, 0x85, - 0x17, 0x63, 0x09, 0x1f, 0x6c, 0xa8, 0xbe, 0x61, 0xc0, 0xfc, 0x9a, 0x1f, 0xd8, 0xee, 0x2a, 0xf1, - 0x03, 0x2a, 0x56, 0xe8, 0xe1, 0xd3, 0x69, 0x0e, 0xe2, 0x07, 0xbd, 0x0a, 0xb3, 0xe2, 0x01, 0xb1, - 0xb3, 0xe5, 0x93, 0x40, 0xd3, 0xe3, 0xd5, 0x3e, 0x5e, 0x89, 0xc1, 0x71, 0x4f, 0x0d, 0x4a, 0x45, - 0xbc, 0x24, 0x86, 0x54, 0xb2, 0x51, 0x2a, 0xd5, 0x18, 0x1c, 0xf7, 0xd4, 0x30, 0xbf, 0x9b, 0x85, - 0x93, 0xac, 0x1b, 0xb1, 0x18, 0x86, 0xcf, 0xf6, 0x8b, 0x61, 0x18, 0x71, 0x2b, 0x33, 0x5e, 0x47, - 0x88, 0x60, 0xf8, 0x75, 0x03, 0x66, 0xea, 0xd1, 0x91, 0x4e, 0xc7, 0x3c, 0x93, 0x34, 0x87, 0xdc, - 0x5f, 0x2a, 0x56, 0x88, 0xe3, 0xfc, 0xd1, 0x17, 0x0c, 0x98, 0x89, 0x36, 0x53, 0x9e, 0xee, 0xc7, - 0x30, 0x48, 0xca, 0xc1, 0x39, 0x5a, 0xee, 0xe3, 0x78, 0x13, 0xcc, 0xef, 0x64, 0xc4, 0x94, 0x1e, - 0x87, 0x83, 0x3e, 0xba, 0x05, 0x85, 0xa0, 0xe9, 0xf3, 0x42, 0xd1, 0xdb, 0x11, 0x6f, 0x84, 0x9b, - 0xeb, 0x55, 0xfe, 0x76, 0x1f, 0x2a, 0x6d, 0xa2, 0x84, 0x2a, 0x9f, 0x92, 0x17, 0x63, 0x5c, 0x6b, - 0x0b, 0xc6, 0xa9, 0x5c, 0x45, 0x37, 0x57, 0x2a, 0x71, 0xc6, 0xa2, 0x84, 0x32, 0x96, 0xbc, 0xcc, - 0xaf, 0x18, 0x50, 0xb8, 0xe8, 0xca, 0x73, 0xe4, 0xc3, 0x29, 0x18, 0x7a, 0x94, 0x3e, 0xa8, 0xde, - 0x08, 0xc3, 0x2b, 0xc6, 0x33, 0x11, 0x33, 0xcf, 0xfd, 0x1a, 0xed, 0x25, 0x96, 0xa8, 0x87, 0x92, - 0xba, 0xe8, 0x6e, 0xf5, 0xb5, 0x22, 0xfe, 0x6e, 0x0e, 0x4e, 0x3c, 0x67, 0xed, 0x11, 0x27, 0xb0, - 0x86, 0x17, 0x12, 0x4f, 0xc0, 0xa4, 0xd5, 0x66, 0x8e, 0xc2, 0x9a, 0x8e, 0x1f, 0x5a, 0x4e, 0x42, - 0x10, 0xd6, 0xf1, 0xc2, 0x03, 0x8d, 0xe7, 0x0d, 0x49, 0x3a, 0x8a, 0x56, 0x62, 0x70, 0xdc, 0x53, - 0x03, 0x5d, 0x04, 0x24, 0xa2, 0x20, 0x4b, 0xb5, 0x9a, 0xdb, 0x71, 0xf8, 0x91, 0xc6, 0x8d, 0x2a, - 0xea, 0xb2, 0xb9, 0xd1, 0x83, 0x81, 0x13, 0x6a, 0xa1, 0x0f, 0xc1, 0x42, 0x8d, 0x51, 0x16, 0x57, - 0x0f, 0x9d, 0x22, 0xbf, 0x7e, 0x2a, 0x27, 0xfd, 0x95, 0x3e, 0x78, 0xb8, 0x2f, 0x05, 0xda, 0x52, - 0x3f, 0x70, 0x3d, 0xab, 0x41, 0x74, 0xba, 0xe3, 0xd1, 0x96, 0x56, 0x7b, 0x30, 0x70, 0x42, 0x2d, - 0xf4, 0x49, 0x28, 0x04, 0x3b, 0x1e, 0xf1, 0x77, 0xdc, 0x66, 0x5d, 0x38, 0x0d, 0x8c, 0x68, 0x69, - 0x13, 0xb3, 0xbf, 0x29, 0xa9, 0x6a, 0xcb, 0x5b, 0x16, 0xe1, 0x90, 0x27, 0xf2, 0x60, 0xdc, 0xaf, - 0xb9, 0x6d, 0xe2, 0x0b, 0x95, 0xfd, 0x62, 0x2a, 0xdc, 0x99, 0xe5, 0x48, 0xb3, 0xf1, 0x31, 0x0e, - 0x58, 0x70, 0x32, 0xbf, 0x99, 0x81, 0x29, 0x1d, 0x71, 0x80, 0xb3, 0xe9, 0x53, 0x06, 0x4c, 0xd5, - 0x5c, 0x27, 0xf0, 0xdc, 0x26, 0xb7, 0x5f, 0xa5, 0xa3, 0x51, 0x50, 0x52, 0xab, 0x24, 0xb0, 0xec, - 0xa6, 0x66, 0x0a, 0xd3, 0xd8, 0xe0, 0x08, 0x53, 0xf4, 0x19, 0x03, 0x66, 0x42, 0x1f, 0xb3, 0xd0, - 0x90, 0x96, 0x6a, 0x43, 0xd4, 0x51, 0x7f, 0x2e, 0xca, 0x09, 0xc7, 0x59, 0x9b, 0x5b, 0x30, 0x1b, - 0x9f, 0x6d, 0x3a, 0x94, 0x6d, 0x4b, 0xec, 0xf5, 0x6c, 0x38, 0x94, 0x15, 0xcb, 0xf7, 0x31, 0x83, - 0xa0, 0x47, 0x20, 0xdf, 0xb2, 0xbc, 0x86, 0xed, 0x58, 0x4d, 0x36, 0x8a, 0x59, 0xed, 0x40, 0x12, - 0xe5, 0x58, 0x61, 0x98, 0xef, 0x86, 0xa9, 0x0d, 0xcb, 0x69, 0x90, 0xba, 0x38, 0x87, 0x0f, 0x0f, - 0x11, 0xfb, 0xf1, 0x18, 0x4c, 0x6a, 0x77, 0xb3, 0xe3, 0xbf, 0x67, 0x45, 0x52, 0x39, 0x64, 0x53, - 0x4c, 0xe5, 0xf0, 0x3c, 0xc0, 0xb6, 0xed, 0xd8, 0xfe, 0xce, 0x11, 0x93, 0x44, 0xb0, 0x27, 0xda, - 0xf3, 0x8a, 0x02, 0xd6, 0xa8, 0x85, 0xef, 0x60, 0xb9, 0x03, 0x52, 0xe7, 0xbc, 0x6a, 0x68, 0xe2, - 0x66, 0x3c, 0x8d, 0x77, 0x7f, 0x6d, 0x62, 0x96, 0xa4, 0xf8, 0x39, 0xe7, 0x04, 0xde, 0xde, 0x81, - 0x52, 0x69, 0x13, 0xf2, 0x1e, 0xf1, 0x3b, 0x2d, 0x7a, 0x63, 0x9c, 0x18, 0x7a, 0x18, 0x98, 0xcf, - 0x04, 0x16, 0xf5, 0xb1, 0xa2, 0xb4, 0xf8, 0x14, 0x9c, 0x88, 0x34, 0x01, 0xcd, 0x42, 0xf6, 0x26, - 0xd9, 0xe3, 0xeb, 0x04, 0xd3, 0x9f, 0x68, 0x3e, 0xf2, 0x5a, 0x28, 0x86, 0xe5, 0x7d, 0x99, 0x27, - 0x0d, 0xd3, 0x85, 0x44, 0x03, 0xc0, 0x51, 0x1e, 0x73, 0xe8, 0x5c, 0x34, 0xb5, 0x2c, 0x11, 0x6a, - 0x2e, 0xb8, 0x67, 0x0c, 0x87, 0x99, 0x3f, 0x1d, 0x07, 0xf1, 0x94, 0x3d, 0xc0, 0x71, 0xa5, 0xbf, - 0x60, 0x65, 0x8e, 0xf0, 0x82, 0x75, 0x11, 0xa6, 0x6c, 0xc7, 0x0e, 0x6c, 0xab, 0xc9, 0x8c, 0x3b, - 0x42, 0x9c, 0x4a, 0xd7, 0xe1, 0xa9, 0x35, 0x0d, 0x96, 0x40, 0x27, 0x52, 0x17, 0x5d, 0x81, 0x1c, - 0x93, 0x37, 0x62, 0x01, 0x0f, 0xff, 0xde, 0xce, 0x5c, 0x2d, 0x78, 0x3c, 0x11, 0xa7, 0xc4, 0x2e, - 0x1f, 0x3c, 0x4d, 0x86, 0xba, 0x7e, 0x8b, 0x75, 0x1c, 0x5e, 0x3e, 0x62, 0x70, 0xdc, 0x53, 0x83, - 0x52, 0xd9, 0xb6, 0xec, 0x66, 0xc7, 0x23, 0x21, 0x95, 0xf1, 0x28, 0x95, 0xf3, 0x31, 0x38, 0xee, - 0xa9, 0x81, 0xb6, 0x61, 0x4a, 0x94, 0x71, 0x7f, 0xa7, 0x89, 0x23, 0xf6, 0x92, 0xf9, 0xb5, 0x9d, - 0xd7, 0x28, 0xe1, 0x08, 0x5d, 0xd4, 0x81, 0x39, 0xdb, 0xa9, 0xb9, 0x4e, 0xad, 0xd9, 0xf1, 0xed, - 0x5d, 0x12, 0x06, 0xf3, 0x1c, 0x85, 0xd9, 0xa9, 0xfd, 0x6e, 0x71, 0x6e, 0x2d, 0x4e, 0x0e, 0xf7, - 0x72, 0x40, 0xaf, 0x18, 0x70, 0xaa, 0xe6, 0x3a, 0x3e, 0x8b, 0x3b, 0xdf, 0x25, 0xe7, 0x3c, 0xcf, - 0xf5, 0x38, 0xef, 0xc2, 0x11, 0x79, 0x33, 0x9b, 0xe2, 0x4a, 0x12, 0x49, 0x9c, 0xcc, 0x09, 0xbd, - 0x08, 0xf9, 0xb6, 0xe7, 0xee, 0xda, 0x75, 0xe2, 0x09, 0xdf, 0xb9, 0xf5, 0x34, 0xf2, 0x60, 0x54, - 0x04, 0xcd, 0xf0, 0xe8, 0x91, 0x25, 0x58, 0xf1, 0x33, 0xdf, 0x28, 0xc0, 0x74, 0x14, 0x1d, 0x7d, - 0x02, 0xa0, 0xed, 0xb9, 0x2d, 0x12, 0xec, 0x10, 0x15, 0x94, 0x71, 0x69, 0xd4, 0x74, 0x0b, 0x92, - 0x9e, 0xf4, 0x5e, 0xa1, 0xc7, 0x45, 0x58, 0x8a, 0x35, 0x8e, 0xc8, 0x83, 0x89, 0x9b, 0x5c, 0xec, - 0x0a, 0x2d, 0xe4, 0xb9, 0x54, 0x74, 0x26, 0xc1, 0x99, 0x45, 0x13, 0x88, 0x22, 0x2c, 0x19, 0xa1, - 0x2d, 0xc8, 0xde, 0x22, 0x5b, 0xe9, 0x84, 0x30, 0x5f, 0x27, 0xe2, 0x36, 0x53, 0x9e, 0xd8, 0xef, - 0x16, 0xb3, 0xd7, 0xc9, 0x16, 0xa6, 0xc4, 0x69, 0xbf, 0xea, 0xfc, 0x1d, 0x5e, 0x1c, 0x15, 0x23, - 0xf6, 0x2b, 0xf2, 0xa8, 0xcf, 0xfb, 0x25, 0x8a, 0xb0, 0x64, 0x84, 0x5e, 0x84, 0xc2, 0x2d, 0x6b, - 0x97, 0x6c, 0x7b, 0xae, 0x13, 0x08, 0x97, 0xa9, 0x11, 0xfd, 0xf4, 0xaf, 0x4b, 0x72, 0x82, 0x2f, - 0x13, 0xef, 0xaa, 0x10, 0x87, 0xec, 0xd0, 0x2e, 0xe4, 0x1d, 0x72, 0x0b, 0x93, 0xa6, 0x5d, 0x4b, - 0xc7, 0x2f, 0xfe, 0x92, 0xa0, 0x26, 0x38, 0x33, 0xb9, 0x27, 0xcb, 0xb0, 0xe2, 0x45, 0xe7, 0xf2, - 0x86, 0xbb, 0x25, 0x0e, 0xaa, 0x11, 0xe7, 0x52, 0xdd, 0x4c, 0xf9, 0x5c, 0x5e, 0x74, 0xb7, 0x30, - 0x25, 0x4e, 0xf7, 0x48, 0x4d, 0xf9, 0xeb, 0x88, 0x63, 0xea, 0x52, 0xba, 0x7e, 0x4a, 0x7c, 0x8f, - 0x84, 0xa5, 0x58, 0xe3, 0x48, 0xc7, 0xb6, 0x21, 0x8c, 0x95, 0xe2, 0xa0, 0x1a, 0x71, 0x6c, 0xa3, - 0xa6, 0x4f, 0x3e, 0xb6, 0xb2, 0x0c, 0x2b, 0x5e, 0x94, 0xaf, 0x2d, 0x2c, 0x7f, 0xe9, 0x1c, 0x55, - 0x51, 0x3b, 0x22, 0xe7, 0x2b, 0xcb, 0xb0, 0xe2, 0x65, 0x7e, 0x65, 0x1c, 0xa6, 0xf4, 0x7c, 0x63, - 0x03, 0xe8, 0x08, 0x4a, 0x2f, 0xce, 0x0c, 0xa3, 0x17, 0xd3, 0x8b, 0x90, 0xf6, 0xc6, 0x21, 0x8d, - 0x30, 0x6b, 0xa9, 0xa9, 0x85, 0xe1, 0x45, 0x48, 0x2b, 0xf4, 0x71, 0x84, 0xe9, 0x10, 0x6e, 0x0f, - 0x54, 0xb9, 0xe2, 0xea, 0x47, 0x2e, 0xaa, 0x5c, 0x45, 0x14, 0x8a, 0x47, 0x01, 0xc2, 0xbc, 0x5b, - 0xe2, 0xed, 0x4b, 0x69, 0x6d, 0x5a, 0x3e, 0x30, 0x0d, 0x0b, 0x3d, 0x04, 0xe3, 0x54, 0x40, 0x93, - 0xba, 0x88, 0xd4, 0x55, 0xb7, 0xcd, 0xf3, 0xac, 0x14, 0x0b, 0x28, 0x7a, 0x92, 0xea, 0x52, 0xa1, - 0x58, 0x15, 0x01, 0xb8, 0xf3, 0xa1, 0x2e, 0x15, 0xc2, 0x70, 0x04, 0x93, 0x36, 0x9d, 0x50, 0x29, - 0xc8, 0x56, 0xb0, 0xd6, 0x74, 0x26, 0x1a, 0x31, 0x87, 0x31, 0xeb, 0x47, 0x4c, 0x6a, 0xb2, 0x95, - 0x97, 0xd3, 0xac, 0x1f, 0x31, 0x38, 0xee, 0xa9, 0x41, 0x3b, 0x23, 0x9e, 0xed, 0x26, 0xb9, 0x77, - 0x67, 0x9f, 0x07, 0xb7, 0xd7, 0xf4, 0x1b, 0xc1, 0x14, 0x9b, 0xfa, 0xf7, 0xa7, 0x97, 0x3b, 0x6f, - 0xf0, 0x2b, 0xc1, 0x68, 0xca, 0xfb, 0x47, 0x61, 0x3a, 0x7a, 0x56, 0xa6, 0x6e, 0x9f, 0xff, 0xab, - 0x2c, 0x9c, 0xbc, 0xd4, 0xb0, 0x9d, 0xdb, 0x31, 0xc3, 0x76, 0x52, 0x4e, 0x5b, 0x63, 0xd8, 0x9c, - 0xb6, 0x61, 0xc8, 0x8f, 0x48, 0x1a, 0x9c, 0x1c, 0xf2, 0x23, 0x33, 0x0a, 0x47, 0x71, 0xd1, 0x8f, - 0x0c, 0xb8, 0xdf, 0xaa, 0x73, 0xed, 0xd5, 0x6a, 0x8a, 0xd2, 0x90, 0xa9, 0xdc, 0xd1, 0xfe, 0x88, - 0xb2, 0xa8, 0xb7, 0xf3, 0x4b, 0xa5, 0x03, 0xb8, 0xf2, 0x19, 0x7f, 0x87, 0xe8, 0xc1, 0xfd, 0x07, - 0xa1, 0xe2, 0x03, 0x9b, 0xbf, 0x78, 0x19, 0xde, 0x7e, 0x28, 0xa3, 0xa1, 0x56, 0xcb, 0xa7, 0x0c, - 0x28, 0x70, 0xf3, 0x29, 0x26, 0xdb, 0xf4, 0xa8, 0xb0, 0xda, 0xf6, 0x35, 0xe2, 0xf9, 0x32, 0xd9, - 0x96, 0x76, 0xc1, 0x2b, 0x55, 0xd6, 0x04, 0x04, 0x6b, 0x58, 0xf4, 0x30, 0xbe, 0x69, 0x3b, 0x75, - 0x31, 0x4d, 0xea, 0x30, 0x7e, 0xce, 0x76, 0xea, 0x98, 0x41, 0xd4, 0x71, 0x9d, 0xed, 0x6b, 0xd6, - 0x78, 0xc3, 0x80, 0x69, 0x16, 0xe7, 0x18, 0x5e, 0x3d, 0x9e, 0x50, 0x3e, 0x2d, 0xbc, 0x19, 0x67, - 0xa2, 0x3e, 0x2d, 0x77, 0xba, 0xc5, 0x49, 0x1e, 0x19, 0x19, 0x75, 0x71, 0xf9, 0xa0, 0xb0, 0x57, - 0x30, 0xcf, 0x9b, 0xcc, 0xd0, 0xd7, 0x69, 0x65, 0xcf, 0xab, 0x4a, 0x22, 0x38, 0xa4, 0x67, 0xbe, - 0x04, 0x53, 0x7a, 0xc0, 0x02, 0x7a, 0x02, 0x26, 0xdb, 0xb6, 0xd3, 0x88, 0x06, 0xb6, 0x29, 0x9b, - 0x6e, 0x25, 0x04, 0x61, 0x1d, 0x8f, 0x55, 0x73, 0xc3, 0x6a, 0x31, 0x53, 0x70, 0xc5, 0xd5, 0xab, - 0x85, 0x7f, 0xcc, 0x3f, 0xce, 0xc2, 0xc9, 0x84, 0xc0, 0x18, 0xf4, 0xaa, 0x01, 0xe3, 0xcc, 0x4b, - 0x5f, 0x7a, 0xad, 0xbc, 0x90, 0x7a, 0xf0, 0xcd, 0x12, 0x0b, 0x06, 0x10, 0xeb, 0x58, 0x1d, 0x9f, - 0xbc, 0x10, 0x0b, 0xe6, 0xe8, 0xb7, 0x0c, 0x98, 0xb4, 0xb4, 0xad, 0xc6, 0x1d, 0x79, 0xb6, 0xd2, - 0x6f, 0x4c, 0xcf, 0xce, 0xd2, 0x1c, 0x10, 0xc3, 0x8d, 0xa4, 0xb7, 0x65, 0xf1, 0xbd, 0x30, 0xa9, - 0x75, 0x61, 0x98, 0x1d, 0xb2, 0xf8, 0x0c, 0xcc, 0x8e, 0xb4, 0xc3, 0x3e, 0x00, 0xc3, 0xe6, 0x8e, - 0xa3, 0x02, 0xeb, 0x96, 0x1e, 0x7c, 0xac, 0x46, 0x5c, 0x44, 0x1f, 0x0b, 0xa8, 0xb9, 0x05, 0xb3, - 0xf1, 0xcb, 0x55, 0xea, 0xef, 0xd6, 0xef, 0x86, 0x21, 0xb3, 0xbd, 0x99, 0xdf, 0xc9, 0xc0, 0x84, - 0x88, 0xae, 0xbb, 0x0b, 0xbe, 0xbb, 0x37, 0x23, 0x8f, 0x3a, 0x6b, 0xa9, 0x04, 0x05, 0xf6, 0x75, - 0xdc, 0xf5, 0x63, 0x8e, 0xbb, 0xcf, 0xa5, 0xc3, 0xee, 0x60, 0xaf, 0xdd, 0x37, 0xc6, 0x60, 0x26, - 0x16, 0xad, 0x48, 0x55, 0x95, 0x1e, 0x67, 0xb5, 0xab, 0xa9, 0x06, 0x44, 0x2a, 0xbf, 0xf2, 0x83, - 0xfd, 0xd6, 0xfc, 0x48, 0x52, 0xcd, 0x2b, 0xa9, 0xe5, 0xe3, 0xfe, 0x45, 0x7e, 0xcd, 0x61, 0xfd, - 0xb0, 0xfe, 0xc9, 0x80, 0x7b, 0xfb, 0x06, 0xb5, 0xb2, 0x9c, 0x28, 0x5e, 0x14, 0x2a, 0x36, 0x64, - 0xca, 0xa1, 0xfb, 0xea, 0x85, 0x25, 0x9e, 0xc6, 0x22, 0xce, 0x1e, 0x3d, 0x0e, 0x53, 0x4c, 0xb4, - 0xd2, 0x33, 0x25, 0x20, 0x6d, 0x61, 0x20, 0x66, 0xa6, 0xc2, 0xaa, 0x56, 0x8e, 0x23, 0x58, 0xe6, - 0x97, 0x0d, 0x58, 0xe8, 0x97, 0x21, 0x63, 0x80, 0x8b, 0xe1, 0xff, 0x8b, 0x39, 0x17, 0x17, 0x7b, - 0x9c, 0x8b, 0x63, 0x57, 0x43, 0xe9, 0x47, 0xac, 0xdd, 0xca, 0xb2, 0x87, 0xf8, 0xce, 0x7e, 0xd6, - 0x80, 0xd3, 0x7d, 0x76, 0x53, 0x8f, 0x93, 0xb9, 0x71, 0x64, 0x27, 0xf3, 0xcc, 0xa0, 0x4e, 0xe6, - 0xe6, 0xf7, 0xb2, 0x30, 0x2b, 0xda, 0x13, 0xea, 0x57, 0x4f, 0x46, 0x5c, 0xb4, 0xdf, 0x11, 0x73, - 0xd1, 0x9e, 0x8f, 0xe3, 0xff, 0xc2, 0x3f, 0xfb, 0xad, 0xe5, 0x9f, 0xfd, 0xb3, 0x0c, 0x9c, 0x4a, - 0x4c, 0xdc, 0x81, 0x3e, 0x9d, 0x20, 0x1a, 0xae, 0xa7, 0x9c, 0x21, 0x64, 0x40, 0xe1, 0x30, 0xaa, - 0x53, 0xf3, 0x17, 0x74, 0x67, 0x62, 0x7e, 0xd4, 0x6f, 0x1f, 0x43, 0xae, 0x93, 0x21, 0xfd, 0x8a, - 0xcd, 0x5f, 0xcb, 0xc2, 0xc3, 0x83, 0x12, 0x7a, 0x8b, 0xc6, 0x9d, 0xf8, 0x91, 0xb8, 0x93, 0xbb, - 0x24, 0xb6, 0x8f, 0x25, 0x04, 0xe5, 0x2b, 0x59, 0x25, 0xf6, 0x7a, 0xd7, 0xe7, 0x40, 0xaf, 0x89, - 0x13, 0x54, 0xb5, 0x93, 0xe9, 0x3c, 0xc3, 0xa3, 0x70, 0xa2, 0xca, 0x8b, 0xef, 0x74, 0x8b, 0x73, - 0x22, 0xc5, 0x5f, 0x95, 0x04, 0xa2, 0x10, 0xcb, 0x4a, 0xe8, 0x61, 0xc8, 0x7b, 0x1c, 0x2a, 0x3d, - 0xed, 0xc5, 0x93, 0x2c, 0x2f, 0xc3, 0x0a, 0x8a, 0x3e, 0xa9, 0xe9, 0xc2, 0x63, 0xc7, 0x95, 0x25, - 0xe1, 0xa0, 0x97, 0xe6, 0x17, 0x20, 0xef, 0xcb, 0xc4, 0x9c, 0xfc, 0x39, 0xe0, 0xb1, 0x01, 0x03, - 0x38, 0xe8, 0xd5, 0x49, 0x66, 0xe9, 0xe4, 0xfd, 0x53, 0x39, 0x3c, 0x15, 0x49, 0x64, 0xaa, 0x5b, - 0x0b, 0xb7, 0x31, 0x42, 0xc2, 0x8d, 0xe5, 0xfb, 0x06, 0x4c, 0x8a, 0xd9, 0xba, 0x0b, 0x31, 0x25, - 0x37, 0xa2, 0x31, 0x25, 0xe7, 0x52, 0x39, 0x3b, 0xfa, 0x04, 0x94, 0xdc, 0x80, 0x29, 0x3d, 0x77, - 0x13, 0x7a, 0x5e, 0x3b, 0xfb, 0x8c, 0x51, 0xb2, 0xa1, 0xc8, 0xd3, 0x31, 0x3c, 0x17, 0xcd, 0x2f, - 0xe5, 0xd5, 0x28, 0x32, 0x3b, 0x84, 0xbe, 0x06, 0x8d, 0x03, 0xd7, 0xa0, 0xbe, 0x04, 0x32, 0xe9, - 0x2f, 0x81, 0x2b, 0x90, 0x97, 0x07, 0x94, 0x10, 0xe3, 0x0f, 0xea, 0x5e, 0x76, 0x54, 0x17, 0xa0, - 0xc4, 0xb4, 0x85, 0xcb, 0xae, 0x5a, 0x6a, 0x0e, 0xd5, 0xc1, 0xa9, 0xc8, 0xa0, 0x17, 0x61, 0xf2, - 0x96, 0xeb, 0xdd, 0x6c, 0xba, 0x16, 0x4b, 0xb9, 0x0b, 0x69, 0x3c, 0xec, 0x28, 0x83, 0x17, 0x77, - 0x75, 0xbe, 0x1e, 0xd2, 0xc7, 0x3a, 0x33, 0x54, 0x82, 0x99, 0x96, 0xed, 0x60, 0x62, 0xd5, 0x55, - 0xe8, 0xc8, 0x18, 0xcf, 0x09, 0x2a, 0x95, 0xdc, 0x8d, 0x28, 0x18, 0xc7, 0xf1, 0xd1, 0xc7, 0x21, - 0xef, 0x8b, 0x4c, 0x48, 0xe9, 0x3c, 0xc1, 0xa9, 0x3b, 0x23, 0x27, 0x1a, 0x8e, 0x9d, 0x2c, 0xc1, - 0x8a, 0x21, 0x5a, 0x87, 0x79, 0x4f, 0xe4, 0x1a, 0x89, 0x7c, 0xb0, 0x83, 0xef, 0x4f, 0x96, 0x7a, - 0x12, 0x27, 0xc0, 0x71, 0x62, 0x2d, 0xaa, 0xc5, 0xb0, 0x24, 0x64, 0xfc, 0x4d, 0x40, 0x33, 0xa3, - 0xb3, 0x05, 0x5f, 0xc7, 0x02, 0x7a, 0x50, 0x28, 0x52, 0x7e, 0x84, 0x50, 0xa4, 0x2a, 0x9c, 0x8a, - 0x83, 0x58, 0x46, 0x14, 0x96, 0x84, 0x45, 0x93, 0x1e, 0x95, 0x24, 0x24, 0x9c, 0x5c, 0x17, 0x5d, - 0x87, 0x82, 0x47, 0xd8, 0xfd, 0xa2, 0x24, 0x1f, 0xfd, 0x87, 0x76, 0x6f, 0xc2, 0x92, 0x00, 0x0e, - 0x69, 0xd1, 0x79, 0xb7, 0xa2, 0x69, 0x31, 0xaf, 0xa4, 0xf8, 0xc9, 0x31, 0x31, 0xf7, 0x7d, 0x32, - 0x15, 0x99, 0x6f, 0x4e, 0xc3, 0x89, 0x88, 0x6d, 0x01, 0x3d, 0x08, 0x39, 0x96, 0x22, 0x86, 0x1d, - 0x0f, 0xf9, 0xf0, 0x08, 0xe3, 0x83, 0xc3, 0x61, 0xe8, 0x73, 0x06, 0xcc, 0xb4, 0x23, 0x56, 0x58, - 0x79, 0x72, 0x8e, 0xf8, 0xce, 0x17, 0x35, 0xed, 0x6a, 0x09, 0xa5, 0xa3, 0xcc, 0x70, 0x9c, 0x3b, - 0xdd, 0x80, 0xc2, 0x47, 0xb0, 0x49, 0x3c, 0x86, 0x2d, 0x74, 0x1c, 0x45, 0x62, 0x25, 0x0a, 0xc6, - 0x71, 0x7c, 0x3a, 0xc3, 0xac, 0x77, 0xa3, 0x7c, 0x8b, 0xa8, 0x24, 0x09, 0xe0, 0x90, 0x16, 0x7a, - 0x06, 0xa6, 0x45, 0x36, 0xc4, 0x8a, 0x5b, 0xbf, 0x60, 0xf9, 0x3b, 0x42, 0xb9, 0x57, 0x97, 0x91, - 0x95, 0x08, 0x14, 0xc7, 0xb0, 0x59, 0xdf, 0xc2, 0x94, 0x93, 0x8c, 0xc0, 0x78, 0x34, 0xdf, 0xf6, - 0x4a, 0x14, 0x8c, 0xe3, 0xf8, 0xe8, 0x11, 0xed, 0xdc, 0xe7, 0xef, 0x74, 0xea, 0x34, 0x48, 0x38, - 0xfb, 0x4b, 0x30, 0xd3, 0x61, 0x77, 0xa1, 0xba, 0x04, 0x8a, 0xfd, 0xa8, 0x18, 0x5e, 0x8d, 0x82, - 0x71, 0x1c, 0x1f, 0x3d, 0x05, 0x27, 0x3c, 0x7a, 0xba, 0x29, 0x02, 0xfc, 0xf1, 0x4e, 0xbd, 0xcd, - 0x60, 0x1d, 0x88, 0xa3, 0xb8, 0xe8, 0x59, 0x98, 0x0b, 0x93, 0x87, 0x49, 0x02, 0xfc, 0x35, 0x4f, - 0xe5, 0xc5, 0x29, 0xc5, 0x11, 0x70, 0x6f, 0x1d, 0xf4, 0x4b, 0x30, 0xab, 0x8d, 0xc4, 0x9a, 0x53, - 0x27, 0xb7, 0x45, 0x82, 0x27, 0xf6, 0x69, 0x84, 0x95, 0x18, 0x0c, 0xf7, 0x60, 0xa3, 0xf7, 0xc1, - 0x74, 0xcd, 0x6d, 0x36, 0xd9, 0x19, 0xc7, 0x73, 0x3d, 0xf3, 0x4c, 0x4e, 0x3c, 0xe7, 0x55, 0x04, - 0x82, 0x63, 0x98, 0xe8, 0x22, 0x20, 0x77, 0xcb, 0x27, 0xde, 0x2e, 0xa9, 0x3f, 0xcb, 0xbf, 0x6e, - 0x4a, 0x45, 0xfc, 0x89, 0xa8, 0x87, 0xf2, 0xe5, 0x1e, 0x0c, 0x9c, 0x50, 0x8b, 0xa5, 0xd5, 0xd1, - 0x22, 0xba, 0xa6, 0xd3, 0xf8, 0x2e, 0x4f, 0xfc, 0xe6, 0x7e, 0x68, 0x38, 0x97, 0x07, 0xe3, 0xdc, - 0x61, 0x3c, 0x9d, 0x94, 0x4e, 0x7a, 0xda, 0xd7, 0x50, 0x46, 0xf0, 0x52, 0x2c, 0x38, 0xa1, 0x4f, - 0x40, 0x61, 0x4b, 0xe6, 0x00, 0x5f, 0x98, 0x4d, 0x43, 0x2e, 0xc6, 0xd2, 0xd9, 0x87, 0x37, 0x53, - 0x05, 0xc0, 0x21, 0x4b, 0xf4, 0x10, 0x4c, 0x5e, 0xa8, 0x94, 0xd4, 0x2a, 0x9c, 0x63, 0xb3, 0x3f, - 0x46, 0xab, 0x60, 0x1d, 0x40, 0x77, 0x98, 0xd2, 0x97, 0x10, 0x9b, 0xe2, 0x50, 0xde, 0xf6, 0xaa, - 0x3f, 0x14, 0x9b, 0x3d, 0x47, 0xe2, 0xea, 0xc2, 0xc9, 0x18, 0xb6, 0x28, 0xc7, 0x0a, 0x03, 0xbd, - 0x00, 0x93, 0x42, 0x5e, 0xb0, 0xb3, 0x69, 0xfe, 0x68, 0xd1, 0x82, 0x38, 0x24, 0x81, 0x75, 0x7a, - 0xec, 0x95, 0x89, 0xa5, 0x46, 0x26, 0xe7, 0x3b, 0xcd, 0xe6, 0xc2, 0x29, 0x76, 0x6e, 0x86, 0xaf, - 0x4c, 0x21, 0x08, 0xeb, 0x78, 0xe8, 0x31, 0xe9, 0x39, 0xf1, 0xb6, 0xc8, 0xb3, 0x9b, 0xf2, 0x9c, - 0x50, 0x5a, 0x6e, 0x1f, 0x87, 0xe2, 0xd3, 0x87, 0xb8, 0x2c, 0x6c, 0xc1, 0xa2, 0x54, 0xb1, 0x7a, - 0x37, 0xc9, 0xc2, 0x42, 0xc4, 0x4a, 0xb0, 0x78, 0xbd, 0x2f, 0x26, 0x3e, 0x80, 0x0a, 0xda, 0x82, - 0xac, 0xd5, 0xdc, 0x5a, 0xb8, 0x37, 0x0d, 0x5d, 0x51, 0x7d, 0xad, 0x98, 0x3b, 0x01, 0x95, 0xd6, - 0xcb, 0x98, 0x12, 0x37, 0x5f, 0xc9, 0x28, 0xab, 0xbc, 0x4a, 0x75, 0xf9, 0x92, 0xbe, 0xaa, 0x8d, - 0x34, 0xbe, 0xc6, 0xd9, 0x93, 0x28, 0x9f, 0x0b, 0xa4, 0xc4, 0x35, 0xdd, 0x56, 0xfb, 0x38, 0x95, - 0x3c, 0x26, 0xd1, 0x34, 0x9e, 0xfc, 0x36, 0x17, 0xdd, 0xc5, 0xe6, 0xfe, 0x84, 0x32, 0x42, 0xc5, - 0x5c, 0x01, 0x3c, 0xc8, 0xd9, 0x7e, 0x60, 0xbb, 0x29, 0x46, 0xb6, 0xc5, 0xf2, 0x5f, 0x32, 0xc7, - 0x59, 0x06, 0xc0, 0x9c, 0x15, 0xe5, 0xe9, 0x34, 0x6c, 0xe7, 0xb6, 0xe8, 0xfe, 0x95, 0xd4, 0xdf, - 0xf8, 0x39, 0x4f, 0x06, 0xc0, 0x9c, 0x15, 0xba, 0xc1, 0x57, 0x5a, 0x3a, 0x5f, 0x5e, 0x8d, 0x7f, - 0x50, 0x39, 0xba, 0xe2, 0x28, 0x2f, 0xbf, 0x65, 0x0b, 0x1d, 0x66, 0x44, 0x5e, 0xd5, 0x8d, 0xb5, - 0x24, 0x5e, 0xd5, 0x8d, 0x35, 0x4c, 0x99, 0xa0, 0xd7, 0x0c, 0x00, 0x4b, 0x7d, 0x59, 0x38, 0x9d, - 0xaf, 0x4a, 0xf4, 0xfb, 0x52, 0x31, 0xf7, 0x75, 0x0b, 0xa1, 0x58, 0xe3, 0x8c, 0x5e, 0x84, 0x09, - 0x8b, 0x7f, 0x13, 0x47, 0xb8, 0x11, 0xa6, 0xf3, 0xa1, 0xa7, 0x58, 0x0b, 0x98, 0xff, 0xa4, 0x00, - 0x61, 0xc9, 0x90, 0xf2, 0x0e, 0x3c, 0x8b, 0x6c, 0xdb, 0x37, 0x85, 0x3f, 0x61, 0x75, 0xe4, 0xd4, - 0xd6, 0x94, 0x58, 0x12, 0x6f, 0x01, 0xc2, 0x92, 0x21, 0xff, 0x98, 0xa7, 0xe5, 0x58, 0x2a, 0x38, - 0x24, 0x9d, 0x10, 0x22, 0x3d, 0xdc, 0x44, 0xfb, 0x98, 0xa7, 0xce, 0x08, 0x47, 0xf9, 0x9a, 0x3f, - 0xc9, 0x02, 0xb0, 0x9f, 0x3c, 0x60, 0xb9, 0xc5, 0x92, 0xdc, 0xed, 0xb8, 0x75, 0xb1, 0xb5, 0x53, - 0x8c, 0x3b, 0x06, 0x91, 0xd1, 0x6e, 0xc7, 0xad, 0x63, 0xc1, 0x04, 0x35, 0x60, 0xac, 0x6d, 0x05, - 0x3b, 0xe9, 0x07, 0x39, 0xe7, 0x79, 0xe4, 0x4e, 0xb0, 0x83, 0x19, 0x03, 0xf4, 0xb2, 0x01, 0x13, - 0x3c, 0xcc, 0x59, 0x9a, 0x9a, 0x47, 0x7e, 0x4f, 0x95, 0x63, 0xb6, 0xc4, 0x63, 0xa9, 0x85, 0xb3, - 0x82, 0x12, 0x8d, 0xa2, 0x14, 0x4b, 0xb6, 0x8b, 0xaf, 0x1a, 0x30, 0xa5, 0xa3, 0x26, 0xb8, 0x19, - 0x7c, 0x44, 0x77, 0x33, 0x48, 0x73, 0x3c, 0x74, 0x8f, 0x85, 0x7f, 0x35, 0x40, 0xfb, 0x04, 0x6a, - 0xe8, 0x64, 0x68, 0x0c, 0xec, 0x64, 0x98, 0x19, 0xd2, 0xc9, 0x30, 0x3b, 0x94, 0x93, 0xe1, 0xd8, - 0xf0, 0x4e, 0x86, 0xb9, 0xfe, 0x4e, 0x86, 0xe6, 0xeb, 0x06, 0xcc, 0xf5, 0x9c, 0x87, 0xf1, 0x4f, - 0xcd, 0x1b, 0x03, 0x7e, 0x6a, 0x7e, 0x15, 0x66, 0x45, 0x12, 0xe6, 0x6a, 0xbb, 0x69, 0x27, 0x06, - 0xa0, 0x6f, 0xc6, 0xe0, 0xb8, 0xa7, 0x86, 0xf9, 0xe7, 0x06, 0x4c, 0x6a, 0x61, 0x6b, 0xb4, 0x1f, - 0x2c, 0xbc, 0x4f, 0x34, 0x23, 0xcc, 0x3f, 0xcd, 0x4c, 0xfb, 0x1c, 0xc6, 0x5f, 0x99, 0x1a, 0x5a, - 0xc2, 0xcf, 0xf0, 0x95, 0x89, 0x96, 0x62, 0x01, 0xe5, 0xa9, 0x1c, 0x49, 0x9b, 0x0d, 0x7a, 0x56, - 0x4f, 0xe5, 0x48, 0xda, 0x98, 0x41, 0x18, 0x3b, 0xaa, 0x47, 0x0a, 0xff, 0x53, 0x2d, 0xdd, 0xb5, - 0xe5, 0x05, 0x98, 0xc3, 0xd0, 0x19, 0xc8, 0x12, 0xa7, 0x2e, 0x2e, 0xbd, 0xea, 0x13, 0x53, 0xe7, - 0x9c, 0x3a, 0xa6, 0xe5, 0xe6, 0x65, 0x98, 0xaa, 0x92, 0x9a, 0x47, 0x82, 0xe7, 0xc8, 0xde, 0xc0, - 0xdf, 0xac, 0xa2, 0xab, 0x3d, 0xf6, 0xcd, 0x2a, 0x5a, 0x9d, 0x96, 0x9b, 0x7f, 0x68, 0x40, 0x2c, - 0x27, 0xbb, 0x66, 0x71, 0x36, 0xfa, 0x59, 0x9c, 0x23, 0xb6, 0xd1, 0xcc, 0x81, 0xb6, 0xd1, 0x8b, - 0x80, 0x5a, 0x74, 0x2b, 0x44, 0xbe, 0x40, 0x20, 0xec, 0x0d, 0x61, 0x90, 0x6c, 0x0f, 0x06, 0x4e, - 0xa8, 0x65, 0xfe, 0x01, 0x6f, 0xac, 0x9e, 0xa5, 0xfd, 0xf0, 0x01, 0xe8, 0x40, 0x8e, 0x91, 0x12, - 0x46, 0x97, 0xca, 0x68, 0x9b, 0xbb, 0x37, 0xd9, 0x44, 0x38, 0x91, 0x62, 0xcb, 0x33, 0x6e, 0xe6, - 0xf7, 0x78, 0x5b, 0xb5, 0x34, 0xee, 0x03, 0xb4, 0xb5, 0x15, 0x6d, 0xeb, 0x85, 0xb4, 0xce, 0xca, - 0xe4, 0x36, 0xa2, 0x25, 0x80, 0x36, 0xf1, 0x6a, 0xc4, 0x09, 0xa4, 0x5b, 0x74, 0x4e, 0x84, 0x91, - 0xa8, 0x52, 0xac, 0x61, 0x98, 0x2f, 0x1b, 0x30, 0x5b, 0x0d, 0xec, 0xda, 0x4d, 0xdb, 0xe1, 0x61, - 0x51, 0xdb, 0x76, 0x83, 0xde, 0x52, 0x88, 0xf8, 0x1c, 0x13, 0x37, 0x83, 0xa9, 0xa3, 0x58, 0x7e, - 0x85, 0x49, 0xc2, 0x51, 0x09, 0x66, 0xa4, 0xb5, 0x5d, 0xda, 0x2e, 0x79, 0x38, 0xa7, 0xb2, 0x95, - 0xac, 0x46, 0xc1, 0x38, 0x8e, 0x6f, 0x7e, 0x12, 0x26, 0xb5, 0xf3, 0x95, 0x1d, 0x45, 0xb7, 0xad, - 0x5a, 0x10, 0xdf, 0xc2, 0xe7, 0x68, 0x21, 0xe6, 0x30, 0x66, 0x62, 0xe5, 0x7e, 0xb3, 0xb1, 0x2d, - 0x2c, 0xbc, 0x65, 0x05, 0x94, 0x12, 0xf3, 0x48, 0x83, 0xdc, 0x96, 0xa9, 0x45, 0x25, 0x31, 0x4c, - 0x0b, 0x31, 0x87, 0x99, 0x8f, 0x40, 0x5e, 0x06, 0xdd, 0xb3, 0xc8, 0x55, 0x69, 0xfe, 0xd3, 0x23, - 0x57, 0x5d, 0x2f, 0xc0, 0x0c, 0x62, 0x5e, 0x83, 0xbc, 0xcc, 0x0d, 0x70, 0x38, 0x36, 0xdd, 0x55, - 0xbe, 0x63, 0x5f, 0x70, 0xfd, 0x40, 0x26, 0x34, 0xe0, 0x4f, 0x02, 0x97, 0xd6, 0x58, 0x19, 0x56, - 0x50, 0x73, 0x0e, 0x66, 0x94, 0xad, 0x5f, 0x38, 0x32, 0x7e, 0x33, 0x0b, 0x53, 0x91, 0x4f, 0x01, - 0x1f, 0xbe, 0xdc, 0x06, 0xdf, 0xc5, 0x09, 0x36, 0xfb, 0xec, 0x90, 0x36, 0x7b, 0xfd, 0x91, 0x64, - 0xec, 0x78, 0x1f, 0x49, 0x72, 0xe9, 0x3c, 0x92, 0x04, 0x30, 0xe1, 0x0b, 0x41, 0x35, 0x9e, 0x86, - 0x31, 0x25, 0x36, 0x63, 0x5c, 0x47, 0x95, 0xf2, 0x4e, 0xb2, 0x32, 0xbf, 0x96, 0x83, 0xe9, 0x68, - 0x56, 0xa4, 0x01, 0x66, 0xf2, 0x91, 0x9e, 0x99, 0x1c, 0xd2, 0x66, 0x99, 0x1d, 0xd5, 0x66, 0x39, - 0x36, 0xaa, 0xcd, 0x32, 0x77, 0x04, 0x9b, 0x65, 0xaf, 0xc5, 0x71, 0x7c, 0x60, 0x8b, 0xe3, 0xd3, - 0xca, 0xe1, 0x66, 0x22, 0xf2, 0x42, 0x1d, 0x3a, 0xdc, 0xa0, 0xe8, 0x34, 0xac, 0xb8, 0xf5, 0x44, - 0xc7, 0xa5, 0xfc, 0x21, 0xb6, 0x19, 0x2f, 0xd1, 0x3f, 0x66, 0xf8, 0x67, 0x91, 0xb7, 0x0d, 0xe1, - 0x1b, 0xf3, 0x04, 0x4c, 0x8a, 0xf5, 0xc4, 0x74, 0x25, 0x88, 0xea, 0x59, 0xd5, 0x10, 0x84, 0x75, - 0x3c, 0xf6, 0xb5, 0xca, 0xe8, 0xe7, 0x39, 0x99, 0x09, 0x58, 0xff, 0x5a, 0x65, 0xec, 0x73, 0x9e, - 0x71, 0x7c, 0xf3, 0xe3, 0x70, 0x2a, 0xf1, 0x46, 0xc6, 0x4c, 0x54, 0x4c, 0x8c, 0x93, 0xba, 0x40, - 0xd0, 0x9a, 0x11, 0x4b, 0x9a, 0xbb, 0x78, 0xbd, 0x2f, 0x26, 0x3e, 0x80, 0x8a, 0xf9, 0xd5, 0x2c, - 0x4c, 0x47, 0x3f, 0x75, 0x84, 0x6e, 0x29, 0xfb, 0x4d, 0x2a, 0xa6, 0x23, 0x4e, 0x56, 0xcb, 0xb4, - 0xd3, 0xd7, 0x18, 0x7b, 0x8b, 0xad, 0xaf, 0x2d, 0x95, 0xf6, 0xe7, 0xf8, 0x18, 0x0b, 0x2b, 0xa8, - 0x60, 0xc7, 0xbe, 0x66, 0x14, 0x86, 0x3b, 0x88, 0x6b, 0x57, 0xea, 0xdc, 0xc3, 0x00, 0x06, 0xc5, - 0x0a, 0x6b, 0x6c, 0xa9, 0x6c, 0xd9, 0x25, 0x9e, 0xbd, 0x6d, 0xab, 0xcf, 0x34, 0xb2, 0x93, 0xfb, - 0x9a, 0x28, 0xc3, 0x0a, 0x6a, 0xbe, 0x9c, 0x81, 0xf0, 0xa3, 0xb4, 0xec, 0x7b, 0x20, 0xbe, 0xa6, - 0xe2, 0x8a, 0x69, 0xbb, 0x38, 0xea, 0x47, 0x77, 0x42, 0x8a, 0xc2, 0x19, 0x52, 0x2b, 0xc1, 0x11, - 0x8e, 0x3f, 0x87, 0x8f, 0xd1, 0x5a, 0x30, 0x13, 0x0b, 0x02, 0x4d, 0xdd, 0xe3, 0xfc, 0x4b, 0x59, - 0x28, 0xa8, 0x30, 0x5a, 0xf4, 0xde, 0x88, 0xbd, 0xa1, 0x50, 0x7e, 0xbb, 0x96, 0xfa, 0x7e, 0xc7, - 0xad, 0xdf, 0xe9, 0x16, 0x67, 0x14, 0x72, 0xcc, 0x76, 0x70, 0x06, 0xb2, 0x1d, 0xaf, 0x19, 0xbf, - 0x50, 0x5c, 0xc5, 0xeb, 0x98, 0x96, 0xa3, 0xdb, 0xf1, 0x0b, 0xff, 0x46, 0x4a, 0xa1, 0xbf, 0x5c, - 0xf3, 0xee, 0x7f, 0xd1, 0xa7, 0x52, 0x72, 0xcb, 0xad, 0xef, 0xc5, 0x53, 0xe5, 0x97, 0xdd, 0xfa, - 0x1e, 0x66, 0x10, 0xf4, 0x0c, 0x4c, 0x07, 0x76, 0x8b, 0xb8, 0x9d, 0x40, 0xff, 0xe4, 0x67, 0x36, - 0x7c, 0x5c, 0xdc, 0x8c, 0x40, 0x71, 0x0c, 0x9b, 0x4a, 0xd9, 0x1b, 0xbe, 0xeb, 0xb0, 0xfc, 0x77, - 0xe3, 0xd1, 0x97, 0x88, 0x8b, 0xd5, 0xcb, 0x97, 0x98, 0xdd, 0x43, 0x61, 0x50, 0x6c, 0x9b, 0xc5, - 0xcc, 0x79, 0x44, 0xbc, 0xed, 0xcf, 0x86, 0x19, 0x15, 0x78, 0x39, 0x56, 0x18, 0xe6, 0x55, 0x98, - 0x89, 0x75, 0x55, 0x5e, 0xdd, 0x8c, 0xe4, 0xab, 0xdb, 0x60, 0x79, 0xe9, 0xff, 0xc4, 0x80, 0xb9, - 0x9e, 0xcd, 0x3b, 0x68, 0x28, 0x44, 0x5c, 0x8c, 0x64, 0x8e, 0x2e, 0x46, 0xb2, 0xc3, 0x89, 0x91, - 0xf2, 0xd6, 0xb7, 0xdf, 0x3c, 0x7b, 0xcf, 0x77, 0xdf, 0x3c, 0x7b, 0xcf, 0x0f, 0xde, 0x3c, 0x7b, - 0xcf, 0xcb, 0xfb, 0x67, 0x8d, 0x6f, 0xef, 0x9f, 0x35, 0xbe, 0xbb, 0x7f, 0xd6, 0xf8, 0xc1, 0xfe, - 0x59, 0xe3, 0x1f, 0xf7, 0xcf, 0x1a, 0xaf, 0xff, 0xf8, 0xec, 0x3d, 0xcf, 0x3f, 0x1d, 0x2e, 0xad, - 0x65, 0xb9, 0xb4, 0xd8, 0x8f, 0x77, 0xc9, 0x85, 0xb4, 0xdc, 0xbe, 0xd9, 0x58, 0xa6, 0x4b, 0x6b, - 0x59, 0x95, 0xc8, 0xa5, 0xf5, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x41, 0x02, 0xde, 0xaf, 0x0f, - 0x93, 0x00, 0x00, + 0x38, 0xf0, 0xe7, 0x7c, 0x9f, 0x23, 0x25, 0xfe, 0xf9, 0xea, 0xc4, 0x86, 0x5b, 0x52, 0xda, 0xf5, + 0x6a, 0x2d, 0xed, 0x72, 0x2f, 0xb5, 0xbb, 0x89, 0x13, 0x27, 0x19, 0x91, 0x57, 0xd4, 0xec, 0x92, + 0x33, 0xcc, 0xcc, 0x50, 0xbb, 0x72, 0x8c, 0xc4, 0x6e, 0x60, 0x37, 0x2d, 0x12, 0xc4, 0x6d, 0x12, + 0x14, 0x45, 0xd1, 0x22, 0x28, 0x0c, 0xf4, 0x27, 0x7d, 0x0a, 0x5a, 0xf4, 0x25, 0x40, 0x8b, 0xe6, + 0xa7, 0xe9, 0x43, 0x8a, 0xa4, 0x40, 0x9b, 0xa4, 0x40, 0xd8, 0x5a, 0xe9, 0x4b, 0x8b, 0x16, 0x41, + 0x81, 0x14, 0x45, 0xf6, 0xa9, 0xb8, 0xbf, 0x73, 0x67, 0x38, 0x94, 0x48, 0x71, 0xb4, 0x31, 0xda, + 0xbc, 0x91, 0xf7, 0x9c, 0x7b, 0xce, 0xb9, 0xbf, 0xe7, 0xdc, 0x73, 0xcf, 0x3d, 0x03, 0xeb, 0x0d, + 0x3b, 0xd8, 0xe9, 0x6c, 0x2d, 0xd5, 0xdc, 0xd6, 0xb2, 0xe5, 0x35, 0xdc, 0xb6, 0xe7, 0xde, 0x60, + 0x3f, 0xde, 0xe5, 0xb9, 0xcd, 0xa6, 0xdb, 0x09, 0xfc, 0xe5, 0xf6, 0xcd, 0xc6, 0xb2, 0xd5, 0xb6, + 0xfd, 0x65, 0x55, 0xb2, 0xfb, 0x1e, 0xab, 0xd9, 0xde, 0xb1, 0xde, 0xb3, 0xdc, 0x20, 0x0e, 0xf1, + 0xac, 0x80, 0xd4, 0x97, 0xda, 0x9e, 0x1b, 0xb8, 0xe8, 0xe9, 0x90, 0xda, 0x92, 0xa4, 0xc6, 0x7e, + 0x7c, 0x44, 0xd6, 0x5d, 0x6a, 0xdf, 0x6c, 0x2c, 0x51, 0x6a, 0x4b, 0xaa, 0x44, 0x52, 0x5b, 0x7c, + 0x97, 0x26, 0x4b, 0xc3, 0x6d, 0xb8, 0xcb, 0x8c, 0xe8, 0x56, 0x67, 0x9b, 0xfd, 0x63, 0x7f, 0xd8, + 0x2f, 0xce, 0x6c, 0xf1, 0xc1, 0x9b, 0x4f, 0xfa, 0x4b, 0xb6, 0x4b, 0x65, 0x5b, 0xde, 0xb2, 0x82, + 0xda, 0xce, 0xf2, 0x6e, 0x8f, 0x44, 0x8b, 0xa6, 0x86, 0x54, 0x73, 0x3d, 0x92, 0x84, 0xf3, 0x78, + 0x88, 0xd3, 0xb2, 0x6a, 0x3b, 0xb6, 0x43, 0xbc, 0xbd, 0xb0, 0xd5, 0x2d, 0x12, 0x58, 0x49, 0xb5, + 0x96, 0xfb, 0xd5, 0xf2, 0x3a, 0x4e, 0x60, 0xb7, 0x48, 0x4f, 0x85, 0xff, 0x7f, 0x58, 0x05, 0xbf, + 0xb6, 0x43, 0x5a, 0x56, 0x4f, 0xbd, 0xc7, 0xfa, 0xd5, 0xeb, 0x04, 0x76, 0x73, 0xd9, 0x76, 0x02, + 0x3f, 0xf0, 0xe2, 0x95, 0xcc, 0xaf, 0x67, 0xa1, 0x50, 0x5a, 0x2f, 0x57, 0x03, 0x2b, 0xe8, 0xf8, + 0xe8, 0x35, 0x03, 0xa6, 0x9a, 0xae, 0x55, 0x2f, 0x5b, 0x4d, 0xcb, 0xa9, 0x11, 0x6f, 0xc1, 0x78, + 0xc0, 0x78, 0x78, 0xf2, 0xd1, 0xf5, 0xa5, 0x51, 0xc6, 0x6b, 0xa9, 0x74, 0xcb, 0xc7, 0xc4, 0x77, + 0x3b, 0x5e, 0x8d, 0x60, 0xb2, 0x5d, 0x9e, 0xff, 0x56, 0xb7, 0x78, 0xcf, 0x7e, 0xb7, 0x38, 0xb5, + 0xae, 0x71, 0xc2, 0x11, 0xbe, 0xe8, 0x8b, 0x06, 0xcc, 0xd5, 0x2c, 0xc7, 0xf2, 0xf6, 0x36, 0x2d, + 0xaf, 0x41, 0x82, 0x67, 0x3d, 0xb7, 0xd3, 0x5e, 0xc8, 0x1c, 0x83, 0x34, 0xf7, 0x0a, 0x69, 0xe6, + 0x56, 0xe2, 0xec, 0x70, 0xaf, 0x04, 0x4c, 0x2e, 0x3f, 0xb0, 0xb6, 0x9a, 0x44, 0x97, 0x2b, 0x7b, + 0x9c, 0x72, 0x55, 0xe3, 0xec, 0x70, 0xaf, 0x04, 0xe6, 0xab, 0x59, 0x98, 0x2b, 0xad, 0x97, 0x37, + 0x3d, 0x6b, 0x7b, 0xdb, 0xae, 0x61, 0xb7, 0x13, 0xd8, 0x4e, 0x03, 0xbd, 0x13, 0x26, 0x6c, 0xa7, + 0xe1, 0x11, 0xdf, 0x67, 0x03, 0x59, 0x28, 0xcf, 0x08, 0xa2, 0x13, 0x6b, 0xbc, 0x18, 0x4b, 0x38, + 0x7a, 0x02, 0x26, 0x7d, 0xe2, 0xed, 0xda, 0x35, 0x52, 0x71, 0xbd, 0x80, 0xf5, 0x74, 0xae, 0x7c, + 0x52, 0xa0, 0x4f, 0x56, 0x43, 0x10, 0xd6, 0xf1, 0x68, 0x35, 0xcf, 0x75, 0x03, 0x01, 0x67, 0x1d, + 0x51, 0x08, 0xab, 0xe1, 0x10, 0x84, 0x75, 0x3c, 0xf4, 0xba, 0x01, 0xb3, 0x7e, 0x60, 0xd7, 0x6e, + 0xda, 0x0e, 0xf1, 0xfd, 0x15, 0xd7, 0xd9, 0xb6, 0x1b, 0x0b, 0x39, 0xd6, 0x8b, 0x97, 0x46, 0xeb, + 0xc5, 0x6a, 0x8c, 0x6a, 0x79, 0x7e, 0xbf, 0x5b, 0x9c, 0x8d, 0x97, 0xe2, 0x1e, 0xee, 0x68, 0x15, + 0x66, 0x2d, 0xc7, 0x71, 0x03, 0x2b, 0xb0, 0x5d, 0xa7, 0xe2, 0x91, 0x6d, 0xfb, 0xf6, 0xc2, 0x18, + 0x6b, 0xce, 0x82, 0x68, 0xce, 0x6c, 0x29, 0x06, 0xc7, 0x3d, 0x35, 0xcc, 0x55, 0x58, 0x28, 0xb5, + 0xb6, 0x2c, 0xdf, 0xb7, 0xea, 0xae, 0x17, 0x1b, 0x8d, 0x87, 0x21, 0xdf, 0xb2, 0xda, 0x6d, 0xdb, + 0x69, 0xd0, 0xe1, 0xc8, 0x3e, 0x5c, 0x28, 0x4f, 0xed, 0x77, 0x8b, 0xf9, 0x0d, 0x51, 0x86, 0x15, + 0xd4, 0xfc, 0x41, 0x06, 0x26, 0x4b, 0x8e, 0xd5, 0xdc, 0xf3, 0x6d, 0x1f, 0x77, 0x1c, 0xf4, 0x51, + 0xc8, 0xd3, 0xdd, 0xa5, 0x6e, 0x05, 0x96, 0x58, 0x91, 0xef, 0x5e, 0xe2, 0x8b, 0x7d, 0x49, 0x5f, + 0xec, 0x61, 0xbf, 0x50, 0xec, 0xa5, 0xdd, 0xf7, 0x2c, 0x5d, 0xde, 0xba, 0x41, 0x6a, 0xc1, 0x06, + 0x09, 0xac, 0x32, 0x12, 0xad, 0x80, 0xb0, 0x0c, 0x2b, 0xaa, 0xc8, 0x85, 0x31, 0xbf, 0x4d, 0x6a, + 0x62, 0x85, 0x6d, 0x8c, 0x38, 0x93, 0x43, 0xd1, 0xab, 0x6d, 0x52, 0x2b, 0x4f, 0x09, 0xd6, 0x63, + 0xf4, 0x1f, 0x66, 0x8c, 0xd0, 0x2d, 0x18, 0xf7, 0xd9, 0x9e, 0x23, 0x16, 0xcf, 0xe5, 0xf4, 0x58, + 0x32, 0xb2, 0xe5, 0x69, 0xc1, 0x74, 0x9c, 0xff, 0xc7, 0x82, 0x9d, 0xf9, 0x0f, 0x06, 0x9c, 0xd4, + 0xb0, 0x4b, 0x5e, 0xa3, 0xd3, 0x22, 0x4e, 0x80, 0x1e, 0x80, 0x31, 0xc7, 0x6a, 0x11, 0xb1, 0x50, + 0x94, 0xc8, 0x97, 0xac, 0x16, 0xc1, 0x0c, 0x82, 0x1e, 0x84, 0xdc, 0xae, 0xd5, 0xec, 0x10, 0xd6, + 0x49, 0x85, 0xf2, 0x09, 0x81, 0x92, 0xbb, 0x46, 0x0b, 0x31, 0x87, 0xa1, 0x97, 0xa0, 0xc0, 0x7e, + 0x9c, 0xf7, 0xdc, 0x56, 0x4a, 0x4d, 0x13, 0x12, 0x5e, 0x93, 0x64, 0xcb, 0x27, 0xf6, 0xbb, 0xc5, + 0x82, 0xfa, 0x8b, 0x43, 0x86, 0xe6, 0x3f, 0x1a, 0x30, 0xa3, 0x35, 0x6e, 0xdd, 0xf6, 0x03, 0xf4, + 0xa1, 0x9e, 0xc9, 0xb3, 0x34, 0xd8, 0xe4, 0xa1, 0xb5, 0xd9, 0xd4, 0x99, 0x15, 0x2d, 0xcd, 0xcb, + 0x12, 0x6d, 0xe2, 0x38, 0x90, 0xb3, 0x03, 0xd2, 0xf2, 0x17, 0x32, 0x0f, 0x64, 0x1f, 0x9e, 0x7c, + 0x74, 0x2d, 0xb5, 0x61, 0x0c, 0xfb, 0x77, 0x8d, 0xd2, 0xc7, 0x9c, 0x8d, 0xf9, 0x95, 0xb1, 0x48, + 0x0b, 0xe9, 0x8c, 0x42, 0x2e, 0x4c, 0xb4, 0x48, 0xe0, 0xd9, 0x35, 0xbe, 0xae, 0x26, 0x1f, 0x5d, + 0x1d, 0x4d, 0x8a, 0x0d, 0x46, 0x2c, 0xdc, 0x2c, 0xf9, 0x7f, 0x1f, 0x4b, 0x2e, 0x68, 0x07, 0xc6, + 0x2c, 0xaf, 0x21, 0xdb, 0x7c, 0x3e, 0x9d, 0xf1, 0x0d, 0xe7, 0x5c, 0xc9, 0x6b, 0xf8, 0x98, 0x71, + 0x40, 0xcb, 0x50, 0x08, 0x88, 0xd7, 0xb2, 0x1d, 0x2b, 0xe0, 0xbb, 0x6b, 0xbe, 0x3c, 0x27, 0xd0, + 0x0a, 0x9b, 0x12, 0x80, 0x43, 0x1c, 0xd4, 0x84, 0xf1, 0xba, 0xb7, 0x87, 0x3b, 0xce, 0xc2, 0x58, + 0x1a, 0x5d, 0xb1, 0xca, 0x68, 0x85, 0x8b, 0x89, 0xff, 0xc7, 0x82, 0x07, 0x7a, 0xc3, 0x80, 0xf9, + 0x16, 0xb1, 0xfc, 0x8e, 0x47, 0x68, 0x13, 0x30, 0x09, 0x88, 0x43, 0x77, 0xc3, 0x85, 0x1c, 0x63, + 0x8e, 0x47, 0x1d, 0x87, 0x5e, 0xca, 0xe5, 0xfb, 0x85, 0x28, 0xf3, 0x49, 0x50, 0x9c, 0x28, 0x8d, + 0xf9, 0x83, 0x31, 0x98, 0xeb, 0xd9, 0x21, 0xd0, 0xe3, 0x90, 0x6b, 0xef, 0x58, 0xbe, 0x5c, 0xf2, + 0x67, 0xe5, 0x7c, 0xab, 0xd0, 0xc2, 0x3b, 0xdd, 0xe2, 0x09, 0x59, 0x85, 0x15, 0x60, 0x8e, 0x4c, + 0x75, 0x6a, 0x8b, 0xf8, 0xbe, 0xd5, 0x90, 0xfb, 0x80, 0x36, 0x4d, 0x58, 0x31, 0x96, 0x70, 0xf4, + 0x2b, 0x06, 0x9c, 0xe0, 0x53, 0x06, 0x13, 0xbf, 0xd3, 0x0c, 0xe8, 0x5e, 0x47, 0xbb, 0xe5, 0x62, + 0x1a, 0xd3, 0x93, 0x93, 0x2c, 0x9f, 0x12, 0xdc, 0x4f, 0xe8, 0xa5, 0x3e, 0x8e, 0xf2, 0x45, 0xd7, + 0xa1, 0xe0, 0x07, 0x96, 0x17, 0x90, 0x7a, 0x29, 0x60, 0x5a, 0x6d, 0xf2, 0xd1, 0xff, 0x3b, 0xd8, + 0x26, 0xb0, 0x69, 0xb7, 0x08, 0xdf, 0x70, 0xaa, 0x92, 0x00, 0x0e, 0x69, 0xa1, 0x97, 0x00, 0xbc, + 0x8e, 0x53, 0xed, 0xb4, 0x5a, 0x96, 0xb7, 0x27, 0x34, 0xf8, 0x85, 0xd1, 0x9a, 0x87, 0x15, 0xbd, + 0x50, 0x67, 0x85, 0x65, 0x58, 0xe3, 0x87, 0x5e, 0x31, 0xe0, 0x04, 0x9f, 0x89, 0x52, 0x82, 0xf1, + 0x94, 0x25, 0x98, 0xa3, 0x5d, 0xbb, 0xaa, 0xb3, 0xc0, 0x51, 0x8e, 0xe6, 0xdf, 0x45, 0xf5, 0x49, + 0x35, 0xa0, 0xd6, 0x75, 0x63, 0x0f, 0x7d, 0x10, 0xee, 0xf5, 0x3b, 0xb5, 0x1a, 0xf1, 0xfd, 0xed, + 0x4e, 0x13, 0x77, 0x9c, 0x0b, 0xb6, 0x1f, 0xb8, 0xde, 0xde, 0xba, 0xdd, 0xb2, 0x03, 0x36, 0xe3, + 0x72, 0xe5, 0x33, 0xfb, 0xdd, 0xe2, 0xbd, 0xd5, 0x7e, 0x48, 0xb8, 0x7f, 0x7d, 0x64, 0xc1, 0x7d, + 0x1d, 0xa7, 0x3f, 0x79, 0x6e, 0xbd, 0x15, 0xf7, 0xbb, 0xc5, 0xfb, 0xae, 0xf6, 0x47, 0xc3, 0x07, + 0xd1, 0x30, 0xff, 0xd5, 0x80, 0x59, 0xd9, 0xae, 0x4d, 0xd2, 0x6a, 0x37, 0xe9, 0xee, 0x72, 0xfc, + 0x86, 0x48, 0x10, 0x31, 0x44, 0x70, 0x3a, 0xea, 0x44, 0xca, 0xdf, 0xcf, 0x1a, 0x31, 0xff, 0xc5, + 0x80, 0xf9, 0x38, 0xf2, 0x5d, 0x50, 0x9e, 0x7e, 0x54, 0x79, 0x5e, 0x4a, 0xb7, 0xb5, 0x7d, 0x34, + 0xe8, 0x6b, 0x63, 0xbd, 0x6d, 0xfd, 0x9f, 0xae, 0x46, 0x43, 0xad, 0x98, 0xfd, 0x59, 0x6a, 0xc5, + 0xb1, 0xb7, 0x94, 0x56, 0xfc, 0x83, 0x31, 0x98, 0x2a, 0x39, 0x81, 0x5d, 0xda, 0xde, 0xb6, 0x1d, + 0x3b, 0xd8, 0x43, 0x9f, 0xc9, 0xc0, 0x72, 0xdb, 0x23, 0xdb, 0xc4, 0xf3, 0x48, 0x7d, 0xb5, 0xe3, + 0xd9, 0x4e, 0xa3, 0x5a, 0xdb, 0x21, 0xf5, 0x4e, 0xd3, 0x76, 0x1a, 0x6b, 0x0d, 0xc7, 0x55, 0xc5, + 0xe7, 0x6e, 0x93, 0x5a, 0x87, 0x35, 0x89, 0x2f, 0x8a, 0xd6, 0x68, 0x4d, 0xaa, 0x0c, 0xc7, 0xb4, + 0xfc, 0xd8, 0x7e, 0xb7, 0xb8, 0x3c, 0x64, 0x25, 0x3c, 0x6c, 0xd3, 0xd0, 0xa7, 0x33, 0xb0, 0xe4, + 0x91, 0x8f, 0x75, 0xec, 0xc1, 0x7b, 0x83, 0xef, 0x5a, 0xcd, 0x11, 0xd5, 0xcf, 0x50, 0x3c, 0xcb, + 0x8f, 0xee, 0x77, 0x8b, 0x43, 0xd6, 0xc1, 0x43, 0xb6, 0xcb, 0xfc, 0x5a, 0x06, 0x4e, 0x95, 0xda, + 0xed, 0x0d, 0xe2, 0xef, 0xc4, 0x0e, 0xb5, 0x9f, 0x33, 0x60, 0x7a, 0xd7, 0xf6, 0x82, 0x8e, 0xd5, + 0x94, 0x4e, 0x00, 0x3e, 0x25, 0xaa, 0x23, 0x2e, 0x67, 0xce, 0xed, 0x5a, 0x84, 0x74, 0x19, 0xed, + 0x77, 0x8b, 0xd3, 0xd1, 0x32, 0x1c, 0x63, 0x8f, 0x7e, 0xd3, 0x80, 0x59, 0x51, 0x74, 0xc9, 0xad, + 0x13, 0xdd, 0x73, 0x74, 0x35, 0x4d, 0x99, 0x14, 0x71, 0xee, 0x62, 0x88, 0x97, 0xe2, 0x1e, 0x21, + 0xcc, 0x7f, 0xcf, 0xc0, 0xe9, 0x3e, 0x34, 0xd0, 0xef, 0x1b, 0x30, 0xcf, 0xdd, 0x4d, 0x1a, 0x08, + 0x93, 0x6d, 0xd1, 0x9b, 0x1f, 0x48, 0x5b, 0x72, 0x4c, 0xd7, 0x02, 0x71, 0x6a, 0xa4, 0xbc, 0x40, + 0xb7, 0x8d, 0x95, 0x04, 0xd6, 0x38, 0x51, 0x20, 0x26, 0x29, 0x77, 0x40, 0xc5, 0x24, 0xcd, 0xdc, + 0x15, 0x49, 0xab, 0x09, 0xac, 0x71, 0xa2, 0x40, 0xe6, 0x2f, 0xc2, 0x7d, 0x07, 0x90, 0x3b, 0xfc, + 0xc4, 0x6f, 0xbe, 0xa0, 0x66, 0x7d, 0x74, 0xce, 0x0d, 0xe0, 0x2c, 0x30, 0x61, 0xdc, 0x73, 0x3b, + 0x01, 0xe1, 0xda, 0xad, 0x50, 0x06, 0xaa, 0x27, 0x30, 0x2b, 0xc1, 0x02, 0x62, 0x7e, 0xcd, 0x80, + 0xfc, 0x10, 0xfe, 0x87, 0x62, 0xd4, 0xff, 0x50, 0xe8, 0xf1, 0x3d, 0x04, 0xbd, 0xbe, 0x87, 0x67, + 0x47, 0x1b, 0x8d, 0x41, 0x7c, 0x0e, 0x3f, 0x36, 0x60, 0xae, 0xc7, 0x47, 0x81, 0x76, 0x60, 0xbe, + 0xed, 0xd6, 0xa5, 0x7d, 0x71, 0xc1, 0xf2, 0x77, 0x18, 0x4c, 0x34, 0xef, 0x71, 0x3a, 0x92, 0x95, + 0x04, 0xf8, 0x9d, 0x6e, 0x71, 0x41, 0x11, 0x89, 0x21, 0xe0, 0x44, 0x8a, 0xa8, 0x0d, 0xf9, 0x6d, + 0x9b, 0x34, 0xeb, 0xe1, 0x14, 0x1c, 0xd1, 0x92, 0x38, 0x2f, 0xa8, 0x71, 0xf7, 0x9c, 0xfc, 0x87, + 0x15, 0x17, 0xf3, 0x0a, 0x4c, 0x47, 0x9d, 0xb5, 0x03, 0x0c, 0xde, 0x19, 0xc8, 0x5a, 0x9e, 0x23, + 0x86, 0x6e, 0x52, 0x20, 0x64, 0x4b, 0xf8, 0x12, 0xa6, 0xe5, 0xe6, 0x4f, 0xc7, 0x60, 0xa6, 0xdc, + 0xec, 0x90, 0x67, 0x3d, 0x42, 0xe4, 0xf9, 0xb4, 0x04, 0x33, 0x6d, 0x8f, 0xec, 0xda, 0xe4, 0x56, + 0x95, 0x34, 0x49, 0x2d, 0x70, 0x3d, 0x41, 0xff, 0xb4, 0xa8, 0x3e, 0x53, 0x89, 0x82, 0x71, 0x1c, + 0x1f, 0x3d, 0x03, 0xd3, 0x56, 0x2d, 0xb0, 0x77, 0x89, 0xa2, 0xc0, 0x05, 0x78, 0x9b, 0xa0, 0x30, + 0x5d, 0x8a, 0x40, 0x71, 0x0c, 0x1b, 0x7d, 0x08, 0x16, 0xfc, 0x9a, 0xd5, 0x24, 0x57, 0xdb, 0x82, + 0xd5, 0xca, 0x0e, 0xa9, 0xdd, 0xac, 0xb8, 0xb6, 0x13, 0x08, 0x6f, 0xc4, 0x03, 0x82, 0xd2, 0x42, + 0xb5, 0x0f, 0x1e, 0xee, 0x4b, 0x01, 0xfd, 0xb9, 0x01, 0x67, 0xda, 0x1e, 0xa9, 0x78, 0x6e, 0xcb, + 0xa5, 0x6a, 0xa6, 0xe7, 0x88, 0x2e, 0x8e, 0xaa, 0xd7, 0x46, 0xd4, 0xa7, 0xbc, 0xa4, 0xd7, 0x45, + 0xf8, 0xf6, 0xfd, 0x6e, 0xf1, 0x4c, 0xe5, 0x20, 0x01, 0xf0, 0xc1, 0xf2, 0xa1, 0xbf, 0x34, 0xe0, + 0x6c, 0xdb, 0xf5, 0x83, 0x03, 0x9a, 0x90, 0x3b, 0xd6, 0x26, 0x98, 0xfb, 0xdd, 0xe2, 0xd9, 0xca, + 0x81, 0x12, 0xe0, 0x43, 0x24, 0x34, 0xf7, 0x27, 0x61, 0x4e, 0x9b, 0x7b, 0xe2, 0xfc, 0xfa, 0x14, + 0x9c, 0x90, 0x93, 0x21, 0x54, 0xeb, 0x85, 0xd0, 0xdf, 0x50, 0xd2, 0x81, 0x38, 0x8a, 0x4b, 0xe7, + 0x9d, 0x9a, 0x8a, 0xbc, 0x76, 0x6c, 0xde, 0x55, 0x22, 0x50, 0x1c, 0xc3, 0x46, 0x6b, 0x70, 0x52, + 0x94, 0x60, 0xd2, 0x6e, 0xda, 0x35, 0x6b, 0xc5, 0xed, 0x88, 0x29, 0x97, 0x2b, 0x9f, 0xde, 0xef, + 0x16, 0x4f, 0x56, 0x7a, 0xc1, 0x38, 0xa9, 0x0e, 0x5a, 0x87, 0x79, 0xab, 0x13, 0xb8, 0xaa, 0xfd, + 0xe7, 0x1c, 0xaa, 0x29, 0xea, 0x6c, 0x6a, 0xe5, 0xb9, 0x4a, 0x29, 0x25, 0xc0, 0x71, 0x62, 0x2d, + 0x54, 0x89, 0x51, 0xab, 0x92, 0x9a, 0xeb, 0xd4, 0xf9, 0x28, 0xe7, 0x42, 0x2b, 0xbc, 0x94, 0x80, + 0x83, 0x13, 0x6b, 0xa2, 0x26, 0x4c, 0xb7, 0xac, 0xdb, 0x57, 0x1d, 0x6b, 0xd7, 0xb2, 0x9b, 0x94, + 0x89, 0xf0, 0x61, 0xf4, 0x3f, 0x58, 0x77, 0x02, 0xbb, 0xb9, 0xc4, 0xaf, 0xf3, 0x96, 0xd6, 0x9c, + 0xe0, 0xb2, 0x57, 0x0d, 0xa8, 0xb5, 0xc6, 0x8d, 0xa3, 0x8d, 0x08, 0x2d, 0x1c, 0xa3, 0x8d, 0x2e, + 0xc3, 0x29, 0xb6, 0x1c, 0x57, 0xdd, 0x5b, 0xce, 0x2a, 0x69, 0x5a, 0x7b, 0xb2, 0x01, 0x13, 0xac, + 0x01, 0xf7, 0xee, 0x77, 0x8b, 0xa7, 0xaa, 0x49, 0x08, 0x38, 0xb9, 0x1e, 0xb2, 0xe0, 0xbe, 0x28, + 0x00, 0x93, 0x5d, 0xdb, 0xb7, 0x5d, 0x87, 0x7b, 0x22, 0xf2, 0xa1, 0x27, 0xa2, 0xda, 0x1f, 0x0d, + 0x1f, 0x44, 0x03, 0xfd, 0xb6, 0x01, 0xf3, 0x49, 0xcb, 0x70, 0xa1, 0x90, 0xc6, 0x65, 0x45, 0x6c, + 0x69, 0xf1, 0x19, 0x91, 0xb8, 0x29, 0x24, 0x0a, 0x81, 0x5e, 0x36, 0x60, 0xca, 0xd2, 0x4e, 0x51, + 0x0b, 0xc0, 0xa4, 0xba, 0x38, 0xea, 0x59, 0x3e, 0xa4, 0x58, 0x9e, 0xdd, 0xef, 0x16, 0x23, 0x27, + 0x35, 0x1c, 0xe1, 0x88, 0x7e, 0xd7, 0x80, 0x53, 0x89, 0x6b, 0x7c, 0x61, 0xf2, 0x38, 0x7a, 0x88, + 0x4d, 0x92, 0xe4, 0x3d, 0x27, 0x59, 0x0c, 0xf4, 0xba, 0xa1, 0x54, 0xd9, 0x86, 0xf4, 0xa6, 0x4c, + 0x31, 0xd1, 0xae, 0x8c, 0x78, 0x70, 0x0c, 0x0d, 0x02, 0x49, 0xb8, 0x7c, 0x52, 0xd3, 0x8c, 0xb2, + 0x10, 0xc7, 0xd9, 0xa3, 0xcf, 0x1a, 0x52, 0x35, 0x2a, 0x89, 0x4e, 0x1c, 0x97, 0x44, 0x28, 0xd4, + 0xb4, 0x4a, 0xa0, 0x18, 0x73, 0xf4, 0x61, 0x58, 0xb4, 0xb6, 0x5c, 0x2f, 0x48, 0x5c, 0x7c, 0x0b, + 0xd3, 0x6c, 0x19, 0x9d, 0xdd, 0xef, 0x16, 0x17, 0x4b, 0x7d, 0xb1, 0xf0, 0x01, 0x14, 0xcc, 0x3f, + 0xce, 0xc1, 0x14, 0x37, 0xf2, 0x85, 0xea, 0xfa, 0xaa, 0x01, 0xf7, 0xd7, 0x3a, 0x9e, 0x47, 0x9c, + 0xa0, 0x1a, 0x90, 0x76, 0xaf, 0xe2, 0x32, 0x8e, 0x55, 0x71, 0x3d, 0xb0, 0xdf, 0x2d, 0xde, 0xbf, + 0x72, 0x00, 0x7f, 0x7c, 0xa0, 0x74, 0xe8, 0x6f, 0x0c, 0x30, 0x05, 0x42, 0xd9, 0xaa, 0xdd, 0x6c, + 0x78, 0x6e, 0xc7, 0xa9, 0xf7, 0x36, 0x22, 0x73, 0xac, 0x8d, 0x78, 0x68, 0xbf, 0x5b, 0x34, 0x57, + 0x0e, 0x95, 0x02, 0x0f, 0x20, 0x29, 0x7a, 0x16, 0xe6, 0x04, 0xd6, 0xb9, 0xdb, 0x6d, 0xe2, 0xd9, + 0xd4, 0x9c, 0x16, 0xf7, 0xe9, 0x61, 0x88, 0x42, 0x1c, 0x01, 0xf7, 0xd6, 0x41, 0x3e, 0x4c, 0xdc, + 0x22, 0x76, 0x63, 0x27, 0x90, 0xe6, 0xd3, 0x88, 0x71, 0x09, 0xe2, 0xc0, 0x7f, 0x9d, 0xd3, 0x2c, + 0x4f, 0xee, 0x77, 0x8b, 0x13, 0xe2, 0x0f, 0x96, 0x9c, 0xd0, 0x25, 0x98, 0xe6, 0x47, 0xb0, 0x8a, + 0xed, 0x34, 0x2a, 0xae, 0xc3, 0x6f, 0xf3, 0x0b, 0xe5, 0x87, 0xa4, 0xc2, 0xaf, 0x46, 0xa0, 0x77, + 0xba, 0xc5, 0x29, 0xf9, 0x7b, 0x73, 0xaf, 0x4d, 0x70, 0xac, 0xb6, 0xf9, 0xcd, 0x71, 0x00, 0x39, + 0x5d, 0x49, 0x1b, 0xfd, 0x3f, 0x28, 0xf8, 0x24, 0xe0, 0x5c, 0x85, 0xf3, 0x9c, 0xdf, 0x49, 0xc8, + 0x42, 0x1c, 0xc2, 0xd1, 0x4d, 0xc8, 0xb5, 0xad, 0x8e, 0x4f, 0xc4, 0xe0, 0x5f, 0x4c, 0x65, 0xf0, + 0x2b, 0x94, 0x22, 0x3f, 0x73, 0xb1, 0x9f, 0x98, 0xf3, 0x40, 0x9f, 0x32, 0x00, 0x48, 0x74, 0xc0, + 0x46, 0xf6, 0x7d, 0x08, 0x96, 0xe1, 0x98, 0xd2, 0x3e, 0x28, 0x4f, 0xef, 0x77, 0x8b, 0xa0, 0x0d, + 0xbd, 0xc6, 0x16, 0xdd, 0x82, 0xbc, 0x25, 0xf7, 0xfc, 0xb1, 0xe3, 0xd8, 0xf3, 0xd9, 0x51, 0x48, + 0x4d, 0x5a, 0xc5, 0x0c, 0x7d, 0xda, 0x80, 0x69, 0x9f, 0x04, 0x62, 0xa8, 0xe8, 0xce, 0x23, 0x0c, + 0xde, 0x11, 0x27, 0x5d, 0x35, 0x42, 0x93, 0xef, 0xa0, 0xd1, 0x32, 0x1c, 0xe3, 0x2b, 0x45, 0xb9, + 0x40, 0xac, 0x3a, 0xf1, 0xd8, 0x49, 0x5b, 0x58, 0x52, 0xa3, 0x8b, 0xa2, 0xd1, 0x54, 0xa2, 0x68, + 0x65, 0x38, 0xc6, 0x57, 0x8a, 0xb2, 0x61, 0x7b, 0x9e, 0x2b, 0x44, 0xc9, 0xa7, 0x24, 0x8a, 0x46, + 0x53, 0x89, 0xa2, 0x95, 0xe1, 0x18, 0x5f, 0xf3, 0x6f, 0xa7, 0x60, 0x5a, 0x2e, 0xa4, 0xd0, 0xb2, + 0xe7, 0x8e, 0x9d, 0x3e, 0x96, 0xfd, 0x8a, 0x0e, 0xc4, 0x51, 0x5c, 0x5a, 0x99, 0x2f, 0xd5, 0xa8, + 0x61, 0xaf, 0x2a, 0x57, 0x75, 0x20, 0x8e, 0xe2, 0xa2, 0x16, 0xe4, 0xfc, 0x80, 0xb4, 0xe5, 0x3d, + 0xe8, 0x88, 0xd7, 0x74, 0xe1, 0xfe, 0x10, 0xde, 0x74, 0xd0, 0x7f, 0x3e, 0xe6, 0x5c, 0x98, 0x6f, + 0x32, 0x88, 0xb8, 0x2b, 0xc5, 0xe2, 0x48, 0x67, 0x7d, 0x46, 0x3d, 0xa1, 0x7c, 0x34, 0xa2, 0x65, + 0x38, 0xc6, 0x3e, 0xc1, 0xd8, 0xcf, 0x1d, 0xa3, 0xb1, 0xff, 0x3c, 0xe4, 0x5b, 0xd6, 0xed, 0x6a, + 0xc7, 0x6b, 0x1c, 0xfd, 0x50, 0x21, 0x42, 0x94, 0x38, 0x15, 0xac, 0xe8, 0xa1, 0x57, 0x0c, 0x6d, + 0xcb, 0x99, 0x60, 0xc4, 0xaf, 0xa7, 0xbb, 0xe5, 0x28, 0x5d, 0xd9, 0x77, 0xf3, 0xe9, 0x31, 0xbd, + 0xf3, 0x77, 0xdd, 0xf4, 0xa6, 0x66, 0x24, 0x5f, 0x20, 0xca, 0x8c, 0x2c, 0x1c, 0xab, 0x19, 0xb9, + 0x12, 0x61, 0x86, 0x63, 0xcc, 0x99, 0x3c, 0x7c, 0xcd, 0x29, 0x79, 0xe0, 0x58, 0xe5, 0xa9, 0x46, + 0x98, 0xe1, 0x18, 0xf3, 0xfe, 0xe7, 0xcd, 0xc9, 0xe3, 0x39, 0x6f, 0x4e, 0xa5, 0x70, 0xde, 0x3c, + 0xd8, 0x14, 0x3f, 0x31, 0xaa, 0x29, 0x8e, 0x2e, 0x02, 0xaa, 0xef, 0x39, 0x56, 0xcb, 0xae, 0x89, + 0xcd, 0x92, 0xa9, 0xcd, 0x69, 0xe6, 0x8f, 0x58, 0x14, 0x1b, 0x19, 0x5a, 0xed, 0xc1, 0xc0, 0x09, + 0xb5, 0x50, 0x00, 0xf9, 0xb6, 0xb4, 0xb8, 0x66, 0xd2, 0x98, 0xfd, 0xd2, 0x02, 0xe3, 0x57, 0xe5, + 0x74, 0xe1, 0xc9, 0x12, 0xac, 0x38, 0x99, 0xff, 0x69, 0xc0, 0xec, 0x4a, 0xd3, 0xed, 0xd4, 0xaf, + 0x5b, 0x41, 0x6d, 0x87, 0xdf, 0xeb, 0xa2, 0x67, 0x20, 0x6f, 0x3b, 0x01, 0xf1, 0x76, 0xad, 0xa6, + 0xd0, 0x28, 0xa6, 0xbc, 0xfa, 0x5e, 0x13, 0xe5, 0x77, 0xba, 0xc5, 0xe9, 0xd5, 0x8e, 0xc7, 0x02, + 0x26, 0xf9, 0xfe, 0x82, 0x55, 0x1d, 0xf4, 0x25, 0x03, 0xe6, 0xf8, 0xcd, 0xf0, 0xaa, 0x15, 0x58, + 0x57, 0x3a, 0xc4, 0xb3, 0x89, 0xbc, 0x1b, 0x1e, 0x71, 0x6b, 0x89, 0xcb, 0x2a, 0x19, 0xec, 0x85, + 0xa6, 0xf5, 0x46, 0x9c, 0x33, 0xee, 0x15, 0xc6, 0xfc, 0x7c, 0x16, 0xee, 0xed, 0x4b, 0x0b, 0x2d, + 0x42, 0xc6, 0xae, 0x8b, 0xa6, 0x83, 0xa0, 0x9b, 0x59, 0xab, 0xe3, 0x8c, 0x5d, 0x47, 0x4b, 0xcc, + 0x4a, 0xf4, 0x88, 0xef, 0xcb, 0x6b, 0xc2, 0x82, 0x32, 0xe8, 0x44, 0x29, 0xd6, 0x30, 0x50, 0x11, + 0x72, 0x4d, 0x6b, 0x8b, 0x34, 0xc5, 0x09, 0x80, 0xd9, 0x9d, 0xeb, 0xb4, 0x00, 0xf3, 0x72, 0xf4, + 0xcb, 0x06, 0x00, 0x17, 0x90, 0x9e, 0x1f, 0x84, 0x5e, 0xc3, 0xe9, 0x76, 0x13, 0xa5, 0xcc, 0xa5, + 0x0c, 0xff, 0x63, 0x8d, 0x2b, 0xda, 0x84, 0x71, 0x6a, 0x82, 0xba, 0xf5, 0x23, 0xab, 0x31, 0x76, + 0x2d, 0x52, 0x61, 0x34, 0xb0, 0xa0, 0x45, 0xfb, 0xca, 0x23, 0x41, 0xc7, 0x73, 0x68, 0xd7, 0x32, + 0xc5, 0x95, 0xe7, 0x52, 0x60, 0x55, 0x8a, 0x35, 0x0c, 0xf3, 0xcf, 0x32, 0x30, 0x9f, 0x24, 0x3a, + 0xd5, 0x0f, 0xe3, 0x5c, 0x5a, 0x71, 0x98, 0x7d, 0x7f, 0xfa, 0xfd, 0x23, 0x82, 0x1c, 0x54, 0x28, + 0x80, 0x08, 0xc3, 0x12, 0x7c, 0xd1, 0xfb, 0x55, 0x0f, 0x65, 0x8e, 0xd8, 0x43, 0x8a, 0x72, 0xac, + 0x97, 0x1e, 0x80, 0x31, 0x9f, 0x8e, 0x7c, 0x36, 0x7a, 0xe5, 0xc0, 0xc6, 0x88, 0x41, 0x28, 0x46, + 0xc7, 0xb1, 0x03, 0x11, 0xc5, 0xac, 0x30, 0xae, 0x3a, 0x76, 0x80, 0x19, 0xc4, 0xfc, 0x62, 0x06, + 0x16, 0xfb, 0x37, 0x0a, 0x7d, 0xd1, 0x00, 0xa8, 0xd3, 0x03, 0x06, 0x9d, 0x92, 0x32, 0x28, 0xc4, + 0x3a, 0xae, 0x3e, 0x5c, 0x95, 0x9c, 0xc2, 0x08, 0x21, 0x55, 0xe4, 0x63, 0x4d, 0x10, 0xf4, 0xa8, + 0x9c, 0xfa, 0x97, 0xac, 0x96, 0x34, 0x40, 0x55, 0x9d, 0x0d, 0x05, 0xc1, 0x1a, 0x16, 0x3d, 0x41, + 0x3a, 0x56, 0x8b, 0xf8, 0x6d, 0x4b, 0x85, 0xa9, 0xb3, 0x13, 0xe4, 0x25, 0x59, 0x88, 0x43, 0xb8, + 0xd9, 0x84, 0x07, 0x07, 0x90, 0x33, 0xa5, 0x90, 0x61, 0xf3, 0x3f, 0x0c, 0x38, 0xbd, 0xd2, 0xec, + 0xf8, 0x01, 0xf1, 0xfe, 0xd7, 0x04, 0x5c, 0xfd, 0x97, 0x01, 0xf7, 0xf5, 0x69, 0xf3, 0x5d, 0x88, + 0xbb, 0x7a, 0x31, 0x1a, 0x77, 0x75, 0x75, 0xd4, 0x29, 0x9d, 0xd8, 0x8e, 0x3e, 0xe1, 0x57, 0x01, + 0x9c, 0xa0, 0xbb, 0x56, 0xdd, 0x6d, 0xa4, 0xa4, 0x37, 0x1f, 0x84, 0xdc, 0xc7, 0xa8, 0xfe, 0x89, + 0xcf, 0x31, 0xa6, 0x94, 0x30, 0x87, 0x99, 0x4f, 0x83, 0x08, 0x52, 0x8a, 0x2d, 0x1e, 0x63, 0x90, + 0xc5, 0x63, 0xfe, 0x7d, 0x06, 0x34, 0xcf, 0xc3, 0x5d, 0x98, 0x94, 0x4e, 0x64, 0x52, 0x8e, 0x78, + 0x6a, 0xd6, 0xfc, 0x28, 0xfd, 0x5e, 0x23, 0xec, 0xc6, 0x5e, 0x23, 0x5c, 0x4a, 0x8d, 0xe3, 0xc1, + 0x8f, 0x11, 0xbe, 0x67, 0xc0, 0x7d, 0x21, 0x72, 0xaf, 0x53, 0xf0, 0xf0, 0x1d, 0xe6, 0x09, 0x98, + 0xb4, 0xc2, 0x6a, 0x62, 0x0e, 0xa8, 0x07, 0x38, 0x1a, 0x45, 0xac, 0xe3, 0x85, 0xb1, 0xcf, 0xd9, + 0x23, 0xc6, 0x3e, 0x8f, 0x1d, 0x1c, 0xfb, 0x6c, 0xfe, 0x24, 0x03, 0x67, 0x7a, 0x5b, 0x26, 0xd7, + 0xc6, 0x60, 0x77, 0xe6, 0x4f, 0xc2, 0x54, 0x20, 0x2a, 0x68, 0x3b, 0xbd, 0x7a, 0x3e, 0xb6, 0xa9, + 0xc1, 0x70, 0x04, 0x93, 0xd6, 0xac, 0xf1, 0x55, 0x59, 0xad, 0xb9, 0x6d, 0x19, 0x39, 0xaf, 0x6a, + 0xae, 0x68, 0x30, 0x1c, 0xc1, 0x54, 0x31, 0x89, 0x63, 0xc7, 0x1e, 0x93, 0x58, 0x85, 0x53, 0x32, + 0x0a, 0xeb, 0xbc, 0xeb, 0xad, 0xb8, 0xad, 0x76, 0x93, 0x88, 0xd8, 0x79, 0x2a, 0xec, 0x19, 0x51, + 0xe5, 0x14, 0x4e, 0x42, 0xc2, 0xc9, 0x75, 0xcd, 0xef, 0x65, 0xe1, 0x64, 0xd8, 0xed, 0x2b, 0xae, + 0x53, 0xb7, 0x59, 0x2c, 0xdb, 0x53, 0x30, 0x16, 0xec, 0xb5, 0x65, 0x67, 0xff, 0x1f, 0x29, 0xce, + 0xe6, 0x5e, 0x9b, 0x8e, 0xf6, 0xe9, 0x84, 0x2a, 0xcc, 0x2d, 0xcb, 0x2a, 0xa1, 0x75, 0xb5, 0x3a, + 0xf8, 0x08, 0x3c, 0x1e, 0x9d, 0xcd, 0x77, 0xba, 0xc5, 0x84, 0xd7, 0x93, 0x4b, 0x8a, 0x52, 0x74, + 0xce, 0xa3, 0x1b, 0x30, 0xdd, 0xb4, 0xfc, 0xe0, 0x6a, 0xbb, 0x6e, 0x05, 0x64, 0xd3, 0x6e, 0x11, + 0xb1, 0xe6, 0x86, 0x09, 0x48, 0x57, 0xf7, 0xc8, 0xeb, 0x11, 0x4a, 0x38, 0x46, 0x19, 0xed, 0x02, + 0xa2, 0x25, 0x9b, 0x9e, 0xe5, 0xf8, 0xbc, 0x55, 0x94, 0xdf, 0xf0, 0x01, 0xf0, 0xea, 0x58, 0xb6, + 0xde, 0x43, 0x0d, 0x27, 0x70, 0x40, 0x0f, 0xc1, 0xb8, 0x47, 0x2c, 0x5f, 0x0c, 0x66, 0x21, 0x5c, + 0xff, 0x98, 0x95, 0x62, 0x01, 0xd5, 0x17, 0xd4, 0xf8, 0x21, 0x0b, 0xea, 0x87, 0x06, 0x4c, 0x87, + 0xc3, 0x74, 0x17, 0x94, 0x64, 0x2b, 0xaa, 0x24, 0x2f, 0xa4, 0xb5, 0x25, 0xf6, 0xd1, 0x8b, 0x7f, + 0x35, 0xae, 0xb7, 0x8f, 0x05, 0x24, 0x7f, 0x1c, 0x0a, 0x72, 0x55, 0x4b, 0xeb, 0x73, 0xc4, 0xd3, + 0x6d, 0xc4, 0x2e, 0xd1, 0x1e, 0xd2, 0x08, 0x26, 0x38, 0xe4, 0x47, 0xd5, 0x72, 0x5d, 0xa8, 0x5c, + 0x31, 0xed, 0x95, 0x5a, 0x96, 0xaa, 0x38, 0x49, 0x2d, 0xcb, 0x3a, 0xe8, 0x2a, 0x9c, 0x6e, 0x7b, + 0x2e, 0x7b, 0x5c, 0xb9, 0x4a, 0xac, 0x7a, 0xd3, 0x76, 0x88, 0x74, 0x21, 0xf0, 0x30, 0x86, 0xfb, + 0xf6, 0xbb, 0xc5, 0xd3, 0x95, 0x64, 0x14, 0xdc, 0xaf, 0x6e, 0xf4, 0x41, 0xd0, 0xd8, 0x00, 0x0f, + 0x82, 0x7e, 0x55, 0x39, 0xea, 0x88, 0x2f, 0x9e, 0xe5, 0x7c, 0x30, 0xad, 0xa1, 0x4c, 0xd8, 0xd6, + 0xc3, 0x29, 0x55, 0x12, 0x4c, 0xb1, 0x62, 0xdf, 0xdf, 0x1b, 0x34, 0x7e, 0x44, 0x6f, 0x50, 0x18, + 0xd7, 0x3d, 0xf1, 0xb3, 0x8c, 0xeb, 0xce, 0xbf, 0xa5, 0xe2, 0xba, 0x5f, 0xcd, 0xc1, 0x6c, 0xdc, + 0x02, 0x39, 0xfe, 0xc7, 0x4e, 0xbf, 0x61, 0xc0, 0xac, 0x5c, 0x3d, 0x9c, 0x27, 0x91, 0x7e, 0xfe, + 0xf5, 0x94, 0x16, 0x2d, 0xb7, 0xa5, 0xd4, 0x73, 0xdc, 0xcd, 0x18, 0x37, 0xdc, 0xc3, 0x1f, 0xbd, + 0x00, 0x93, 0xca, 0x1d, 0x7e, 0xa4, 0x97, 0x4f, 0x33, 0xcc, 0x8a, 0x0a, 0x49, 0x60, 0x9d, 0x1e, + 0x7a, 0xd5, 0x00, 0xa8, 0x49, 0x35, 0x27, 0x57, 0xd7, 0x95, 0xb4, 0x56, 0x97, 0x52, 0xa0, 0xa1, + 0xb1, 0xac, 0x8a, 0x7c, 0xac, 0x31, 0x46, 0x9f, 0x67, 0x8e, 0x70, 0x65, 0xdd, 0xd1, 0xf5, 0x94, + 0x1d, 0x3d, 0x14, 0xf7, 0x00, 0xc3, 0x34, 0x34, 0xa5, 0x34, 0x90, 0x8f, 0x23, 0x42, 0x98, 0x4f, + 0x81, 0x0a, 0x9e, 0xa4, 0xdb, 0x16, 0x0b, 0x9f, 0xac, 0x58, 0xc1, 0x8e, 0x98, 0x82, 0x6a, 0xdb, + 0x3a, 0x2f, 0x01, 0x38, 0xc4, 0x31, 0x3f, 0x0a, 0xd3, 0xcf, 0x7a, 0x56, 0x7b, 0xc7, 0x66, 0x0e, + 0x67, 0x7a, 0x4e, 0x7a, 0x27, 0x4c, 0x58, 0xf5, 0x7a, 0xd2, 0x63, 0xf6, 0x12, 0x2f, 0xc6, 0x12, + 0x3e, 0xd8, 0x91, 0xe8, 0x9b, 0x06, 0xa0, 0xf0, 0xd2, 0xce, 0x76, 0x1a, 0x1b, 0xf4, 0xb4, 0x4f, + 0xcf, 0x47, 0x3b, 0xac, 0x34, 0xe9, 0x7c, 0x74, 0x41, 0x41, 0xb0, 0x86, 0x85, 0x5e, 0x82, 0x49, + 0xfe, 0xef, 0x9a, 0x3a, 0xec, 0x8f, 0xfc, 0x14, 0x96, 0x2b, 0x14, 0x26, 0x13, 0x9f, 0x85, 0x17, + 0x42, 0x0e, 0x58, 0x67, 0x47, 0xbb, 0x6a, 0xcd, 0xd9, 0x6e, 0x76, 0x6e, 0xd7, 0xb7, 0xc2, 0xae, + 0x6a, 0x7b, 0xee, 0xb6, 0xdd, 0x24, 0xf1, 0xae, 0xaa, 0xf0, 0x62, 0x2c, 0xe1, 0x83, 0x75, 0xd5, + 0xd7, 0x0d, 0x98, 0x5f, 0xf3, 0x03, 0xdb, 0x5d, 0x25, 0x7e, 0x40, 0xd5, 0x0a, 0xdd, 0x7c, 0x3a, + 0xcd, 0x41, 0xe2, 0xa0, 0x57, 0x61, 0x56, 0x5c, 0x20, 0x76, 0xb6, 0x7c, 0x12, 0x68, 0x76, 0xbc, + 0x5a, 0xc7, 0x2b, 0x31, 0x38, 0xee, 0xa9, 0x41, 0xa9, 0x88, 0x9b, 0xc4, 0x90, 0x4a, 0x36, 0x4a, + 0xa5, 0x1a, 0x83, 0xe3, 0x9e, 0x1a, 0xe6, 0x77, 0xb2, 0x70, 0x92, 0x35, 0x23, 0xf6, 0x86, 0xe1, + 0xb3, 0xfd, 0xde, 0x30, 0x8c, 0xb8, 0x94, 0x19, 0xaf, 0x23, 0xbc, 0x60, 0xf8, 0x75, 0x03, 0x66, + 0xea, 0xd1, 0x9e, 0x4e, 0xc7, 0x3d, 0x93, 0x34, 0x86, 0x3c, 0x5e, 0x2a, 0x56, 0x88, 0xe3, 0xfc, + 0xd1, 0x17, 0x0c, 0x98, 0x89, 0x8a, 0x29, 0x77, 0xf7, 0x63, 0xe8, 0x24, 0x15, 0xe0, 0x1c, 0x2d, + 0xf7, 0x71, 0x5c, 0x04, 0xf3, 0xdb, 0x19, 0x31, 0xa4, 0xc7, 0x11, 0xa0, 0x8f, 0x6e, 0x41, 0x21, + 0x68, 0xfa, 0xbc, 0x50, 0xb4, 0x76, 0xc4, 0x13, 0xe1, 0xe6, 0x7a, 0x95, 0xdf, 0xdd, 0x87, 0x46, + 0x9b, 0x28, 0xa1, 0xc6, 0xa7, 0xe4, 0xc5, 0x18, 0xd7, 0xda, 0x82, 0x71, 0x2a, 0x47, 0xd1, 0xcd, + 0x95, 0x4a, 0x9c, 0xb1, 0x28, 0xa1, 0x8c, 0x25, 0x2f, 0xf3, 0xcb, 0x06, 0x14, 0x2e, 0xba, 0x72, + 0x1f, 0xf9, 0x70, 0x0a, 0x8e, 0x1e, 0x65, 0x0f, 0xaa, 0x3b, 0xc2, 0xf0, 0x88, 0xf1, 0x4c, 0xc4, + 0xcd, 0x73, 0xbf, 0x46, 0x7b, 0x89, 0x25, 0xea, 0xa1, 0xa4, 0x2e, 0xba, 0x5b, 0x7d, 0xbd, 0x88, + 0xbf, 0x97, 0x83, 0x13, 0xcf, 0x59, 0x7b, 0xc4, 0x09, 0xac, 0xe1, 0x95, 0xc4, 0x13, 0x30, 0x69, + 0xb5, 0x59, 0xa0, 0xb0, 0x66, 0xe3, 0x87, 0x9e, 0x93, 0x10, 0x84, 0x75, 0xbc, 0x70, 0x43, 0xe3, + 0x79, 0x43, 0x92, 0xb6, 0xa2, 0x95, 0x18, 0x1c, 0xf7, 0xd4, 0x40, 0x17, 0x01, 0x89, 0x57, 0x90, + 0xa5, 0x5a, 0xcd, 0xed, 0x38, 0x7c, 0x4b, 0xe3, 0x4e, 0x15, 0x75, 0xd8, 0xdc, 0xe8, 0xc1, 0xc0, + 0x09, 0xb5, 0xd0, 0x87, 0x60, 0xa1, 0xc6, 0x28, 0x8b, 0xa3, 0x87, 0x4e, 0x91, 0x1f, 0x3f, 0x55, + 0x90, 0xfe, 0x4a, 0x1f, 0x3c, 0xdc, 0x97, 0x02, 0x95, 0xd4, 0x0f, 0x5c, 0xcf, 0x6a, 0x10, 0x9d, + 0xee, 0x78, 0x54, 0xd2, 0x6a, 0x0f, 0x06, 0x4e, 0xa8, 0x85, 0x3e, 0x09, 0x85, 0x60, 0xc7, 0x23, + 0xfe, 0x8e, 0xdb, 0xac, 0x8b, 0xa0, 0x81, 0x11, 0x3d, 0x6d, 0x62, 0xf4, 0x37, 0x25, 0x55, 0x6d, + 0x7a, 0xcb, 0x22, 0x1c, 0xf2, 0x44, 0x1e, 0x8c, 0xfb, 0x35, 0xb7, 0x4d, 0x7c, 0x61, 0xb2, 0x5f, + 0x4c, 0x85, 0x3b, 0xf3, 0x1c, 0x69, 0x3e, 0x3e, 0xc6, 0x01, 0x0b, 0x4e, 0xe6, 0x37, 0x32, 0x30, + 0xa5, 0x23, 0x0e, 0xb0, 0x37, 0x7d, 0xca, 0x80, 0xa9, 0x9a, 0xeb, 0x04, 0x9e, 0xdb, 0xe4, 0xfe, + 0xab, 0x74, 0x2c, 0x0a, 0x4a, 0x6a, 0x95, 0x04, 0x96, 0xdd, 0xd4, 0x5c, 0x61, 0x1a, 0x1b, 0x1c, + 0x61, 0x8a, 0x3e, 0x63, 0xc0, 0x4c, 0x18, 0x63, 0x16, 0x3a, 0xd2, 0x52, 0x15, 0x44, 0x6d, 0xf5, + 0xe7, 0xa2, 0x9c, 0x70, 0x9c, 0xb5, 0xb9, 0x05, 0xb3, 0xf1, 0xd1, 0xa6, 0x5d, 0xd9, 0xb6, 0xc4, + 0x5a, 0xcf, 0x86, 0x5d, 0x59, 0xb1, 0x7c, 0x1f, 0x33, 0x08, 0x7a, 0x04, 0xf2, 0x2d, 0xcb, 0x6b, + 0xd8, 0x8e, 0xd5, 0x64, 0xbd, 0x98, 0xd5, 0x36, 0x24, 0x51, 0x8e, 0x15, 0x86, 0xf9, 0x6e, 0x98, + 0xda, 0xb0, 0x9c, 0x06, 0xa9, 0x8b, 0x7d, 0xf8, 0xf0, 0x27, 0x62, 0x3f, 0x1a, 0x83, 0x49, 0xed, + 0x6c, 0x76, 0xfc, 0xe7, 0xac, 0x48, 0x2a, 0x87, 0x6c, 0x8a, 0xa9, 0x1c, 0x9e, 0x07, 0xd8, 0xb6, + 0x1d, 0xdb, 0xdf, 0x39, 0x62, 0x92, 0x08, 0x76, 0x45, 0x7b, 0x5e, 0x51, 0xc0, 0x1a, 0xb5, 0xf0, + 0x1e, 0x2c, 0x77, 0x40, 0xea, 0x9c, 0x57, 0x0d, 0x4d, 0xdd, 0x8c, 0xa7, 0x71, 0xef, 0xaf, 0x0d, + 0xcc, 0x92, 0x54, 0x3f, 0xe7, 0x9c, 0xc0, 0xdb, 0x3b, 0x50, 0x2b, 0x6d, 0x42, 0xde, 0x23, 0x7e, + 0xa7, 0x45, 0x4f, 0x8c, 0x13, 0x43, 0x77, 0x03, 0x8b, 0x99, 0xc0, 0xa2, 0x3e, 0x56, 0x94, 0x16, + 0x9f, 0x82, 0x13, 0x11, 0x11, 0xd0, 0x2c, 0x64, 0x6f, 0x92, 0x3d, 0x3e, 0x4f, 0x30, 0xfd, 0x89, + 0xe6, 0x23, 0xb7, 0x85, 0xa2, 0x5b, 0xde, 0x97, 0x79, 0xd2, 0x30, 0x5d, 0x48, 0x74, 0x00, 0x1c, + 0xe5, 0x32, 0x87, 0x8e, 0x45, 0x53, 0xcb, 0x12, 0xa1, 0xc6, 0x82, 0x47, 0xc6, 0x70, 0x98, 0xf9, + 0x93, 0x71, 0x10, 0x57, 0xd9, 0x03, 0x6c, 0x57, 0xfa, 0x0d, 0x56, 0xe6, 0x08, 0x37, 0x58, 0x17, + 0x61, 0xca, 0x76, 0xec, 0xc0, 0xb6, 0x9a, 0xcc, 0xb9, 0x23, 0xd4, 0xa9, 0x0c, 0x1d, 0x9e, 0x5a, + 0xd3, 0x60, 0x09, 0x74, 0x22, 0x75, 0xd1, 0x15, 0xc8, 0x31, 0x7d, 0x23, 0x26, 0xf0, 0xf0, 0xf7, + 0xed, 0x2c, 0xd4, 0x82, 0xbf, 0x27, 0xe2, 0x94, 0xd8, 0xe1, 0x83, 0xa7, 0xc9, 0x50, 0xc7, 0x6f, + 0x31, 0x8f, 0xc3, 0xc3, 0x47, 0x0c, 0x8e, 0x7b, 0x6a, 0x50, 0x2a, 0xdb, 0x96, 0xdd, 0xec, 0x78, + 0x24, 0xa4, 0x32, 0x1e, 0xa5, 0x72, 0x3e, 0x06, 0xc7, 0x3d, 0x35, 0xd0, 0x36, 0x4c, 0x89, 0x32, + 0x1e, 0xef, 0x34, 0x71, 0xc4, 0x56, 0xb2, 0xb8, 0xb6, 0xf3, 0x1a, 0x25, 0x1c, 0xa1, 0x8b, 0x3a, + 0x30, 0x67, 0x3b, 0x35, 0xd7, 0xa9, 0x35, 0x3b, 0xbe, 0xbd, 0x4b, 0xc2, 0xc7, 0x3c, 0x47, 0x61, + 0x76, 0x6a, 0xbf, 0x5b, 0x9c, 0x5b, 0x8b, 0x93, 0xc3, 0xbd, 0x1c, 0xd0, 0x2b, 0x06, 0x9c, 0xaa, + 0xb9, 0x8e, 0xcf, 0xde, 0x9d, 0xef, 0x92, 0x73, 0x9e, 0xe7, 0x7a, 0x9c, 0x77, 0xe1, 0x88, 0xbc, + 0x99, 0x4f, 0x71, 0x25, 0x89, 0x24, 0x4e, 0xe6, 0x84, 0x5e, 0x84, 0x7c, 0xdb, 0x73, 0x77, 0xed, + 0x3a, 0xf1, 0x44, 0xec, 0xdc, 0x7a, 0x1a, 0x79, 0x30, 0x2a, 0x82, 0x66, 0xb8, 0xf5, 0xc8, 0x12, + 0xac, 0xf8, 0x99, 0x6f, 0x14, 0x60, 0x3a, 0x8a, 0x8e, 0x3e, 0x01, 0xd0, 0xf6, 0xdc, 0x16, 0x09, + 0x76, 0x88, 0x7a, 0x94, 0x71, 0x69, 0xd4, 0x74, 0x0b, 0x92, 0x9e, 0x8c, 0x5e, 0xa1, 0xdb, 0x45, + 0x58, 0x8a, 0x35, 0x8e, 0xc8, 0x83, 0x89, 0x9b, 0x5c, 0xed, 0x0a, 0x2b, 0xe4, 0xb9, 0x54, 0x6c, + 0x26, 0xc1, 0x99, 0xbd, 0x26, 0x10, 0x45, 0x58, 0x32, 0x42, 0x5b, 0x90, 0xbd, 0x45, 0xb6, 0xd2, + 0x79, 0xc2, 0x7c, 0x9d, 0x88, 0xd3, 0x4c, 0x79, 0x62, 0xbf, 0x5b, 0xcc, 0x5e, 0x27, 0x5b, 0x98, + 0x12, 0xa7, 0xed, 0xaa, 0xf3, 0x7b, 0x78, 0xb1, 0x55, 0x8c, 0xd8, 0xae, 0xc8, 0xa5, 0x3e, 0x6f, + 0x97, 0x28, 0xc2, 0x92, 0x11, 0x7a, 0x11, 0x0a, 0xb7, 0xac, 0x5d, 0xb2, 0xed, 0xb9, 0x4e, 0x20, + 0x42, 0xa6, 0x46, 0x8c, 0xd3, 0xbf, 0x2e, 0xc9, 0x09, 0xbe, 0x4c, 0xbd, 0xab, 0x42, 0x1c, 0xb2, + 0x43, 0xbb, 0x90, 0x77, 0xc8, 0x2d, 0x4c, 0x9a, 0x76, 0x2d, 0x9d, 0xb8, 0xf8, 0x4b, 0x82, 0x9a, + 0xe0, 0xcc, 0xf4, 0x9e, 0x2c, 0xc3, 0x8a, 0x17, 0x1d, 0xcb, 0x1b, 0xee, 0x96, 0xd8, 0xa8, 0x46, + 0x1c, 0x4b, 0x75, 0x32, 0xe5, 0x63, 0x79, 0xd1, 0xdd, 0xc2, 0x94, 0x38, 0x5d, 0x23, 0x35, 0x15, + 0xaf, 0x23, 0xb6, 0xa9, 0x4b, 0xe9, 0xc6, 0x29, 0xf1, 0x35, 0x12, 0x96, 0x62, 0x8d, 0x23, 0xed, + 0xdb, 0x86, 0x70, 0x56, 0x8a, 0x8d, 0x6a, 0xc4, 0xbe, 0x8d, 0xba, 0x3e, 0x79, 0xdf, 0xca, 0x32, + 0xac, 0x78, 0x51, 0xbe, 0xb6, 0xf0, 0xfc, 0xa5, 0xb3, 0x55, 0x45, 0xfd, 0x88, 0x9c, 0xaf, 0x2c, + 0xc3, 0x8a, 0x97, 0xf9, 0xe5, 0x71, 0x98, 0xd2, 0xf3, 0x8d, 0x0d, 0x60, 0x23, 0x28, 0xbb, 0x38, + 0x33, 0x8c, 0x5d, 0x4c, 0x0f, 0x42, 0xda, 0x1d, 0x87, 0x74, 0xc2, 0xac, 0xa5, 0x66, 0x16, 0x86, + 0x07, 0x21, 0xad, 0xd0, 0xc7, 0x11, 0xa6, 0x43, 0x84, 0x3d, 0x50, 0xe3, 0x8a, 0x9b, 0x1f, 0xb9, + 0xa8, 0x71, 0x15, 0x31, 0x28, 0x1e, 0x05, 0x08, 0xf3, 0x6e, 0x89, 0xbb, 0x2f, 0x65, 0xb5, 0x69, + 0xf9, 0xc0, 0x34, 0x2c, 0xf4, 0x10, 0x8c, 0x53, 0x05, 0x4d, 0xea, 0xe2, 0xa5, 0xae, 0x3a, 0x6d, + 0x9e, 0x67, 0xa5, 0x58, 0x40, 0xd1, 0x93, 0xd4, 0x96, 0x0a, 0xd5, 0xaa, 0x78, 0x80, 0x3b, 0x1f, + 0xda, 0x52, 0x21, 0x0c, 0x47, 0x30, 0xa9, 0xe8, 0x84, 0x6a, 0x41, 0x36, 0x83, 0x35, 0xd1, 0x99, + 0x6a, 0xc4, 0x1c, 0xc6, 0xbc, 0x1f, 0x31, 0xad, 0xc9, 0x66, 0x5e, 0x4e, 0xf3, 0x7e, 0xc4, 0xe0, + 0xb8, 0xa7, 0x06, 0x6d, 0x8c, 0xb8, 0xb6, 0x9b, 0xe4, 0xd1, 0x9d, 0x7d, 0x2e, 0xdc, 0x5e, 0xd3, + 0x4f, 0x04, 0x53, 0x6c, 0xe8, 0xdf, 0x9f, 0x5e, 0xee, 0xbc, 0xc1, 0x8f, 0x04, 0xa3, 0x19, 0xef, + 0x1f, 0x85, 0xe9, 0xe8, 0x5e, 0x99, 0xba, 0x7f, 0xfe, 0xaf, 0xb3, 0x70, 0xf2, 0x52, 0xc3, 0x76, + 0x6e, 0xc7, 0x1c, 0xdb, 0x49, 0x39, 0x6d, 0x8d, 0x61, 0x73, 0xda, 0x86, 0x4f, 0x7e, 0x44, 0xd2, + 0xe0, 0xe4, 0x27, 0x3f, 0x32, 0xa3, 0x70, 0x14, 0x17, 0xfd, 0xd0, 0x80, 0xfb, 0xad, 0x3a, 0xb7, + 0x5e, 0xad, 0xa6, 0x28, 0x0d, 0x99, 0xca, 0x15, 0xed, 0x8f, 0xa8, 0x8b, 0x7a, 0x1b, 0xbf, 0x54, + 0x3a, 0x80, 0x2b, 0x1f, 0xf1, 0x77, 0x88, 0x16, 0xdc, 0x7f, 0x10, 0x2a, 0x3e, 0x50, 0xfc, 0xc5, + 0xcb, 0xf0, 0xf6, 0x43, 0x19, 0x0d, 0x35, 0x5b, 0x3e, 0x65, 0x40, 0x81, 0xbb, 0x4f, 0x31, 0xd9, + 0xa6, 0x5b, 0x85, 0xd5, 0xb6, 0xaf, 0x11, 0xcf, 0x97, 0xc9, 0xb6, 0xb4, 0x03, 0x5e, 0xa9, 0xb2, + 0x26, 0x20, 0x58, 0xc3, 0xa2, 0x9b, 0xf1, 0x4d, 0xdb, 0xa9, 0x8b, 0x61, 0x52, 0x9b, 0xf1, 0x73, + 0xb6, 0x53, 0xc7, 0x0c, 0xa2, 0xb6, 0xeb, 0x6c, 0x5f, 0xb7, 0xc6, 0x1b, 0x06, 0x4c, 0xb3, 0x77, + 0x8e, 0xe1, 0xd1, 0xe3, 0x09, 0x15, 0xd3, 0xc2, 0xc5, 0x38, 0x13, 0x8d, 0x69, 0xb9, 0xd3, 0x2d, + 0x4e, 0xf2, 0x97, 0x91, 0xd1, 0x10, 0x97, 0x0f, 0x0a, 0x7f, 0x05, 0x8b, 0xbc, 0xc9, 0x0c, 0x7d, + 0x9c, 0x56, 0xfe, 0xbc, 0xaa, 0x24, 0x82, 0x43, 0x7a, 0xe6, 0x4b, 0x30, 0xa5, 0x3f, 0x58, 0x40, + 0x4f, 0xc0, 0x64, 0xdb, 0x76, 0x1a, 0xd1, 0x87, 0x6d, 0xca, 0xa7, 0x5b, 0x09, 0x41, 0x58, 0xc7, + 0x63, 0xd5, 0xdc, 0xb0, 0x5a, 0xcc, 0x15, 0x5c, 0x71, 0xf5, 0x6a, 0xe1, 0x1f, 0xf3, 0x4f, 0xb2, + 0x70, 0x32, 0xe1, 0x61, 0x0c, 0x7a, 0xd5, 0x80, 0x71, 0x16, 0xa5, 0x2f, 0xa3, 0x56, 0x5e, 0x48, + 0xfd, 0xf1, 0xcd, 0x12, 0x7b, 0x0c, 0x20, 0xe6, 0xb1, 0xda, 0x3e, 0x79, 0x21, 0x16, 0xcc, 0xd1, + 0x6f, 0x19, 0x30, 0x69, 0x69, 0x4b, 0x8d, 0x07, 0xf2, 0x6c, 0xa5, 0x2f, 0x4c, 0xcf, 0xca, 0xd2, + 0x02, 0x10, 0xc3, 0x85, 0xa4, 0xcb, 0xb2, 0xf8, 0x5e, 0x98, 0xd4, 0x9a, 0x30, 0xcc, 0x0a, 0x59, + 0x7c, 0x06, 0x66, 0x47, 0x5a, 0x61, 0x1f, 0x80, 0x61, 0x73, 0xc7, 0x51, 0x85, 0x75, 0x4b, 0x7f, + 0x7c, 0xac, 0x7a, 0x5c, 0xbc, 0x3e, 0x16, 0x50, 0x73, 0x0b, 0x66, 0xe3, 0x87, 0xab, 0xd4, 0xef, + 0xad, 0xdf, 0x0d, 0x43, 0x66, 0x7b, 0x33, 0xbf, 0x9d, 0x81, 0x09, 0xf1, 0xba, 0xee, 0x2e, 0xc4, + 0xee, 0xde, 0x8c, 0x5c, 0xea, 0xac, 0xa5, 0xf2, 0x28, 0xb0, 0x6f, 0xe0, 0xae, 0x1f, 0x0b, 0xdc, + 0x7d, 0x2e, 0x1d, 0x76, 0x07, 0x47, 0xed, 0xbe, 0x31, 0x06, 0x33, 0xb1, 0xd7, 0x8a, 0xd4, 0x54, + 0xe9, 0x09, 0x56, 0xbb, 0x9a, 0xea, 0x83, 0x48, 0x15, 0x57, 0x7e, 0x70, 0xdc, 0x9a, 0x1f, 0x49, + 0xaa, 0x79, 0x25, 0xb5, 0x7c, 0xdc, 0x3f, 0xcf, 0xaf, 0x39, 0x6c, 0x1c, 0xd6, 0x3f, 0x1b, 0x70, + 0x6f, 0xdf, 0x47, 0xad, 0x2c, 0x27, 0x8a, 0x17, 0x85, 0x8a, 0x05, 0x99, 0xf2, 0xd3, 0x7d, 0x75, + 0xc3, 0x12, 0x4f, 0x63, 0x11, 0x67, 0x8f, 0x1e, 0x87, 0x29, 0xa6, 0x5a, 0xe9, 0x9e, 0x12, 0x90, + 0xb6, 0x70, 0x10, 0x33, 0x57, 0x61, 0x55, 0x2b, 0xc7, 0x11, 0x2c, 0xf3, 0x4b, 0x06, 0x2c, 0xf4, + 0xcb, 0x90, 0x31, 0xc0, 0xc1, 0xf0, 0x17, 0x62, 0xc1, 0xc5, 0xc5, 0x9e, 0xe0, 0xe2, 0xd8, 0xd1, + 0x50, 0xc6, 0x11, 0x6b, 0xa7, 0xb2, 0xec, 0x21, 0xb1, 0xb3, 0x9f, 0x35, 0xe0, 0x74, 0x9f, 0xd5, + 0xd4, 0x13, 0x64, 0x6e, 0x1c, 0x39, 0xc8, 0x3c, 0x33, 0x68, 0x90, 0xb9, 0xf9, 0xdd, 0x2c, 0xcc, + 0x0a, 0x79, 0x42, 0xfb, 0xea, 0xc9, 0x48, 0x88, 0xf6, 0x3b, 0x62, 0x21, 0xda, 0xf3, 0x71, 0xfc, + 0x9f, 0xc7, 0x67, 0xbf, 0xb5, 0xe2, 0xb3, 0x7f, 0x9a, 0x81, 0x53, 0x89, 0x89, 0x3b, 0xd0, 0xa7, + 0x13, 0x54, 0xc3, 0xf5, 0x94, 0x33, 0x84, 0x0c, 0xa8, 0x1c, 0x46, 0x0d, 0x6a, 0xfe, 0x82, 0x1e, + 0x4c, 0xcc, 0xb7, 0xfa, 0xed, 0x63, 0xc8, 0x75, 0x32, 0x64, 0x5c, 0xb1, 0xf9, 0x6b, 0x59, 0x78, + 0x78, 0x50, 0x42, 0x6f, 0xd1, 0x77, 0x27, 0x7e, 0xe4, 0xdd, 0xc9, 0x5d, 0x52, 0xdb, 0xc7, 0xf2, + 0x04, 0xe5, 0xcb, 0x59, 0xa5, 0xf6, 0x7a, 0xe7, 0xe7, 0x40, 0xb7, 0x89, 0x13, 0xd4, 0xb4, 0x93, + 0xe9, 0x3c, 0xc3, 0xad, 0x70, 0xa2, 0xca, 0x8b, 0xef, 0x74, 0x8b, 0x73, 0x22, 0xc5, 0x5f, 0x95, + 0x04, 0xa2, 0x10, 0xcb, 0x4a, 0xe8, 0x61, 0xc8, 0x7b, 0x1c, 0x2a, 0x23, 0xed, 0xc5, 0x95, 0x2c, + 0x2f, 0xc3, 0x0a, 0x8a, 0x3e, 0xa9, 0xd9, 0xc2, 0x63, 0xc7, 0x95, 0x25, 0xe1, 0xa0, 0x9b, 0xe6, + 0x17, 0x20, 0xef, 0xcb, 0xc4, 0x9c, 0xfc, 0x3a, 0xe0, 0xb1, 0x01, 0x1f, 0x70, 0xd0, 0xa3, 0x93, + 0xcc, 0xd2, 0xc9, 0xdb, 0xa7, 0x72, 0x78, 0x2a, 0x92, 0xc8, 0x54, 0xa7, 0x16, 0xee, 0x63, 0x84, + 0x84, 0x13, 0xcb, 0xf7, 0x0c, 0x98, 0x14, 0xa3, 0x75, 0x17, 0xde, 0x94, 0xdc, 0x88, 0xbe, 0x29, + 0x39, 0x97, 0xca, 0xde, 0xd1, 0xe7, 0x41, 0xc9, 0x0d, 0x98, 0xd2, 0x73, 0x37, 0xa1, 0xe7, 0xb5, + 0xbd, 0xcf, 0x18, 0x25, 0x1b, 0x8a, 0xdc, 0x1d, 0xc3, 0x7d, 0xd1, 0xfc, 0x9d, 0xbc, 0xea, 0x45, + 0xe6, 0x87, 0xd0, 0xe7, 0xa0, 0x71, 0xe0, 0x1c, 0xd4, 0xa7, 0x40, 0x26, 0xfd, 0x29, 0x70, 0x05, + 0xf2, 0x72, 0x83, 0x12, 0x6a, 0xfc, 0x41, 0x3d, 0xca, 0x8e, 0xda, 0x02, 0x94, 0x98, 0x36, 0x71, + 0xd9, 0x51, 0x4b, 0x8d, 0xa1, 0xda, 0x38, 0x15, 0x19, 0xf4, 0x22, 0x4c, 0xde, 0x72, 0xbd, 0x9b, + 0x4d, 0xd7, 0x62, 0x29, 0x77, 0x21, 0x8d, 0x8b, 0x1d, 0xe5, 0xf0, 0xe2, 0xa1, 0xce, 0xd7, 0x43, + 0xfa, 0x58, 0x67, 0x86, 0x4a, 0x30, 0xd3, 0xb2, 0x1d, 0x4c, 0xac, 0xba, 0x7a, 0x3a, 0x32, 0xc6, + 0x73, 0x82, 0x4a, 0x23, 0x77, 0x23, 0x0a, 0xc6, 0x71, 0x7c, 0xf4, 0x71, 0xc8, 0xfb, 0x22, 0x13, + 0x52, 0x3a, 0x57, 0x70, 0xea, 0xcc, 0xc8, 0x89, 0x86, 0x7d, 0x27, 0x4b, 0xb0, 0x62, 0x88, 0xd6, + 0x61, 0xde, 0x13, 0xb9, 0x46, 0x22, 0x1f, 0xec, 0xe0, 0xeb, 0x93, 0xa5, 0x9e, 0xc4, 0x09, 0x70, + 0x9c, 0x58, 0x8b, 0x5a, 0x31, 0x2c, 0x09, 0x19, 0xbf, 0x13, 0xd0, 0xdc, 0xe8, 0x6c, 0xc2, 0xd7, + 0xb1, 0x80, 0x1e, 0xf4, 0x14, 0x29, 0x3f, 0xc2, 0x53, 0xa4, 0x2a, 0x9c, 0x8a, 0x83, 0x58, 0x46, + 0x14, 0x96, 0x84, 0x45, 0xd3, 0x1e, 0x95, 0x24, 0x24, 0x9c, 0x5c, 0x17, 0x5d, 0x87, 0x82, 0x47, + 0xd8, 0xf9, 0xa2, 0x24, 0x2f, 0xfd, 0x87, 0x0e, 0x6f, 0xc2, 0x92, 0x00, 0x0e, 0x69, 0xd1, 0x71, + 0xb7, 0xa2, 0x69, 0x31, 0xaf, 0xa4, 0xf8, 0xc9, 0x31, 0x31, 0xf6, 0x7d, 0x32, 0x15, 0x99, 0x6f, + 0x4e, 0xc3, 0x89, 0x88, 0x6f, 0x01, 0x3d, 0x08, 0x39, 0x96, 0x22, 0x86, 0x6d, 0x0f, 0xf9, 0x70, + 0x0b, 0xe3, 0x9d, 0xc3, 0x61, 0xe8, 0x73, 0x06, 0xcc, 0xb4, 0x23, 0x5e, 0x58, 0xb9, 0x73, 0x8e, + 0x78, 0xcf, 0x17, 0x75, 0xed, 0x6a, 0x09, 0xa5, 0xa3, 0xcc, 0x70, 0x9c, 0x3b, 0x5d, 0x80, 0x22, + 0x46, 0xb0, 0x49, 0x3c, 0x86, 0x2d, 0x6c, 0x1c, 0x45, 0x62, 0x25, 0x0a, 0xc6, 0x71, 0x7c, 0x3a, + 0xc2, 0xac, 0x75, 0xa3, 0x7c, 0x8b, 0xa8, 0x24, 0x09, 0xe0, 0x90, 0x16, 0x7a, 0x06, 0xa6, 0x45, + 0x36, 0xc4, 0x8a, 0x5b, 0xbf, 0x60, 0xf9, 0x3b, 0xc2, 0xb8, 0x57, 0x87, 0x91, 0x95, 0x08, 0x14, + 0xc7, 0xb0, 0x59, 0xdb, 0xc2, 0x94, 0x93, 0x8c, 0xc0, 0x78, 0x34, 0xdf, 0xf6, 0x4a, 0x14, 0x8c, + 0xe3, 0xf8, 0xe8, 0x11, 0x6d, 0xdf, 0xe7, 0xf7, 0x74, 0x6a, 0x37, 0x48, 0xd8, 0xfb, 0x4b, 0x30, + 0xd3, 0x61, 0x67, 0xa1, 0xba, 0x04, 0x8a, 0xf5, 0xa8, 0x18, 0x5e, 0x8d, 0x82, 0x71, 0x1c, 0x1f, + 0x3d, 0x05, 0x27, 0x3c, 0xba, 0xbb, 0x29, 0x02, 0xfc, 0xf2, 0x4e, 0xdd, 0xcd, 0x60, 0x1d, 0x88, + 0xa3, 0xb8, 0xe8, 0x59, 0x98, 0x0b, 0x93, 0x87, 0x49, 0x02, 0xfc, 0x36, 0x4f, 0xe5, 0xc5, 0x29, + 0xc5, 0x11, 0x70, 0x6f, 0x1d, 0xf4, 0x4b, 0x30, 0xab, 0xf5, 0xc4, 0x9a, 0x53, 0x27, 0xb7, 0x45, + 0x82, 0x27, 0xf6, 0x69, 0x84, 0x95, 0x18, 0x0c, 0xf7, 0x60, 0xa3, 0xf7, 0xc1, 0x74, 0xcd, 0x6d, + 0x36, 0xd9, 0x1e, 0xc7, 0x73, 0x3d, 0xf3, 0x4c, 0x4e, 0x3c, 0xe7, 0x55, 0x04, 0x82, 0x63, 0x98, + 0xe8, 0x22, 0x20, 0x77, 0xcb, 0x27, 0xde, 0x2e, 0xa9, 0x3f, 0xcb, 0xbf, 0x6e, 0x4a, 0x55, 0xfc, + 0x89, 0x68, 0x84, 0xf2, 0xe5, 0x1e, 0x0c, 0x9c, 0x50, 0x8b, 0xa5, 0xd5, 0xd1, 0x5e, 0x74, 0x4d, + 0xa7, 0xf1, 0x5d, 0x9e, 0xf8, 0xc9, 0xfd, 0xd0, 0xe7, 0x5c, 0x1e, 0x8c, 0xf3, 0x80, 0xf1, 0x74, + 0x52, 0x3a, 0xe9, 0x69, 0x5f, 0x43, 0x1d, 0xc1, 0x4b, 0xb1, 0xe0, 0x84, 0x3e, 0x01, 0x85, 0x2d, + 0x99, 0x03, 0x7c, 0x61, 0x36, 0x0d, 0xbd, 0x18, 0x4b, 0x67, 0x1f, 0x9e, 0x4c, 0x15, 0x00, 0x87, + 0x2c, 0xd1, 0x43, 0x30, 0x79, 0xa1, 0x52, 0x52, 0xb3, 0x70, 0x8e, 0x8d, 0xfe, 0x18, 0xad, 0x82, + 0x75, 0x00, 0x5d, 0x61, 0xca, 0x5e, 0x42, 0x6c, 0x88, 0x43, 0x7d, 0xdb, 0x6b, 0xfe, 0x50, 0x6c, + 0x76, 0x1d, 0x89, 0xab, 0x0b, 0x27, 0x63, 0xd8, 0xa2, 0x1c, 0x2b, 0x0c, 0xf4, 0x02, 0x4c, 0x0a, + 0x7d, 0xc1, 0xf6, 0xa6, 0xf9, 0xa3, 0xbd, 0x16, 0xc4, 0x21, 0x09, 0xac, 0xd3, 0x63, 0xb7, 0x4c, + 0x2c, 0x35, 0x32, 0x39, 0xdf, 0x69, 0x36, 0x17, 0x4e, 0xb1, 0x7d, 0x33, 0xbc, 0x65, 0x0a, 0x41, + 0x58, 0xc7, 0x43, 0x8f, 0xc9, 0xc8, 0x89, 0xb7, 0x45, 0xae, 0xdd, 0x54, 0xe4, 0x84, 0xb2, 0x72, + 0xfb, 0x04, 0x14, 0x9f, 0x3e, 0x24, 0x64, 0x61, 0x0b, 0x16, 0xa5, 0x89, 0xd5, 0xbb, 0x48, 0x16, + 0x16, 0x22, 0x5e, 0x82, 0xc5, 0xeb, 0x7d, 0x31, 0xf1, 0x01, 0x54, 0xd0, 0x16, 0x64, 0xad, 0xe6, + 0xd6, 0xc2, 0xbd, 0x69, 0xd8, 0x8a, 0xea, 0x6b, 0xc5, 0x3c, 0x08, 0xa8, 0xb4, 0x5e, 0xc6, 0x94, + 0xb8, 0xf9, 0x4a, 0x46, 0x79, 0xe5, 0x55, 0xaa, 0xcb, 0x97, 0xf4, 0x59, 0x6d, 0xa4, 0xf1, 0x35, + 0xce, 0x9e, 0x44, 0xf9, 0x5c, 0x21, 0x25, 0xce, 0xe9, 0xb6, 0x5a, 0xc7, 0xa9, 0xe4, 0x31, 0x89, + 0xa6, 0xf1, 0xe4, 0xa7, 0xb9, 0xe8, 0x2a, 0x36, 0xf7, 0x27, 0x94, 0x13, 0x2a, 0x16, 0x0a, 0xe0, + 0x41, 0xce, 0xf6, 0x03, 0xdb, 0x4d, 0xf1, 0x65, 0x5b, 0x2c, 0xff, 0x25, 0x0b, 0x9c, 0x65, 0x00, + 0xcc, 0x59, 0x51, 0x9e, 0x4e, 0xc3, 0x76, 0x6e, 0x8b, 0xe6, 0x5f, 0x49, 0xfd, 0x8e, 0x9f, 0xf3, + 0x64, 0x00, 0xcc, 0x59, 0xa1, 0x1b, 0x7c, 0xa6, 0xa5, 0xf3, 0xe5, 0xd5, 0xf8, 0x07, 0x95, 0xa3, + 0x33, 0x8e, 0xf2, 0xf2, 0x5b, 0xb6, 0xb0, 0x61, 0x46, 0xe4, 0x55, 0xdd, 0x58, 0x4b, 0xe2, 0x55, + 0xdd, 0x58, 0xc3, 0x94, 0x09, 0x7a, 0xcd, 0x00, 0xb0, 0xd4, 0x97, 0x85, 0xd3, 0xf9, 0xaa, 0x44, + 0xbf, 0x2f, 0x15, 0xf3, 0x58, 0xb7, 0x10, 0x8a, 0x35, 0xce, 0xe8, 0x45, 0x98, 0xb0, 0xf8, 0x37, + 0x71, 0x44, 0x18, 0x61, 0x3a, 0x1f, 0x7a, 0x8a, 0x49, 0xc0, 0xe2, 0x27, 0x05, 0x08, 0x4b, 0x86, + 0x94, 0x77, 0xe0, 0x59, 0x64, 0xdb, 0xbe, 0x29, 0xe2, 0x09, 0xab, 0x23, 0xa7, 0xb6, 0xa6, 0xc4, + 0x92, 0x78, 0x0b, 0x10, 0x96, 0x0c, 0xf9, 0xc7, 0x3c, 0x2d, 0xc7, 0x52, 0x8f, 0x43, 0xd2, 0x79, + 0x42, 0xa4, 0x3f, 0x37, 0xd1, 0x3e, 0xe6, 0xa9, 0x33, 0xc2, 0x51, 0xbe, 0xe6, 0x8f, 0xb3, 0x00, + 0xec, 0x27, 0x7f, 0xb0, 0xdc, 0x62, 0x49, 0xee, 0x76, 0xdc, 0xba, 0x58, 0xda, 0x29, 0xbe, 0x3b, + 0x06, 0x91, 0xd1, 0x6e, 0xc7, 0xad, 0x63, 0xc1, 0x04, 0x35, 0x60, 0xac, 0x6d, 0x05, 0x3b, 0xe9, + 0x3f, 0x72, 0xce, 0xf3, 0x97, 0x3b, 0xc1, 0x0e, 0x66, 0x0c, 0xd0, 0xcb, 0x06, 0x4c, 0xf0, 0x67, + 0xce, 0xd2, 0xd5, 0x3c, 0xf2, 0x7d, 0xaa, 0xec, 0xb3, 0x25, 0xfe, 0x96, 0x5a, 0x04, 0x2b, 0x28, + 0xd5, 0x28, 0x4a, 0xb1, 0x64, 0xbb, 0xf8, 0xaa, 0x01, 0x53, 0x3a, 0x6a, 0x42, 0x98, 0xc1, 0x47, + 0xf4, 0x30, 0x83, 0x34, 0xfb, 0x43, 0x8f, 0x58, 0xf8, 0x37, 0x03, 0xb4, 0x4f, 0xa0, 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, 0x6e, 0xc0, 0x5c, 0xcf, 0x7e, 0x18, 0xff, 0xd4, 0xbc, + 0x31, 0xe0, 0xa7, 0xe6, 0x57, 0x61, 0x56, 0x24, 0x61, 0xae, 0xb6, 0x9b, 0x76, 0xe2, 0x03, 0xf4, + 0xcd, 0x18, 0x1c, 0xf7, 0xd4, 0x30, 0xff, 0xc2, 0x80, 0x49, 0xed, 0xd9, 0x1a, 0x6d, 0x07, 0x7b, + 0xde, 0x27, 0xc4, 0x08, 0xf3, 0x4f, 0x33, 0xd7, 0x3e, 0x87, 0xf1, 0x5b, 0xa6, 0x86, 0x96, 0xf0, + 0x33, 0xbc, 0x65, 0xa2, 0xa5, 0x58, 0x40, 0x79, 0x2a, 0x47, 0xd2, 0x66, 0x9d, 0x9e, 0xd5, 0x53, + 0x39, 0x92, 0x36, 0x66, 0x10, 0xc6, 0x8e, 0xda, 0x91, 0x22, 0xfe, 0x54, 0x4b, 0x77, 0x6d, 0x79, + 0x01, 0xe6, 0x30, 0x74, 0x06, 0xb2, 0xc4, 0xa9, 0x8b, 0x43, 0xaf, 0xfa, 0xc4, 0xd4, 0x39, 0xa7, + 0x8e, 0x69, 0xb9, 0x79, 0x19, 0xa6, 0xaa, 0xa4, 0xe6, 0x91, 0xe0, 0x39, 0xb2, 0x37, 0xf0, 0x37, + 0xab, 0xe8, 0x6c, 0x8f, 0x7d, 0xb3, 0x8a, 0x56, 0xa7, 0xe5, 0xe6, 0x1f, 0x19, 0x10, 0xcb, 0xc9, + 0xae, 0x79, 0x9c, 0x8d, 0x7e, 0x1e, 0xe7, 0x88, 0x6f, 0x34, 0x73, 0xa0, 0x6f, 0xf4, 0x22, 0xa0, + 0x16, 0x5d, 0x0a, 0x91, 0x2f, 0x10, 0x08, 0x7f, 0x43, 0xf8, 0x48, 0xb6, 0x07, 0x03, 0x27, 0xd4, + 0x32, 0xff, 0x90, 0x0b, 0xab, 0x67, 0x69, 0x3f, 0xbc, 0x03, 0x3a, 0x90, 0x63, 0xa4, 0x84, 0xd3, + 0xa5, 0x32, 0xda, 0xe2, 0xee, 0x4d, 0x36, 0x11, 0x0e, 0xa4, 0x58, 0xf2, 0x8c, 0x9b, 0xf9, 0x5d, + 0x2e, 0xab, 0x96, 0xc6, 0x7d, 0x00, 0x59, 0x5b, 0x51, 0x59, 0x2f, 0xa4, 0xb5, 0x57, 0x26, 0xcb, + 0x88, 0x96, 0x00, 0xda, 0xc4, 0xab, 0x11, 0x27, 0x90, 0x61, 0xd1, 0x39, 0xf1, 0x8c, 0x44, 0x95, + 0x62, 0x0d, 0xc3, 0x7c, 0xd9, 0x80, 0xd9, 0x6a, 0x60, 0xd7, 0x6e, 0xda, 0x0e, 0x7f, 0x16, 0xb5, + 0x6d, 0x37, 0xe8, 0x29, 0x85, 0x88, 0xcf, 0x31, 0x71, 0x37, 0x98, 0xda, 0x8a, 0xe5, 0x57, 0x98, + 0x24, 0x1c, 0x95, 0x60, 0x46, 0x7a, 0xdb, 0xa5, 0xef, 0x92, 0x3f, 0xe7, 0x54, 0xbe, 0x92, 0xd5, + 0x28, 0x18, 0xc7, 0xf1, 0xcd, 0x4f, 0xc2, 0xa4, 0xb6, 0xbf, 0xb2, 0xad, 0xe8, 0xb6, 0x55, 0x0b, + 0xe2, 0x4b, 0xf8, 0x1c, 0x2d, 0xc4, 0x1c, 0xc6, 0x5c, 0xac, 0x3c, 0x6e, 0x36, 0xb6, 0x84, 0x45, + 0xb4, 0xac, 0x80, 0x52, 0x62, 0x1e, 0x69, 0x90, 0xdb, 0x32, 0xb5, 0xa8, 0x24, 0x86, 0x69, 0x21, + 0xe6, 0x30, 0xf3, 0x11, 0xc8, 0xcb, 0x47, 0xf7, 0xec, 0xe5, 0xaa, 0x74, 0xff, 0xe9, 0x2f, 0x57, + 0x5d, 0x2f, 0xc0, 0x0c, 0x62, 0x5e, 0x83, 0xbc, 0xcc, 0x0d, 0x70, 0x38, 0x36, 0x5d, 0x55, 0xbe, + 0x63, 0x5f, 0x70, 0xfd, 0x40, 0x26, 0x34, 0xe0, 0x57, 0x02, 0x97, 0xd6, 0x58, 0x19, 0x56, 0x50, + 0x73, 0x0e, 0x66, 0x94, 0xaf, 0x5f, 0x04, 0x32, 0x7e, 0x23, 0x0b, 0x53, 0x91, 0x4f, 0x01, 0x1f, + 0x3e, 0xdd, 0x06, 0x5f, 0xc5, 0x09, 0x3e, 0xfb, 0xec, 0x90, 0x3e, 0x7b, 0xfd, 0x92, 0x64, 0xec, + 0x78, 0x2f, 0x49, 0x72, 0xe9, 0x5c, 0x92, 0x04, 0x30, 0xe1, 0x0b, 0x45, 0x35, 0x9e, 0x86, 0x33, + 0x25, 0x36, 0x62, 0xdc, 0x46, 0x95, 0xfa, 0x4e, 0xb2, 0x32, 0xbf, 0x9a, 0x83, 0xe9, 0x68, 0x56, + 0xa4, 0x01, 0x46, 0xf2, 0x91, 0x9e, 0x91, 0x1c, 0xd2, 0x67, 0x99, 0x1d, 0xd5, 0x67, 0x39, 0x36, + 0xaa, 0xcf, 0x32, 0x77, 0x04, 0x9f, 0x65, 0xaf, 0xc7, 0x71, 0x7c, 0x60, 0x8f, 0xe3, 0xd3, 0x2a, + 0xe0, 0x66, 0x22, 0x72, 0x43, 0x1d, 0x06, 0xdc, 0xa0, 0xe8, 0x30, 0xac, 0xb8, 0xf5, 0xc4, 0xc0, + 0xa5, 0xfc, 0x21, 0xbe, 0x19, 0x2f, 0x31, 0x3e, 0x66, 0xf8, 0x6b, 0x91, 0xb7, 0x0d, 0x11, 0x1b, + 0xf3, 0x04, 0x4c, 0x8a, 0xf9, 0xc4, 0x6c, 0x25, 0x88, 0xda, 0x59, 0xd5, 0x10, 0x84, 0x75, 0x3c, + 0xf6, 0xb5, 0xca, 0xe8, 0xe7, 0x39, 0x99, 0x0b, 0x58, 0xff, 0x5a, 0x65, 0xec, 0x73, 0x9e, 0x71, + 0x7c, 0xf3, 0xe3, 0x70, 0x2a, 0xf1, 0x44, 0xc6, 0x5c, 0x54, 0x4c, 0x8d, 0x93, 0xba, 0x40, 0xd0, + 0xc4, 0x88, 0x25, 0xcd, 0x5d, 0xbc, 0xde, 0x17, 0x13, 0x1f, 0x40, 0xc5, 0xfc, 0x4a, 0x16, 0xa6, + 0xa3, 0x9f, 0x3a, 0x42, 0xb7, 0x94, 0xff, 0x26, 0x15, 0xd7, 0x11, 0x27, 0xab, 0x65, 0xda, 0xe9, + 0xeb, 0x8c, 0xbd, 0xc5, 0xe6, 0xd7, 0x96, 0x4a, 0xfb, 0x73, 0x7c, 0x8c, 0x85, 0x17, 0x54, 0xb0, + 0x63, 0x5f, 0x33, 0x0a, 0x9f, 0x3b, 0x88, 0x63, 0x57, 0xea, 0xdc, 0xc3, 0x07, 0x0c, 0x8a, 0x15, + 0xd6, 0xd8, 0x52, 0xdd, 0xb2, 0x4b, 0x3c, 0x7b, 0xdb, 0x56, 0x9f, 0x69, 0x64, 0x3b, 0xf7, 0x35, + 0x51, 0x86, 0x15, 0xd4, 0x7c, 0x39, 0x03, 0xe1, 0x47, 0x69, 0xd9, 0xf7, 0x40, 0x7c, 0xcd, 0xc4, + 0x15, 0xc3, 0x76, 0x71, 0xd4, 0x8f, 0xee, 0x84, 0x14, 0x45, 0x30, 0xa4, 0x56, 0x82, 0x23, 0x1c, + 0x7f, 0x06, 0x1f, 0xa3, 0xb5, 0x60, 0x26, 0xf6, 0x08, 0x34, 0xf5, 0x88, 0xf3, 0x1f, 0x65, 0xa1, + 0xa0, 0x9e, 0xd1, 0xa2, 0xf7, 0x46, 0xfc, 0x0d, 0x85, 0xf2, 0xdb, 0xb5, 0xd4, 0xf7, 0x3b, 0x6e, + 0xfd, 0x4e, 0xb7, 0x38, 0xa3, 0x90, 0x63, 0xbe, 0x83, 0x33, 0x90, 0xed, 0x78, 0xcd, 0xf8, 0x81, + 0xe2, 0x2a, 0x5e, 0xc7, 0xb4, 0x1c, 0xdd, 0x8e, 0x1f, 0xf8, 0x37, 0x52, 0x7a, 0xfa, 0xcb, 0x2d, + 0xef, 0xfe, 0x07, 0x7d, 0xaa, 0x25, 0xb7, 0xdc, 0xfa, 0x5e, 0x3c, 0x55, 0x7e, 0xd9, 0xad, 0xef, + 0x61, 0x06, 0x41, 0xcf, 0xc0, 0x74, 0x60, 0xb7, 0x88, 0xdb, 0x09, 0xf4, 0x4f, 0x7e, 0x66, 0xc3, + 0xcb, 0xc5, 0xcd, 0x08, 0x14, 0xc7, 0xb0, 0xa9, 0x96, 0xbd, 0xe1, 0xbb, 0x0e, 0xcb, 0x7f, 0x37, + 0x1e, 0xbd, 0x89, 0xb8, 0x58, 0xbd, 0x7c, 0x89, 0xf9, 0x3d, 0x14, 0x06, 0xc5, 0xb6, 0xd9, 0x9b, + 0x39, 0x8f, 0x88, 0xbb, 0xfd, 0xd9, 0x30, 0xa3, 0x02, 0x2f, 0xc7, 0x0a, 0x03, 0xad, 0x72, 0xda, + 0x54, 0x5a, 0xa6, 0x51, 0xa6, 0xca, 0x0f, 0x4b, 0xba, 0xb4, 0xec, 0x4e, 0xb7, 0xb8, 0x40, 0x9c, + 0x9a, 0x5b, 0xb7, 0x9d, 0xc6, 0x32, 0x45, 0x5c, 0xc2, 0xd6, 0x2d, 0xa9, 0x6a, 0x54, 0x4d, 0xf3, + 0x2a, 0xcc, 0xc4, 0x3a, 0x4c, 0x1e, 0x00, 0x8d, 0xe4, 0x03, 0xe0, 0x60, 0xd9, 0xed, 0xff, 0xd4, + 0x80, 0xb9, 0x9e, 0x2d, 0x60, 0xd0, 0x07, 0x15, 0x71, 0x65, 0x94, 0x39, 0xba, 0x32, 0xca, 0x0e, + 0xa7, 0x8c, 0xca, 0x5b, 0xdf, 0x7a, 0xf3, 0xec, 0x3d, 0xdf, 0x79, 0xf3, 0xec, 0x3d, 0xdf, 0x7f, + 0xf3, 0xec, 0x3d, 0x2f, 0xef, 0x9f, 0x35, 0xbe, 0xb5, 0x7f, 0xd6, 0xf8, 0xce, 0xfe, 0x59, 0xe3, + 0xfb, 0xfb, 0x67, 0x8d, 0x7f, 0xda, 0x3f, 0x6b, 0xbc, 0xfe, 0xa3, 0xb3, 0xf7, 0x3c, 0xff, 0x74, + 0x38, 0x41, 0x97, 0xe5, 0x04, 0x65, 0x3f, 0xde, 0x25, 0xa7, 0xe3, 0x72, 0xfb, 0x66, 0x63, 0x99, + 0x4e, 0xd0, 0x65, 0x55, 0x22, 0x27, 0xe8, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0xf8, 0x2a, 0x23, + 0xab, 0x55, 0x93, 0x00, 0x00, } func (m *ALBStatus) Marshal() (dAtA []byte, err error) { @@ -9233,6 +9235,13 @@ func (m *WebMetric) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.JSONBody != nil { + i -= len(m.JSONBody) + copy(dAtA[i:], m.JSONBody) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.JSONBody))) + i-- + dAtA[i] = 0x42 + } i-- if m.Insecure { dAtA[i] = 1 @@ -11460,6 +11469,10 @@ func (m *WebMetric) Size() (n int) { l = len(m.JSONPath) n += 1 + l + sovGenerated(uint64(l)) n += 2 + if m.JSONBody != nil { + l = len(m.JSONBody) + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -13089,6 +13102,7 @@ func (this *WebMetric) String() string { `TimeoutSeconds:` + fmt.Sprintf("%v", this.TimeoutSeconds) + `,`, `JSONPath:` + fmt.Sprintf("%v", this.JSONPath) + `,`, `Insecure:` + fmt.Sprintf("%v", this.Insecure) + `,`, + `JSONBody:` + valueToStringGenerated(this.JSONBody) + `,`, `}`, }, "") return s @@ -31042,6 +31056,40 @@ func (m *WebMetric) Unmarshal(dAtA []byte) error { } } m.Insecure = bool(v != 0) + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field JSONBody", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.JSONBody = append(m.JSONBody[:0], dAtA[iNdEx:postIndex]...) + if m.JSONBody == nil { + m.JSONBody = []byte{} + } + 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 490aad9581..c90faf3a42 100644 --- a/pkg/apis/rollouts/v1alpha1/generated.proto +++ b/pkg/apis/rollouts/v1alpha1/generated.proto @@ -1701,7 +1701,7 @@ message WebMetric { // Headers are optional HTTP headers to use in the request repeated WebMetricHeader headers = 3; - // Body is the body of the we metric (must be POST/PUT) + // Body is the body of the web metric (must be POST/PUT) optional string body = 4; // TimeoutSeconds is the timeout for the request in seconds (default: 10) @@ -1712,6 +1712,12 @@ message WebMetric { // Insecure skips host TLS verification optional bool insecure = 7; + + // +kubebuilder:validation:Schemaless + // +kubebuilder:pruning:PreserveUnknownFields + // +kubebuilder:validation:Type=object + // JSONBody is the body of the web metric in a json format (method must be POST/PUT) + optional bytes jsonBody = 8; } message WebMetricHeader { diff --git a/pkg/apis/rollouts/v1alpha1/openapi_generated.go b/pkg/apis/rollouts/v1alpha1/openapi_generated.go index 222b2fc46f..ac729e0107 100644 --- a/pkg/apis/rollouts/v1alpha1/openapi_generated.go +++ b/pkg/apis/rollouts/v1alpha1/openapi_generated.go @@ -5012,7 +5012,7 @@ func schema_pkg_apis_rollouts_v1alpha1_WebMetric(ref common.ReferenceCallback) c }, "body": { SchemaProps: spec.SchemaProps{ - Description: "Body is the body of the we metric (must be POST/PUT)", + Description: "Body is the body of the web metric (must be POST/PUT)", Type: []string{"string"}, Format: "", }, @@ -5038,6 +5038,13 @@ func schema_pkg_apis_rollouts_v1alpha1_WebMetric(ref common.ReferenceCallback) c Format: "", }, }, + "jsonBody": { + SchemaProps: spec.SchemaProps{ + Description: "JSONBody is the body of the web metric in a json format (method must be POST/PUT)", + Type: []string{"string"}, + Format: "byte", + }, + }, }, Required: []string{"url"}, }, diff --git a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go index 58d6135a98..1a64ef2cca 100644 --- a/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/rollouts/v1alpha1/zz_generated.deepcopy.go @@ -22,6 +22,8 @@ limitations under the License. package v1alpha1 import ( + json "encoding/json" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" intstr "k8s.io/apimachinery/pkg/util/intstr" @@ -2699,6 +2701,11 @@ func (in *WebMetric) DeepCopyInto(out *WebMetric) { *out = make([]WebMetricHeader, len(*in)) copy(*out, *in) } + if in.JSONBody != nil { + in, out := &in.JSONBody, &out.JSONBody + *out = make(json.RawMessage, len(*in)) + copy(*out, *in) + } return } From 3c49f200f59b5b94ab7c2fe5e540244a3de5296c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Oct 2022 00:49:57 +0000 Subject: [PATCH 63/68] chore(deps): bump github.com/newrelic/newrelic-client-go (#2267) Bumps [github.com/newrelic/newrelic-client-go](https://github.com/newrelic/newrelic-client-go) from 0.86.5 to 1.0.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.86.5...v1.0.0) --- updated-dependencies: - dependency-name: github.com/newrelic/newrelic-client-go dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.sum | 1 + 1 file changed, 1 insertion(+) diff --git a/go.sum b/go.sum index aa02c9424d..e1658f5b5e 100644 --- a/go.sum +++ b/go.sum @@ -807,6 +807,7 @@ 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 v1.1.0 h1:aflNjzQ21c+2GwBVh+UbAf9lznkRfCcVABoc5UM4IXw= github.com/newrelic/newrelic-client-go v1.1.0/go.mod h1:RYMXt7hgYw7nzuXIGd2BH0F1AivgWw7WrBhNBQZEB4k= +>>>>>>> 40c2599 (chore(deps): bump github.com/newrelic/newrelic-client-go (#2267)) 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/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= From adbbac405279007cc36b6fabfbb4e6b2380bfcec Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Fri, 14 Oct 2022 17:52:24 -0500 Subject: [PATCH 64/68] ci: Add github action for PR Conventional Commits (#2320) * feat(ci): Add github action for PR Conventional Commits Signed-off-by: zachaller * add example scope Signed-off-by: zachaller * add cli as scope Signed-off-by: zachaller * Remove configuration Signed-off-by: zachaller * scopes not required Signed-off-by: zachaller Signed-off-by: zachaller --- .github/workflows/pr-title-check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-title-check.yml b/.github/workflows/pr-title-check.yml index d24c6d268e..948ac1ccac 100644 --- a/.github/workflows/pr-title-check.yml +++ b/.github/workflows/pr-title-check.yml @@ -50,4 +50,4 @@ jobs: # Configure that a scope must always be provided. requireScope: false env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From a64e7e15f8adb947b327aaebc58cff2dcaee7357 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Sat, 15 Oct 2022 18:58:44 -0500 Subject: [PATCH 65/68] ci: add auto close to issues and prs (#2319) * add auto close issues and prs Signed-off-by: zachaller * Add awaiting-response label closer Signed-off-by: zachaller * Change name Signed-off-by: zachaller * dont close any milestones Signed-off-by: zachaller * correct label in messages Signed-off-by: zachaller * github trigger re-run Signed-off-by: zachaller * add permissions Signed-off-by: zachaller * move perms to job Signed-off-by: zachaller Signed-off-by: zachaller --- .github/workflows/stale-issues-pr.yml | 2 +- .github/workflows/waiting-issues.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stale-issues-pr.yml b/.github/workflows/stale-issues-pr.yml index 3cb789f394..ab6f640106 100644 --- a/.github/workflows/stale-issues-pr.yml +++ b/.github/workflows/stale-issues-pr.yml @@ -27,4 +27,4 @@ jobs: exempt-issue-labels: 'awaiting-approval,work-in-progress' stale-pr-label: 'no-pr-activity' exempt-pr-labels: 'awaiting-approval,work-in-progress' - exempt-all-milestones: true \ No newline at end of file + exempt-all-milestones: true diff --git a/.github/workflows/waiting-issues.yml b/.github/workflows/waiting-issues.yml index f8c1a6cae8..5e21bced7f 100644 --- a/.github/workflows/waiting-issues.yml +++ b/.github/workflows/waiting-issues.yml @@ -28,4 +28,4 @@ jobs: stale-pr-label: 'no-pr-activity' exempt-pr-labels: 'awaiting-approval,work-in-progress' exempt-all-milestones: true - any-of-labels: 'awaiting-response' \ No newline at end of file + any-of-labels: 'awaiting-response' From 750a1981484d5ea36c7fb4e19771c29f8707f1f7 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Sat, 15 Oct 2022 19:03:53 -0500 Subject: [PATCH 66/68] move perms to job for clomonitor (#2333) Signed-off-by: zachaller Signed-off-by: zachaller --- .github/workflows/dependabot_automerge.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependabot_automerge.yml b/.github/workflows/dependabot_automerge.yml index 2bdab7b838..c082cb91a8 100644 --- a/.github/workflows/dependabot_automerge.yml +++ b/.github/workflows/dependabot_automerge.yml @@ -27,4 +27,4 @@ jobs: run: gh pr merge --auto --squash "$PR_URL" env: PR_URL: ${{github.event.pull_request.html_url}} - GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} \ No newline at end of file + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} From efe3ba8e58bdd9381dde7d1c1da654522e85883b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Oct 2022 00:03:10 +0000 Subject: [PATCH 67/68] chore(deps): bump github.com/newrelic/newrelic-client-go (#2344) Bumps [github.com/newrelic/newrelic-client-go](https://github.com/newrelic/newrelic-client-go) from 1.0.0 to 1.1.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/v1.0.0...v1.1.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] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.sum | 1 - 1 file changed, 1 deletion(-) diff --git a/go.sum b/go.sum index e1658f5b5e..aa02c9424d 100644 --- a/go.sum +++ b/go.sum @@ -807,7 +807,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 v1.1.0 h1:aflNjzQ21c+2GwBVh+UbAf9lznkRfCcVABoc5UM4IXw= github.com/newrelic/newrelic-client-go v1.1.0/go.mod h1:RYMXt7hgYw7nzuXIGd2BH0F1AivgWw7WrBhNBQZEB4k= ->>>>>>> 40c2599 (chore(deps): bump github.com/newrelic/newrelic-client-go (#2267)) 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/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= From 9ea34a8de7eb3a77fbc5312cbe8c48fb1a1c2c6f Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Tue, 18 Oct 2022 13:32:42 -0500 Subject: [PATCH 68/68] fix all workflows to follow best practices of clo monitor via https://app.stepsecurity.io/ (#2343) Signed-off-by: zachaller Signed-off-by: zachaller Signed-off-by: Ariel Simhon --- .github/workflows/pr-title-check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-title-check.yml b/.github/workflows/pr-title-check.yml index 948ac1ccac..d24c6d268e 100644 --- a/.github/workflows/pr-title-check.yml +++ b/.github/workflows/pr-title-check.yml @@ -50,4 +50,4 @@ jobs: # Configure that a scope must always be provided. requireScope: false env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file