Repository: code-ready/crc
Pull request #1761 (2020-12-08 10:24:43)

Initial telemetry implementation
- Add config option for telemeter
- Send only error and log in case of error to segment
- No personal data collection
- Use the anonymous id based on random generated one




openshift-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/code-ready/crc/pull/1761#" title="Author self-approved">praveenkumar</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=code-ready%2Fcrc).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/code-ready/crc/blob/master/OWNERS)~~ [praveenkumar]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
cfergeau: Is 'telemeter' intentional? or should it be 'telemetry'?
gbraad: > AWS region can be guessed from quay.io

this is GeoIP and is not considered PII (Personal Identifying Information)
cfergeau: > > AWS region can be guessed from quay.io
> 
> This is caused by GeoIP and is not considered PII (Personal Identifying Information), 

Yes, if there was only this piece of information, it would be ok. In combination with the username, it becomes one additional piece of (vague) personal data collected by crc about 'username'
openshift-ci-robot: @praveenkumar: PR needs rebase.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>
openshift-ci-robot: @praveenkumar: PR needs rebase.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>
openshift-merge-robot: @praveenkumar: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/images | b0ba19c650fa88d8527bd0a7ee816d0e0658d626 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1761/pull-ci-code-ready-crc-master-images/1338868956030570496) | `/test images`

[Full PR test history](https://prow.ci.openshift.org/pr-history?org=code-ready&repo=crc&pr=1761). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:praveenkumar).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-merge-robot: @praveenkumar: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/images | b0ba19c650fa88d8527bd0a7ee816d0e0658d626 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1761/pull-ci-code-ready-crc-master-images/1338868956030570496) | `/test images`
ci/prow/e2e-crc | b0ba19c650fa88d8527bd0a7ee816d0e0658d626 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1761/pull-ci-code-ready-crc-master-e2e-crc/1338868955946684416) | `/test e2e-crc`

[Full PR test history](https://prow.ci.openshift.org/pr-history?org=code-ready&repo=crc&pr=1761). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:praveenkumar).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-merge-robot: @praveenkumar: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/images | 3d8cb81d59943bad9e39aa9d7358e36f7b41378f | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1761/pull-ci-code-ready-crc-master-images/1339492640659345408) | `/test images`

[Full PR test history](https://prow.ci.openshift.org/pr-history?org=code-ready&repo=crc&pr=1761). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:praveenkumar).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-merge-robot: @praveenkumar: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/images | 3d8cb81d59943bad9e39aa9d7358e36f7b41378f | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1761/pull-ci-code-ready-crc-master-images/1339492640659345408) | `/test images`
ci/prow/e2e-crc | 3d8cb81d59943bad9e39aa9d7358e36f7b41378f | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1761/pull-ci-code-ready-crc-master-e2e-crc/1339492640621596672) | `/test e2e-crc`

[Full PR test history](https://prow.ci.openshift.org/pr-history?org=code-ready&repo=crc&pr=1761). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:praveenkumar).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-merge-robot: @praveenkumar: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/images | 3d8cb81d59943bad9e39aa9d7358e36f7b41378f | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1761/pull-ci-code-ready-crc-master-images/1339492640659345408) | `/test images`
ci/prow/e2e-crc | 52f0afac8e3bbcbea1014e3329eb6c8c465a0a87 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1761/pull-ci-code-ready-crc-master-e2e-crc/1339501679451574272) | `/test e2e-crc`

[Full PR test history](https://prow.ci.openshift.org/pr-history?org=code-ready&repo=crc&pr=1761). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:praveenkumar).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-merge-robot: @praveenkumar: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/e2e-crc | 52f0afac8e3bbcbea1014e3329eb6c8c465a0a87 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1761/pull-ci-code-ready-crc-master-e2e-crc/1339501679451574272) | `/test e2e-crc`
ci/prow/images | 52f0afac8e3bbcbea1014e3329eb6c8c465a0a87 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1761/pull-ci-code-ready-crc-master-images/1339501679480934400) | `/test images`

[Full PR test history](https://prow.ci.openshift.org/pr-history?org=code-ready&repo=crc&pr=1761). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:praveenkumar).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/code-ready/crc/pull/1761#pullrequestreview-554604264" title="Approved">guillaumerose</a>*, *<a href="https://github.com/code-ready/crc/pull/1761#" title="Author self-approved">praveenkumar</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=code-ready%2Fcrc).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/code-ready/crc/blob/master/OWNERS)~~ [guillaumerose,praveenkumar]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
openshift-merge-robot: @praveenkumar: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/images | 52f0afac8e3bbcbea1014e3329eb6c8c465a0a87 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1761/pull-ci-code-ready-crc-master-images/1339501679480934400) | `/test images`
ci/prow/e2e-crc | afe59544ac65c4cca264f7fe6994b5112f2eab71 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1761/pull-ci-code-ready-crc-master-e2e-crc/1339563225586339840) | `/test e2e-crc`

[Full PR test history](https://prow.ci.openshift.org/pr-history?org=code-ready&repo=crc&pr=1761). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:praveenkumar).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-merge-robot: @praveenkumar: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/e2e-crc | afe59544ac65c4cca264f7fe6994b5112f2eab71 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1761/pull-ci-code-ready-crc-master-e2e-crc/1339563225586339840) | `/test e2e-crc`
ci/prow/images | afe59544ac65c4cca264f7fe6994b5112f2eab71 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1761/pull-ci-code-ready-crc-master-images/1339563225615699968) | `/test images`

[Full PR test history](https://prow.ci.openshift.org/pr-history?org=code-ready&repo=crc&pr=1761). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:praveenkumar).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-ci-robot: New changes are detected. LGTM label has been removed.
openshift-merge-robot: @praveenkumar: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/e2e-crc | afe59544ac65c4cca264f7fe6994b5112f2eab71 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1761/pull-ci-code-ready-crc-master-e2e-crc/1339563225586339840) | `/test e2e-crc`
ci/prow/images | b818db5b21ecd3a3a0145ddf76e44be9483a6192 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1761/pull-ci-code-ready-crc-master-images/1339580749375868928) | `/test images`

[Full PR test history](https://prow.ci.openshift.org/pr-history?org=code-ready&repo=crc&pr=1761). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:praveenkumar).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-merge-robot: @praveenkumar: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/images | b818db5b21ecd3a3a0145ddf76e44be9483a6192 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1761/pull-ci-code-ready-crc-master-images/1339580749375868928) | `/test images`
ci/prow/e2e-crc | b818db5b21ecd3a3a0145ddf76e44be9483a6192 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1761/pull-ci-code-ready-crc-master-e2e-crc/1339580749329731584) | `/test e2e-crc`

[Full PR test history](https://prow.ci.openshift.org/pr-history?org=code-ready&repo=crc&pr=1761). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:praveenkumar).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->

Patch:
diff --git a/cmd/crc/cmd/config/config.go b/cmd/crc/cmd/config/config.go
index 1e0036a83..fe9c3304e 100644
--- a/cmd/crc/cmd/config/config.go
+++ b/cmd/crc/cmd/config/config.go
@@ -25,6 +25,7 @@ const (
 	NoProxy              = "no-proxy"
 	ProxyCAFile          = "proxy-ca-file"
 	EnableMonitoring     = "enable-monitoring"
+	ConsentTelemetry     = "consent-telemetry"
 )
 
 func RegisterSettings(cfg *config.Config) {
@@ -45,6 +46,9 @@ func RegisterSettings(cfg *config.Config) {
 	cfg.AddSetting(ProxyCAFile, "", config.ValidatePath, config.SuccessfullyApplied)
 
 	cfg.AddSetting(EnableMonitoring, false, config.ValidateBool, config.SuccessfullyApplied)
+
+	// Telemeter Configuration
+	cfg.AddSetting(ConsentTelemetry, false, config.ValidateBool, config.SuccessfullyApplied)
 }
 
 func isPreflightKey(key string) bool {
diff --git a/cmd/crc/cmd/root.go b/cmd/crc/cmd/root.go
index 4e3a9e558..a0c1d562a 100644
--- a/cmd/crc/cmd/root.go
+++ b/cmd/crc/cmd/root.go
@@ -14,6 +14,7 @@ import (
 	"github.com/code-ready/crc/pkg/crc/network"
 	"github.com/code-ready/crc/pkg/crc/output"
 	"github.com/code-ready/crc/pkg/crc/preflight"
+	"github.com/code-ready/crc/pkg/crc/segment"
 	"github.com/spf13/cobra"
 )
 
@@ -34,9 +35,10 @@ var rootCmd = &cobra.Command{
 }
 
 var (
-	globalForce bool
-	viper       *crcConfig.ViperStorage
-	config      *crcConfig.Config
+	globalForce   bool
+	viper         *crcConfig.ViperStorage
+	config        *crcConfig.Config
+	segmentClient *segment.Client
 )
 
 func init() {
@@ -48,6 +50,10 @@ func init() {
 	if err != nil {
 		logging.Fatal(err.Error())
 	}
+	// Initiate segment client
+	if segmentClient, err = segment.NewClient(config); err != nil {
+		logging.Fatal(err.Error())
+	}
 
 	// subcommands
 	rootCmd.AddCommand(cmdConfig.GetConfigCmd(config))
diff --git a/cmd/crc/cmd/start.go b/cmd/crc/cmd/start.go
index 6891f43e8..90c95d202 100644
--- a/cmd/crc/cmd/start.go
+++ b/cmd/crc/cmd/start.go
@@ -48,6 +48,9 @@ var startCmd = &cobra.Command{
 			exit.WithMessage(1, err.Error())
 		}
 		if err := renderStartResult(runStart(args)); err != nil {
+			if serr := segmentClient.Upload(err); serr != nil {
+				fmt.Println(serr.Error())
+			}
 			exit.WithMessage(1, err.Error())
 		}
 	},
diff --git a/go.mod b/go.mod
index ff82d965d..241e1d808 100644
--- a/go.mod
+++ b/go.mod
@@ -35,6 +35,8 @@ require (
 	github.com/pelletier/go-toml v1.8.1 // indirect
 	github.com/pkg/browser v0.0.0-20201207095918-0426ae3fba23
 	github.com/pkg/errors v0.9.1
+	github.com/segmentio/analytics-go v3.1.0+incompatible
+	github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3 // indirect
 	github.com/sirupsen/logrus v1.7.0
 	github.com/spf13/afero v1.4.1 // indirect
 	github.com/spf13/cast v1.3.1
@@ -43,6 +45,7 @@ require (
 	github.com/spf13/viper v1.7.1
 	github.com/stretchr/testify v1.6.1
 	github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8
+	github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
 	golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c
 	golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb // indirect
 	golang.org/x/oauth2 v0.0.0-20201203001011-0b49973bad19 // indirect
diff --git a/go.sum b/go.sum
index 0b161996a..e167954b3 100644
--- a/go.sum
+++ b/go.sum
@@ -18,7 +18,6 @@ cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bP
 cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
 cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
 cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
-cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8=
 cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
 cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
 cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
@@ -38,7 +37,6 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
 cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
 cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
 cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
-dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 github.com/AaronO/go-git-http v0.0.0-20161214145340-1d9485b3a98f/go.mod h1:+6Yuq73F9068Na+mSBNXCvyuxvgw4f/g5ii40e3U8Sc=
 github.com/AlecAivazis/survey/v2 v2.0.5/go.mod h1:WYBhg6f0y/fNYUuesWQc0PKbJcEliGcYHB9sNT3Bg74=
@@ -58,7 +56,6 @@ github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocm
 github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8=
 github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
 github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
-github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/DataDog/zstd v1.4.0/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
@@ -70,9 +67,7 @@ github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF0
 github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
 github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
 github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
-github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab h1:9pygWVFqbY9lPxM0peffumuVDyMuIMzNLyO9uFjJuQo=
 github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
-github.com/Microsoft/hcsshim v0.8.10 h1:k5wTrpnVU2/xv8ZuzGkbXVd3js5zJ8RnumPo5RxiIxU=
 github.com/Microsoft/hcsshim v0.8.10/go.mod h1:g5uw8EV2mAlzqe94tfNBNdr89fnbD/n3HV0OhsddkmM=
 github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
 github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw=
@@ -112,7 +107,6 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
-github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
 github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
 github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg=
 github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
@@ -132,6 +126,7 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm
 github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
 github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
 github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
 github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
 github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
 github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
@@ -174,7 +169,6 @@ github.com/code-ready/machine v0.0.0-20201202090222-9558ae8c05b9/go.mod h1:g30jK
 github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
 github.com/container-storage-interface/spec v1.2.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4=
 github.com/containerd/cgroups v0.0.0-20181219155423-39b18af02c41/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI=
-github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59 h1:qWj4qVYZ95vLWwqyNJCQg7rDsG5wPdze0UaPolH7DUk=
 github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
 github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
 github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
@@ -201,7 +195,6 @@ github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ
 github.com/containers/storage v0.0.0-20190726081758-912de200380a/go.mod h1:QsZp4XMJjyPNNbQHZeyNW3OmhwsWviI+7S6iOcu6a4c=
 github.com/coredns/corefile-migration v1.0.10/go.mod h1:RMy/mXdeDlYwzt0vdMEJvT2hGJ2I86/eO0UdXmH9XNI=
 github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
-github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04=
 github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
 github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
 github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
@@ -210,10 +203,8 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
 github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
 github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
-github.com/coreos/go-systemd/v22 v22.1.0 h1:kq/SbG2BCKLkDKkjQf5OWwKWUKj1lgs3lFI4PxnR5lg=
 github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
 github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
@@ -291,13 +282,11 @@ github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdR
 github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
 github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
-github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
 github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
 github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
 github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
-github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
@@ -312,10 +301,8 @@ github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0
 github.com/go-acme/lego v2.5.0+incompatible/go.mod h1:yzMNe9CasVUhkquNvti5nAtPmG94USbYxYrZfTkIn0M=
 github.com/go-bindata/go-bindata v3.1.1+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo=
 github.com/go-bindata/go-bindata v3.1.2+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo=
-github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-ini/ini v1.9.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
@@ -374,7 +361,6 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
 github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80=
 github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0=
 github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
-github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME=
 github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/gofrs/flock v0.6.1-0.20180915234121-886344bea079/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
 github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
@@ -392,7 +378,6 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er
 github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
 github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
@@ -403,7 +388,6 @@ github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
 github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
 github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
@@ -414,7 +398,6 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
 github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
 github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
 github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
 github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
@@ -441,11 +424,9 @@ github.com/google/cadvisor v0.37.0/go.mod h1:OhDE+goNVel0eGY8mR7Ifq1QUI1in5vJBIg
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
 github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
 github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -470,9 +451,7 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
 github.com/google/subcommands v1.0.2-0.20190508160503-636abe8753b8/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
 github.com/google/tcpproxy v0.0.0-20200125044825-b6bb9b5b8252 h1:tAkooHvRrtO8kFB6YOPTpLQok3Hfv1DNDXdNqgi29Ao=
 github.com/google/tcpproxy v0.0.0-20200125044825-b6bb9b5b8252/go.mod h1:DavVbd41y+b7ukKDmlnPR4nGYmkWXR6vHUkjQNiHPBs=
-github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA=
 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -541,7 +520,6 @@ github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
 github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/intel-go/cpuid v0.0.0-20181003105527-1a4a6f06a1c6 h1:XboatR7lasl05yel5hNXF7kQBw2oFUGdMztcgisfhNU=
 github.com/intel-go/cpuid v0.0.0-20181003105527-1a4a6f06a1c6/go.mod h1:RmeVYf9XrPRbRc3XIx0gLYA8qOFvNoPOfaEZduRlEp4=
 github.com/ishidawataru/sctp v0.0.0-20190723014705-7c296d48a2b5/go.mod h1:DM4VvS+hD/kDi1U1QsX2fnZowwBhqD0Dk3bRPKF/Oc8=
 github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
@@ -557,13 +535,11 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u
 github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
 github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
-github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
-github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
 github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
 github.com/karrick/godirwalk v1.7.5/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34=
 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
@@ -575,25 +551,19 @@ github.com/klauspost/compress v1.7.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0
 github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
 github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
 github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
 github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
 github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
 github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
-github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
 github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/pty v1.1.4-0.20190131011033-7dc38fb350b1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/pty v1.1.5 h1:hyz3dwM5QLc1Rfoz4FuWJQG5BN7tc6K1MndAUnGpQr4=
 github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
@@ -612,9 +582,7 @@ github.com/lucas-clemente/aes12 v0.0.0-20171027163421-cd47fb39b79f/go.mod h1:JpH
 github.com/lucas-clemente/quic-clients v0.1.0/go.mod h1:y5xVIEoObKqULIKivu+gD/LU90pL73bTdtQjPBvtCBk=
 github.com/lucas-clemente/quic-go v0.10.2/go.mod h1:hvaRS9IHjFLMq76puFJeWNfmn+H70QZ/CXoxqw9bzao=
 github.com/lucas-clemente/quic-go-certificates v0.0.0-20160823095156-d2f86524cced/go.mod h1:NCcRLrOTZbzhZvixZLlERbJtDtYsmMw8Jc4vS8Z0g58=
-github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
 github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY=
 github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
@@ -625,9 +593,7 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN
 github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
 github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
-github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
-github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
 github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
 github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
 github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
@@ -637,7 +603,6 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
 github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
 github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
 github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
-github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
 github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
 github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
 github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
@@ -648,7 +613,6 @@ github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182aff
 github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
 github.com/mdlayher/vsock v0.0.0-20200508120832-7ad3638b3fbc h1:7EXQyTVWQtagOIR7s0tNFKX7ex4Lxq+sIR0jZ82cSP4=
 github.com/mdlayher/vsock v0.0.0-20200508120832-7ad3638b3fbc/go.mod h1:OGwlMd1v7fjifRz7LiKLMfs7fS1G72qRZD71PTjH0aY=
-github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
 github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
 github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
 github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
@@ -670,7 +634,6 @@ github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUb
 github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
 github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.4.0 h1:7ks8ZkOP5/ujthUsT07rNv+nkLXCQWKNHuwzOAesEks=
 github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
@@ -719,7 +682,6 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J
 github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
 github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
 github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
-github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
 github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
 github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
@@ -734,7 +696,6 @@ github.com/opencontainers/runtime-spec v0.1.2-0.20190618234442-a950415649c7/go.m
 github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
 github.com/opencontainers/runtime-spec v1.0.2-0.20181111125026-1722abf79c2f/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
 github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
-github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2 h1:9mv9SC7GWmRWE0J/+oD8w3GsN2KYGKtg6uwLN7hfP5E=
 github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
 github.com/opencontainers/selinux v1.2.2/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
 github.com/opencontainers/selinux v1.5.1/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
@@ -777,11 +738,9 @@ github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT9
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pbnjay/memory v0.0.0-20201129165224-b12e5d931931 h1:EeWknjeRU+R3O4ghG7XZCpgSfJNStZyEP8aWyQwJM8s=
 github.com/pbnjay/memory v0.0.0-20201129165224-b12e5d931931/go.mod h1:RMU2gJXhratVxBDTFeOdNhd540tG57lt9FIUV0YLvIQ=
-github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
 github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
 github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw=
 github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
-github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM=
 github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
@@ -792,7 +751,6 @@ github.com/pkg/browser v0.0.0-20201207095918-0426ae3fba23 h1:dofHuld+js7eKSemxqT
 github.com/pkg/browser v0.0.0-20201207095918-0426ae3fba23/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -846,16 +804,17 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh
 github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
 github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
+github.com/segmentio/analytics-go v3.1.0+incompatible h1:IyiOfUgQFVHvsykKKbdI7ZsH374uv3/DfZUo9+G0Z80=
+github.com/segmentio/analytics-go v3.1.0+incompatible/go.mod h1:C7CYBtQWk4vRk2RyLu0qOcbHJ18E3F1HV2C/8JvKN48=
+github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3 h1:ZuhckGJ10ulaKkdvJtiAqsLTiPrLaXSdnVgXJKJkTxE=
+github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3/go.mod h1:9/Rh6yILuLysoQnZ2oNooD2g7aBnvM7r/fNVxRNWfBc=
 github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
 github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
 github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
-github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
-github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
 github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
 github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
 github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
@@ -867,40 +826,30 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k
 github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091/go.mod h1:N20Z5Y8oye9a7HmytmZ+tr8Q2vlP0tAHP13kTHzwvQY=
 github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
 github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
-github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
 github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
 github.com/spf13/afero v1.4.1 h1:asw9sl74539yqavKaglDM5hFpdJVK0Y5Dr/JOgQ89nQ=
 github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
-github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
 github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
 github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
-github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
 github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
-github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs=
 github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
-github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
 github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
 github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=
 github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
-github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
 github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
 github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
 github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
 github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M=
 github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
-github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
 github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
 github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
 github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
@@ -911,7 +860,6 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
 github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
 github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
@@ -926,7 +874,6 @@ github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1C
 github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw=
 github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
 github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
@@ -952,10 +899,11 @@ github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMx
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
 github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8=
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g=
+github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM=
 github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yvasiyarov/go-metrics v0.0.0-20150112132944-c25f46c4b940/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
 github.com/yvasiyarov/gorelic v0.0.7/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
@@ -975,7 +923,6 @@ go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
 go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@@ -993,7 +940,6 @@ golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACk
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd h1:sMHc2rZHuzQmrbVoSpt9HgerkXPyIeCSO6k0zUMGfFk=
 golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -1004,9 +950,7 @@ golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
 golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c h1:9HhBz5L/UjnK9XLtiZhYAdue5BVKep3PMmS2LuPDt8k=
 golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
@@ -1024,11 +968,9 @@ golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u0
 golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
-golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y=
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
-golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -1041,7 +983,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu
 golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
-golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs=
 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
 golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
 golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
@@ -1092,10 +1033,8 @@ golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/
 golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
 golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20201026091529-146b70c837a4 h1:awiuzyrRjJDb+OXi9ceHO3SDxVoN3JER57mhtqkdQBs=
 golang.org/x/net v0.0.0-20201026091529-146b70c837a4/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U=
 golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
@@ -1105,7 +1044,6 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr
 golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
 golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20201203001011-0b49973bad19 h1:ZD+2Sd/BnevwJp8PSli8WgGAGzb9IZtxBsv1iZMYeEA=
 golang.org/x/oauth2 v0.0.0-20201203001011-0b49973bad19/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
@@ -1114,10 +1052,8 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=
 golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1192,17 +1128,13 @@ golang.org/x/sys v0.0.0-20201026133411-418715ba6fdd/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201204225414-ed752295db88 h1:KmZPnMocC93w341XZp26yTJg8Za7lhb2KhkYmixoeso=
 golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
 golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -1270,11 +1202,9 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY
 golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
 golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
 golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d h1:vWQvJ/Z0Lu+9/8oQ/pAYXNzbc7CMnBl+tULGVHOy3oE=
 golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1303,15 +1233,12 @@ google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/
 google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
 google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
 google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
-google.golang.org/api v0.30.0 h1:yfrXXP61wVuLb0vBcG6qaOoIoqYEzOQS8jum51jkv2w=
 google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
-google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
 google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
 google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
 google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
@@ -1346,7 +1273,6 @@ google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEY
 google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
 google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 h1:PDIOdWxZ8eRizhKa1AAvY53xsvLB1cWorMjslvY3VA8=
 google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@@ -1363,7 +1289,6 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
 google.golang.org/grpc v1.29.0/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
 google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
 google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.31.0 h1:T7P4R73V3SSDPhH7WW7ATbfViLtmamH0DKrP3f9AuDI=
 google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
 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=
@@ -1373,7 +1298,6 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
 google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
 google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
 google.golang.org/protobuf v1.25.1-0.20200808011614-a180de9f97d9 h1:poC0iCcx0QXFYlS6nuq/8K+Ng5T55k0FXdzq52hVi4w=
@@ -1383,9 +1307,7 @@ gopkg.in/AlecAivazis/survey.v1 v1.8.8/go.mod h1:CaHjv79TCgAvXMSFJSVgonHXYWxnhzI3
 gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
@@ -1409,12 +1331,10 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
 gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
 gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
 gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
@@ -1470,7 +1390,6 @@ k8s.io/system-validators v1.1.2/go.mod h1:bPldcLgkIUK22ALflnsXk8pvkTEndYdNuaHH6g
 k8s.io/utils v0.0.0-20200414100711-2df71ebbae66/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
 k8s.io/utils v0.0.0-20200729134348-d5654de09c73 h1:uJmqzgNWG7XyClnU/mLPBWwfKKF1K8Hf8whTseBgJcg=
 k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
-modernc.org/cc v1.0.0 h1:nPibNuDEx6tvYrUAtvDTTw98rx5juGsa5zuDnKwEEQQ=
 modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
 modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
 modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
diff --git a/pkg/crc/segment/segment.go b/pkg/crc/segment/segment.go
new file mode 100644
index 000000000..25c612184
--- /dev/null
+++ b/pkg/crc/segment/segment.go
@@ -0,0 +1,85 @@
+package segment
+
+import (
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/code-ready/crc/cmd/crc/cmd/config"
+	crcConfig "github.com/code-ready/crc/pkg/crc/config"
+	"github.com/code-ready/crc/pkg/crc/constants"
+	"github.com/code-ready/crc/pkg/crc/logging"
+	"github.com/code-ready/crc/pkg/crc/version"
+	"github.com/pborman/uuid"
+	"github.com/segmentio/analytics-go"
+)
+
+type Client struct {
+	segmentClient     analytics.Client
+	config            *crcConfig.Config
+	telemetryFilePath string
+}
+
+func NewClient(config *crcConfig.Config) (*Client, error) {
+	telemetryFilePath := filepath.Join(constants.GetHomeDir(), ".redhat", "anonymousId")
+
+	client, err := analytics.NewWithConfig("cvpHsNcmGCJqVzf6YxrSnVlwFSAZaYtp", analytics.Config{
+		DefaultContext: &analytics.Context{
+			App: analytics.AppInfo{
+				Name:    constants.DefaultName,
+				Version: version.GetCRCVersion(),
+			},
+		},
+	})
+	if err != nil {
+		return &Client{}, err
+	}
+
+	return &Client{segmentClient: client, config: config, telemetryFilePath: telemetryFilePath}, nil
+}
+
+func (c *Client) Upload(err error) error {
+	defer c.segmentClient.Close()
+	if !c.config.Get(config.ConsentTelemetry).AsBool() {
+		return nil
+	}
+	logging.Info("Uploading the error to segment")
+
+	anonymousID, uerr := getUserIdentity(c.telemetryFilePath)
+	if uerr != nil {
+		return uerr
+	}
+
+	t := analytics.NewTraits()
+	t = setError(t, err)
+
+	return c.segmentClient.Enqueue(analytics.Identify{
+		AnonymousId: anonymousID,
+		Traits:      t,
+	})
+}
+
+func getUserIdentity(telemetryFilePath string) (string, error) {
+	var id []byte
+	if err := os.MkdirAll(filepath.Dir(telemetryFilePath), 0750); err != nil {
+		return "", err
+	}
+	if _, err := os.Stat(telemetryFilePath); !os.IsNotExist(err) {
+		id, err = ioutil.ReadFile(telemetryFilePath)
+		if err != nil {
+			return "", err
+		}
+	}
+	if uuid.Parse(strings.TrimSpace(string(id))) == nil {
+		id = []byte(uuid.NewRandom().String())
+		if err := ioutil.WriteFile(telemetryFilePath, id, 0600); err != nil {
+			return "", err
+		}
+	}
+	return strings.TrimSpace(string(id)), nil
+}
+
+func setError(t analytics.Traits, err error) analytics.Traits {
+	return t.Set("error", err.Error())
+}
diff --git a/pkg/crc/ssh/client.go b/pkg/crc/ssh/client.go
index f3865ee1c..a8e56764f 100644
--- a/pkg/crc/ssh/client.go
+++ b/pkg/crc/ssh/client.go
@@ -113,6 +113,6 @@ func (client *NativeClient) Close() {
 	}
 	err := client.conn.Close()
 	if err != nil {
-		log.Debugf("Error closing SSH Client: %s", err)
+		log.Debugf("Error closing SSH segmentClient: %s", err)
 	}
 }
diff --git a/vendor/github.com/segmentio/analytics-go/.gitignore b/vendor/github.com/segmentio/analytics-go/.gitignore
new file mode 100644
index 000000000..942678bd9
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/.gitignore
@@ -0,0 +1,32 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
+
+# Emacs
+*~
+\#*
+.\#*
+
+# Artifacts
+tmp/*
diff --git a/vendor/github.com/segmentio/analytics-go/.gitmodules b/vendor/github.com/segmentio/analytics-go/.gitmodules
new file mode 100644
index 000000000..b2150b342
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/.gitmodules
@@ -0,0 +1,6 @@
+[submodule "vendor/github.com/segmentio/backo-go"]
+	path = vendor/github.com/segmentio/backo-go
+	url = https://github.com/segmentio/backo-go
+[submodule "vendor/github.com/xtgo/uuid"]
+	path = vendor/github.com/xtgo/uuid
+	url = https://github.com/xtgo/uuid
diff --git a/vendor/github.com/segmentio/analytics-go/History.md b/vendor/github.com/segmentio/analytics-go/History.md
new file mode 100644
index 000000000..d01214e65
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/History.md
@@ -0,0 +1,88 @@
+
+v3.1.0 / 2019-09-20
+===================
+
+  * add consistent panic error message
+  * Expose the Message interface Validate method
+  * return error if a custom type is enqueued
+  * Handle pointer types in Enqueue()
+  * message: update maxMessageBytes to 32KB
+
+v3.0.1 / 2018-10-02
+===================
+
+* Migrate from Circle V1 format to Circle V2
+* Adds CLI for sending segment events
+* Vendor packages back-go and uuid instead of using gitsubmodules
+
+
+v3.0.0 / 2016-06-02
+===================
+
+ * 3.0 is a significant rewrite with multiple breaking changes.
+ * [Quickstart](https://segment.com/docs/sources/server/go/quickstart/).
+ * [Documentation](https://segment.com/docs/sources/server/go/).
+ * [GoDocs](https://godoc.org/gopkg.in/segmentio/analytics-go.v3).
+ * [What's New in v3](https://segment.com/docs/sources/server/go/#what-s-new-in-v3).
+
+
+v2.1.0 / 2015-12-28
+===================
+
+ * Add ability to set custom timestamps for messages.
+ * Add ability to set a custom `net/http` client.
+ * Add ability to set a custom logger.
+ * Fix edge case when client would try to upload no messages.
+ * Properly upload in-flight messages when client is asked to shutdown.
+ * Add ability to set `.integrations` field on messages.
+ * Fix resource leak with interval ticker after shutdown.
+ * Add retries and back-off when uploading messages.
+ * Add ability to set  custom flush interval.
+
+v2.0.0 / 2015-02-03
+===================
+
+ * rewrite with breaking API changes
+
+v1.2.0 / 2014-09-03
+==================
+
+ * add public .Flush() method
+ * rename .Stop() to .Close()
+
+v1.1.0 / 2014-09-02
+==================
+
+ * add client.Stop() to flash/wait. Closes #7
+
+v1.0.0 / 2014-08-26
+==================
+
+ * fix response close
+ * change comments to be more go-like
+ * change uuid libraries
+
+0.1.2 / 2014-06-11
+==================
+
+ * add runnable example
+ * fix: close body
+
+0.1.1 / 2014-05-31
+==================
+
+ * refactor locking
+
+0.1.0 / 2014-05-22
+==================
+
+ * replace Debug option with debug package
+
+0.0.2 / 2014-05-20
+==================
+
+ * add .Start()
+ * add mutexes
+ * rename BufferSize to FlushAt and FlushInterval to FlushAfter
+ * lower FlushInterval to 5 seconds
+ * lower BufferSize to 20 to match other clients
diff --git a/vendor/github.com/segmentio/analytics-go/License.md b/vendor/github.com/segmentio/analytics-go/License.md
new file mode 100644
index 000000000..f452c5d0f
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/License.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Segment, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/segmentio/analytics-go/Makefile b/vendor/github.com/segmentio/analytics-go/Makefile
new file mode 100644
index 000000000..9de0d1ba7
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/Makefile
@@ -0,0 +1,31 @@
+ifndef CIRCLE_ARTIFACTS
+CIRCLE_ARTIFACTS=tmp
+endif
+
+bootstrap:
+	.buildscript/bootstrap.sh
+
+dependencies:
+	@go get -v -t ./...
+
+vet:
+	@go vet ./...
+
+test: vet
+	@mkdir -p ${CIRCLE_ARTIFACTS}
+	@go test -race -coverprofile=${CIRCLE_ARTIFACTS}/cover.out .
+	@go tool cover -func ${CIRCLE_ARTIFACTS}/cover.out -o ${CIRCLE_ARTIFACTS}/cover.txt
+	@go tool cover -html ${CIRCLE_ARTIFACTS}/cover.out -o ${CIRCLE_ARTIFACTS}/cover.html
+
+build: test
+	@go build ./...
+
+e2e:
+	@if [ "$(RUN_E2E_TESTS)" != "true" ]; then \
+	  echo "Skipping end to end tests."; else \
+		go get github.com/segmentio/library-e2e-tester/cmd/tester; \
+		tester -segment-write-key=$(SEGMENT_WRITE_KEY) -webhook-auth-username=$(WEBHOOK_AUTH_USERNAME) -webhook-bucket=$(WEBHOOK_BUCKET) -path='cli' -concurrency=2 -skip='advance|alias'; fi
+
+ci: dependencies test e2e
+
+.PHONY: bootstrap dependencies vet test e2e ci
diff --git a/vendor/github.com/segmentio/analytics-go/Readme.md b/vendor/github.com/segmentio/analytics-go/Readme.md
new file mode 100644
index 000000000..7d369c16e
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/Readme.md
@@ -0,0 +1,55 @@
+# analytics-go [![Circle CI](https://circleci.com/gh/segmentio/analytics-go/tree/master.svg?style=shield)](https://circleci.com/gh/segmentio/analytics-go/tree/master) [![go-doc](https://godoc.org/github.com/segmentio/analytics-go?status.svg)](https://godoc.org/github.com/segmentio/analytics-go)
+
+Segment analytics client for Go.
+
+## Installation
+
+The package can be simply installed via go get, we recommend that you use a
+package version management system like the Go vendor directory or a tool like
+Godep to avoid issues related to API breaking changes introduced between major
+versions of the library.
+
+To install it in the GOPATH:
+```
+go get https://github.com/segmentio/analytics-go
+```
+
+## Documentation
+
+The links bellow should provide all the documentation needed to make the best
+use of the library and the Segment API:
+
+- [Documentation](https://segment.com/docs/libraries/go/)
+- [godoc](https://godoc.org/gopkg.in/segmentio/analytics-go.v3)
+- [API](https://segment.com/docs/libraries/http/)
+- [Specs](https://segment.com/docs/spec/)
+
+## Usage
+
+```go
+package main
+
+import (
+    "os"
+
+    "github.com/segmentio/analytics-go"
+)
+
+func main() {
+    // Instantiates a client to use send messages to the segment API.
+    client := analytics.New(os.Getenv("SEGMENT_WRITE_KEY"))
+
+    // Enqueues a track event that will be sent asynchronously.
+    client.Enqueue(analytics.Track{
+        UserId: "test-user",
+        Event:  "test-snippet",
+    })
+
+    // Flushes any queued messages and closes the client.
+    client.Close()
+}
+```
+
+## License
+
+The library is released under the [MIT license](License.md).
diff --git a/vendor/github.com/segmentio/analytics-go/alias.go b/vendor/github.com/segmentio/analytics-go/alias.go
new file mode 100644
index 000000000..e9dbe85aa
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/alias.go
@@ -0,0 +1,44 @@
+package analytics
+
+import "time"
+
+var _ Message = (*Alias)(nil)
+
+// This type represents object sent in a alias call as described in
+// https://segment.com/docs/libraries/http/#alias
+type Alias struct {
+	// This field is exported for serialization purposes and shouldn't be set by
+	// the application, its value is always overwritten by the library.
+	Type string `json:"type,omitempty"`
+
+	MessageId    string       `json:"messageId,omitempty"`
+	PreviousId   string       `json:"previousId"`
+	UserId       string       `json:"userId"`
+	Timestamp    time.Time    `json:"timestamp,omitempty"`
+	Context      *Context     `json:"context,omitempty"`
+	Integrations Integrations `json:"integrations,omitempty"`
+}
+
+func (msg Alias) internal() {
+	panic(unimplementedError)
+}
+
+func (msg Alias) Validate() error {
+	if len(msg.UserId) == 0 {
+		return FieldError{
+			Type:  "analytics.Alias",
+			Name:  "UserId",
+			Value: msg.UserId,
+		}
+	}
+
+	if len(msg.PreviousId) == 0 {
+		return FieldError{
+			Type:  "analytics.Alias",
+			Name:  "PreviousId",
+			Value: msg.PreviousId,
+		}
+	}
+
+	return nil
+}
diff --git a/vendor/github.com/segmentio/analytics-go/analytics.go b/vendor/github.com/segmentio/analytics-go/analytics.go
new file mode 100644
index 000000000..d0f089fb6
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/analytics.go
@@ -0,0 +1,431 @@
+package analytics
+
+import (
+	"fmt"
+	"io"
+	"io/ioutil"
+	"sync"
+
+	"bytes"
+	"encoding/json"
+	"net/http"
+	"time"
+)
+
+// Version of the client.
+const Version = "3.0.0"
+const unimplementedError = "not implemented"
+
+// This interface is the main API exposed by the analytics package.
+// Values that satsify this interface are returned by the client constructors
+// provided by the package and provide a way to send messages via the HTTP API.
+type Client interface {
+	io.Closer
+
+	// Queues a message to be sent by the client when the conditions for a batch
+	// upload are met.
+	// This is the main method you'll be using, a typical flow would look like
+	// this:
+	//
+	//	client := analytics.New(writeKey)
+	//	...
+	//	client.Enqueue(analytics.Track{ ... })
+	//	...
+	//	client.Close()
+	//
+	// The method returns an error if the message queue not be queued, which
+	// happens if the client was already closed at the time the method was
+	// called or if the message was malformed.
+	Enqueue(Message) error
+}
+
+type client struct {
+	Config
+	key string
+
+	// This channel is where the `Enqueue` method writes messages so they can be
+	// picked up and pushed by the backend goroutine taking care of applying the
+	// batching rules.
+	msgs chan Message
+
+	// These two channels are used to synchronize the client shutting down when
+	// `Close` is called.
+	// The first channel is closed to signal the backend goroutine that it has
+	// to stop, then the second one is closed by the backend goroutine to signal
+	// that it has finished flushing all queued messages.
+	quit     chan struct{}
+	shutdown chan struct{}
+
+	// This HTTP client is used to send requests to the backend, it uses the
+	// HTTP transport provided in the configuration.
+	http http.Client
+}
+
+// Instantiate a new client that uses the write key passed as first argument to
+// send messages to the backend.
+// The client is created with the default configuration.
+func New(writeKey string) Client {
+	// Here we can ignore the error because the default config is always valid.
+	c, _ := NewWithConfig(writeKey, Config{})
+	return c
+}
+
+// Instantiate a new client that uses the write key and configuration passed as
+// arguments to send messages to the backend.
+// The function will return an error if the configuration contained impossible
+// values (like a negative flush interval for example).
+// When the function returns an error the returned client will always be nil.
+func NewWithConfig(writeKey string, config Config) (cli Client, err error) {
+	if err = config.validate(); err != nil {
+		return
+	}
+
+	c := &client{
+		Config:   makeConfig(config),
+		key:      writeKey,
+		msgs:     make(chan Message, 100),
+		quit:     make(chan struct{}),
+		shutdown: make(chan struct{}),
+		http:     makeHttpClient(config.Transport),
+	}
+
+	go c.loop()
+
+	cli = c
+	return
+}
+
+func makeHttpClient(transport http.RoundTripper) http.Client {
+	httpClient := http.Client{
+		Transport: transport,
+	}
+	if supportsTimeout(transport) {
+		httpClient.Timeout = 10 * time.Second
+	}
+	return httpClient
+}
+
+func dereferenceMessage(msg Message) Message {
+	switch m := msg.(type) {
+	case *Alias:
+		if m == nil {
+			return nil
+		}
+		return *m
+	case *Group:
+		if m == nil {
+			return nil
+		}
+		return *m
+	case *Identify:
+		if m == nil {
+			return nil
+		}
+		return *m
+	case *Page:
+		if m == nil {
+			return nil
+		}
+		return *m
+	case *Screen:
+		if m == nil {
+			return nil
+		}
+		return *m
+	case *Track:
+		if m == nil {
+			return nil
+		}
+		return *m
+	}
+
+	return msg
+}
+
+func (c *client) Enqueue(msg Message) (err error) {
+	msg = dereferenceMessage(msg)
+	if err = msg.Validate(); err != nil {
+		return
+	}
+
+	var id = c.uid()
+	var ts = c.now()
+
+	switch m := msg.(type) {
+	case Alias:
+		m.Type = "alias"
+		m.MessageId = makeMessageId(m.MessageId, id)
+		m.Timestamp = makeTimestamp(m.Timestamp, ts)
+		msg = m
+
+	case Group:
+		m.Type = "group"
+		m.MessageId = makeMessageId(m.MessageId, id)
+		m.Timestamp = makeTimestamp(m.Timestamp, ts)
+		msg = m
+
+	case Identify:
+		m.Type = "identify"
+		m.MessageId = makeMessageId(m.MessageId, id)
+		m.Timestamp = makeTimestamp(m.Timestamp, ts)
+		msg = m
+
+	case Page:
+		m.Type = "page"
+		m.MessageId = makeMessageId(m.MessageId, id)
+		m.Timestamp = makeTimestamp(m.Timestamp, ts)
+		msg = m
+
+	case Screen:
+		m.Type = "screen"
+		m.MessageId = makeMessageId(m.MessageId, id)
+		m.Timestamp = makeTimestamp(m.Timestamp, ts)
+		msg = m
+
+	case Track:
+		m.Type = "track"
+		m.MessageId = makeMessageId(m.MessageId, id)
+		m.Timestamp = makeTimestamp(m.Timestamp, ts)
+		msg = m
+
+	default:
+		err = fmt.Errorf("messages with custom types cannot be enqueued: %T", msg)
+		return
+	}
+
+	defer func() {
+		// When the `msgs` channel is closed writing to it will trigger a panic.
+		// To avoid letting the panic propagate to the caller we recover from it
+		// and instead report that the client has been closed and shouldn't be
+		// used anymore.
+		if recover() != nil {
+			err = ErrClosed
+		}
+	}()
+
+	c.msgs <- msg
+	return
+}
+
+// Close and flush metrics.
+func (c *client) Close() (err error) {
+	defer func() {
+		// Always recover, a panic could be raised if `c`.quit was closed which
+		// means the method was called more than once.
+		if recover() != nil {
+			err = ErrClosed
+		}
+	}()
+	close(c.quit)
+	<-c.shutdown
+	return
+}
+
+// Asychronously send a batched requests.
+func (c *client) sendAsync(msgs []message, wg *sync.WaitGroup, ex *executor) {
+	wg.Add(1)
+
+	if !ex.do(func() {
+		defer wg.Done()
+		defer func() {
+			// In case a bug is introduced in the send function that triggers
+			// a panic, we don't want this to ever crash the application so we
+			// catch it here and log it instead.
+			if err := recover(); err != nil {
+				c.errorf("panic - %s", err)
+			}
+		}()
+		c.send(msgs)
+	}) {
+		wg.Done()
+		c.errorf("sending messages failed - %s", ErrTooManyRequests)
+		c.notifyFailure(msgs, ErrTooManyRequests)
+	}
+}
+
+// Send batch request.
+func (c *client) send(msgs []message) {
+	const attempts = 10
+
+	b, err := json.Marshal(batch{
+		MessageId: c.uid(),
+		SentAt:    c.now(),
+		Messages:  msgs,
+		Context:   c.DefaultContext,
+	})
+
+	if err != nil {
+		c.errorf("marshalling messages - %s", err)
+		c.notifyFailure(msgs, err)
+		return
+	}
+
+	for i := 0; i != attempts; i++ {
+		if err = c.upload(b); err == nil {
+			c.notifySuccess(msgs)
+			return
+		}
+
+		// Wait for either a retry timeout or the client to be closed.
+		select {
+		case <-time.After(c.RetryAfter(i)):
+		case <-c.quit:
+			c.errorf("%d messages dropped because they failed to be sent and the client was closed", len(msgs))
+			c.notifyFailure(msgs, err)
+			return
+		}
+	}
+
+	c.errorf("%d messages dropped because they failed to be sent after %d attempts", len(msgs), attempts)
+	c.notifyFailure(msgs, err)
+}
+
+// Upload serialized batch message.
+func (c *client) upload(b []byte) error {
+	url := c.Endpoint + "/v1/batch"
+	req, err := http.NewRequest("POST", url, bytes.NewReader(b))
+	if err != nil {
+		c.errorf("creating request - %s", err)
+		return err
+	}
+
+	req.Header.Add("User-Agent", "analytics-go (version: "+Version+")")
+	req.Header.Add("Content-Type", "application/json")
+	req.Header.Add("Content-Length", string(len(b)))
+	req.SetBasicAuth(c.key, "")
+
+	res, err := c.http.Do(req)
+
+	if err != nil {
+		c.errorf("sending request - %s", err)
+		return err
+	}
+
+	defer res.Body.Close()
+	return c.report(res)
+}
+
+// Report on response body.
+func (c *client) report(res *http.Response) (err error) {
+	var body []byte
+
+	if res.StatusCode < 300 {
+		c.debugf("response %s", res.Status)
+		return
+	}
+
+	if body, err = ioutil.ReadAll(res.Body); err != nil {
+		c.errorf("response %d %s - %s", res.StatusCode, res.Status, err)
+		return
+	}
+
+	c.logf("response %d %s – %s", res.StatusCode, res.Status, string(body))
+	return fmt.Errorf("%d %s", res.StatusCode, res.Status)
+}
+
+// Batch loop.
+func (c *client) loop() {
+	defer close(c.shutdown)
+
+	wg := &sync.WaitGroup{}
+	defer wg.Wait()
+
+	tick := time.NewTicker(c.Interval)
+	defer tick.Stop()
+
+	ex := newExecutor(c.maxConcurrentRequests)
+	defer ex.close()
+
+	mq := messageQueue{
+		maxBatchSize:  c.BatchSize,
+		maxBatchBytes: c.maxBatchBytes(),
+	}
+
+	for {
+		select {
+		case msg := <-c.msgs:
+			c.push(&mq, msg, wg, ex)
+
+		case <-tick.C:
+			c.flush(&mq, wg, ex)
+
+		case <-c.quit:
+			c.debugf("exit requested – draining messages")
+
+			// Drain the msg channel, we have to close it first so no more
+			// messages can be pushed and otherwise the loop would never end.
+			close(c.msgs)
+			for msg := range c.msgs {
+				c.push(&mq, msg, wg, ex)
+			}
+
+			c.flush(&mq, wg, ex)
+			c.debugf("exit")
+			return
+		}
+	}
+}
+
+func (c *client) push(q *messageQueue, m Message, wg *sync.WaitGroup, ex *executor) {
+	var msg message
+	var err error
+
+	if msg, err = makeMessage(m, maxMessageBytes); err != nil {
+		c.errorf("%s - %v", err, m)
+		c.notifyFailure([]message{{m, nil}}, err)
+		return
+	}
+
+	c.debugf("buffer (%d/%d) %v", len(q.pending), c.BatchSize, m)
+
+	if msgs := q.push(msg); msgs != nil {
+		c.debugf("exceeded messages batch limit with batch of %d messages – flushing", len(msgs))
+		c.sendAsync(msgs, wg, ex)
+	}
+}
+
+func (c *client) flush(q *messageQueue, wg *sync.WaitGroup, ex *executor) {
+	if msgs := q.flush(); msgs != nil {
+		c.debugf("flushing %d messages", len(msgs))
+		c.sendAsync(msgs, wg, ex)
+	}
+}
+
+func (c *client) debugf(format string, args ...interface{}) {
+	if c.Verbose {
+		c.logf(format, args...)
+	}
+}
+
+func (c *client) logf(format string, args ...interface{}) {
+	c.Logger.Logf(format, args...)
+}
+
+func (c *client) errorf(format string, args ...interface{}) {
+	c.Logger.Errorf(format, args...)
+}
+
+func (c *client) maxBatchBytes() int {
+	b, _ := json.Marshal(batch{
+		MessageId: c.uid(),
+		SentAt:    c.now(),
+		Context:   c.DefaultContext,
+	})
+	return maxBatchBytes - len(b)
+}
+
+func (c *client) notifySuccess(msgs []message) {
+	if c.Callback != nil {
+		for _, m := range msgs {
+			c.Callback.Success(m.msg)
+		}
+	}
+}
+
+func (c *client) notifyFailure(msgs []message, err error) {
+	if c.Callback != nil {
+		for _, m := range msgs {
+			c.Callback.Failure(m.msg, err)
+		}
+	}
+}
diff --git a/vendor/github.com/segmentio/analytics-go/config.go b/vendor/github.com/segmentio/analytics-go/config.go
new file mode 100644
index 000000000..c16775730
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/config.go
@@ -0,0 +1,173 @@
+package analytics
+
+import (
+	"net/http"
+	"time"
+
+	"github.com/segmentio/backo-go"
+	"github.com/xtgo/uuid"
+)
+
+// Instances of this type carry the different configuration options that may
+// be set when instantiating a client.
+//
+// Each field's zero-value is either meaningful or interpreted as using the
+// default value defined by the library.
+type Config struct {
+
+	// The endpoint to which the client connect and send their messages, set to
+	// `DefaultEndpoint` by default.
+	Endpoint string
+
+	// The flushing interval of the client. Messages will be sent when they've
+	// been queued up to the maximum batch size or when the flushing interval
+	// timer triggers.
+	Interval time.Duration
+
+	// The HTTP transport used by the client, this allows an application to
+	// redefine how requests are being sent at the HTTP level (for example,
+	// to change the connection pooling policy).
+	// If none is specified the client uses `http.DefaultTransport`.
+	Transport http.RoundTripper
+
+	// The logger used by the client to output info or error messages when that
+	// are generated by background operations.
+	// If none is specified the client uses a standard logger that outputs to
+	// `os.Stderr`.
+	Logger Logger
+
+	// The callback object that will be used by the client to notify the
+	// application when messages sends to the backend API succeeded or failed.
+	Callback Callback
+
+	// The maximum number of messages that will be sent in one API call.
+	// Messages will be sent when they've been queued up to the maximum batch
+	// size or when the flushing interval timer triggers.
+	// Note that the API will still enforce a 500KB limit on each HTTP request
+	// which is independent from the number of embedded messages.
+	BatchSize int
+
+	// When set to true the client will send more frequent and detailed messages
+	// to its logger.
+	Verbose bool
+
+	// The default context set on each message sent by the client.
+	DefaultContext *Context
+
+	// The retry policy used by the client to resend requests that have failed.
+	// The function is called with how many times the operation has been retried
+	// and is expected to return how long the client should wait before trying
+	// again.
+	// If not set the client will fallback to use a default retry policy.
+	RetryAfter func(int) time.Duration
+
+	// A function called by the client to generate unique message identifiers.
+	// The client uses a UUID generator if none is provided.
+	// This field is not exported and only exposed internally to let unit tests
+	// mock the id generation.
+	uid func() string
+
+	// A function called by the client to get the current time, `time.Now` is
+	// used by default.
+	// This field is not exported and only exposed internally to let unit tests
+	// mock the current time.
+	now func() time.Time
+
+	// The maximum number of goroutines that will be spawned by a client to send
+	// requests to the backend API.
+	// This field is not exported and only exposed internally to let unit tests
+	// mock the current time.
+	maxConcurrentRequests int
+}
+
+// This constant sets the default endpoint to which client instances send
+// messages if none was explictly set.
+const DefaultEndpoint = "https://api.segment.io"
+
+// This constant sets the default flush interval used by client instances if
+// none was explicitly set.
+const DefaultInterval = 5 * time.Second
+
+// This constant sets the default batch size used by client instances if none
+// was explicitly set.
+const DefaultBatchSize = 250
+
+// Verifies that fields that don't have zero-values are set to valid values,
+// returns an error describing the problem if a field was invalid.
+func (c *Config) validate() error {
+	if c.Interval < 0 {
+		return ConfigError{
+			Reason: "negative time intervals are not supported",
+			Field:  "Interval",
+			Value:  c.Interval,
+		}
+	}
+
+	if c.BatchSize < 0 {
+		return ConfigError{
+			Reason: "negative batch sizes are not supported",
+			Field:  "BatchSize",
+			Value:  c.BatchSize,
+		}
+	}
+
+	return nil
+}
+
+// Given a config object as argument the function will set all zero-values to
+// their defaults and return the modified object.
+func makeConfig(c Config) Config {
+	if len(c.Endpoint) == 0 {
+		c.Endpoint = DefaultEndpoint
+	}
+
+	if c.Interval == 0 {
+		c.Interval = DefaultInterval
+	}
+
+	if c.Transport == nil {
+		c.Transport = http.DefaultTransport
+	}
+
+	if c.Logger == nil {
+		c.Logger = newDefaultLogger()
+	}
+
+	if c.BatchSize == 0 {
+		c.BatchSize = DefaultBatchSize
+	}
+
+	if c.DefaultContext == nil {
+		c.DefaultContext = &Context{}
+	}
+
+	if c.RetryAfter == nil {
+		c.RetryAfter = backo.DefaultBacko().Duration
+	}
+
+	if c.uid == nil {
+		c.uid = uid
+	}
+
+	if c.now == nil {
+		c.now = time.Now
+	}
+
+	if c.maxConcurrentRequests == 0 {
+		c.maxConcurrentRequests = 1000
+	}
+
+	// We always overwrite the 'library' field of the default context set on the
+	// client because we want this information to be accurate.
+	c.DefaultContext.Library = LibraryInfo{
+		Name:    "analytics-go",
+		Version: Version,
+	}
+	return c
+}
+
+// This function returns a string representation of a UUID, it's the default
+// function used for generating unique IDs.
+func uid() string {
+	return uuid.NewRandom().String()
+}
diff --git a/vendor/github.com/segmentio/analytics-go/context.go b/vendor/github.com/segmentio/analytics-go/context.go
new file mode 100644
index 000000000..7a30c1b98
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/context.go
@@ -0,0 +1,148 @@
+package analytics
+
+import (
+	"encoding/json"
+	"net"
+	"reflect"
+)
+
+// This type provides the representation of the `context` object as defined in
+// https://segment.com/docs/spec/common/#context
+type Context struct {
+	App       AppInfo      `json:"app,omitempty"`
+	Campaign  CampaignInfo `json:"campaign,omitempty"`
+	Device    DeviceInfo   `json:"device,omitempty"`
+	Library   LibraryInfo  `json:"library,omitempty"`
+	Location  LocationInfo `json:"location,omitempty"`
+	Network   NetworkInfo  `json:"network,omitempty"`
+	OS        OSInfo       `json:"os,omitempty"`
+	Page      PageInfo     `json:"page,omitempty"`
+	Referrer  ReferrerInfo `json:"referrer,omitempty"`
+	Screen    ScreenInfo   `json:"screen,omitempty"`
+	IP        net.IP       `json:"ip,omitempty"`
+	Locale    string       `json:"locale,omitempty"`
+	Timezone  string       `json:"timezone,omitempty"`
+	UserAgent string       `json:"userAgent,omitempty"`
+	Traits    Traits       `json:"traits,omitempty"`
+
+	// This map is used to allow extensions to the context specifications that
+	// may not be documented or could be introduced in the future.
+	// The fields of this map are inlined in the serialized context object,
+	// there is no actual "extra" field in the JSON representation.
+	Extra map[string]interface{} `json:"-"`
+}
+
+// This type provides the representation of the `context.app` object as defined
+// in https://segment.com/docs/spec/common/#context
+type AppInfo struct {
+	Name      string `json:"name,omitempty"`
+	Version   string `json:"version,omitempty"`
+	Build     string `json:"build,omitempty"`
+	Namespace string `json:"namespace,omitempty"`
+}
+
+// This type provides the representation of the `context.campaign` object as
+// defined in https://segment.com/docs/spec/common/#context
+type CampaignInfo struct {
+	Name    string `json:"name,omitempty"`
+	Source  string `json:"source,omitempty"`
+	Medium  string `json:"medium,omitempty"`
+	Term    string `json:"term,omitempty"`
+	Content string `json:"content,omitempty"`
+}
+
+// This type provides the representation of the `context.device` object as
+// defined in https://segment.com/docs/spec/common/#context
+type DeviceInfo struct {
+	Id            string `json:"id,omitempty"`
+	Manufacturer  string `json:"manufacturer,omitempty"`
+	Model         string `json:"model,omitempty"`
+	Name          string `json:"name,omitempty"`
+	Type          string `json:"type,omitempty"`
+	Version       string `json:"version,omitempty"`
+	AdvertisingID string `json:"advertisingId,omitempty"`
+}
+
+// This type provides the representation of the `context.library` object as
+// defined in https://segment.com/docs/spec/common/#context
+type LibraryInfo struct {
+	Name    string `json:"name,omitempty"`
+	Version string `json:"version,omitempty"`
+}
+
+// This type provides the representation of the `context.location` object as
+// defined in https://segment.com/docs/spec/common/#context
+type LocationInfo struct {
+	City      string  `json:"city,omitempty"`
+	Country   string  `json:"country,omitempty"`
+	Region    string  `json:"region,omitempty"`
+	Latitude  float64 `json:"latitude,omitempty"`
+	Longitude float64 `json:"longitude,omitempty"`
+	Speed     float64 `json:"speed,omitempty"`
+}
+
+// This type provides the representation of the `context.network` object as
+// defined in https://segment.com/docs/spec/common/#context
+type NetworkInfo struct {
+	Bluetooth bool   `json:"bluetooth,omitempty"`
+	Cellular  bool   `json:"cellular,omitempty"`
+	WIFI      bool   `json:"wifi,omitempty"`
+	Carrier   string `json:"carrier,omitempty"`
+}
+
+// This type provides the representation of the `context.os` object as defined
+// in https://segment.com/docs/spec/common/#context
+type OSInfo struct {
+	Name    string `json:"name,omitempty"`
+	Version string `json:"version,omitempty"`
+}
+
+// This type provides the representation of the `context.page` object as
+// defined in https://segment.com/docs/spec/common/#context
+type PageInfo struct {
+	Hash     string `json:"hash,omitempty"`
+	Path     string `json:"path,omitempty"`
+	Referrer string `json:"referrer,omitempty"`
+	Search   string `json:"search,omitempty"`
+	Title    string `json:"title,omitempty"`
+	URL      string `json:"url,omitempty"`
+}
+
+// This type provides the representation of the `context.referrer` object as
+// defined in https://segment.com/docs/spec/common/#context
+type ReferrerInfo struct {
+	Type string `json:"type,omitempty"`
+	Name string `json:"name,omitempty"`
+	URL  string `json:"url,omitempty"`
+	Link string `json:"link,omitempty"`
+}
+
+// This type provides the representation of the `context.screen` object as
+// defined in https://segment.com/docs/spec/common/#context
+type ScreenInfo struct {
+	Density int `json:"density,omitempty"`
+	Width   int `json:"width,omitempty"`
+	Height  int `json:"height,omitempty"`
+}
+
+// Satisfy the `json.Marshaler` interface. We have to flatten out the `Extra`
+// field but the standard json package doesn't support it yet.
+// Implementing this interface allows us to override the default marshaling of
+// the context object and to the inlining ourselves.
+//
+// Related discussion: https://github.com/golang/go/issues/6213
+func (ctx Context) MarshalJSON() ([]byte, error) {
+	v := reflect.ValueOf(ctx)
+	n := v.NumField()
+	m := make(map[string]interface{}, n+len(ctx.Extra))
+
+	// Copy the `Extra` map into the map representation of the context, it is
+	// important to do this operation before going through the actual struct
+	// fields so the latter take precendence and override duplicated values
+	// that would be set in the extensions.
+	for name, value := range ctx.Extra {
+		m[name] = value
+	}
+
+	return json.Marshal(structToMap(v, m))
+}
diff --git a/vendor/github.com/segmentio/analytics-go/error.go b/vendor/github.com/segmentio/analytics-go/error.go
new file mode 100644
index 000000000..d5503864e
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/error.go
@@ -0,0 +1,60 @@
+package analytics
+
+import (
+	"errors"
+	"fmt"
+)
+
+// Returned by the `NewWithConfig` function when the one of the configuration
+// fields was set to an impossible value (like a negative duration).
+type ConfigError struct {
+
+	// A human-readable message explaining why the configuration field's value
+	// is invalid.
+	Reason string
+
+	// The name of the configuration field that was carrying an invalid value.
+	Field string
+
+	// The value of the configuration field that caused the error.
+	Value interface{}
+}
+
+func (e ConfigError) Error() string {
+	return fmt.Sprintf("analytics.NewWithConfig: %s (analytics.Config.%s: %#v)", e.Reason, e.Field, e.Value)
+}
+
+// Instances of this type are used to represent errors returned when a field was
+// no initialize properly in a structure passed as argument to one of the
+// functions of this package.
+type FieldError struct {
+
+	// The human-readable representation of the type of structure that wasn't
+	// initialized properly.
+	Type string
+
+	// The name of the field that wasn't properly initialized.
+	Name string
+
+	// The value of the field that wasn't properly initialized.
+	Value interface{}
+}
+
+func (e FieldError) Error() string {
+	return fmt.Sprintf("%s.%s: invalid field value: %#v", e.Type, e.Name, e.Value)
+}
+
+var (
+	// This error is returned by methods of the `Client` interface when they are
+	// called after the client was already closed.
+	ErrClosed = errors.New("the client was already closed")
+
+	// This error is used to notify the application that too many requests are
+	// already being sent and no more messages can be accepted.
+	ErrTooManyRequests = errors.New("too many requests are already in-flight")
+
+	// This error is used to notify the client callbacks that a message send
+	// failed because the JSON representation of a message exceeded the upper
+	// limit.
+	ErrMessageTooBig = errors.New("the message exceeds the maximum allowed size")
+)
diff --git a/vendor/github.com/segmentio/analytics-go/executor.go b/vendor/github.com/segmentio/analytics-go/executor.go
new file mode 100644
index 000000000..405ee98ee
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/executor.go
@@ -0,0 +1,53 @@
+package analytics
+
+import "sync"
+
+type executor struct {
+	queue chan func()
+	mutex sync.Mutex
+	size  int
+	cap   int
+}
+
+func newExecutor(cap int) *executor {
+	e := &executor{
+		queue: make(chan func(), 1),
+		cap:   cap,
+	}
+	go e.loop()
+	return e
+}
+
+func (e *executor) do(task func()) (ok bool) {
+	e.mutex.Lock()
+
+	if e.size != e.cap {
+		e.queue <- task
+		e.size++
+		ok = true
+	}
+
+	e.mutex.Unlock()
+	return
+}
+
+func (e *executor) close() {
+	close(e.queue)
+}
+
+func (e *executor) loop() {
+	for task := range e.queue {
+		go e.run(task)
+	}
+}
+
+func (e *executor) run(task func()) {
+	defer e.done()
+	task()
+}
+
+func (e *executor) done() {
+	e.mutex.Lock()
+	e.size--
+	e.mutex.Unlock()
+}
diff --git a/vendor/github.com/segmentio/analytics-go/group.go b/vendor/github.com/segmentio/analytics-go/group.go
new file mode 100644
index 000000000..1da00faaa
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/group.go
@@ -0,0 +1,46 @@
+package analytics
+
+import "time"
+
+var _ Message = (*Group)(nil)
+
+// This type represents object sent in a group call as described in
+// https://segment.com/docs/libraries/http/#group
+type Group struct {
+	// This field is exported for serialization purposes and shouldn't be set by
+	// the application, its value is always overwritten by the library.
+	Type string `json:"type,omitempty"`
+
+	MessageId    string       `json:"messageId,omitempty"`
+	AnonymousId  string       `json:"anonymousId,omitempty"`
+	UserId       string       `json:"userId,omitempty"`
+	GroupId      string       `json:"groupId"`
+	Timestamp    time.Time    `json:"timestamp,omitempty"`
+	Context      *Context     `json:"context,omitempty"`
+	Traits       Traits       `json:"traits,omitempty"`
+	Integrations Integrations `json:"integrations,omitempty"`
+}
+
+func (msg Group) internal() {
+	panic(unimplementedError)
+}
+
+func (msg Group) Validate() error {
+	if len(msg.GroupId) == 0 {
+		return FieldError{
+			Type:  "analytics.Group",
+			Name:  "GroupId",
+			Value: msg.GroupId,
+		}
+	}
+
+	if len(msg.UserId) == 0 && len(msg.AnonymousId) == 0 {
+		return FieldError{
+			Type:  "analytics.Group",
+			Name:  "UserId",
+			Value: msg.UserId,
+		}
+	}
+
+	return nil
+}
diff --git a/vendor/github.com/segmentio/analytics-go/identify.go b/vendor/github.com/segmentio/analytics-go/identify.go
new file mode 100644
index 000000000..ab078aa08
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/identify.go
@@ -0,0 +1,37 @@
+package analytics
+
+import "time"
+
+var _ Message = (*Identify)(nil)
+
+// This type represents object sent in an identify call as described in
+// https://segment.com/docs/libraries/http/#identify
+type Identify struct {
+	// This field is exported for serialization purposes and shouldn't be set by
+	// the application, its value is always overwritten by the library.
+	Type string `json:"type,omitempty"`
+
+	MessageId    string       `json:"messageId,omitempty"`
+	AnonymousId  string       `json:"anonymousId,omitempty"`
+	UserId       string       `json:"userId,omitempty"`
+	Timestamp    time.Time    `json:"timestamp,omitempty"`
+	Context      *Context     `json:"context,omitempty"`
+	Traits       Traits       `json:"traits,omitempty"`
+	Integrations Integrations `json:"integrations,omitempty"`
+}
+
+func (msg Identify) internal() {
+	panic(unimplementedError)
+}
+
+func (msg Identify) Validate() error {
+	if len(msg.UserId) == 0 && len(msg.AnonymousId) == 0 {
+		return FieldError{
+			Type:  "analytics.Identify",
+			Name:  "UserId",
+			Value: msg.UserId,
+		}
+	}
+
+	return nil
+}
diff --git a/vendor/github.com/segmentio/analytics-go/integrations.go b/vendor/github.com/segmentio/analytics-go/integrations.go
new file mode 100644
index 000000000..407b4912b
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/integrations.go
@@ -0,0 +1,44 @@
+package analytics
+
+// This type is used to represent integrations in messages that support it.
+// It is a free-form where values are most often booleans that enable or
+// disable integrations.
+// Here's a quick example of how this type is meant to be used:
+//
+//	analytics.Track{
+//		UserId:       "0123456789",
+//		Integrations: analytics.NewIntegrations()
+//			.EnableAll()
+//			.Disable("Salesforce")
+//			.Disable("Marketo"),
+//	}
+//
+// The specifications can be found at https://segment.com/docs/spec/common/#integrations
+type Integrations map[string]interface{}
+
+func NewIntegrations() Integrations {
+	return make(Integrations, 10)
+}
+
+func (i Integrations) EnableAll() Integrations {
+	return i.Enable("all")
+}
+
+func (i Integrations) DisableAll() Integrations {
+	return i.Disable("all")
+}
+
+func (i Integrations) Enable(name string) Integrations {
+	return i.Set(name, true)
+}
+
+func (i Integrations) Disable(name string) Integrations {
+	return i.Set(name, false)
+}
+
+// Sets an integration named by the first argument to the specified value, any
+// value other than `false` will be interpreted as enabling the integration.
+func (i Integrations) Set(name string, value interface{}) Integrations {
+	i[name] = value
+	return i
+}
diff --git a/vendor/github.com/segmentio/analytics-go/json.go b/vendor/github.com/segmentio/analytics-go/json.go
new file mode 100644
index 000000000..cd3b1752e
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/json.go
@@ -0,0 +1,87 @@
+package analytics
+
+import (
+	"reflect"
+	"strings"
+)
+
+// Imitate what what the JSON package would do when serializing a struct value,
+// the only difference is we we don't serialize zero-value struct fields as well.
+// Note that this function doesn't recursively convert structures to maps, only
+// the value passed as argument is transformed.
+func structToMap(v reflect.Value, m map[string]interface{}) map[string]interface{} {
+	t := v.Type()
+	n := t.NumField()
+
+	if m == nil {
+		m = make(map[string]interface{}, n)
+	}
+
+	for i := 0; i != n; i++ {
+		field := t.Field(i)
+		value := v.Field(i)
+		name, omitempty := parseJsonTag(field.Tag.Get("json"), field.Name)
+
+		if name != "-" && !(omitempty && isZeroValue(value)) {
+			m[name] = value.Interface()
+		}
+	}
+
+	return m
+}
+
+// Parses a JSON tag the way the json package would do it, returing the expected
+// name of the field once serialized and if empty values should be omitted.
+func parseJsonTag(tag string, defName string) (name string, omitempty bool) {
+	args := strings.Split(tag, ",")
+
+	if len(args) == 0 || len(args[0]) == 0 {
+		name = defName
+	} else {
+		name = args[0]
+	}
+
+	if len(args) > 1 && args[1] == "omitempty" {
+		omitempty = true
+	}
+
+	return
+}
+
+// Checks if the value given as argument is a zero-value, it is based on the
+// isEmptyValue function in https://golang.org/src/encoding/json/encode.go
+// but also checks struct types recursively.
+func isZeroValue(v reflect.Value) bool {
+	switch v.Kind() {
+	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+		return v.Len() == 0
+
+	case reflect.Bool:
+		return !v.Bool()
+
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return v.Int() == 0
+
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		return v.Uint() == 0
+
+	case reflect.Float32, reflect.Float64:
+		return v.Float() == 0
+
+	case reflect.Interface, reflect.Ptr:
+		return v.IsNil()
+
+	case reflect.Struct:
+		for i, n := 0, v.NumField(); i != n; i++ {
+			if !isZeroValue(v.Field(i)) {
+				return false
+			}
+		}
+		return true
+
+	case reflect.Invalid:
+		return true
+	}
+
+	return false
+}
diff --git a/vendor/github.com/segmentio/analytics-go/logger.go b/vendor/github.com/segmentio/analytics-go/logger.go
new file mode 100644
index 000000000..54190c5f3
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/logger.go
@@ -0,0 +1,47 @@
+package analytics
+
+import (
+	"log"
+	"os"
+)
+
+// Instances of types implementing this interface can be used to define where
+// the analytics client logs are written.
+type Logger interface {
+
+	// Analytics clients call this method to log regular messages about the
+	// operations they perform.
+	// Messages logged by this method are usually tagged with an `INFO` log
+	// level in common logging libraries.
+	Logf(format string, args ...interface{})
+
+	// Analytics clients call this method to log errors they encounter while
+	// sending events to the backend servers.
+	// Messages logged by this method are usually tagged with an `ERROR` log
+	// level in common logging libraries.
+	Errorf(format string, args ...interface{})
+}
+
+// This function instantiate an object that statisfies the analytics.Logger
+// interface and send logs to standard logger passed as argument.
+func StdLogger(logger *log.Logger) Logger {
+	return stdLogger{
+		logger: logger,
+	}
+}
+
+type stdLogger struct {
+	logger *log.Logger
+}
+
+func (l stdLogger) Logf(format string, args ...interface{}) {
+	l.logger.Printf("INFO: "+format, args...)
+}
+
+func (l stdLogger) Errorf(format string, args ...interface{}) {
+	l.logger.Printf("ERROR: "+format, args...)
+}
+
+func newDefaultLogger() Logger {
+	return StdLogger(log.New(os.Stderr, "segment ", log.LstdFlags))
+}
diff --git a/vendor/github.com/segmentio/analytics-go/message.go b/vendor/github.com/segmentio/analytics-go/message.go
new file mode 100644
index 000000000..a4999c645
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/message.go
@@ -0,0 +1,131 @@
+package analytics
+
+import (
+	"encoding/json"
+	"time"
+)
+
+// Values implementing this interface are used by analytics clients to notify
+// the application when a message send succeeded or failed.
+//
+// Callback methods are called by a client's internal goroutines, there are no
+// guarantees on which goroutine will trigger the callbacks, the calls can be
+// made sequentially or in parallel, the order doesn't depend on the order of
+// messages were queued to the client.
+//
+// Callback methods must return quickly and not cause long blocking operations
+// to avoid interferring with the client's internal work flow.
+type Callback interface {
+
+	// This method is called for every message that was successfully sent to
+	// the API.
+	Success(Message)
+
+	// This method is called for every message that failed to be sent to the
+	// API and will be discarded by the client.
+	Failure(Message, error)
+}
+
+// This interface is used to represent analytics objects that can be sent via
+// a client.
+//
+// Types like analytics.Track, analytics.Page, etc... implement this interface
+// and therefore can be passed to the analytics.Client.Send method.
+type Message interface {
+
+	// Validate validates the internal structure of the message, the method must return
+	// nil if the message is valid, or an error describing what went wrong.
+	Validate() error
+
+	// internal is an unexposed interface function to ensure only types defined within this package can satisfy the Message interface. Invoking this method will panic.
+	internal()
+}
+
+// Takes a message id as first argument and returns it, unless it's the zero-
+// value, in that case the default id passed as second argument is returned.
+func makeMessageId(id string, def string) string {
+	if len(id) == 0 {
+		return def
+	}
+	return id
+}
+
+// Returns the time value passed as first argument, unless it's the zero-value,
+// in that case the default value passed as second argument is returned.
+func makeTimestamp(t time.Time, def time.Time) time.Time {
+	if t == (time.Time{}) {
+		return def
+	}
+	return t
+}
+
+// This structure represents objects sent to the /v1/batch endpoint. We don't
+// export this type because it's only meant to be used internally to send groups
+// of messages in one API call.
+type batch struct {
+	MessageId string    `json:"messageId"`
+	SentAt    time.Time `json:"sentAt"`
+	Messages  []message `json:"batch"`
+	Context   *Context  `json:"context"`
+}
+
+type message struct {
+	msg  Message
+	json []byte
+}
+
+func makeMessage(m Message, maxBytes int) (msg message, err error) {
+	if msg.json, err = json.Marshal(m); err == nil {
+		if len(msg.json) > maxBytes {
+			err = ErrMessageTooBig
+		} else {
+			msg.msg = m
+		}
+	}
+	return
+}
+
+func (m message) MarshalJSON() ([]byte, error) {
+	return m.json, nil
+}
+
+func (m message) size() int {
+	// The `+ 1` is for the comma that sits between each items of a JSON array.
+	return len(m.json) + 1
+}
+
+type messageQueue struct {
+	pending       []message
+	bytes         int
+	maxBatchSize  int
+	maxBatchBytes int
+}
+
+func (q *messageQueue) push(m message) (b []message) {
+	if (q.bytes + m.size()) > q.maxBatchBytes {
+		b = q.flush()
+	}
+
+	if q.pending == nil {
+		q.pending = make([]message, 0, q.maxBatchSize)
+	}
+
+	q.pending = append(q.pending, m)
+	q.bytes += len(m.json)
+
+	if b == nil && len(q.pending) == q.maxBatchSize {
+		b = q.flush()
+	}
+
+	return
+}
+
+func (q *messageQueue) flush() (msgs []message) {
+	msgs, q.pending, q.bytes = q.pending, nil, 0
+	return
+}
+
+const (
+	maxBatchBytes   = 500000
+	maxMessageBytes = 32000
+)
diff --git a/vendor/github.com/segmentio/analytics-go/page.go b/vendor/github.com/segmentio/analytics-go/page.go
new file mode 100644
index 000000000..5a3b231f5
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/page.go
@@ -0,0 +1,38 @@
+package analytics
+
+import "time"
+
+var _ Message = (*Page)(nil)
+
+// This type represents object sent in a page call as described in
+// https://segment.com/docs/libraries/http/#page
+type Page struct {
+	// This field is exported for serialization purposes and shouldn't be set by
+	// the application, its value is always overwritten by the library.
+	Type string `json:"type,omitempty"`
+
+	MessageId    string       `json:"messageId,omitempty"`
+	AnonymousId  string       `json:"anonymousId,omitempty"`
+	UserId       string       `json:"userId,omitempty"`
+	Name         string       `json:"name,omitempty"`
+	Timestamp    time.Time    `json:"timestamp,omitempty"`
+	Context      *Context     `json:"context,omitempty"`
+	Properties   Properties   `json:"properties,omitempty"`
+	Integrations Integrations `json:"integrations,omitempty"`
+}
+
+func (msg Page) internal() {
+	panic(unimplementedError)
+}
+
+func (msg Page) Validate() error {
+	if len(msg.UserId) == 0 && len(msg.AnonymousId) == 0 {
+		return FieldError{
+			Type:  "analytics.Page",
+			Name:  "UserId",
+			Value: msg.UserId,
+		}
+	}
+
+	return nil
+}
diff --git a/vendor/github.com/segmentio/analytics-go/properties.go b/vendor/github.com/segmentio/analytics-go/properties.go
new file mode 100644
index 000000000..8b218aebd
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/properties.go
@@ -0,0 +1,117 @@
+package analytics
+
+// This type is used to represent properties in messages that support it.
+// It is a free-form object so the application can set any value it sees fit but
+// a few helper method are defined to make it easier to instantiate properties with
+// common fields.
+// Here's a quick example of how this type is meant to be used:
+//
+//	analytics.Page{
+//		UserId: "0123456789",
+//		Properties: analytics.NewProperties()
+//			.SetRevenue(10.0)
+//			.SetCurrency("USD"),
+//	}
+//
+type Properties map[string]interface{}
+
+func NewProperties() Properties {
+	return make(Properties, 10)
+}
+
+func (p Properties) SetRevenue(revenue float64) Properties {
+	return p.Set("revenue", revenue)
+}
+
+func (p Properties) SetCurrency(currency string) Properties {
+	return p.Set("currency", currency)
+}
+
+func (p Properties) SetValue(value float64) Properties {
+	return p.Set("value", value)
+}
+
+func (p Properties) SetPath(path string) Properties {
+	return p.Set("path", path)
+}
+
+func (p Properties) SetReferrer(referrer string) Properties {
+	return p.Set("referrer", referrer)
+}
+
+func (p Properties) SetTitle(title string) Properties {
+	return p.Set("title", title)
+}
+
+func (p Properties) SetURL(url string) Properties {
+	return p.Set("url", url)
+}
+
+func (p Properties) SetName(name string) Properties {
+	return p.Set("name", name)
+}
+
+func (p Properties) SetCategory(category string) Properties {
+	return p.Set("category", category)
+}
+
+func (p Properties) SetSKU(sku string) Properties {
+	return p.Set("sku", sku)
+}
+
+func (p Properties) SetPrice(price float64) Properties {
+	return p.Set("price", price)
+}
+
+func (p Properties) SetProductId(id string) Properties {
+	return p.Set("id", id)
+}
+
+func (p Properties) SetOrderId(id string) Properties {
+	return p.Set("orderId", id)
+}
+
+func (p Properties) SetTotal(total float64) Properties {
+	return p.Set("total", total)
+}
+
+func (p Properties) SetSubtotal(subtotal float64) Properties {
+	return p.Set("subtotal", subtotal)
+}
+
+func (p Properties) SetShipping(shipping float64) Properties {
+	return p.Set("shipping", shipping)
+}
+
+func (p Properties) SetTax(tax float64) Properties {
+	return p.Set("tax", tax)
+}
+
+func (p Properties) SetDiscount(discount float64) Properties {
+	return p.Set("discount", discount)
+}
+
+func (p Properties) SetCoupon(coupon string) Properties {
+	return p.Set("coupon", coupon)
+}
+
+func (p Properties) SetProducts(products ...Product) Properties {
+	return p.Set("products", products)
+}
+
+func (p Properties) SetRepeat(repeat bool) Properties {
+	return p.Set("repeat", repeat)
+}
+
+func (p Properties) Set(name string, value interface{}) Properties {
+	p[name] = value
+	return p
+}
+
+// This type represents products in the E-commerce API.
+type Product struct {
+	ID    string  `json:"id,omitempty"`
+	SKU   string  `json:"sky,omitempty"`
+	Name  string  `json:"name,omitempty"`
+	Price float64 `json:"price"`
+}
diff --git a/vendor/github.com/segmentio/analytics-go/screen.go b/vendor/github.com/segmentio/analytics-go/screen.go
new file mode 100644
index 000000000..e810e79da
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/screen.go
@@ -0,0 +1,38 @@
+package analytics
+
+import "time"
+
+var _ Message = (*Screen)(nil)
+
+// This type represents object sent in a screen call as described in
+// https://segment.com/docs/libraries/http/#screen
+type Screen struct {
+	// This field is exported for serialization purposes and shouldn't be set by
+	// the application, its value is always overwritten by the library.
+	Type string `json:"type,omitempty"`
+
+	MessageId    string       `json:"messageId,omitempty"`
+	AnonymousId  string       `json:"anonymousId,omitempty"`
+	UserId       string       `json:"userId,omitempty"`
+	Name         string       `json:"name,omitempty"`
+	Timestamp    time.Time    `json:"timestamp,omitempty"`
+	Context      *Context     `json:"context,omitempty"`
+	Properties   Properties   `json:"properties,omitempty"`
+	Integrations Integrations `json:"integrations,omitempty"`
+}
+
+func (msg Screen) internal() {
+	panic(unimplementedError)
+}
+
+func (msg Screen) Validate() error {
+	if len(msg.UserId) == 0 && len(msg.AnonymousId) == 0 {
+		return FieldError{
+			Type:  "analytics.Screen",
+			Name:  "UserId",
+			Value: msg.UserId,
+		}
+	}
+
+	return nil
+}
diff --git a/vendor/github.com/segmentio/analytics-go/timeout_15.go b/vendor/github.com/segmentio/analytics-go/timeout_15.go
new file mode 100644
index 000000000..12b963edd
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/timeout_15.go
@@ -0,0 +1,16 @@
+// +build !go1.6
+
+package analytics
+
+import "net/http"
+
+// http clients on versions of go before 1.6 only support timeout if the
+// transport implements the `CancelRequest` method.
+func supportsTimeout(transport http.RoundTripper) bool {
+	_, ok := transport.(requestCanceler)
+	return ok
+}
+
+type requestCanceler interface {
+	CancelRequest(*http.Request)
+}
diff --git a/vendor/github.com/segmentio/analytics-go/timeout_16.go b/vendor/github.com/segmentio/analytics-go/timeout_16.go
new file mode 100644
index 000000000..1115cafb7
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/timeout_16.go
@@ -0,0 +1,10 @@
+// +build go1.6
+
+package analytics
+
+import "net/http"
+
+// http clients on versions of go after 1.6 always support timeout.
+func supportsTimeout(transport http.RoundTripper) bool {
+	return true
+}
diff --git a/vendor/github.com/segmentio/analytics-go/track.go b/vendor/github.com/segmentio/analytics-go/track.go
new file mode 100644
index 000000000..9c92a809a
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/track.go
@@ -0,0 +1,46 @@
+package analytics
+
+import "time"
+
+var _ Message = (*Track)(nil)
+
+// This type represents object sent in a track call as described in
+// https://segment.com/docs/libraries/http/#track
+type Track struct {
+	// This field is exported for serialization purposes and shouldn't be set by
+	// the application, its value is always overwritten by the library.
+	Type string `json:"type,omitempty"`
+
+	MessageId    string       `json:"messageId,omitempty"`
+	AnonymousId  string       `json:"anonymousId,omitempty"`
+	UserId       string       `json:"userId,omitempty"`
+	Event        string       `json:"event"`
+	Timestamp    time.Time    `json:"timestamp,omitempty"`
+	Context      *Context     `json:"context,omitempty"`
+	Properties   Properties   `json:"properties,omitempty"`
+	Integrations Integrations `json:"integrations,omitempty"`
+}
+
+func (msg Track) internal() {
+	panic(unimplementedError)
+}
+
+func (msg Track) Validate() error {
+	if len(msg.Event) == 0 {
+		return FieldError{
+			Type:  "analytics.Track",
+			Name:  "Event",
+			Value: msg.Event,
+		}
+	}
+
+	if len(msg.UserId) == 0 && len(msg.AnonymousId) == 0 {
+		return FieldError{
+			Type:  "analytics.Track",
+			Name:  "UserId",
+			Value: msg.UserId,
+		}
+	}
+
+	return nil
+}
diff --git a/vendor/github.com/segmentio/analytics-go/traits.go b/vendor/github.com/segmentio/analytics-go/traits.go
new file mode 100644
index 000000000..d4e82f07a
--- /dev/null
+++ b/vendor/github.com/segmentio/analytics-go/traits.go
@@ -0,0 +1,89 @@
+package analytics
+
+import "time"
+
+// This type is used to represent traits in messages that support it.
+// It is a free-form object so the application can set any value it sees fit but
+// a few helper method are defined to make it easier to instantiate traits with
+// common fields.
+// Here's a quick example of how this type is meant to be used:
+//
+//	analytics.Identify{
+//		UserId: "0123456789",
+//		Traits: analytics.NewTraits()
+//			.SetFirstName("Luke")
+//			.SetLastName("Skywalker")
+//			.Set("Role", "Jedi"),
+//	}
+//
+// The specifications can be found at https://segment.com/docs/spec/identify/#traits
+type Traits map[string]interface{}
+
+func NewTraits() Traits {
+	return make(Traits, 10)
+}
+
+func (t Traits) SetAddress(address string) Traits {
+	return t.Set("address", address)
+}
+
+func (t Traits) SetAge(age int) Traits {
+	return t.Set("age", age)
+}
+
+func (t Traits) SetAvatar(url string) Traits {
+	return t.Set("avatar", url)
+}
+
+func (t Traits) SetBirthday(date time.Time) Traits {
+	return t.Set("birthday", date)
+}
+
+func (t Traits) SetCreatedAt(date time.Time) Traits {
+	return t.Set("createdAt", date)
+}
+
+func (t Traits) SetDescription(desc string) Traits {
+	return t.Set("description", desc)
+}
+
+func (t Traits) SetEmail(email string) Traits {
+	return t.Set("email", email)
+}
+
+func (t Traits) SetFirstName(firstName string) Traits {
+	return t.Set("firstName", firstName)
+}
+
+func (t Traits) SetGender(gender string) Traits {
+	return t.Set("gender", gender)
+}
+
+func (t Traits) SetLastName(lastName string) Traits {
+	return t.Set("lastName", lastName)
+}
+
+func (t Traits) SetName(name string) Traits {
+	return t.Set("name", name)
+}
+
+func (t Traits) SetPhone(phone string) Traits {
+	return t.Set("phone", phone)
+}
+
+func (t Traits) SetTitle(title string) Traits {
+	return t.Set("title", title)
+}
+
+func (t Traits) SetUsername(username string) Traits {
+	return t.Set("username", username)
+}
+
+func (t Traits) SetWebsite(url string) Traits {
+	return t.Set("website", url)
+}
+
+func (t Traits) Set(field string, value interface{}) Traits {
+	t[field] = value
+	return t
+}
diff --git a/vendor/github.com/segmentio/backo-go/.gitmodules b/vendor/github.com/segmentio/backo-go/.gitmodules
new file mode 100644
index 000000000..36de92977
--- /dev/null
+++ b/vendor/github.com/segmentio/backo-go/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "vendor/github.com/bmizerany/assert"]
+	path = vendor/github.com/bmizerany/assert
+	url = https://github.com/bmizerany/assert
diff --git a/vendor/github.com/segmentio/backo-go/LICENSE b/vendor/github.com/segmentio/backo-go/LICENSE
new file mode 100644
index 000000000..f83bd9f13
--- /dev/null
+++ b/vendor/github.com/segmentio/backo-go/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Segment, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/segmentio/backo-go/README.md b/vendor/github.com/segmentio/backo-go/README.md
new file mode 100644
index 000000000..1362becf1
--- /dev/null
+++ b/vendor/github.com/segmentio/backo-go/README.md
@@ -0,0 +1,80 @@
+Backo [![GoDoc](http://godoc.org/github.com/segmentio/backo-go?status.png)](http://godoc.org/github.com/segmentio/backo-go)
+-----
+
+Exponential backoff for Go (Go port of segmentio/backo).
+
+
+Usage
+-----
+
+```go
+import "github.com/segmentio/backo-go"
+
+// Create a Backo instance.
+backo := backo.NewBacko(milliseconds(100), 2, 1, milliseconds(10*1000))
+// OR with defaults.
+backo := backo.DefaultBacko()
+
+// Use the ticker API.
+ticker := b.NewTicker()
+for {
+    timeout := time.After(5 * time.Minute)
+    select {
+    case  <-ticker.C:
+        fmt.Println("ticked")
+    case <- timeout:
+        fmt.Println("timed out")
+    }
+}
+
+// Or simply work with backoff intervals directly.
+for i := 0; i < n; i++ {
+    // Sleep the current goroutine.
+    backo.Sleep(i)
+    // Retrieve the duration manually.
+    duration := backo.Duration(i)
+}
+```
+
+License
+-------
+
+```
+WWWWWW||WWWWWW
+ W W W||W W W
+      ||
+    ( OO )__________
+     /  |           \
+    /o o|    MIT     \
+    \___/||_||__||_|| *
+         || ||  || ||
+        _||_|| _||_||
+       (__|__|(__|__|
+
+The MIT License (MIT)
+
+Copyright (c) 2015 Segment, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+```
+
+
+
+ [1]: http://github.com/segmentio/backo-java
+ [2]: http://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=com.segment.backo&a=backo&v=LATEST
\ No newline at end of file
diff --git a/vendor/github.com/segmentio/backo-go/backo.go b/vendor/github.com/segmentio/backo-go/backo.go
new file mode 100644
index 000000000..6f7b6d5e2
--- /dev/null
+++ b/vendor/github.com/segmentio/backo-go/backo.go
@@ -0,0 +1,83 @@
+package backo
+
+import (
+	"math"
+	"math/rand"
+	"time"
+)
+
+type Backo struct {
+	base   time.Duration
+	factor uint8
+	jitter float64
+	cap    time.Duration
+}
+
+// Creates a backo instance with the given parameters
+func NewBacko(base time.Duration, factor uint8, jitter float64, cap time.Duration) *Backo {
+	return &Backo{base, factor, jitter, cap}
+}
+
+// Creates a backo instance with the following defaults:
+//   base: 100 milliseconds
+//   factor: 2
+//   jitter: 0
+//   cap: 10 seconds
+func DefaultBacko() *Backo {
+	return NewBacko(time.Millisecond*100, 2, 0, time.Second*10)
+}
+
+// Duration returns the backoff interval for the given attempt.
+func (backo *Backo) Duration(attempt int) time.Duration {
+	duration := float64(backo.base) * math.Pow(float64(backo.factor), float64(attempt))
+
+	if backo.jitter != 0 {
+		random := rand.Float64()
+		deviation := math.Floor(random * backo.jitter * duration)
+		if (int(math.Floor(random*10)) & 1) == 0 {
+			duration = duration - deviation
+		} else {
+			duration = duration + deviation
+		}
+	}
+
+	duration = math.Min(float64(duration), float64(backo.cap))
+	return time.Duration(duration)
+}
+
+// Sleep pauses the current goroutine for the backoff interval for the given attempt.
+func (backo *Backo) Sleep(attempt int) {
+	duration := backo.Duration(attempt)
+	time.Sleep(duration)
+}
+
+type Ticker struct {
+	done chan struct{}
+	C    <-chan time.Time
+}
+
+func (b *Backo) NewTicker() *Ticker {
+	c := make(chan time.Time, 1)
+	ticker := &Ticker{
+		done: make(chan struct{}, 1),
+		C:    c,
+	}
+
+	go func() {
+		for i := 0; ; i++ {
+			select {
+			case t := <-time.After(b.Duration(i)):
+				c <- t
+			case <-ticker.done:
+				close(c)
+				return
+			}
+		}
+	}()
+
+	return ticker
+}
+
+func (t *Ticker) Stop() {
+	t.done <- struct{}{}
+}
diff --git a/vendor/github.com/segmentio/backo-go/go.mod b/vendor/github.com/segmentio/backo-go/go.mod
new file mode 100644
index 000000000..af284eb98
--- /dev/null
+++ b/vendor/github.com/segmentio/backo-go/go.mod
@@ -0,0 +1,3 @@
+module github.com/segmentio/backo-go
+
+go 1.13
diff --git a/vendor/github.com/xtgo/uuid/AUTHORS b/vendor/github.com/xtgo/uuid/AUTHORS
new file mode 100644
index 000000000..a6f045160
--- /dev/null
+++ b/vendor/github.com/xtgo/uuid/AUTHORS
@@ -0,0 +1,5 @@
+# This source file refers to The gocql Authors for copyright purposes.
+
+Christoph Hack <christoph@tux21b.org>
+Jonathan Rudenberg <jonathan@titanous.com>
+Thorsten von Eicken <tve@rightscale.com>
diff --git a/vendor/github.com/xtgo/uuid/LICENSE b/vendor/github.com/xtgo/uuid/LICENSE
new file mode 100644
index 000000000..18d25f923
--- /dev/null
+++ b/vendor/github.com/xtgo/uuid/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2012 The gocql Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/xtgo/uuid/uuid.go b/vendor/github.com/xtgo/uuid/uuid.go
new file mode 100644
index 000000000..a0fd7a5a5
--- /dev/null
+++ b/vendor/github.com/xtgo/uuid/uuid.go
@@ -0,0 +1,204 @@
+// Copyright (c) 2012 The gocql Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package uuid can be used to generate and parse universally unique
+// identifiers, a standardized format in the form of a 128 bit number.
+//
+// http://tools.ietf.org/html/rfc4122
+package uuid
+
+import (
+	"crypto/rand"
+	"encoding/hex"
+	"errors"
+	"io"
+	"net"
+	"strconv"
+	"time"
+)
+
+type UUID [16]byte
+
+var hardwareAddr []byte
+
+const (
+	VariantNCSCompat = 0
+	VariantIETF      = 2
+	VariantMicrosoft = 6
+	VariantFuture    = 7
+)
+
+func init() {
+	if interfaces, err := net.Interfaces(); err == nil {
+		for _, i := range interfaces {
+			if i.Flags&net.FlagLoopback == 0 && len(i.HardwareAddr) > 0 {
+				hardwareAddr = i.HardwareAddr
+				break
+			}
+		}
+	}
+	if hardwareAddr == nil {
+		// If we failed to obtain the MAC address of the current computer,
+		// we will use a randomly generated 6 byte sequence instead and set
+		// the multicast bit as recommended in RFC 4122.
+		hardwareAddr = make([]byte, 6)
+		_, err := io.ReadFull(rand.Reader, hardwareAddr)
+		if err != nil {
+			panic(err)
+		}
+		hardwareAddr[0] = hardwareAddr[0] | 0x01
+	}
+}
+
+// Parse parses a 32 digit hexadecimal number (that might contain hyphens)
+// representing an UUID.
+func Parse(input string) (UUID, error) {
+	var u UUID
+	j := 0
+	for i := 0; i < len(input); i++ {
+		b := input[i]
+		switch {
+		default:
+			fallthrough
+		case j == 32:
+			goto err
+		case b == '-':
+			continue
+		case '0' <= b && b <= '9':
+			b -= '0'
+		case 'a' <= b && b <= 'f':
+			b -= 'a' - 10
+		case 'A' <= b && b <= 'F':
+			b -= 'A' - 10
+		}
+		u[j/2] |= b << byte(^j&1<<2)
+		j++
+	}
+	if j == 32 {
+		return u, nil
+	}
+err:
+	return UUID{}, errors.New("invalid UUID " + strconv.Quote(input))
+}
+
+// FromBytes converts a raw byte slice to an UUID. It will panic if the slice
+// isn't exactly 16 bytes long.
+func FromBytes(input []byte) UUID {
+	var u UUID
+	if len(input) != 16 {
+		panic("UUIDs must be exactly 16 bytes long")
+	}
+	copy(u[:], input)
+	return u
+}
+
+// NewRandom generates a totally random UUID (version 4) as described in
+// RFC 4122.
+func NewRandom() UUID {
+	var u UUID
+	io.ReadFull(rand.Reader, u[:])
+	u[6] &= 0x0F // clear version
+	u[6] |= 0x40 // set version to 4 (random uuid)
+	u[8] &= 0x3F // clear variant
+	u[8] |= 0x80 // set to IETF variant
+	return u
+}
+
+var timeBase = time.Date(1582, time.October, 15, 0, 0, 0, 0, time.UTC).Unix()
+
+// NewTime generates a new time based UUID (version 1) as described in RFC
+// 4122. This UUID contains the MAC address of the node that generated the
+// UUID, a timestamp and a sequence number.
+func NewTime() UUID {
+	var u UUID
+
+	now := time.Now().In(time.UTC)
+	t := uint64(now.Unix()-timeBase)*10000000 + uint64(now.Nanosecond()/100)
+	u[0], u[1], u[2], u[3] = byte(t>>24), byte(t>>16), byte(t>>8), byte(t)
+	u[4], u[5] = byte(t>>40), byte(t>>32)
+	u[6], u[7] = byte(t>>56)&0x0F, byte(t>>48)
+
+	var clockSeq [2]byte
+	io.ReadFull(rand.Reader, clockSeq[:])
+	u[8] = clockSeq[1]
+	u[9] = clockSeq[0]
+
+	copy(u[10:], hardwareAddr)
+
+	u[6] |= 0x10 // set version to 1 (time based uuid)
+	u[8] &= 0x3F // clear variant
+	u[8] |= 0x80 // set to IETF variant
+
+	return u
+}
+
+// String returns the UUID in it's canonical form, a 32 digit hexadecimal
+// number in the form of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
+func (u UUID) String() string {
+	buf := [36]byte{8: '-', 13: '-', 18: '-', 23: '-'}
+	hex.Encode(buf[0:], u[0:4])
+	hex.Encode(buf[9:], u[4:6])
+	hex.Encode(buf[14:], u[6:8])
+	hex.Encode(buf[19:], u[8:10])
+	hex.Encode(buf[24:], u[10:])
+	return string(buf[:])
+}
+
+// Bytes returns the raw byte slice for this UUID. A UUID is always 128 bits
+// (16 bytes) long.
+func (u UUID) Bytes() []byte {
+	return u[:]
+}
+
+// Variant returns the variant of this UUID. This package will only generate
+// UUIDs in the IETF variant.
+func (u UUID) Variant() int {
+	x := u[8]
+	switch byte(0) {
+	case x & 0x80:
+		return VariantNCSCompat
+	case x & 0x40:
+		return VariantIETF
+	case x & 0x20:
+		return VariantMicrosoft
+	}
+	return VariantFuture
+}
+
+// Version extracts the version of this UUID variant. The RFC 4122 describes
+// five kinds of UUIDs.
+func (u UUID) Version() int {
+	return int(u[6] & 0xF0 >> 4)
+}
+
+// Node extracts the MAC address of the node who generated this UUID. It will
+// return nil if the UUID is not a time based UUID (version 1).
+func (u UUID) Node() []byte {
+	if u.Version() != 1 {
+		return nil
+	}
+	return u[10:]
+}
+
+// Timestamp extracts the timestamp information from a time based UUID
+// (version 1).
+func (u UUID) Timestamp() uint64 {
+	if u.Version() != 1 {
+		return 0
+	}
+	return uint64(u[0])<<24 + uint64(u[1])<<16 + uint64(u[2])<<8 +
+		uint64(u[3]) + uint64(u[4])<<40 + uint64(u[5])<<32 +
+		uint64(u[7])<<48 + uint64(u[6]&0x0F)<<56
+}
+
+// Time is like Timestamp, except that it returns a time.Time.
+func (u UUID) Time() time.Time {
+	t := u.Timestamp()
+	if t == 0 {
+		return time.Time{}
+	}
+	sec := t / 10000000
+	nsec := t - sec
+	return time.Unix(int64(sec)+timeBase, int64(nsec))
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 0b6f6c18b..26119e3f7 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -199,6 +199,12 @@ github.com/pkg/browser
 github.com/pkg/errors
 # github.com/pmezard/go-difflib v1.0.0
 github.com/pmezard/go-difflib/difflib
+# github.com/segmentio/analytics-go v3.1.0+incompatible
+## explicit
+github.com/segmentio/analytics-go
+# github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3
+## explicit
+github.com/segmentio/backo-go
 # github.com/sirupsen/logrus v1.7.0
 ## explicit
 github.com/sirupsen/logrus
@@ -229,6 +235,9 @@ github.com/subosito/gotenv
 # github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8
 ## explicit
 github.com/xi2/xz
+# github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c
+## explicit
+github.com/xtgo/uuid
 # golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c
 ## explicit
 golang.org/x/crypto/blowfish


Test patch:
diff --git a/pkg/crc/segment/segment_test.go b/pkg/crc/segment/segment_test.go
new file mode 100644
index 000000000..2f7acce08
--- /dev/null
+++ b/pkg/crc/segment/segment_test.go
@@ -0,0 +1,156 @@
+package segment
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"net/http/httptest"
+	"os"
+	"path/filepath"
+	"testing"
+
+	crcConfig "github.com/code-ready/crc/pkg/crc/config"
+	"github.com/segmentio/analytics-go"
+	"github.com/stretchr/testify/require"
+)
+
+const (
+	ConsentTelemetry = "consent-telemetry"
+)
+
+type segmentResponse struct {
+	Batch []struct {
+		AnonymousID string `json:"anonymousId"`
+		MessageID   string `json:"messageId"`
+		Traits      struct {
+			Error string `json:"error"`
+		} `json:"traits"`
+		Type string `json:"type"`
+	} `json:"batch"`
+	Context struct {
+		App struct {
+			Name    string `json:"name"`
+			Version string `json:"version"`
+		} `json:"app"`
+		Library struct {
+			Name    string `json:"name"`
+			Version string `json:"version"`
+		} `json:"library"`
+	} `json:"context"`
+	MessageID string `json:"messageId"`
+}
+
+func mockServer() (chan []byte, *httptest.Server) {
+	done := make(chan []byte, 1)
+
+	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		buf := bytes.NewBuffer(nil)
+		io.Copy(buf, r.Body) // nolint
+
+		var v interface{}
+		err := json.Unmarshal(buf.Bytes(), &v)
+		if err != nil {
+			panic(err)
+		}
+
+		b, err := json.MarshalIndent(v, "", "  ")
+		if err != nil {
+			panic(err)
+		}
+
+		done <- b
+	}))
+
+	return done, server
+}
+
+func newTestConfig(value bool) (*crcConfig.Config, error) {
+	storage := crcConfig.NewEmptyInMemoryStorage()
+	config := crcConfig.New(storage)
+	config.AddSetting(ConsentTelemetry, value, crcConfig.ValidateBool, crcConfig.SuccessfullyApplied)
+	return config, nil
+}
+
+func TestClientUploadWithConsent(t *testing.T) {
+	body, server := mockServer()
+	defer server.Close()
+	defer close(body)
+
+	client, err := analytics.NewWithConfig("dummykey", analytics.Config{
+		DefaultContext: &analytics.Context{
+			App: analytics.AppInfo{
+				Name:    "crc",
+				Version: "1.20.0",
+			},
+		},
+		Endpoint: server.URL,
+	})
+	require.NoError(t, err)
+
+	dir, err := ioutil.TempDir("", "cfg")
+	require.NoError(t, err)
+	defer os.RemoveAll(dir)
+
+	config, err := newTestConfig(true)
+	require.NoError(t, err)
+
+	c := &Client{segmentClient: client, config: config, telemetryFilePath: filepath.Join(dir, "telemetry")}
+
+	require.NoError(t, c.Upload(errors.New("an error occurred")))
+
+	s := segmentResponse{}
+	select {
+	case x, ok := <-body:
+		if ok {
+			err = json.Unmarshal(x, &s)
+			require.NoError(t, err)
+		}
+	default:
+	}
+	require.Equal(t, s.Batch[0].Traits.Error, "an error occurred")
+	require.Equal(t, s.Context.App.Name, "crc")
+	require.Equal(t, s.Context.App.Version, "1.20.0")
+}
+
+func TestClientUploadWithOutConsent(t *testing.T) {
+	body, server := mockServer()
+	defer server.Close()
+	defer close(body)
+
+	client, err := analytics.NewWithConfig("dummykey", analytics.Config{
+		DefaultContext: &analytics.Context{
+			App: analytics.AppInfo{
+				Name:    "crc",
+				Version: "1.20.0",
+			},
+		},
+		Endpoint: server.URL,
+	})
+	require.NoError(t, err)
+
+	dir, err := ioutil.TempDir("", "cfg")
+	require.NoError(t, err)
+	defer os.RemoveAll(dir)
+
+	config, err := newTestConfig(false)
+	require.NoError(t, err)
+
+	c := &Client{segmentClient: client, config: config, telemetryFilePath: filepath.Join(dir, "telemetry")}
+
+	require.NoError(t, c.Upload(errors.New("an error occurred")))
+
+	s := segmentResponse{}
+	select {
+	case x, ok := <-body:
+		if ok {
+			err = json.Unmarshal(x, &s)
+			require.NoError(t, err)
+		}
+	default:
+	}
+
+	require.Len(t, s.Batch, 0)
+}
diff --git a/test/testdata/etcd-cluster3.yaml b/test/testdata/etcd-cluster3.yaml
index 1fa017989..28ebb25a4 100644
--- a/test/testdata/etcd-cluster3.yaml
+++ b/test/testdata/etcd-cluster3.yaml
@@ -8,3 +8,5 @@ metadata:
 spec:
   size: 3
   version: 3.2.13
+  pod:
+    busyboxImage: quay.io/libpod/alpine:3.10.2
diff --git a/test/testdata/etcd-cluster5.yaml b/test/testdata/etcd-cluster5.yaml
index 724ca7b0c..a40f69291 100644
--- a/test/testdata/etcd-cluster5.yaml
+++ b/test/testdata/etcd-cluster5.yaml
@@ -8,3 +8,5 @@ metadata:
 spec:
   size: 5
   version: 3.2.13
+  pod:
+    busyboxImage: quay.io/libpod/alpine:3.10.2