Repository: txtdirect/txtdirect
Pull request #347 (2020-07-22 19:09:46)

[v2]: Migrate Caddy to v2 and refactor structure
**What this PR does / why we need it**:
Upgrades:
 - Caddy to v2

Refactors:
 - Config parser
 - Limit the supported types to `host` and `path`
 - Temporarily disables Promethues (caddy-promethues doesn't support v2. needs to be replaced)
 - Temporarily disables Mailout (doesn't support v2. needs to be replaced)
 - ...

<!--
**Which issue this PR fixes** *(optional - uncomment and add issue)*:
fixes #0
-->

**Special notes for your reviewer**:
Not ready for merge yet, still need to clean up the comments and unnecessary codes. It works fine right now tho.

**Release note**:
<!--
Optional one line note for this specific change, that can be used in a release-note or changelog.
-->
```release-note

```



Patch:
diff --git a/.travis.yml b/.travis.yml
index 95f13e1..54f6acc 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,7 @@
 language: go
 
 go:
-  - 1.13
+  - 1.14
 
 services:
   - docker
diff --git a/Makefile b/Makefile
index 945d165..8b43970 100644
--- a/Makefile
+++ b/Makefile
@@ -27,11 +27,11 @@ docker-run: image-build
 	docker run --name $(CONTAINER) $(IMAGE)
 
 docker-test:
-	docker run --network=host -v $(shell pwd):/source -v $(GOPATH)/pkg/mod:/go/pkg/mod golang:1.13-alpine /bin/sh \
+	docker run --network=host -v $(shell pwd):/source -v $(GOPATH)/pkg/mod:/go/pkg/mod golang:1.14-alpine /bin/sh \
 	-c "cd /source && apk add git gcc musl-dev make && GOROOT=\"/usr/local/go\" make test"
 
 docker-build:
-	docker run --network=host -v $(shell pwd):/source -v $(GOPATH)/pkg/mod:/go/pkg/mod golang:1.13-alpine /bin/sh \
+	docker run --network=host -v $(shell pwd):/source -v $(GOPATH)/pkg/mod:/go/pkg/mod golang:1.14-alpine /bin/sh \
 	-c "cd /source && apk add git gcc musl-dev make && make build"
 
 endtoend-test: docker-build
diff --git a/cmd/txtdirect/main.go b/cmd/txtdirect/main.go
deleted file mode 100644
index ea669a1..0000000
--- a/cmd/txtdirect/main.go
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
-Copyright 2019 - The TXTDirect Authors
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-    http://www.apache.org/licenses/LICENSE-2.0
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package main
-
-import (
-	"go.txtdirect.org/txtdirect/txtdirectmain"
-
-	_ "github.com/SchumacherFM/mailout"
-	_ "github.com/captncraig/caddy-realip"
-	_ "github.com/miekg/caddy-prometheus"
-	_ "go.txtdirect.org/txtdirect"
-)
-
-func main() {
-	txtdirectmain.Run()
-}
diff --git a/cmd/txtdirect/txtdirect.go b/cmd/txtdirect/txtdirect.go
new file mode 100644
index 0000000..4a66773
--- /dev/null
+++ b/cmd/txtdirect/txtdirect.go
@@ -0,0 +1,117 @@
+/*
+Copyright 2017 - The TXTDirect Authors
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+    http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package main
+
+import (
+	"fmt"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"os"
+	"strings"
+
+	lumberjack "gopkg.in/natefinch/lumberjack.v2"
+
+	"github.com/caddyserver/caddy/v2"
+	"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
+	"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
+	caddycmd "github.com/caddyserver/caddy/v2/cmd"
+	"github.com/caddyserver/caddy/v2/modules/caddyhttp"
+
+	"go.txtdirect.org/txtdirect"
+)
+
+func main() {
+	caddycmd.Main()
+}
+
+func init() {
+	caddy.RegisterModule(TXTDirect{})
+	httpcaddyfile.RegisterHandlerDirective("txtdirect", parseCaddyfile)
+}
+
+// TXTDirect implements an HTTP handler that calls
+// Redirect method on requests and writes back the response
+type TXTDirect struct {
+	*txtdirect.Config
+}
+
+// CaddyModule returns the Caddy module information.
+func (TXTDirect) CaddyModule() caddy.ModuleInfo {
+	return caddy.ModuleInfo{
+		ID:  "http.handlers.txtdirect",
+		New: func() caddy.Module { return new(TXTDirect) },
+	}
+}
+
+// ServeHTTP implements caddyhttp.MiddlewareHandler.
+func (t TXTDirect) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
+	r.URL.Host = strings.ToLower(r.URL.Host)
+	if err := txtdirect.Redirect(w, r, *t.Config); err != nil {
+		if err.Error() == "option disabled" {
+			return next.ServeHTTP(w, r)
+		}
+		return err
+	}
+
+	if w.Header().Get("Status-Code") == "301" || w.Header().Get("Status-Code") == "302" {
+		// Set Cache-Control header on permanent redirects
+		if w.Header().Get("Status-Code") == "301" {
+			w.Header().Add("Cache-Control", fmt.Sprintf("max-age=%d", txtdirect.Status301CacheAge))
+		}
+	}
+
+	return nil
+}
+
+// UnmarshalCaddyfile implements caddyfile.Unmarshaler.
+func (t *TXTDirect) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
+	var err error
+	if t.Config, err = txtdirect.ParseCaddy(d); err != nil {
+		return fmt.Errorf("[txtdirect]: Couldn't parse the config: %s", err.Error())
+	}
+
+	return nil
+}
+
+// parseCaddyfile unmarshals tokens from h into a new Middleware.
+func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
+	var t TXTDirect
+	err := t.UnmarshalCaddyfile(h.Dispenser)
+	return t, err
+}
+
+// Interface guards
+var (
+	_ caddyhttp.MiddlewareHandler = (*TXTDirect)(nil)
+	_ caddyfile.Unmarshaler       = (*TXTDirect)(nil)
+)
+
+func parseLogfile(logfile string) {
+	switch logfile {
+	case "stdout":
+		log.SetOutput(os.Stdout)
+	case "stderr":
+		log.SetOutput(os.Stderr)
+	case "":
+		log.SetOutput(ioutil.Discard)
+	default:
+		log.SetOutput(&lumberjack.Logger{
+			Filename:   logfile,
+			MaxSize:    100,
+			MaxAge:     14,
+			MaxBackups: 10,
+		})
+	}
+}
diff --git a/config.go b/config.go
new file mode 100644
index 0000000..4a5610d
--- /dev/null
+++ b/config.go
@@ -0,0 +1,124 @@
+package txtdirect
+
+import (
+	"io/ioutil"
+	"log"
+	"os"
+
+	"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
+	"gopkg.in/natefinch/lumberjack.v2"
+)
+
+var allOptions = []string{"host", "path", "gometa", "www"}
+
+// Config contains the middleware's configuration
+type Config struct {
+	Enable    []string `json:"enable"`
+	Redirect  string   `json:"redirect,omitempty"`
+	Resolver  string   `json:"resolver,omitempty"`
+	LogOutput string   `json:"logfile,omitempty"`
+	Qr        Qr
+}
+
+func ParseCaddy(d *caddyfile.Dispenser) (*Config, error) {
+	var enable []string
+	var redirect string
+	var resolver string
+	var logfile string
+
+	for d.Next() {
+		for nesting := d.Nesting(); d.NextBlock(nesting); {
+			switch d.Val() {
+			case "disable":
+				if enable != nil {
+					return nil, d.ArgErr()
+				}
+				toDisable := d.RemainingArgs()
+				if len(toDisable) == 0 {
+					return nil, d.ArgErr()
+				}
+				enable = removeArrayFromArray(allOptions, toDisable)
+
+			case "enable":
+				if enable != nil {
+					return nil, d.ArgErr()
+				}
+				enable = d.RemainingArgs()
+				if len(enable) == 0 {
+					return nil, d.ArgErr()
+				}
+
+			case "redirect":
+				toRedirect := d.RemainingArgs()
+				if len(toRedirect) != 1 {
+					return nil, d.ArgErr()
+				}
+				redirect = toRedirect[0]
+
+			case "resolver":
+				resolverAddr := d.RemainingArgs()
+				if len(resolverAddr) != 1 {
+					return nil, d.ArgErr()
+				}
+				resolver = resolverAddr[0]
+
+			case "logfile":
+				logfile = "stdout"
+				// Set stdout as the default value
+				if d.NextArg() {
+					logfile = d.Val()
+				}
+			}
+		}
+
+	}
+
+	// If nothing is specified, enable everything
+	if enable == nil {
+		enable = allOptions
+	}
+
+	conf := Config{
+		Enable:    enable,
+		Redirect:  redirect,
+		Resolver:  resolver,
+		LogOutput: logfile,
+	}
+
+	parseLogfile(logfile)
+
+	return &conf, nil
+}
+
+func removeArrayFromArray(array, toBeRemoved []string) []string {
+	t := make([]string, len(array))
+	copy(t, array)
+	for _, toRemove := range toBeRemoved {
+		for i, option := range t {
+			if option == toRemove {
+				t[i] = t[len(t)-1]
+				t = t[:len(t)-1]
+				break
+			}
+		}
+	}
+	return t
+}
+
+func parseLogfile(logfile string) {
+	switch logfile {
+	case "stdout":
+		log.SetOutput(os.Stdout)
+	case "stderr":
+		log.SetOutput(os.Stderr)
+	case "":
+		log.SetOutput(ioutil.Discard)
+	default:
+		log.SetOutput(&lumberjack.Logger{
+			Filename:   logfile,
+			MaxSize:    100,
+			MaxAge:     14,
+			MaxBackups: 10,
+		})
+	}
+}
diff --git a/dockerv2.go b/dockerv2.go
deleted file mode 100644
index b68b49b..0000000
--- a/dockerv2.go
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
-Copyright 2019 - The TXTDirect Authors
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-    http://www.apache.org/licenses/LICENSE-2.0
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package txtdirect
-
-import (
-	"fmt"
-	"log"
-	"net/http"
-	"net/url"
-	"regexp"
-	"strconv"
-	"strings"
-)
-
-// Dockerv2 keeps data for "dockerv2" type requests
-type Dockerv2 struct {
-	rw  http.ResponseWriter
-	req *http.Request
-	c   Config
-	rec record
-
-	image Image
-}
-
-type Image struct {
-	Registry string
-	Image    string
-	Tag      string
-}
-
-// NewDockerv2 returns a fresh instance of Dockerv2 struct
-func NewDockerv2(w http.ResponseWriter, r *http.Request, rec record, c Config) *Dockerv2 {
-	return &Dockerv2{
-		rw:  w,
-		req: r,
-		rec: rec,
-		c:   c,
-	}
-}
-
-var dockerRegexes = map[string]*regexp.Regexp{
-	"v2":        regexp.MustCompile("^\\/?v2\\/?$"),
-	"container": regexp.MustCompile("/v2/(.*?)\\/\\s*(blobs|manifests)/(.*)"),
-}
-
-// Redirect handles the requests for "dockerv2" type
-func (d *Dockerv2) Redirect() error {
-	path := d.req.URL.Path
-	if !strings.HasPrefix(path, "/v2") {
-		log.Printf("[txtdirect]: unrecognized path for dockerv2: %s", path)
-		if path == "" || path == "/" {
-			fallback(d.rw, d.req, "root", http.StatusPermanentRedirect, Config{})
-			return nil
-		}
-		fallback(d.rw, d.req, "website", http.StatusPermanentRedirect, Config{})
-		return nil
-	}
-	if dockerRegexes["v2"].MatchString(path) {
-		d.rw.Header().Set("Docker-Distribution-Api-Version", "registry/2.0")
-		_, err := d.rw.Write([]byte(http.StatusText(http.StatusOK)))
-		return err
-	}
-	if path != "/" {
-		uri, err := d.ParseReference()
-		if err != nil {
-			return err
-		}
-		d.rw.Header().Add("Cache-Control", fmt.Sprintf("max-age=%d", status301CacheAge))
-		d.rw.Header().Add("Status-Code", strconv.Itoa(http.StatusMovedPermanently))
-		http.Redirect(d.rw, d.req, uri, http.StatusMovedPermanently)
-		return nil
-	}
-	d.rw.Header().Add("Cache-Control", fmt.Sprintf("max-age=%d", status301CacheAge))
-	d.rw.Header().Add("Status-Code", strconv.Itoa(http.StatusMovedPermanently))
-	http.Redirect(d.rw, d.req, d.rec.To, http.StatusMovedPermanently)
-	return nil
-}
-
-func (d *Dockerv2) ParseRecordReference() error {
-	uri, err := url.Parse(d.rec.To)
-	if err != nil {
-		return fmt.Errorf("Couldn't parse the record endpoint: %s", err.Error())
-	}
-
-	if uri.Path == "" {
-		uri.Path = "/"
-	}
-
-	path := strings.Split(uri.Path, ":")
-	if len(path) == 2 {
-		d.image.Tag = path[1]
-	}
-
-	d.image.Registry = fmt.Sprintf("%s://%s", uri.Scheme, uri.Host)
-
-	d.image.Image = path[0][1:]
-
-	return nil
-}
-
-func (d *Dockerv2) ParseReference() (string, error) {
-	path := d.req.URL.Path
-	if err := d.ParseRecordReference(); err != nil {
-		return "", fmt.Errorf("Couldn't parse the image reference: %s", err.Error())
-	}
-
-	matches := dockerRegexes["container"].FindAllStringSubmatch(path, -1)[0]
-
-	// Replace image tag on manifests requests
-	if matches[2] == "manifests" {
-		if d.image.Tag != "" {
-			path = strings.Replace(path, matches[3], d.image.Tag, -1)
-		}
-	}
-
-	// Replace image name and namepsace
-	if d.image.Image != "" {
-		path = strings.Replace(path, matches[1], d.image.Image, -1)
-	}
-
-	return fmt.Sprintf("%s%s", d.image.Registry, path), nil
-}
diff --git a/fallback.go b/fallback.go
index 28a9c3c..f9b9d70 100644
--- a/fallback.go
+++ b/fallback.go
@@ -14,9 +14,9 @@ type Fallback struct {
 	request *http.Request
 	config  Config
 
-	records    []record
-	pathRecord record
-	lastRecord record
+	records    []Record
+	pathRecord Record
+	lastRecord Record
 
 	fallbackType string
 	code         int
@@ -31,7 +31,7 @@ type Fallback struct {
 // default fallback address
 func fallback(w http.ResponseWriter, r *http.Request, fallbackType string, code int, c Config) {
 	if code == http.StatusMovedPermanently {
-		w.Header().Add("Cache-Control", fmt.Sprintf("max-age=%d", status301CacheAge))
+		w.Header().Add("Cache-Control", fmt.Sprintf("max-age=%d", Status301CacheAge))
 	}
 	w.Header().Add("Status-Code", strconv.Itoa(code))
 
@@ -62,20 +62,12 @@ func fallback(w http.ResponseWriter, r *http.Request, fallbackType string, code
 	log.Printf("[txtdirect]: %s > %s", r.Host+r.URL.Path, w.Header().Get("Location"))
 }
 
-func (f *Fallback) countFallback(recType string) {
-	if f.config.Prometheus.Enable {
-		FallbacksCount.WithLabelValues(f.request.Host, recType, f.fallbackType).Add(1)
-		RequestsByStatus.WithLabelValues(f.request.URL.Host, strconv.Itoa(f.code)).Add(1)
-	}
-}
-
 func (f *Fallback) globalFallbacks(recordType string) {
 	if contains(f.config.Enable, "www") {
 		s := strings.Join([]string{defaultProtocol, "://", defaultSub, ".", f.request.URL.Host}, "")
 
 		http.Redirect(f.rw, f.request, s, f.code)
 
-		f.countFallback(recordType)
 	} else if f.config.Redirect != "" {
 		f.rw.Header().Set("Status-Code", strconv.Itoa(http.StatusMovedPermanently))
 
@@ -83,14 +75,13 @@ func (f *Fallback) globalFallbacks(recordType string) {
 
 		f.code = http.StatusMovedPermanently
 
-		f.countFallback(recordType)
 	} else {
 		http.NotFound(f.rw, f.request)
 	}
 }
 
 func (f *Fallback) fetchRecords() {
-	f.records = f.request.Context().Value("records").([]record)
+	f.records = f.request.Context().Value("records").([]Record)
 	// Note: This condition should get changed when we support more record aggregations.
 	if len(f.records) >= 2 {
 		f.pathRecord = f.records[len(f.records)-2]
@@ -104,21 +95,18 @@ func (f *Fallback) lastRecordFallback() bool {
 	// Redirect to first record's `to=` field
 	if f.fallbackType == "to" && f.lastRecord.To != "" {
 		http.Redirect(f.rw, f.request, f.lastRecord.To, f.code)
-		f.countFallback(f.lastRecord.Type)
 		return true
 	}
 
 	// Redirect to first record's `website=` field
 	if f.fallbackType == "website" && f.lastRecord.Website != "" {
 		http.Redirect(f.rw, f.request, f.lastRecord.Website, f.code)
-		f.countFallback(f.lastRecord.Type)
 		return true
 	}
 
 	// Redirect to first record's `root=` field
 	if f.fallbackType == "root" && f.lastRecord.Root != "" {
 		http.Redirect(f.rw, f.request, f.lastRecord.Root, f.code)
-		f.countFallback(f.lastRecord.Type)
 		return true
 	}
 	return false
@@ -130,21 +118,18 @@ func (f *Fallback) pathFallback() bool {
 	// Redirect to path record's `website=` field
 	if f.fallbackType == "website" && f.pathRecord.Website != "" {
 		http.Redirect(f.rw, f.request, f.pathRecord.Website, f.code)
-		f.countFallback(f.pathRecord.Type)
 		return true
 	}
 
 	// Redirect to path record's `root=` field
 	if f.fallbackType == "root" && f.pathRecord.Root != "" {
 		http.Redirect(f.rw, f.request, f.pathRecord.Root, f.code)
-		f.countFallback(f.pathRecord.Type)
 		return true
 	}
 
 	// Redirect to path record's `to=` field
 	if f.pathRecord.To != "" {
 		http.Redirect(f.rw, f.request, f.pathRecord.To, f.code)
-		f.countFallback(f.pathRecord.Type)
 		return true
 	}
 	return false
diff --git a/git.go b/git.go
deleted file mode 100644
index 7521649..0000000
--- a/git.go
+++ /dev/null
@@ -1,83 +0,0 @@
-package txtdirect
-
-import (
-	"fmt"
-	"net/http"
-	"net/url"
-	"strings"
-
-	"github.com/caddyserver/caddy/caddyhttp/proxy"
-	"github.com/prometheus/common/log"
-)
-
-// Git keeps data for "git" type requests
-type Git struct {
-	rw  http.ResponseWriter
-	req *http.Request
-	c   Config
-	rec record
-}
-
-// NewGit returns a fresh instance of Git struct
-func NewGit(w http.ResponseWriter, r *http.Request, c Config, rec record) *Git {
-	return &Git{
-		rw:  w,
-		req: r,
-		c:   c,
-		rec: rec,
-	}
-}
-
-// Proxy handles the requests for "git" type
-func (g *Git) Proxy() error {
-	to, _, err := getBaseTarget(g.rec, g.req)
-	if err != nil {
-		return err
-	}
-
-	if !strings.HasPrefix(g.req.URL.Path, "/info") {
-		g.req.URL.Path = "/" + strings.Join(strings.Split(g.req.URL.Path, "/")[2:], "/")
-	}
-
-	u, err := url.Parse(to)
-	if err != nil {
-		return err
-	}
-
-	reverseProxy := proxy.NewSingleHostReverseProxy(u, "", proxyKeepalive, proxyTimeout, fallbackDelay)
-
-	tmpResponse := ProxyResponse{headers: make(http.Header)}
-	reverseProxy.ServeHTTP(&tmpResponse, g.req, nil)
-
-	// Decompress the body based on "Content-Encoding" header and write to a writer buffer
-	if err := tmpResponse.WriteBody(); err != nil {
-		return fmt.Errorf("[txtdirect]: Couldn't write the response body: %s", err.Error())
-	}
-
-	// Replace the URL hosts with the request's host
-	if err := tmpResponse.ReplaceBody(u.Scheme, u.Host, g.req.Host); err != nil {
-		return fmt.Errorf("[txtdirect]: Couldn't replace urls inside the response body: %s", err.Error())
-	}
-
-	copyHeader(g.rw.Header(), tmpResponse.Header())
-
-	// Write the status from the temporary ResponseWriter to the main ResponseWriter
-	g.rw.WriteHeader(tmpResponse.status)
-
-	// Write the final response from the temporary ResponseWriter to the main ResponseWriter
-	if _, err := g.rw.Write(tmpResponse.Body()); err != nil {
-		return fmt.Errorf("[txtdirect]: Couldn't write the temporary response to main response body: %s", err.Error())
-	}
-	return nil
-}
-
-// ValidGitQuery checks the User-Agent header to make sure the requests are
-// coming from a Git client.
-func (g *Git) ValidGitQuery() bool {
-	if !strings.HasPrefix(g.req.Header.Get("User-Agent"), "git") {
-		fallback(g.rw, g.req, "website", g.rec.Code, g.c)
-		log.Errorf("[txtdirect]: The incoming request is not from a Git client.")
-		return false
-	}
-	return true
-}
diff --git a/go.mod b/go.mod
index ff37b3d..9db1a48 100644
--- a/go.mod
+++ b/go.mod
@@ -1,33 +1,10 @@
 module go.txtdirect.org/txtdirect
 
-go 1.13
+go 1.14
 
 require (
-	github.com/SchumacherFM/mailout v1.3.0
-	github.com/beorn7/perks v1.0.1 // indirect
-	github.com/caddyserver/caddy v1.0.3
-	github.com/captncraig/caddy-realip v0.0.0-20190710144553-6df827e22ab8
-	github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
-	github.com/golang/protobuf v1.3.2 // indirect
-	github.com/gorilla/sessions v1.1.3 // indirect
-	github.com/gorilla/websocket v1.4.1 // indirect
-	github.com/juju/ratelimit v1.0.1 // indirect
-	github.com/klauspost/cpuid v1.2.1 // indirect
-	github.com/kr/pretty v0.1.0 // indirect
-	github.com/mholt/certmagic v0.6.2 // indirect
-	github.com/miekg/caddy-prometheus v0.0.0-20190709133612-1fe4cb19becd
-	github.com/miekg/dns v1.1.16
-	github.com/prometheus/client_golang v1.0.0
-	github.com/prometheus/common v0.4.1
-	github.com/prometheus/procfs v0.0.4 // indirect
-	github.com/quasoft/memstore v0.0.0-20180925164028-84a050167438 // indirect
-	github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9
-	github.com/steambap/captcha v1.3.0 // indirect
-	golang.org/x/image v0.0.0-20190424155947-59b11bec70c7 // indirect
-	golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a // indirect
-	golang.org/x/text v0.3.2 // indirect
-	gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
-	gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
-	gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
+	github.com/caddyserver/caddy/v2 v2.1.1
+	github.com/miekg/dns v1.1.27
+	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
 	gopkg.in/natefinch/lumberjack.v2 v2.0.0
 )
diff --git a/go.sum b/go.sum
index cb940ee..982f72e 100644
--- a/go.sum
+++ b/go.sum
@@ -1,211 +1,1091 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0 h1:3ithwDMr7/3vpAMXiH+ZQnYbuIsh+OPhUPMFC9enmn0=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA=
+contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw=
+contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA=
+dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
+dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
+dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
+git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
+github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9 h1:HD8gA2tkByhMAwYaFAX9w2l7vxvBQ5NMoxDrkhqhtn4=
+github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
+github.com/Azure/azure-sdk-for-go v32.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/go-autorest/autorest v0.1.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg=
+github.com/Azure/go-autorest/autorest v0.5.0/go.mod h1:9HLKlQjVBH6U3oDfsXOeVc56THsLPw1L03yban4xThw=
+github.com/Azure/go-autorest/autorest/adal v0.1.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E=
+github.com/Azure/go-autorest/autorest/adal v0.2.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E=
+github.com/Azure/go-autorest/autorest/azure/auth v0.1.0/go.mod h1:Gf7/i2FUpyb/sGBLIFxTBzrNzBo7aPXXE3ZVeDRwdpM=
+github.com/Azure/go-autorest/autorest/azure/cli v0.1.0/go.mod h1:Dk8CUAt/b/PzkfeRsWzVG9Yj3ps8mS8ECztu43rdU8U=
+github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
+github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
+github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc=
+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.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvdeRAgDr0izn4z5Ij88=
 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/SchumacherFM/mailout v1.3.0 h1:p65otJmAVOe7fAW59+Yc790QI00Ca7aevExGGXokRtA=
-github.com/SchumacherFM/mailout v1.3.0/go.mod h1:MMCu15Q6CNvE3kYceiazp/WcvSseLmXdJ/53pgwIY6k=
-github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM=
+github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
+github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
+github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
+github.com/Masterminds/glide v0.13.2/go.mod h1:STyF5vcenH/rUqTEv+/hBXlSTo7KYwg2oc2f4tzPWic=
+github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
+github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
+github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc=
+github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
+github.com/Masterminds/semver/v3 v3.0.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
+github.com/Masterminds/semver/v3 v3.1.0 h1:Y2lUDsFKVRSYGojLJ1yLxSXdMmMYTYls0rCvoqmMUQk=
+github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
+github.com/Masterminds/sprig/v3 v3.0.0/go.mod h1:NEUY/Qq8Gdm2xgYA+NwJM6wmfdRV9xkh8h/Rld20R0U=
+github.com/Masterminds/sprig/v3 v3.1.0 h1:j7GpgZ7PdFqNsmncycTHsLmVPf5/3wJtlgW9TNDYD9Y=
+github.com/Masterminds/sprig/v3 v3.1.0/go.mod h1:ONGMf7UfYGAbMXCZmQLy8x3lCDIPrEZE/rU8pmrbihA=
+github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
+github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
+github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
+github.com/OpenPeeDeeP/depguard v1.0.0/go.mod h1:7/4sitnI9YlQgTLLk734QlzXT8DuHVnAyztLplQjk+o=
+github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM=
+github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
+github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
+github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
+github.com/ThomasRooney/gexpect v0.0.0-20161231170123-5482f0350944/go.mod h1:sPML5WwI6oxLRLPuuqbtoOKhtmpVDCYtwsps+I+vjIY=
+github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.8/go.mod h1:aVvklgKsPENRkl29bNwrHISa1F+YLGTHArMxZMBqWM8=
+github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
+github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
+github.com/alecthomas/chroma v0.7.2-0.20200305040604-4f3623dce67a/go.mod h1:fv5SzZPFJbwp2NXJWpFIX7DZS4HgV1K4ew4Pc2OZD9s=
+github.com/alecthomas/chroma v0.7.4-0.20200517063913-500529fd43c1/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM=
+github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
+github.com/alecthomas/kong v0.1.17-0.20190424132513-439c674f7ae0/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI=
+github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI=
+github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
+github.com/alecthomas/kong-hcl v0.1.8-0.20190615233001-b21fea9723c8/go.mod h1:MRgZdU3vrFd05IQ89AxUZ0aYdF39BYoNFa324SodPCA=
+github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/aliyun/alibaba-cloud-sdk-go v1.61.112/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA=
+github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
+github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
+github.com/antlr/antlr4 v0.0.0-20200503195918-621b933c7a7f h1:0cEys61Sr2hUBEXfNV8eyQP01oZuBgoMeHunebPirK8=
+github.com/antlr/antlr4 v0.0.0-20200503195918-621b933c7a7f/go.mod h1:T7PbCXFs94rrTttyxjbyT5+/1V8T2TYDejxUfHJjw1Y=
+github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
+github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go v1.30.20/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
-github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
-github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/bifurcation/mint v0.0.0-20180715133206-93c51c6ce115 h1:fUjoj2bT6dG8LoEe+uNsKk8J+sLkDbQkJnB6Z1F02Bc=
-github.com/bifurcation/mint v0.0.0-20180715133206-93c51c6ce115/go.mod h1:zVt7zX3K/aDCk9Tj+VM7YymsX66ERvzCJzw8rFCX2JU=
-github.com/caddyserver/caddy v1.0.1 h1:oor6ep+8NoJOabpFXhvjqjfeldtw1XSzfISVrbfqTKo=
-github.com/caddyserver/caddy v1.0.1/go.mod h1:G+ouvOY32gENkJC+jhgl62TyhvqEsFaDiZ4uw0RzP1E=
-github.com/caddyserver/caddy v1.0.3 h1:i9gRhBgvc5ifchwWtSe7pDpsdS9+Q0Rw9oYQmYUTw1w=
-github.com/caddyserver/caddy v1.0.3/go.mod h1:G+ouvOY32gENkJC+jhgl62TyhvqEsFaDiZ4uw0RzP1E=
-github.com/captncraig/caddy-realip v0.0.0-20190710144553-6df827e22ab8 h1:320uR5NtFzRWiBE9onnKYnOTbVDBd8LfQTZ8L71JcBw=
-github.com/captncraig/caddy-realip v0.0.0-20190710144553-6df827e22ab8/go.mod h1:FDAVVa4GEST826nE+S0cZQb5LLDt6yANh9OvWyh4oEM=
-github.com/cenkalti/backoff v2.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY=
-github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
-github.com/cheekybits/genny v0.0.0-20170328200008-9127e812e1e9 h1:a1zrFsLFac2xoM6zG1u72DWJwZG3ayttYLfmLbxVETk=
-github.com/cheekybits/genny v0.0.0-20170328200008-9127e812e1e9/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bombsimon/wsl/v2 v2.0.0/go.mod h1:mf25kr/SqFEPhhcxW1+7pxzGlW+hIl/hYTKY95VwV8U=
+github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
+github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
+github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
+github.com/caddyserver/caddy/v2 v2.1.1 h1:X9k1+ehZPYYrSqBvf/ocUgdLSRIuiNiMo7CvyGUQKeA=
+github.com/caddyserver/caddy/v2 v2.1.1/go.mod h1:TIAlPMcVlm9gD/ZicynFkIq3ZPvG5kfRuDX0RpFpLAs=
+github.com/caddyserver/certmagic v0.11.2 h1:nPBqyuFNHJEf2FwC1ixJjArtTKWyPqpaH6k4jl7gxYI=
+github.com/caddyserver/certmagic v0.11.2/go.mod h1:fqY1IZk5iqhsj5FU3Vw20Sjq66tEKaanTFYNZ74soMY=
+github.com/cenkalti/backoff/v4 v4.0.0 h1:6VeaLF9aI+MAUQ95106HwWzYZgJJpZ4stumjj6RFYAU=
+github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
+github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
+github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
+github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cloudflare/cloudflare-go v0.10.2/go.mod h1:qhVI5MKwBGhdNU89ZRz2plgYutcJ5PCekLxXn56w6SY=
+github.com/codegangsta/cli v1.20.0/go.mod h1:/qJNoX69yVSKu5o4jLyXAENLRyk1uhi7zkbQ3slBdOA=
+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/etcd v3.3.18+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/corpix/uarand v0.1.1/go.mod h1:SFKZvkcRoLqVRFZ4u25xPmp6m9ktANfbpXZ7SJ0/FNU=
+github.com/cpu/goacmedns v0.0.2/go.mod h1:4MipLkI+qScwqtVxcNO6okBhbgRrr7/tKXUSgSL0teQ=
+github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
+github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=
+github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
+github.com/dgraph-io/badger v1.5.3 h1:5oWIuRvwn93cie+OSt1zSnkaIQ1JFQM8bGlIv6O6Sts=
+github.com/dgraph-io/badger v1.5.3/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ=
+github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200413122845-09dd2e1a4195 h1:n8KbImHW5qZCXv1y3tHjz5yz418/eTxeRJZ2ZuDm1ZU=
+github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200413122845-09dd2e1a4195/go.mod h1:3KY8+bsP8wI0OEnQJAKpd4wIJW/Mm32yw2j/9FUVnIM=
+github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3 h1:MQLRM35Pp0yAyBYksjbj1nZI/w6eyRY/mWoM1sFf4kU=
+github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
+github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
+github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
+github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
+github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
+github.com/dnsimple/dnsimple-go v0.60.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg=
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
+github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac h1:opbrjaN/L8gg6Xh5D04Tem+8xVcz6ajZlGCs49mQgyg=
+github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
+github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
+github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/exoscale/egoscale v0.18.1/go.mod h1:Z7OOdzzTOz1Q1PjQXumlz9Wn/CddH0zSYdCF3rnBKXE=
+github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8=
+github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
 github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
+github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
+github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
 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/go-acme/lego v2.5.0+incompatible h1:5fNN9yRQfv8ymH3DSsxla+4aYeQt2IgfZqHKVnK8f0s=
-github.com/go-acme/lego v2.5.0+incompatible/go.mod h1:yzMNe9CasVUhkquNvti5nAtPmG94USbYxYrZfTkIn0M=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
+github.com/go-acme/lego/v3 v3.7.0 h1:qC5/8/CbltyAE8fGLE6bGlqucj7pXc/vBxiLwLOsmAQ=
+github.com/go-acme/lego/v3 v3.7.0/go.mod h1:4eDjjYkAsDXyNcwN8IhhZAwxz9Ltiks1Zmpv0q20J7A=
+github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
+github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
+github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
+github.com/go-critic/go-critic v0.3.5-0.20190526074819-1df300866540/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA=
+github.com/go-critic/go-critic v0.4.0/go.mod h1:7/14rZGnZbY6E38VEGk2kVhoq6itzc1E68facVDK23g=
+github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM=
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
+github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
+github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4=
+github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ=
+github.com/go-toolsmith/astequal v0.0.0-20180903214952-dcb477bfacd6/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
+github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
+github.com/go-toolsmith/astfmt v0.0.0-20180903215011-8f8ee99c3086/go.mod h1:mP93XdblcopXwlyN4X4uodxXQhldPGZbcEJIimQHrkg=
+github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw=
+github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU=
+github.com/go-toolsmith/astp v0.0.0-20180903215135-0af7e3c24f30/go.mod h1:SV2ur98SGypH1UjcPpCatrV5hPazG6+IfNHbkDXBRrk=
+github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI=
+github.com/go-toolsmith/pkgload v0.0.0-20181119091011-e9e65178eee8/go.mod h1:WoMrjiy4zvdS+Bg6z9jZH82QXwkcgCBX6nOfnmdaHks=
+github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc=
+github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
+github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
+github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
+github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
+github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
-github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
-github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
+github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-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/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
+github.com/golang/mock v1.0.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1 h1:ocYkMQY5RrXTYgXl7ICpV0IXwlEQGwKIsery4gyXa1U=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
 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/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
+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=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+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 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
+github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4=
+github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk=
+github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0=
+github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8=
+github.com/golangci/go-tools v0.0.0-20190318055746-e32c54105b7c/go.mod h1:unzUULGw35sjyOYjUt0jMTXqHlZPpPc6e+xfO4cd6mM=
+github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o=
+github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU=
+github.com/golangci/gocyclo v0.0.0-20180528144436-0a533e8fa43d/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU=
+github.com/golangci/gofmt v0.0.0-20181222123516-0b8337e80d98/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU=
+github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU=
+github.com/golangci/golangci-lint v1.17.2-0.20190910081718-bad04bb7378f/go.mod h1:kaqo8l0OZKYPtjNmG4z4HrWLgcYNIJ9B9q3LWri9uLg=
+github.com/golangci/golangci-lint v1.22.2/go.mod h1:2Bj42k6hPQFTRxkDb7S3TQ+EsnumZXOmIYNqlQrp0FI=
+github.com/golangci/gosec v0.0.0-20190211064107-66fb7fc33547/go.mod h1:0qUabqiIQgfmlAmulqxyiGkkyF6/tOGSnY2cnPVwrzU=
+github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU=
+github.com/golangci/lint-1 v0.0.0-20190420132249-ee948d087217/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg=
+github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg=
+github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o=
+github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA=
+github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bzsHdTM0bsB7+8mt0GUMvjCgwLpTapNZHU8AajI=
+github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4=
+github.com/golangci/revgrep v0.0.0-20180812185044-276a5c0a1039/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4=
+github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/cel-go v0.5.1 h1:oDsbtAwlwFPEcC8dMoRWNuVzWJUDeDZeHjoet9rXjTs=
+github.com/google/cel-go v0.5.1/go.mod h1:9SvtVVTtZV4DTB1/RuAD1D2HhuqEIdmZEE/r/lrFyKE=
+github.com/google/cel-spec v0.4.0/go.mod h1:2pBM5cU4UKjbPDXBgwWkiwBsVgnxknuEJ7C5TDWwORQ=
+github.com/google/certificate-transparency-go v1.1.0/go.mod h1:i+Q7XY+ArBveOUT36jiHGfuSK1fHICIg6sUkRxPAbCs=
+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/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
+github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/monologue v0.0.0-20190606152607-4b11a32b5934/go.mod h1:6NTfaQoUpg5QmPsCUWLR3ig33FHrKXhTtWzF0DVdmuk=
+github.com/google/monologue v0.0.0-20191220140058-35abc9683a6c/go.mod h1:6NTfaQoUpg5QmPsCUWLR3ig33FHrKXhTtWzF0DVdmuk=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/trillian v1.2.2-0.20190612132142-05461f4df60a/go.mod h1:YPmUVn5NGwgnDUgqlVyFGMTgaWlnSvH7W5p+NdOG8UA=
+github.com/google/trillian-examples v0.0.0-20190603134952-4e75ba15216c/go.mod h1:WgL3XZ3pA8/9cm7yxqWrZE6iZkESB2ItGxy5Fo6k2lk=
+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/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
+github.com/googleapis/gax-go v2.0.0+incompatible h1:j0GKcs05QVmm7yesiZq2+9cxHkNK9YM6zKx4D2qucQU=
+github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
+github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
-github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
+github.com/gorilla/csrf v1.6.0/go.mod h1:7tSf8kmjNYr7IWDCYhd3U8Ck34iQ/Yw5CJu7bAkHEGI=
+github.com/gorilla/handlers v1.4.1/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
+github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
 github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
-github.com/gorilla/sessions v1.1.3 h1:uXoZdcdA5XdXF3QzuSlheVRUvjl+1rKY7zBXL68L9RU=
-github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
-github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
 github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
-github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
 github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE=
-github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
-github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47 h1:UnszMmmmm5vLwWzDjTFVIkfhvWF1NdrmChl8L2NUDCw=
-github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
+github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
+github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
+github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c=
+github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a h1:BcF8coBl0QFVhe8vAMMlD+CV8EISiu9MGKLoj6ZEyJA=
-github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8=
+github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
+github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs=
+github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428/go.mod h1:uhpZMVGznybq1itEKXj6RYw9I71qK4kH+OGMjRC4KEo=
+github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
+github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
+github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
+github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/juju/ratelimit v1.0.1 h1:+7AIFJVQ0EQgq/K9+0Krm7m530Du7tIz0METWzN0RgY=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/jsternberg/zap-logfmt v1.2.0 h1:1v+PK4/B48cy8cfQbxL4FmmNZrjnIMr2BsnyEmXqv2o=
+github.com/jsternberg/zap-logfmt v1.2.0/go.mod h1:kz+1CUmCutPWABnNkOu9hOHKdT2q3TDYCcsFy9hpqb0=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU=
+github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU=
 github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-github.com/klauspost/cpuid v1.2.0 h1:NMpwD2G9JSFOE1/TJjGSo5zG7Yb2bTe7eq1jH+irmeE=
+github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/kisielk/gotool v0.0.0-20161130080628-0de1eaf82fa3/go.mod h1:jxZFDH7ILpTPQTk+E2s+z4CUas9lVNjIuKR4c5/zKgM=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
+github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
+github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
 github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
-github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=
-github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
+github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
+github.com/klauspost/cpuid v1.3.0 h1:2JqaNE1hGdABW2YbA3TenkO7RiPFRvSWnEnGqWh9sHE=
+github.com/klauspost/cpuid v1.3.0/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
+github.com/kolo/xmlrpc v0.0.0-20190717152603-07c4ee3fd181/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/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/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
 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/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4=
-github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
-github.com/lucas-clemente/aes12 v0.0.0-20171027163421-cd47fb39b79f h1:sSeNEkJrs+0F9TUau0CgWTTNEwF23HST3Eq0A+QIx+A=
-github.com/lucas-clemente/aes12 v0.0.0-20171027163421-cd47fb39b79f/go.mod h1:JpH9J1c9oX6otFSgdUHwUBUizmKlrMjxWnIAjff4m04=
-github.com/lucas-clemente/quic-clients v0.1.0/go.mod h1:y5xVIEoObKqULIKivu+gD/LU90pL73bTdtQjPBvtCBk=
-github.com/lucas-clemente/quic-go v0.10.2 h1:iQtTSZVbd44k94Lu0U16lLBIG3lrnjDvQongjPd4B/s=
-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 h1:zqEC1GJZFbGZA0tRyNZqRjep92K5fujFtFsu5ZW7Aug=
-github.com/lucas-clemente/quic-go-certificates v0.0.0-20160823095156-d2f86524cced/go.mod h1:NCcRLrOTZbzhZvixZLlERbJtDtYsmMw8Jc4vS8Z0g58=
-github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
-github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA=
+github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w=
+github.com/letsencrypt/pkcs11key v2.0.1-0.20170608213348-396559074696+incompatible/go.mod h1:iGYXKqDXt0cpBthCHdr9ZdsQwyGlYFh/+8xa4WzIQ34=
+github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/libdns/libdns v0.0.0-20200501023120-186724ffc821 h1:663opx/RKxiISi1ozf0WbvweQpYBgf34dx8hKSIau3w=
+github.com/libdns/libdns v0.0.0-20200501023120-186724ffc821/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
+github.com/linode/linodego v0.10.0/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8LANE4eXA=
+github.com/liquidweb/liquidweb-go v1.6.0/go.mod h1:UDcVnAMDkZxpw4Y7NOHkqoeiGacVLEIG/i5J9cyixzQ=
+github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
+github.com/lucas-clemente/quic-go v0.17.1 h1:ezsH76xpn6hKugfsXUy6voIJBFmAOwnM/Oy9F4b/n+M=
+github.com/lucas-clemente/quic-go v0.17.1/go.mod h1:I0+fcNTdb9eS1ZcjQZbDVPGchJ86chcIxPALn9lEJqE=
+github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8=
+github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
+github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/manifoldco/promptui v0.3.1 h1:BxqNa7q1hVHXIXy3iupJMkXYS3aHhbubJWv2Jmg6x64=
+github.com/manifoldco/promptui v0.3.1/go.mod h1:zoCNXiJnyM03LlBgTsWv8mq28s7aTC71UgKasqRJHww=
+github.com/marten-seemann/qpack v0.1.0 h1:/0M7lkda/6mus9B8u34Asqm8ZhHAAt9Ho0vniNuVSVg=
+github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI=
+github.com/marten-seemann/qtls v0.9.1 h1:O0YKQxNVPaiFgMng0suWEOY2Sb4LT2sRn9Qimq3Z1IQ=
+github.com/marten-seemann/qtls v0.9.1/go.mod h1:T1MmAdDPyISzxlK6kjRr0pcZFBVd1OZbBb/j3cvzHhk=
+github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
+github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
+github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
+github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
+github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/mholt/certmagic v0.6.2-0.20190624175158-6a42ef9fe8c2 h1:xKE9kZ5C8gelJC3+BNM6LJs1x21rivK7yxfTZMAuY2s=
-github.com/mholt/certmagic v0.6.2-0.20190624175158-6a42ef9fe8c2/go.mod h1:g4cOPxcjV0oFq3qwpjSA30LReKD8AoIfwAY9VvG35NY=
-github.com/mholt/certmagic v0.6.2 h1:yy9cKm3rtxdh12SW4E51lzG3Eo6N59LEOfBQ0CTnMms=
-github.com/mholt/certmagic v0.6.2/go.mod h1:g4cOPxcjV0oFq3qwpjSA30LReKD8AoIfwAY9VvG35NY=
-github.com/miekg/caddy-prometheus v0.0.0-20190709133612-1fe4cb19becd h1:zOaKBuWRW1kv9OgXzcbtYu7ufI15qrSx5ZvDi5ibQ3U=
-github.com/miekg/caddy-prometheus v0.0.0-20190709133612-1fe4cb19becd/go.mod h1:Frq7K/sHl4kD2HWrwUr7AZQF87KUPNuI6YKzCCLaJCU=
-github.com/miekg/dns v1.1.3 h1:1g0r1IvskvgL8rR+AcHzUA+oFmGcQlaIm4IqakufeMM=
-github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
-github.com/miekg/dns v1.1.16 h1:iMEQ/IVHxPTtx2Q07JP/k4CKRvSjiAZjZ0hnhgYEDmE=
-github.com/miekg/dns v1.1.16/go.mod h1:YNV562EiewvSmpCB6/W4c6yqjK7Z+M/aIS1JHsIVeg8=
+github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
+github.com/miekg/dns v1.1.27 h1:aEH/kqUzUxGJ/UHcEKdJY+ugH6WEzsEBBSPa8zuy1aM=
+github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
+github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
+github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
+github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk=
+github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk=
+github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed/go.mod h1:3rdaFaCv4AyBgu5ALFM0+tSuHrBh6v692nyQe3ikrq0=
+github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
+github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
+github.com/mozilla/tls-observatory v0.0.0-20180409132520-8791a200eb40/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
+github.com/mozilla/tls-observatory v0.0.0-20190404164649-a3c1b6cfecfd/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
+github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks=
+github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8=
 github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
-github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8=
 github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
+github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
+github.com/nbutton23/zxcvbn-go v0.0.0-20160627004424-a22cb81b2ecd/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
+github.com/nbutton23/zxcvbn-go v0.0.0-20171102151520-eafdab6b0663/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
+github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
+github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
+github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
+github.com/newrelic/go-agent v2.15.0+incompatible/go.mod h1:a8Fv1b/fYhFSReoTU6HDkTYIMZeSVNffmoS726Y0LzQ=
+github.com/ngdinhtoan/glide-cleanup v0.2.0/go.mod h1:UQzsmiDOb8YV3nOsCxK/c9zPpCZVNoHScRE3EO9pVMM=
+github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
+github.com/nrdcg/auroradns v1.0.1/go.mod h1:y4pc0i9QXYlFCWrhWrUSIETnZgrf4KuwjDIWmmXo3JI=
+github.com/nrdcg/dnspod-go v0.4.0/go.mod h1:vZSoFSFeQVm2gWLMkyX61LZ8HI3BaqtHZWgPTGKr6KQ=
+github.com/nrdcg/goinwx v0.6.1/go.mod h1:XPiut7enlbEdntAqalBIqcYcTEVhpv/dKWgDCX2SwKQ=
+github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
+github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
+github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
-github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
-github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
+github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw=
+github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
+github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34=
+github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
+github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
+github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
+github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
+github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
+github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ=
+github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
+github.com/pelletier/go-toml v1.1.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
+github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pquerna/otp v1.0.0/go.mod h1:Zad1CMQfSQZI5KLpahDiSUX4tMMREnXw98IvL1nhgMk=
+github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM=
+github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_golang v0.9.4/go.mod h1:oCXIBxdI62A4cR6aTRJCgetEjecSIYzOEaeAn4iYEpM=
 github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
-github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
+github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
+github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
+github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
+github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
+github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs=
+github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
 github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.4 h1:w8DjqFMJDjuVwdZBQoOozr4MVWOnwF7RcL/7uxBjY78=
-github.com/prometheus/procfs v0.0.4/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
-github.com/quasoft/memstore v0.0.0-20180925164028-84a050167438 h1:jnz/4VenymvySjE+Ez511s0pqVzkUOmr1fwCVytNNWk=
-github.com/quasoft/memstore v0.0.0-20180925164028-84a050167438/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg=
-github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4 h1:S9YlS71UNJIyS61OqGAmLXv3w5zclSidN+qwr80XxKs=
-github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
-github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
+github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
+github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
+github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA=
+github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
+github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
+github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
+github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
+github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
+github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
+github.com/sacloud/libsacloud v1.26.1/go.mod h1:79ZwATmHLIFZIMd7sxA3LwzVy/B77uj3LDoToVTxDoQ=
+github.com/samfoo/ansi v0.0.0-20160124022901-b6bd2ded7189 h1:CmSpbxmewNQbzqztaY0bke1qzHhyNyC29wYgh17Gxfo=
+github.com/samfoo/ansi v0.0.0-20160124022901-b6bd2ded7189/go.mod h1:UUwuHEJ9zkkPDxspIHOa59PUeSkGFljESGzbxntLmIg=
+github.com/securego/gosec v0.0.0-20191002120514-e680875ea14d/go.mod h1:w5+eXa0mYznDkHaMCXA4XYffjlH+cy1oyKbfzJXa2Do=
+github.com/securego/gosec v0.0.0-20200106085552-9cb83e10afad/go.mod h1:7fJLcv5NlMd4t9waQEDLgpZeE3nv4D5DMz5JuZZGufg=
+github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
+github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc=
+github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
+github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
+github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
+github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
+github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
+github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
+github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
+github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
+github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
+github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
+github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
+github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
+github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
+github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
+github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
+github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
+github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
+github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
+github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
+github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
+github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
+github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
+github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9 h1:lpEzuenPuO1XNTeikEmvqYFcU37GVLl8SRNblzyvGBE=
-github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo=
-github.com/steambap/captcha v1.3.0 h1:WhvKZRxwRDee0MQjVtWxQAtXyghV3wnUlkV8QzHJcpc=
-github.com/steambap/captcha v1.3.0/go.mod h1:r3X+ngYAvaBDl03rnWlQUKhaltygg0bxc/g7+9JU2LM=
+github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
+github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
+github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
+github.com/smallstep/assert v0.0.0-20180720014142-de77670473b5/go.mod h1:TC9A4+RjIOS+HyTH7wG17/gSqVv95uDw2J64dQZx7RE=
+github.com/smallstep/assert v0.0.0-20200103212524-b99dc1097b15 h1:kSImCuenAkXtCaBeQ1UhmzzJGRhSm8sVH7I3sHE2Qdg=
+github.com/smallstep/assert v0.0.0-20200103212524-b99dc1097b15/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc=
+github.com/smallstep/certificates v0.14.4/go.mod h1:Y9ug0+ZTB0k22BBV/2K+LAZIVDCMjAAtbQ0XWS+E870=
+github.com/smallstep/certificates v0.15.0-rc.1.0.20200506212953-e855707dc274 h1:3rzfukPUfHp5K4gscalOzpCDAfnZJKETfZpmGLprFt4=
+github.com/smallstep/certificates v0.15.0-rc.1.0.20200506212953-e855707dc274/go.mod h1:tARNIrrKV9x+uiTVESAONGfS3GA2GdE3pGfNscMPvDc=
+github.com/smallstep/certinfo v1.2.1/go.mod h1:1gQJekdPwPvUwFWGTi7bZELmQT09cxC9wJ0VBkBNiwU=
+github.com/smallstep/certinfo v1.3.0/go.mod h1:1gQJekdPwPvUwFWGTi7bZELmQT09cxC9wJ0VBkBNiwU=
+github.com/smallstep/cli v0.14.3/go.mod h1:U3WVQBS6udgpyHg+d0FQxodNGXBwikoXbERyfgcAhs8=
+github.com/smallstep/cli v0.14.4 h1:oaaGwY1iNSHmIC6baiJhdZoLGmXJ0rXyRcxl3Q73SDE=
+github.com/smallstep/cli v0.14.4/go.mod h1:cI1F2o1ugIcP1qklLPBECfeR7v7mFxVE6pVNQIMNWpA=
+github.com/smallstep/nosql v0.3.0 h1:V1X5vfDsDt89499h3jZFUlR4VnnsYYs5tXaQZ0w8z5U=
+github.com/smallstep/nosql v0.3.0/go.mod h1:QG7gNOpidifn99MjZaiNbm7HPesIyBd97F/OfacNz8Q=
+github.com/smallstep/truststore v0.9.3/go.mod h1:PRSkpRIhAYBK/KLWkHNgRdYgzWMEy45bN7PSJCfKKGE=
+github.com/smallstep/truststore v0.9.5 h1:KQ6bFXUadu3PG57sFSIBsu2pb/35NqO+MyS2Pvi62bA=
+github.com/smallstep/truststore v0.9.5/go.mod h1:HwHKRcBi0RUxxw1LYDpTRhYC4jZUuxPpkHdVonlkoDM=
+github.com/smallstep/zcrypto v0.0.0-20200203191936-fbc32cf76bce/go.mod h1:+F24VU3UCxfVFvvqgm5jNUFQOm/L6ed13ImwWGFgg/g=
+github.com/smallstep/zlint v0.0.0-20180727184541-d84eaafe274f/go.mod h1:GeHHT7sJDI9ti3oEaFnvx1F4N8n3ZSw2YM1+sbEoxc4=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
+github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE=
+github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
+github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.0/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
+github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
+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/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
+github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
+github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.0.2/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
+github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
+github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
 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 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
+github.com/timakin/bodyclose v0.0.0-20190721030226-87058b9bfcec/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk=
+github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk=
+github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7/go.mod h1:imsgLplxEC/etjIhdr3dNzV3JeT27LbVu5pYWm0JCBY=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4=
+github.com/tommy-muehle/go-mnd v1.1.1/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig=
+github.com/transip/gotransip/v6 v6.0.2/go.mod h1:pQZ36hWWRahCUXkFWlx9Hs711gLd8J4qdgLdRzmtY+g=
+github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
+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/ultraware/funlen v0.0.1/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
+github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
+github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA=
+github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
+github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/uudashr/gocognit v1.0.1/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM=
+github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
+github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s=
+github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
+github.com/valyala/quicktemplate v1.1.1/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4=
+github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4=
+github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
+github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
+github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
+github.com/vultr/govultr v0.1.4/go.mod h1:9H008Uxr/C4vFNGLqKx232C206GL0PBHzOP0809bGNA=
+github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/yuin/goldmark v1.1.22/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691/go.mod h1:YLF3kDffRfUH/bTxOxHhV6lxwIB3Vfj91rEwNMS9MXo=
+github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
+github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
+github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is=
+github.com/zmap/zcertificate v0.0.0-20190521191901-30e388164f71/go.mod h1:gIZi1KPgkZNUQzPZXsZrNnUnxy05nTc0+tmlqvIkhRw=
+github.com/zmap/zcrypto v0.0.0-20190329181646-dff83107394d/go.mod h1:ix3q2kpLy0ibAuFXlr7qOhPKwFRRSjuynGuTR8EUPCk=
+github.com/zmap/zlint v0.0.0-20190516161541-9047d02cf65a/go.mod h1:xwLbce0UzBXp44sIAL1cii+hoK8j4AxRKlymZA2AIcY=
+go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk=
+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/etcd v3.3.13+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI=
+go.etcd.io/etcd v3.3.18+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI=
+go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
+go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
+go.opencensus.io v0.22.3/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=
+go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
+go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
+go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
+go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
+go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
+go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
+go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
+go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
+go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
+golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
+golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
+golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/image v0.0.0-20190424155947-59b11bec70c7 h1:OIchhgIITCxOyycwe8n9adxV37/WqbetxrpXNm7oPqI=
-golang.org/x/image v0.0.0-20190424155947-59b11bec70c7/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/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/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+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/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+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=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
+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/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=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20170915142106-8351a756f30f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180611182652-db08ff08e862/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190328230028-74de082e2cca h1:hyA6yiAgbUwuWqtscNvWAI7U1CtlaD1KilQ6iudt1aI=
-golang.org/x/net v0.0.0-20190328230028-74de082e2cca/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190301231341-16b79f2e4e95/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
 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/sys v0.0.0-20171026204733-164713f0dfce/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180202135801-37707fdb30a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180928133829-e4b3c5e90611/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e h1:ZytStCyV048ZqDsWHiYDdoI2Vd4msMcrDECFxS+tL9c=
-golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
-golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HXxFpW2sdCiP8MJSKLQY=
+golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.0.0-20170915090833-1cbadb444a80/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 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/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20170915040203-e531a2a1c15f/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
+golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190121143147-24cd39ecf745/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190221204921-83362c3779f5/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190909030654-5b82db07426d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911151314-feee8acb394c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190930201159-7c411dea38b0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113232020-e2727e816f5a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200106190116-7be0a674c9fc/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb h1:iKlO7ROJc6SttHKlxzwGytRtBUqX4VARrNTgP2YLX5M=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+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=
+google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
+google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
+google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
+google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0 h1:jz2KixHX7EcCPiQrySzPdnYT7DbINAypCqKZ1Z7GM40=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+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/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
+google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190605220351-eb0b1bdb6ae6/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
+google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
+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=
+google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+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.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+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/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
-gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
 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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
-gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
-gopkg.in/mcuadros/go-syslog.v2 v2.2.1 h1:60g8zx1BijSVSgLTzLCW9UC4/+i1Ih9jJ1DR5Tgp9vE=
-gopkg.in/mcuadros/go-syslog.v2 v2.2.1/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U=
+gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
+gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
 gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
-gopkg.in/square/go-jose.v2 v2.2.2 h1:orlkJ3myw8CN1nVQHBFfloD+L3egixIa4FvUP6RosSA=
-gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/ns1/ns1-go.v2 v2.0.0-20190730140822-b51389932cbc/go.mod h1:VV+3haRsgDiVLxyifmMBrBIuCWFBPYKbRssXB9z67Hw=
+gopkg.in/resty.v1 v1.9.1/go.mod h1:vo52Hzryw9PnPHcJfPsBiFW62XhNx5OczbV9y+IMpgc=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/square/go-jose.v2 v2.4.0 h1:0kXPskUMGAXXWJlP05ktEMOV0vmzFQUWw6d+aZJQU8A=
+gopkg.in/square/go-jose.v2 v2.4.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/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.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
+honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
+howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5 h1:AQkaJpH+/FmqRjmXZPELom5zIERYZfwTjnHpfoVMQEc=
+howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
+mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
+mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
+mvdan.cc/unparam v0.0.0-20190209190245-fbb59629db34/go.mod h1:H6SUd1XjIs+qQCyskXg5OFSrilMRUkD8ePJpHKDPaeY=
+mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=
+mvdan.cc/unparam v0.0.0-20191111180625-960b1ec0f2c2/go.mod h1:rCqoQrfAmpTX/h2APczwM7UymU/uvaOluiVPIYCSY/k=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
+sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
+sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
+sourcegraph.com/sqs/pbtypes v1.0.0/go.mod h1:3AciMUv4qUuRHRHhOG4TZOB+72GdPVz5k+c648qsFS4=
diff --git a/gometa.go b/gometa.go
index 5e82d46..d7a50d8 100644
--- a/gometa.go
+++ b/gometa.go
@@ -16,7 +16,6 @@ package txtdirect
 import (
 	"html/template"
 	"net/http"
-	"strconv"
 	"strings"
 )
 
@@ -25,11 +24,11 @@ type Gometa struct {
 	rw  http.ResponseWriter
 	req *http.Request
 	c   Config
-	rec record
+	rec Record
 }
 
 // NewGometa returns a fresh instance of Gometa struct
-func NewGometa(w http.ResponseWriter, r *http.Request, rec record, c Config) *Gometa {
+func NewGometa(w http.ResponseWriter, r *http.Request, rec Record, c Config) *Gometa {
 	return &Gometa{
 		rw:  w,
 		req: r,
@@ -58,7 +57,7 @@ func (g *Gometa) Serve() error {
 
 	gosource := strings.Contains(g.rec.To, "github.com")
 
-	RequestsByStatus.WithLabelValues(g.req.Host, strconv.Itoa(http.StatusFound)).Add(1)
+	// RequestsByStatus.WithLabelValues(g.req.Host, strconv.Itoa(http.StatusFound)).Add(1)
 	return tmpl.Execute(g.rw, struct {
 		Host        string
 		Path        string
diff --git a/host.go b/host.go
index a6f7750..63e44ba 100644
--- a/host.go
+++ b/host.go
@@ -12,11 +12,11 @@ type Host struct {
 	rw  http.ResponseWriter
 	req *http.Request
 	c   Config
-	rec record
+	rec Record
 }
 
 // NewHost returns a fresh instance of Host struct
-func NewHost(w http.ResponseWriter, r *http.Request, rec record, c Config) *Host {
+func NewHost(w http.ResponseWriter, r *http.Request, rec Record, c Config) *Host {
 	return &Host{
 		rw:  w,
 		req: r,
@@ -35,12 +35,9 @@ func (h *Host) Redirect() error {
 	}
 	log.Printf("[txtdirect]: %s > %s", h.req.Host+h.req.URL.Path, to)
 	if code == http.StatusMovedPermanently {
-		h.rw.Header().Add("Cache-Control", fmt.Sprintf("max-age=%d", status301CacheAge))
+		h.rw.Header().Add("Cache-Control", fmt.Sprintf("max-age=%d", Status301CacheAge))
 	}
 	h.rw.Header().Add("Status-Code", strconv.Itoa(code))
 	http.Redirect(h.rw, h.req, to, code)
-	if h.c.Prometheus.Enable {
-		RequestsByStatus.WithLabelValues(h.req.Host, strconv.Itoa(code)).Add(1)
-	}
 	return nil
 }
diff --git a/path.go b/path.go
index 2b23265..0e3a60f 100644
--- a/path.go
+++ b/path.go
@@ -18,7 +18,6 @@ import (
 	"fmt"
 	"log"
 	"net/http"
-	"net/url"
 	"reflect"
 	"regexp"
 	"sort"
@@ -33,7 +32,7 @@ type Path struct {
 	req  *http.Request
 	c    Config
 	path string
-	rec  record
+	rec  Record
 }
 
 // RegexRecord holds the TXT record and re= field of a predefined regex record
@@ -58,7 +57,7 @@ var GroupRegex = regexp.MustCompile("P<[a-zA-Z]+[a-zA-Z0-9]*>")
 var GroupOrderRegex = regexp.MustCompile("P<([a-zA-Z]+[a-zA-Z0-9]*)>")
 
 // NewPath returns an instance of Path struct using the given data
-func NewPath(w http.ResponseWriter, r *http.Request, path string, rec record, c Config) *Path {
+func NewPath(w http.ResponseWriter, r *http.Request, path string, rec Record, c Config) *Path {
 	return &Path{
 		rw:   w,
 		req:  r,
@@ -69,7 +68,7 @@ func NewPath(w http.ResponseWriter, r *http.Request, path string, rec record, c
 }
 
 // Redirect finds and returns the final record
-func (p *Path) Redirect() *record {
+func (p *Path) Redirect() *Record {
 	zone, from, pathSlice, err := zoneFromPath(p.req, p.rec)
 	rec, err := getFinalRecord(zone, from, p.c, p.rw, p.req, pathSlice)
 	*p.req = *rec.addToContext(p.req)
@@ -80,20 +79,12 @@ func (p *Path) Redirect() *record {
 	}
 
 	if rec.Type == "path" {
-		// If the current record and the last record added to the context
-		// are equal, use the current record's to= field to find the final record.
-		// Without this check, a request loop to the same zone will happen because
-		// the chained record would redirect the request with the same path to
-		// itself.
 		if last := p.lastPathRecord(); last != nil && reflect.DeepEqual(rec, *last) {
-			url, err := url.Parse(rec.To)
-			rec, err := getRecord(url.Host, p.c, p.rw, p.req)
-			if err != nil {
-				log.Print("Fallback is triggered because an error has occurred: ", err)
-				fallback(p.rw, p.req, "to", p.rec.Code, p.c)
-				return nil
+			if rec.Code == http.StatusMovedPermanently {
+				p.rw.Header().Add("Cache-Control", fmt.Sprintf("max-age=%d", Status301CacheAge))
 			}
-			return &rec
+			http.Redirect(p.rw, p.req, rec.To, rec.Code)
+			return nil
 		}
 		p.rec = rec
 		return p.Redirect()
@@ -112,20 +103,17 @@ func (p *Path) RedirectRoot() error {
 	}
 	log.Printf("[txtdirect]: %s > %s", UpstreamZone(p.req)+p.req.URL.Path, p.rec.Root)
 	if p.rec.Code == http.StatusMovedPermanently {
-		p.rw.Header().Add("Cache-Control", fmt.Sprintf("max-age=%d", status301CacheAge))
+		p.rw.Header().Add("Cache-Control", fmt.Sprintf("max-age=%d", Status301CacheAge))
 	}
 	p.rw.Header().Add("Status-Code", strconv.Itoa(p.rec.Code))
 	http.Redirect(p.rw, p.req, p.rec.Root, p.rec.Code)
-	if p.c.Prometheus.Enable {
-		RequestsByStatus.WithLabelValues(UpstreamZone(p.req), strconv.Itoa(p.rec.Code)).Add(1)
-	}
 	return nil
 }
 
 // SpecificRecord finds the most specific match using the custom regexes from subzones
 // It goes through all the custom regexes specified in each subzone and uses the
 // most specific match to return the final record.
-func (p *Path) SpecificRecord() (*record, error) {
+func (p *Path) SpecificRecord() (*Record, error) {
 	// Iterate subzones and parse the records
 	regexes, err := p.fetchRegexes()
 	if err != nil {
@@ -141,7 +129,7 @@ func (p *Path) SpecificRecord() (*record, error) {
 	return record, nil
 }
 
-func (p *Path) specificMatch(regexes []RegexRecord) (*record, error) {
+func (p *Path) specificMatch(regexes []RegexRecord) (*Record, error) {
 	var specificZone RegexRecord
 	// Run each regex on the path and list them in a map
 	for _, zone := range regexes {
@@ -168,7 +156,7 @@ func (p *Path) specificMatch(regexes []RegexRecord) (*record, error) {
 	*p.req = *p.req.WithContext(context.WithValue(p.req.Context(), "regexMatches", specificZone.Submatches))
 
 	// Parse the specific regex record
-	var rec record
+	var rec Record
 	var err error
 	if rec, err = ParseRecord(specificZone.TXT, p.rw, p.req, p.c); err != nil {
 		return nil, fmt.Errorf("Could not parse record: %s", err)
@@ -212,14 +200,9 @@ func (p *Path) fetchRegexes() ([]RegexRecord, error) {
 // zoneFromPath generates a DNS zone with the given request's path and host
 // It will use custom regex to parse the path if it's provided in
 // the given record.
-func zoneFromPath(r *http.Request, rec record) (string, int, []string, error) {
+func zoneFromPath(r *http.Request, rec Record) (string, int, []string, error) {
 	path := r.URL.Path
 
-	// Check if request is from a Git client
-	if strings.HasPrefix(r.Header.Get("User-Agent"), "git") {
-		path = path[:strings.Index(path, "/info/refs")]
-	}
-
 	// Only add request query to path if the custom regex needs it. Unless it
 	// might cause problems on custom regexes that don't need query to generate
 	// the zone
@@ -228,6 +211,8 @@ func zoneFromPath(r *http.Request, rec record) (string, int, []string, error) {
 	}
 
 	pathSubmatchs := PathRegex.FindAllStringSubmatch(path, -1)
+
+	// Use the custom regex to parse request's path
 	if rec.Re != "" {
 		// Compile the record regex and find path submatches
 		CustomRegex, err := regexp.Compile(rec.Re)
@@ -260,6 +245,7 @@ func zoneFromPath(r *http.Request, rec record) (string, int, []string, error) {
 			return strings.Join(url, "."), from, pathSlice, nil
 		}
 	}
+
 	pathSlice := []string{}
 	for _, v := range pathSubmatchs {
 		pathSlice = append(pathSlice, v[1])
@@ -309,7 +295,7 @@ func zoneFromPath(r *http.Request, rec record) (string, int, []string, error) {
 
 // getFinalRecord finds the final TXT record for the given zone.
 // It will try wildcards if the first zone return error
-func getFinalRecord(zone string, from int, c Config, w http.ResponseWriter, r *http.Request, pathSlice []string) (record, error) {
+func getFinalRecord(zone string, from int, c Config, w http.ResponseWriter, r *http.Request, pathSlice []string) (Record, error) {
 	txts, err := query(zone, r.Context(), c)
 	if err != nil {
 		// if nothing found, jump into wildcards
@@ -321,17 +307,17 @@ func getFinalRecord(zone string, from int, c Config, w http.ResponseWriter, r *h
 		}
 	}
 	if err != nil || len(txts) == 0 {
-		return record{}, fmt.Errorf("could not get TXT record: %s", err)
+		return Record{}, fmt.Errorf("could not get TXT record: %s", err)
 	}
 
 	txts[0], err = parsePlaceholders(txts[0], r, pathSlice)
-	var rec record
+	var rec Record
 	if rec, err = ParseRecord(txts[0], w, r, c); err != nil {
 		return rec, fmt.Errorf("could not parse record: %s", err)
 	}
 
 	if rec.Type == "path" {
-		records := r.Context().Value("records").([]record)
+		records := r.Context().Value("records").([]Record)
 		parent := records[len(records)-1]
 
 		// Use the parent's custom regex if available
@@ -379,8 +365,8 @@ func normalize(input []string) []string {
 	return result
 }
 
-func (p *Path) lastPathRecord() *record {
-	records := p.req.Context().Value("records").([]record)
+func (p *Path) lastPathRecord() *Record {
+	records := p.req.Context().Value("records").([]Record)
 
 	if len(records) < 2 {
 		return nil
diff --git a/prometheus.go b/prometheus.go
deleted file mode 100644
index 4bbf10d..0000000
--- a/prometheus.go
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
-Copyright 2019 - The TXTDirect Authors
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-    http://www.apache.org/licenses/LICENSE-2.0
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package txtdirect
-
-import (
-	"log"
-	"net/http"
-	"os"
-	"strconv"
-	"strings"
-	"sync"
-	"time"
-
-	"github.com/caddyserver/caddy"
-	"github.com/caddyserver/caddy/caddyhttp/httpserver"
-	"github.com/prometheus/client_golang/prometheus"
-	"github.com/prometheus/client_golang/prometheus/promhttp"
-)
-
-// Prometheus contains Prometheus's configuration
-type Prometheus struct {
-	Enable        bool
-	Address       string
-	Path          string
-	PathWhitelist []string
-
-	next    httpserver.Handler
-	handler http.Handler
-}
-
-var (
-	// RequestsCount counts the total requests per host
-	RequestsCount = prometheus.NewCounterVec(prometheus.CounterOpts{
-		Namespace: "txtdirect",
-		Name:      "redirect_count_total",
-		Help:      "Total requests per host",
-	}, []string{"host"})
-
-	// RequestsByStatus counts the total returned statuses per host
-	RequestsByStatus = prometheus.NewCounterVec(prometheus.CounterOpts{
-		Namespace: "txtdirect",
-		Name:      "redirect_status_count_total",
-		Help:      "Total returned statuses per host",
-	}, []string{"host", "status"})
-
-	// RequestsCountBasedOnType counts the total requests for each host based on type
-	RequestsCountBasedOnType = prometheus.NewCounterVec(prometheus.CounterOpts{
-		Namespace: "txtdirect",
-		Name:      "redirect_type_count_total",
-		Help:      "Total requests for each host based on type",
-	}, []string{"host", "type"})
-
-	// FallbacksCount counts the total fallbacks triggered for each type
-	FallbacksCount = prometheus.NewCounterVec(prometheus.CounterOpts{
-		Namespace: "txtdirect",
-		Name:      "fallback_type_count_total",
-		Help:      "Total fallbacks triggered for each type",
-	}, []string{"host", "type", "fallback"})
-
-	// PathRedirectCount counts the total redirects per path for each host
-	PathRedirectCount = prometheus.NewCounterVec(prometheus.CounterOpts{
-		Namespace: "txtdirect",
-		Name:      "redirect_path_count_total",
-		Help:      "Total redirects per path for each host",
-	}, []string{"host", "path"})
-
-	once sync.Once
-)
-
-const (
-	shutdownTimeout time.Duration = time.Second * 5
-	// prometheusAddr is the address the where the metrics are exported by default.
-	prometheusAddr string = "localhost:9183"
-	prometheusPath string = "/metrics"
-)
-
-// SetDefaults sets the default values for prometheus config
-// if the fields are empty
-func (p *Prometheus) SetDefaults() {
-	if p.Address == "" {
-		p.Address = prometheusAddr
-	}
-	if p.Path == "" {
-		p.Path = prometheusPath
-	}
-}
-
-func (p *Prometheus) start() error {
-	prometheus.MustRegister(RequestsCount)
-	prometheus.MustRegister(RequestsByStatus)
-	prometheus.MustRegister(RequestsCountBasedOnType)
-	prometheus.MustRegister(FallbacksCount)
-	prometheus.MustRegister(PathRedirectCount)
-	http.Handle(p.Path, p.handler)
-	go func() {
-		err := http.ListenAndServe(p.Address, nil)
-		if err != nil {
-			log.Printf("[txtdirect]: Couldn't start http handler for prometheus metrics. %s", err.Error())
-		}
-	}()
-	return nil
-}
-
-// Setup registers the metrics on startup and creates the promethues request handler
-func (p *Prometheus) Setup(c *caddy.Controller) {
-	p.handler = promhttp.HandlerFor(prometheus.DefaultGatherer, promhttp.HandlerOpts{
-		ErrorHandling: promhttp.HTTPErrorOnError,
-		ErrorLog:      log.New(os.Stderr, "", log.LstdFlags),
-	})
-
-	once.Do(func() {
-		c.OnStartup(p.start)
-	})
-
-	cfg := httpserver.GetConfig(c)
-	cfg.AddMiddleware(func(next httpserver.Handler) httpserver.Handler {
-		p.next = next
-		return p
-	})
-}
-
-func (p *Prometheus) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
-	next := p.next
-
-	rw := httpserver.NewResponseRecorder(w)
-
-	status, err := next.ServeHTTP(rw, r)
-
-	return status, err
-}
-
-// ParsePrometheus parses the txtdirect config for Prometheus
-func (p *Prometheus) ParsePrometheus(c *caddy.Controller, key, value string) error {
-	switch key {
-	case "enable":
-		value, err := strconv.ParseBool(value)
-		if err != nil {
-			return c.ArgErr()
-		}
-		p.Enable = value
-	case "address":
-		// TODO: validate the given address
-		p.Address = value
-	case "path":
-		p.Path = value
-	case "path_metrics_whitelist":
-		p.PathWhitelist = strings.Split(value, ",")
-	default:
-		return c.ArgErr() // unhandled option for prometheus
-	}
-	return nil
-}
diff --git a/proxy.go b/proxy.go
deleted file mode 100644
index b5db25e..0000000
--- a/proxy.go
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
-Copyright 2019 - The TXTDirect Authors
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-    http://www.apache.org/licenses/LICENSE-2.0
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package txtdirect
-
-import (
-	"bytes"
-	"compress/gzip"
-	"fmt"
-	"io"
-	"net/http"
-	"net/url"
-	"sync"
-
-	"github.com/caddyserver/caddy/caddyhttp/proxy"
-)
-
-// ProxyResponse keeps the custom response writer data and is
-// a custom implementation of net/http's default response writer
-type ProxyResponse struct {
-	headers    http.Header
-	body       []byte
-	bodyReader bytes.Buffer
-	bodyWriter bytes.Buffer
-	status     int
-}
-
-// Proxy contains the data that are needed to proxy the request
-type Proxy struct {
-	rw  http.ResponseWriter
-	req *http.Request
-	c   Config
-	rec record
-}
-
-// NewProxy returns a fresh instance of Proxy struct
-func NewProxy(w http.ResponseWriter, r *http.Request, rec record, c Config) *Proxy {
-	return &Proxy{
-		rw:  w,
-		req: r,
-		rec: rec,
-		c:   c,
-	}
-}
-
-// Proxy proxies the request to the endpoint defined in the record
-func (p *Proxy) Proxy() error {
-	to, _, err := getBaseTarget(p.rec, p.req)
-	if err != nil {
-		return err
-	}
-	u, err := url.Parse(to)
-	if err != nil {
-		return err
-	}
-	reverseProxy := proxy.NewSingleHostReverseProxy(u, "", proxyKeepalive, proxyTimeout, fallbackDelay)
-
-	tmpResponse := ProxyResponse{headers: make(http.Header)}
-	reverseProxy.ServeHTTP(&tmpResponse, p.req, nil)
-
-	// Decompress the body based on "Content-Encoding" header and write to a writer buffer
-	if err := tmpResponse.WriteBody(); err != nil {
-		return fmt.Errorf("[txtdirect]: Couldn't write the response body: %s", err.Error())
-	}
-
-	// Replace the URL hosts with the request's host
-	if err := tmpResponse.ReplaceBody(u.Scheme, u.Host, p.req.Host); err != nil {
-		return fmt.Errorf("[txtdirect]: Couldn't replace urls inside the response body: %s", err.Error())
-	}
-
-	copyHeader(p.rw.Header(), tmpResponse.Header())
-
-	// Write the status from the temporary ResponseWriter to the main ResponseWriter
-	p.rw.WriteHeader(tmpResponse.status)
-
-	// Write the final response from the temporary ResponseWriter to the main ResponseWriter
-	if _, err := p.rw.Write(tmpResponse.Body()); err != nil {
-		return fmt.Errorf("[txtdirect]: Couldn't write the temporary response to main response body: %s", err.Error())
-	}
-	return nil
-}
-
-// Header returns response headers
-func (p *ProxyResponse) Header() http.Header {
-	return p.headers
-}
-
-func (p *ProxyResponse) Write(body []byte) (int, error) {
-	reader := bytes.NewReader(body)
-	pooledIoCopy(&p.bodyReader, reader)
-	p.body = body
-	return len(body), nil
-}
-
-// Body returns response's body. This method should only get called after WriteBody()
-func (p *ProxyResponse) Body() []byte {
-	return p.bodyWriter.Bytes()
-}
-
-// WriteHeader Writes the given status code to response
-func (p *ProxyResponse) WriteHeader(status int) {
-	p.status = status
-}
-
-// ReplaceBody replaces the URIs inside the response body
-// to use the request's host instead of the endpoint's host
-func (p *ProxyResponse) ReplaceBody(scheme, to, host string) error {
-	replacedBody := bytes.Replace(p.bodyWriter.Bytes(), []byte(scheme+"://"+to), []byte(scheme+"://"+host), -1)
-	p.bodyWriter.Reset()
-	if _, err := p.bodyWriter.Write(replacedBody); err != nil {
-		return err
-	}
-	return nil
-}
-
-// WriteBody writes the response body to custom response writer's body
-func (p *ProxyResponse) WriteBody() error {
-	switch p.Header().Get("Content-Encoding") {
-	case "gzip":
-		reader, err := gzip.NewReader(&p.bodyReader)
-		if err != nil {
-			return err
-		}
-		defer reader.Close()
-		_, err = io.Copy(&p.bodyWriter, reader)
-		if err != nil {
-			return err
-		}
-		p.Header().Del("Content-Encoding")
-	default:
-		_, err := io.Copy(&p.bodyWriter, &p.bodyReader)
-		if err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-var bufferPool = sync.Pool{New: createBuffer}
-
-func createBuffer() interface{} {
-	return make([]byte, 0, 32*1024)
-}
-
-var skipHeaders = map[string]struct{}{
-	"Content-Type":        {},
-	"Content-Disposition": {},
-	"Accept-Ranges":       {},
-	"Set-Cookie":          {},
-	"Cache-Control":       {},
-	"Expires":             {},
-}
-
-func copyHeader(dst, src http.Header) {
-	for k, vv := range src {
-		if _, ok := dst[k]; ok {
-			if _, shouldSkip := skipHeaders[k]; shouldSkip {
-				continue
-			}
-			if k != "Server" {
-				dst.Del(k)
-			}
-		}
-		for _, v := range vv {
-			dst.Add(k, v)
-		}
-	}
-}
-
-func pooledIoCopy(dst io.Writer, src io.Reader) {
-	buf := bufferPool.Get().([]byte)
-	defer bufferPool.Put(buf)
-
-	bufCap := cap(buf)
-	io.CopyBuffer(dst, src, buf[0:bufCap:bufCap])
-}
diff --git a/qr.go b/qr.go
index 060dd32..cee77f4 100644
--- a/qr.go
+++ b/qr.go
@@ -7,8 +7,8 @@ import (
 	"net/http"
 	"strconv"
 
-	"github.com/caddyserver/caddy"
-	qrcode "github.com/skip2/go-qrcode"
+	"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
+	"github.com/skip2/go-qrcode"
 )
 
 // Qr contains Qr code generator's configuration
@@ -54,7 +54,7 @@ func (qr *Qr) ParseColors() error {
 }
 
 // ParseQr parses the config for QR requests
-func (qr *Qr) ParseQr(c *caddy.Controller) error {
+func (qr *Qr) ParseQr(c *caddyfile.Dispenser) error {
 	switch c.Val() {
 	case "size":
 		value, err := strconv.Atoi(c.RemainingArgs()[0])
diff --git a/record.go b/record.go
index 89b8842..34a62f8 100644
--- a/record.go
+++ b/record.go
@@ -17,13 +17,14 @@ import (
 	"context"
 	"fmt"
 	"log"
+	"net"
 	"net/http"
 	"net/url"
 	"strconv"
 	"strings"
 )
 
-type record struct {
+type Record struct {
 	Version string
 	To      string
 	Code    int
@@ -38,11 +39,11 @@ type record struct {
 	Headers map[string]string
 }
 
-// getRecord uses the given host to find a TXT record
+// GetRecord uses the given host to find a TXT record
 // and then parses the txt record and returns a TXTDirect record
 // struct instance. It returns an error when it can't find any txt
 // records or if the TXT record is not standard.
-func getRecord(host string, c Config, w http.ResponseWriter, r *http.Request) (record, error) {
+func GetRecord(host string, c Config, w http.ResponseWriter, r *http.Request) (Record, error) {
 	txts, err := query(host, r.Context(), c)
 	if err != nil {
 		log.Printf("Initial DNS query failed: %s", err)
@@ -64,15 +65,15 @@ func getRecord(host string, c Config, w http.ResponseWriter, r *http.Request) (r
 		txts, err = query(host, r.Context(), c)
 		if err != nil {
 			log.Printf("Wildcard DNS query failed: %s", err.Error())
-			return record{}, err
+			return Record{}, err
 		}
 	}
 
 	if len(txts) != 1 {
-		return record{}, fmt.Errorf("could not parse TXT record with %d records", len(txts))
+		return Record{}, fmt.Errorf("could not parse TXT record with %d records", len(txts))
 	}
 
-	var rec record
+	var rec Record
 	if rec, err = ParseRecord(txts[0], w, r, c); err != nil {
 		return rec, fmt.Errorf("could not parse record: %s", err)
 	}
@@ -93,8 +94,8 @@ func getRecord(host string, c Config, w http.ResponseWriter, r *http.Request) (r
 // a TXTDirect record struct instance.
 // It will return an error if the DNS TXT record is not standard or
 // if the record type is not enabled in the TXTDirect's config.
-func ParseRecord(str string, w http.ResponseWriter, req *http.Request, c Config) (record, error) {
-	r := record{
+func ParseRecord(str string, w http.ResponseWriter, req *http.Request, c Config) (Record, error) {
+	r := Record{
 		Headers: map[string]string{},
 	}
 
@@ -111,7 +112,7 @@ func ParseRecord(str string, w http.ResponseWriter, req *http.Request, c Config)
 			l = strings.TrimPrefix(l, "code=")
 			i, err := strconv.Atoi(l)
 			if err != nil {
-				return record{}, fmt.Errorf("could not parse status code: %s", err)
+				return Record{}, fmt.Errorf("could not parse status code: %s", err)
 			}
 			r.Code = i
 
@@ -119,7 +120,7 @@ func ParseRecord(str string, w http.ResponseWriter, req *http.Request, c Config)
 			l = strings.TrimPrefix(l, "from=")
 			l, err := parsePlaceholders(l, req, []string{})
 			if err != nil {
-				return record{}, err
+				return Record{}, err
 			}
 			r.From = l
 
@@ -131,7 +132,7 @@ func ParseRecord(str string, w http.ResponseWriter, req *http.Request, c Config)
 			l, err := strconv.ParseBool(strings.TrimPrefix(l, "ref="))
 			if err != nil {
 				fallback(w, req, "global", http.StatusMovedPermanently, c)
-				return record{}, err
+				return Record{}, err
 			}
 			r.Ref = l
 
@@ -139,7 +140,7 @@ func ParseRecord(str string, w http.ResponseWriter, req *http.Request, c Config)
 			l = strings.TrimPrefix(l, "root=")
 			l, err := parsePlaceholders(l, req, []string{})
 			if err != nil {
-				return record{}, err
+				return Record{}, err
 			}
 			l = ParseURI(l, w, req, c)
 			r.Root = l
@@ -148,7 +149,7 @@ func ParseRecord(str string, w http.ResponseWriter, req *http.Request, c Config)
 			l = strings.TrimPrefix(l, "to=")
 			l, err := parsePlaceholders(l, req, []string{})
 			if err != nil {
-				return record{}, err
+				return Record{}, err
 			}
 			l = ParseURI(l, w, req, c)
 			r.To = l
@@ -160,7 +161,7 @@ func ParseRecord(str string, w http.ResponseWriter, req *http.Request, c Config)
 		case strings.HasPrefix(l, "use="):
 			l = strings.TrimPrefix(l, "use=")
 			if !strings.HasPrefix(l, "_redirect.") {
-				return record{}, fmt.Errorf("The given zone address is invalid")
+				return Record{}, fmt.Errorf("The given zone address is invalid")
 			}
 			r.Use = append(r.Use, l)
 
@@ -168,7 +169,7 @@ func ParseRecord(str string, w http.ResponseWriter, req *http.Request, c Config)
 			l = strings.TrimPrefix(l, "v=")
 			r.Version = l
 			if r.Version != "txtv0" {
-				return record{}, fmt.Errorf("unhandled version '%s'", r.Version)
+				return Record{}, fmt.Errorf("unhandled version '%s'", r.Version)
 			}
 			log.Print("WARN: txtv0 is not suitable for production")
 
@@ -184,23 +185,23 @@ func ParseRecord(str string, w http.ResponseWriter, req *http.Request, c Config)
 			header := strings.Split(l, "=")
 			h, err := url.PathUnescape(header[1])
 			if err != nil {
-				return record{}, err
+				return Record{}, err
 			}
 			r.Headers[header[0][1:]] = h
 		default:
 			tuple := strings.Split(l, "=")
 			if len(tuple) != 2 {
-				return record{}, fmt.Errorf("arbitrary data not allowed")
+				return Record{}, fmt.Errorf("arbitrary data not allowed")
 			}
 			continue
 		}
 		if len(l) > 255 {
-			return record{}, fmt.Errorf("TXT record cannot exceed the maximum of 255 characters")
+			return Record{}, fmt.Errorf("TXT record cannot exceed the maximum of 255 characters")
 		}
 	}
 
 	if r.Type == "dockerv2" && r.To == "" {
-		return record{}, fmt.Errorf("[txtdirect]: to= field is required in dockerv2 type")
+		return Record{}, fmt.Errorf("[txtdirect]: to= field is required in dockerv2 type")
 	}
 
 	if r.Code == 0 {
@@ -215,11 +216,11 @@ func ParseRecord(str string, w http.ResponseWriter, req *http.Request, c Config)
 
 		if r.Type == "host" && r.To == "" {
 			fallback(w, req, "global", http.StatusMovedPermanently, c)
-			return record{}, nil
+			return Record{}, nil
 		}
 
 		if !contains(c.Enable, r.Type) {
-			return record{}, fmt.Errorf("%s type is not enabled in configuration", r.Type)
+			return Record{}, fmt.Errorf("%s type is not enabled in configuration", r.Type)
 		}
 	}
 
@@ -227,21 +228,61 @@ func ParseRecord(str string, w http.ResponseWriter, req *http.Request, c Config)
 }
 
 // Adds the given record to the request's context with "records" key.
-func (rec record) addToContext(r *http.Request) *http.Request {
+func (rec Record) addToContext(r *http.Request) *http.Request {
 	// Fetch fallback config from context and add the record to it
 	recordsContext := r.Context().Value("records")
 
 	// Create a new records field in the context if it doesn't exist
 	if recordsContext == nil {
-		return r.WithContext(context.WithValue(r.Context(), "records", []record{rec}))
+		return r.WithContext(context.WithValue(r.Context(), "records", []Record{rec}))
 	}
 
-	records := append(recordsContext.([]record), rec)
+	records := append(recordsContext.([]Record), rec)
 
 	// Replace the fallback config instance inside the request's context
 	return r.WithContext(context.WithValue(r.Context(), "records", records))
 }
 
+// UpstreamRecord will check all of the use= fields and sends a request to each
+// upstream zone address and choses the first one that returns the final TXT
+// record
+func (rec *Record) UpstreamRecord(c Config, w http.ResponseWriter, r *http.Request) (Record, string, error) {
+	var upstreamRec Record
+	var err error
+
+	for _, zone := range rec.Use {
+		upstreamRec, err = GetRecord(zone, c, w, r)
+		if err != nil {
+			continue
+		}
+		return upstreamRec, zone, nil
+	}
+
+	return Record{}, "", fmt.Errorf("Couldn't find any records from upstream")
+}
+
+func (rec *Record) CheckUpstream(w http.ResponseWriter, r *http.Request, c Config) (*http.Request, error) {
+	// Add the upstream zone address from the use= fields to the request context
+	if len(rec.Use) != 0 {
+		var zone string
+		upstreamRec, zone, err := rec.UpstreamRecord(c, w, r)
+		if err != nil {
+			return r, err
+		}
+
+		*rec = upstreamRec
+
+		zoneSplited := strings.Split(zone, ".")
+
+		return r.WithContext(context.WithValue(
+			r.Context(),
+			"upstreamZone",
+			strings.Join(zoneSplited[1:], "."),
+		)), nil
+	}
+	return r, nil
+}
+
 // ParseURI parses the given URI and triggers fallback if the URI isn't valid
 func ParseURI(uri string, w http.ResponseWriter, r *http.Request, c Config) string {
 	url, err := url.Parse(uri)
@@ -252,20 +293,53 @@ func ParseURI(uri string, w http.ResponseWriter, r *http.Request, c Config) stri
 	return url.String()
 }
 
-// UpstreamRecord will check all of the use= fields and sends a request to each
-// upstream zone address and choses the first one that returns the final TXT
-// record
-func (rec *record) UpstreamRecord(c Config, w http.ResponseWriter, r *http.Request) (record, string, error) {
-	var upstreamRec record
-	var err error
-
-	for _, zone := range rec.Use {
-		upstreamRec, err = getRecord(zone, c, w, r)
+// getBaseTarget parses the placeholder in the given record's To= field
+// and returns the final address and http status code
+func getBaseTarget(rec Record, r *http.Request) (string, int, error) {
+	if strings.ContainsAny(rec.To, "{}") {
+		to, err := parsePlaceholders(rec.To, r, []string{})
 		if err != nil {
-			continue
+			return "", 0, err
 		}
-		return upstreamRec, zone, nil
+		rec.To = to
+	}
+	return rec.To, rec.Code, nil
+}
+
+func absoluteZone(zone string) string {
+	// Removes port from zone
+	if strings.Contains(zone, ":") {
+		zoneSlice := strings.Split(zone, ":")
+		zone = zoneSlice[0]
 	}
 
-	return record{}, "", fmt.Errorf("Couldn't find any records from upstream")
+	if !strings.HasPrefix(zone, basezone) {
+		zone = strings.Join([]string{basezone, zone}, ".")
+	}
+
+	if strings.HasSuffix(zone, ".") {
+		return zone
+	}
+
+	return strings.Join([]string{zone, "."}, "")
+}
+
+// query checks the given zone using net.LookupTXT to
+// find TXT records in that zone
+func query(zone string, ctx context.Context, c Config) ([]string, error) {
+	var txts []string
+	var err error
+	if c.Resolver != "" {
+		net := customResolver(c)
+		txts, err = net.LookupTXT(ctx, absoluteZone(zone))
+	} else {
+		txts, err = net.LookupTXT(absoluteZone(zone))
+	}
+	if err != nil {
+		return nil, fmt.Errorf("could not get TXT record: %s", err)
+	}
+	if txts[0] == "" {
+		return nil, fmt.Errorf("TXT record doesn't exist or is empty")
+	}
+	return txts, nil
 }
diff --git a/setup.go b/setup.go
deleted file mode 100644
index 27c281f..0000000
--- a/setup.go
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
-Copyright 2017 - The TXTDirect Authors
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-    http://www.apache.org/licenses/LICENSE-2.0
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package txtdirect
-
-import (
-	"fmt"
-	"io/ioutil"
-	"log"
-	"net/http"
-	"os"
-	"strings"
-
-	lumberjack "gopkg.in/natefinch/lumberjack.v2"
-
-	"github.com/caddyserver/caddy"
-	"github.com/caddyserver/caddy/caddy/caddymain"
-	"github.com/caddyserver/caddy/caddyhttp/httpserver"
-)
-
-func main() {
-	caddymain.EnableTelemetry = false
-	caddymain.Run()
-}
-
-func init() {
-	caddy.RegisterPlugin("txtdirect", caddy.Plugin{
-		ServerType: "http",
-		Action:     setup,
-	})
-	// TODO: hardcode directive after stable release into Caddy
-	httpserver.RegisterDevDirective("txtdirect", "")
-}
-
-var allOptions = []string{"host", "path", "gometa", "www"}
-
-func ParseConfig(c *caddy.Controller) (Config, error) {
-	var enable []string
-	var redirect string
-	var resolver string
-	var prometheus Prometheus
-	var logfile string
-	var qr Qr
-
-	c.Next() // skip directive name
-	for c.NextBlock() {
-		option := c.Val()
-		switch option {
-		case "disable":
-			if enable != nil {
-				return Config{}, c.ArgErr()
-			}
-			toDisable := c.RemainingArgs()
-			if len(toDisable) == 0 {
-				return Config{}, c.ArgErr()
-			}
-			enable = removeArrayFromArray(allOptions, toDisable)
-
-		case "enable":
-			if enable != nil {
-				return Config{}, c.ArgErr()
-			}
-			enable = c.RemainingArgs()
-			if len(enable) == 0 {
-				return Config{}, c.ArgErr()
-			}
-
-		case "redirect":
-			toRedirect := c.RemainingArgs()
-			if len(toRedirect) != 1 {
-				return Config{}, c.ArgErr()
-			}
-			redirect = toRedirect[0]
-
-		case "resolver":
-			resolverAddr := c.RemainingArgs()
-			if len(resolverAddr) != 1 {
-				return Config{}, c.ArgErr()
-			}
-			resolver = resolverAddr[0]
-
-		case "logfile":
-			logfile = "stdout"
-			// Set stdout as the default value
-			if c.NextArg() {
-				logfile = c.Val()
-			}
-
-		case "prometheus":
-			prometheus.Enable = true
-			c.NextArg()
-			if c.Val() != "{" {
-				continue
-			}
-			for c.Next() {
-				if c.Val() == "}" {
-					break
-				}
-				err := prometheus.ParsePrometheus(c, c.Val(), c.RemainingArgs()[0])
-				if err != nil {
-					return Config{}, err
-				}
-			}
-
-		case "qr":
-			qr.Enable = true
-			c.NextArg()
-			if c.Val() != "{" {
-				continue
-			}
-			for c.Next() {
-				if c.Val() == "}" {
-					break
-				}
-				if err := qr.ParseQr(c); err != nil {
-					return Config{}, err
-				}
-			}
-
-		default:
-			return Config{}, c.ArgErr() // unhandled option
-		}
-	}
-
-	// If nothing is specified, enable everything
-	if enable == nil {
-		enable = allOptions
-	}
-
-	// Set the default values
-	if prometheus.Enable {
-		prometheus.SetDefaults()
-	}
-	if qr.Enable {
-		qr.SetDefaults()
-	}
-
-	config := Config{
-		Enable:     enable,
-		Redirect:   redirect,
-		Resolver:   resolver,
-		LogOutput:  logfile,
-		Prometheus: prometheus,
-		Qr:         qr,
-	}
-
-	parseLogfile(logfile)
-
-	return config, nil
-}
-
-func setup(c *caddy.Controller) error {
-	config, err := ParseConfig(c)
-	if err != nil {
-		return err
-	}
-
-	// Setup and add promethues middleware to caddy
-	if config.Prometheus.Enable {
-		config.Prometheus.SetDefaults()
-		config.Prometheus.Setup(c)
-	}
-
-	// Add handler to Caddy
-	cfg := httpserver.GetConfig(c)
-	mid := func(next httpserver.Handler) httpserver.Handler {
-		return TXTDirect{
-			Next:   next,
-			Config: config,
-		}
-	}
-	cfg.AddMiddleware(mid)
-
-	return nil
-}
-
-func removeArrayFromArray(array, toBeRemoved []string) []string {
-	tmp := make([]string, len(array))
-	copy(tmp, array)
-	for _, toRemove := range toBeRemoved {
-		for i, option := range tmp {
-			if option == toRemove {
-				tmp[i] = tmp[len(tmp)-1]
-				tmp = tmp[:len(tmp)-1]
-				break
-			}
-		}
-	}
-	return tmp
-}
-
-// TXTDirect is middleware to redirect requests based on TXT records
-type TXTDirect struct {
-	Next   httpserver.Handler
-	Config Config
-}
-
-func (rd TXTDirect) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
-	r.URL.Host = strings.ToLower(r.URL.Host)
-	if err := Redirect(w, r, rd.Config); err != nil {
-		if err.Error() == "option disabled" {
-			return rd.Next.ServeHTTP(w, r)
-		}
-		return http.StatusInternalServerError, err
-	}
-
-	// Count total redirects if prometheus is enabled and set cache header
-	if w.Header().Get("Status-Code") == "301" || w.Header().Get("Status-Code") == "302" {
-		if rd.Config.Prometheus.Enable {
-			RequestsCount.WithLabelValues(r.Host).Add(1)
-		}
-		// Set Cache-Control header on permanent redirects
-		if w.Header().Get("Status-Code") == "301" {
-			w.Header().Add("Cache-Control", fmt.Sprintf("max-age=%d", status301CacheAge))
-		}
-	}
-
-	return 0, nil
-}
-
-func parseLogfile(logfile string) {
-	switch logfile {
-	case "stdout":
-		log.SetOutput(os.Stdout)
-	case "stderr":
-		log.SetOutput(os.Stderr)
-	case "":
-		log.SetOutput(ioutil.Discard)
-	default:
-		log.SetOutput(&lumberjack.Logger{
-			Filename:   logfile,
-			MaxSize:    100,
-			MaxAge:     14,
-			MaxBackups: 10,
-		})
-	}
-}
diff --git a/txtdirect.go b/txtdirect.go
index 5f203f9..3e82c39 100644
--- a/txtdirect.go
+++ b/txtdirect.go
@@ -31,129 +31,13 @@ const (
 	proxyKeepalive    = 30
 	fallbackDelay     = 300 * time.Millisecond
 	proxyTimeout      = 30 * time.Second
-	status301CacheAge = 604800
+	Status301CacheAge = 604800
 )
 
 var bl = map[string]bool{
 	"/favicon.ico": true,
 }
 
-// Config contains the middleware's configuration
-type Config struct {
-	Enable     []string
-	Redirect   string
-	Resolver   string
-	LogOutput  string
-	Prometheus Prometheus
-	Qr         Qr
-}
-
-// getBaseTarget parses the placeholder in the given record's To= field
-// and returns the final address and http status code
-func getBaseTarget(rec record, r *http.Request) (string, int, error) {
-	if strings.ContainsAny(rec.To, "{}") {
-		to, err := parsePlaceholders(rec.To, r, []string{})
-		if err != nil {
-			return "", 0, err
-		}
-		rec.To = to
-	}
-	return rec.To, rec.Code, nil
-}
-
-// contains checks the given slice to see if an item exists
-// in that slice or not
-func contains(array []string, word string) bool {
-	for _, w := range array {
-		if w == word {
-			return true
-		}
-	}
-	return false
-}
-
-// customResolver returns a net.Resolver instance based
-// on the given txtdirect config to use a custom DNS resolver.
-func customResolver(c Config) net.Resolver {
-	return net.Resolver{
-		PreferGo: true,
-		Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
-			d := net.Dialer{}
-			return d.DialContext(ctx, network, c.Resolver)
-		},
-	}
-}
-
-func absoluteZone(zone string) string {
-	// Removes port from zone
-	if strings.Contains(zone, ":") {
-		zoneSlice := strings.Split(zone, ":")
-		zone = zoneSlice[0]
-	}
-
-	if !strings.HasPrefix(zone, basezone) {
-		zone = strings.Join([]string{basezone, zone}, ".")
-	}
-
-	if strings.HasSuffix(zone, ".") {
-		return zone
-	}
-
-	return strings.Join([]string{zone, "."}, "")
-}
-
-// query checks the given zone using net.LookupTXT to
-// find TXT records in that zone
-func query(zone string, ctx context.Context, c Config) ([]string, error) {
-	var txts []string
-	var err error
-	if c.Resolver != "" {
-		net := customResolver(c)
-		txts, err = net.LookupTXT(ctx, absoluteZone(zone))
-	} else {
-		txts, err = net.LookupTXT(absoluteZone(zone))
-	}
-	if err != nil {
-		return nil, fmt.Errorf("could not get TXT record: %s", err)
-	}
-	if txts[0] == "" {
-		return nil, fmt.Errorf("TXT record doesn't exist or is empty")
-	}
-	return txts, nil
-}
-
-func isIP(host string) bool {
-	if v6slice := strings.Split(host, ":"); len(v6slice) > 2 {
-		return true
-	}
-	hostSlice := strings.Split(host, ".")
-	_, err := strconv.Atoi(hostSlice[len(hostSlice)-1])
-	return err == nil
-}
-
-func blacklistRedirect(w http.ResponseWriter, r *http.Request, c Config) error {
-	if bl[r.URL.Path] {
-		redirect := strings.Join([]string{r.Host, r.URL.Path}, "")
-
-		log.Printf("[txtdirect]: %s > %s", r.Host+r.URL.Path, redirect)
-		// Empty Content-Type to prevent http.Redirect from writing an html response body
-		w.Header().Set("Content-Type", "")
-		w.Header().Add("Status-Code", strconv.Itoa(http.StatusNotFound))
-		http.Redirect(w, r, redirect, http.StatusNotFound)
-		if c.Prometheus.Enable {
-			RequestsByStatus.WithLabelValues(r.Host, strconv.Itoa(http.StatusNotFound)).Add(1)
-		}
-	}
-	return nil
-}
-
-func UpstreamZone(r *http.Request) string {
-	if zone := r.Context().Value("upstreamZone"); zone != nil {
-		return zone.(string)
-	}
-	return r.Host
-}
-
 // Redirect the request depending on the redirect record found
 func Redirect(w http.ResponseWriter, r *http.Request, c Config) error {
 	w.Header().Set("Server", "TXTDirect")
@@ -179,29 +63,17 @@ func Redirect(w http.ResponseWriter, r *http.Request, c Config) error {
 		return nil
 	}
 
-	rec, err := getRecord(host, c, w, r)
+	rec, err := GetRecord(host, c, w, r)
 	if err != nil {
 		fallback(w, r, "global", http.StatusFound, c)
 		return nil
 	}
 
 	// Add the upstream zone address from the use= fields to the request context
-	if len(rec.Use) != 0 {
-		var zone string
-		rec, zone, err = rec.UpstreamRecord(c, w, r)
-		if err != nil {
-			log.Printf("[txtdirect]: Couldn't fetch the upstream record: %s", err.Error())
-			fallback(w, r, "global", http.StatusFound, c)
-			return nil
-		}
-
-		zoneSplited := strings.Split(zone, ".")
-
-		r = r.WithContext(context.WithValue(
-			r.Context(),
-			"upstreamZone",
-			strings.Join(zoneSplited[1:], "."),
-		))
+	if r, err = rec.CheckUpstream(w, r, c); err != nil {
+		log.Printf("[txtdirect]: Couldn't fetch the upstream record: %s", err.Error())
+		fallback(w, r, "global", http.StatusFound, c)
+		return nil
 	}
 
 	r = rec.addToContext(r)
@@ -227,11 +99,6 @@ func Redirect(w http.ResponseWriter, r *http.Request, c Config) error {
 	}
 
 	if rec.Type == "path" {
-		RequestsCountBasedOnType.WithLabelValues(host, "path").Add(1)
-		if contains(c.Prometheus.PathWhitelist, host) {
-			PathRedirectCount.WithLabelValues(host, path).Add(1)
-		}
-
 		path := NewPath(w, r, path, rec, c)
 
 		if path.path == "/" {
@@ -259,35 +126,7 @@ func Redirect(w http.ResponseWriter, r *http.Request, c Config) error {
 		}
 	}
 
-	if rec.Type == "proxy" {
-		RequestsCountBasedOnType.WithLabelValues(host, "proxy").Add(1)
-		log.Printf("[txtdirect]: %s > %s", rec.From, rec.To)
-
-		proxy := NewProxy(w, r, rec, c)
-		if err = proxy.Proxy(); err != nil {
-			log.Print("Fallback is triggered because an error has occurred: ", err)
-			fallback(w, r, "to", rec.Code, c)
-		}
-
-		return nil
-	}
-
-	if rec.Type == "dockerv2" {
-		RequestsCountBasedOnType.WithLabelValues(host, "dockerv2").Add(1)
-
-		docker := NewDockerv2(w, r, rec, c)
-
-		if err := docker.Redirect(); err != nil {
-			log.Printf("[txtdirect]: couldn't redirect to the requested container: %s", err.Error())
-			fallback(w, r, "to", rec.Code, c)
-			return nil
-		}
-		return nil
-	}
-
 	if rec.Type == "host" {
-		RequestsCountBasedOnType.WithLabelValues(host, "host").Add(1)
-
 		host := NewHost(w, r, rec, c)
 
 		if err := host.Redirect(); err != nil {
@@ -297,8 +136,6 @@ func Redirect(w http.ResponseWriter, r *http.Request, c Config) error {
 	}
 
 	if rec.Type == "gometa" {
-		RequestsCountBasedOnType.WithLabelValues(host, "gometa").Add(1)
-
 		gometa := NewGometa(w, r, rec, c)
 
 		// Triggers fallback when request isn't from `go get`
@@ -309,16 +146,58 @@ func Redirect(w http.ResponseWriter, r *http.Request, c Config) error {
 		return gometa.Serve()
 	}
 
-	if rec.Type == "git" {
-		git := NewGit(w, r, c, rec)
+	return fmt.Errorf("record type %s unsupported", rec.Type)
+}
 
-		// Triggers fallback when request isn't from a Git client
-		if !git.ValidGitQuery() {
-			return nil
-		}
+// UpstreamZone returns the upstream zone from request's context
+func UpstreamZone(r *http.Request) string {
+	if zone := r.Context().Value("upstreamZone"); zone != nil {
+		return zone.(string)
+	}
+	return r.Host
+}
+
+// customResolver returns a net.Resolver instance based
+// on the given txtdirect config to use a custom DNS resolver.
+func customResolver(c Config) net.Resolver {
+	return net.Resolver{
+		PreferGo: true,
+		Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
+			d := net.Dialer{}
+			return d.DialContext(ctx, network, c.Resolver)
+		},
+	}
+}
 
-		return git.Proxy()
+func isIP(host string) bool {
+	if v6slice := strings.Split(host, ":"); len(v6slice) > 2 {
+		return true
 	}
+	hostSlice := strings.Split(host, ".")
+	_, err := strconv.Atoi(hostSlice[len(hostSlice)-1])
+	return err == nil
+}
 
-	return fmt.Errorf("record type %s unsupported", rec.Type)
+func blacklistRedirect(w http.ResponseWriter, r *http.Request, c Config) error {
+	if bl[r.URL.Path] {
+		redirect := strings.Join([]string{r.Host, r.URL.Path}, "")
+
+		log.Printf("[txtdirect]: %s > %s", r.Host+r.URL.Path, redirect)
+		// Empty Content-Type to prevent http.Redirect from writing an html response body
+		w.Header().Set("Content-Type", "")
+		w.Header().Add("Status-Code", strconv.Itoa(http.StatusNotFound))
+		http.Redirect(w, r, redirect, http.StatusNotFound)
+	}
+	return nil
+}
+
+// contains checks the given slice to see if an item exists
+// in that slice or not
+func contains(array []string, word string) bool {
+	for _, w := range array {
+		if w == word {
+			return true
+		}
+	}
+	return false
 }
diff --git a/txtdirectmain/run.go b/txtdirectmain/run.go
deleted file mode 100644
index 69cd1ea..0000000
--- a/txtdirectmain/run.go
+++ /dev/null
@@ -1,179 +0,0 @@
-// Package txtdirectmain contains the functions for starting TXTDirect.
-package txtdirectmain
-
-import (
-	"flag"
-	"fmt"
-	"io/ioutil"
-	"log"
-	"os"
-	"runtime"
-	"strconv"
-	"strings"
-
-	"github.com/caddyserver/caddy"
-)
-
-func init() {
-	caddy.Quiet = true // don't show init stuff from caddy
-	setVersion()
-
-	caddy.RegisterCaddyfileLoader("flag", caddy.LoaderFunc(confLoader))
-	caddy.SetDefaultCaddyfileLoader("default", caddy.LoaderFunc(defaultLoader))
-
-	caddy.AppName = TXTDirectName
-	caddy.AppVersion = TXTDirectVersion
-}
-
-// Run is TXTDirect's main() function.
-func Run() {
-	flag.Parse()
-	caddy.TrapSignals()
-
-	if err := getFlags(); err != nil {
-		log.Fatalf("[txtdirect]: Couldn't parse the flags: %s", err.Error())
-	}
-
-	if version {
-		showVersion()
-		os.Exit(0)
-	}
-
-	// Get TXTDirect config input
-	caddyfile, err := caddy.LoadCaddyfile("http")
-	if err != nil {
-		mustLogFatal(err)
-	}
-
-	// Start your engines
-	instance, err := caddy.Start(caddyfile)
-	if err != nil {
-		mustLogFatal(err)
-	}
-
-	// Twiddle your thumbs
-	instance.Wait()
-}
-
-// mustLogFatal wraps log.Fatal() in a way that ensures the
-// output is always printed to stderr so the user can see it
-// if the user is still there, even if the process log was not
-// enabled. If this process is an upgrade, however, and the user
-// might not be there anymore, this just logs to the process
-// log and exits.
-func mustLogFatal(args ...interface{}) {
-	if !caddy.IsUpgrade() {
-		log.SetOutput(os.Stderr)
-	}
-	log.Fatal(args...)
-}
-
-// confLoader loads the Caddyfile using the -conf flag.
-func confLoader(serverType string) (caddy.Input, error) {
-	if conf == "" {
-		return nil, nil
-	}
-
-	if conf == "stdin" {
-		return caddy.CaddyfileFromPipe(os.Stdin, serverType)
-	}
-
-	contents, err := ioutil.ReadFile(conf)
-	if err != nil {
-		return nil, err
-	}
-
-	return caddy.CaddyfileInput{
-		Contents:       contents,
-		Filepath:       conf,
-		ServerTypeName: serverType,
-	}, nil
-}
-
-// defaultLoader loads the TXTDirect config from the current working directory.
-func defaultLoader(serverType string) (caddy.Input, error) {
-	contents, err := ioutil.ReadFile(caddy.DefaultConfigFile)
-	if err != nil {
-		if os.IsNotExist(err) {
-			return nil, nil
-		}
-		return nil, err
-	}
-	return caddy.CaddyfileInput{
-		Contents:       contents,
-		Filepath:       caddy.DefaultConfigFile,
-		ServerTypeName: serverType,
-	}, nil
-}
-
-// showVersion prints the version that is starting.
-func showVersion() {
-	fmt.Print(versionString())
-	fmt.Print(releaseString())
-	if devBuild && gitShortStat != "" {
-		fmt.Printf("%s\n%s\n", gitShortStat, gitFilesModified)
-	}
-}
-
-// versionString returns the TXTDirect version as a string.
-func versionString() string {
-	return fmt.Sprintf("%s-%s\n", caddy.AppName, caddy.AppVersion)
-}
-
-// releaseString returns the release information related to TXTDirect version:
-// <OS>/<ARCH>, <go version>, <commit>
-// e.g.,
-// linux/amd64, go1.8.3, a6d2d7b5
-func releaseString() string {
-	return fmt.Sprintf("%s/%s, %s, %s\n", runtime.GOOS, runtime.GOARCH, runtime.Version(), GitCommit)
-}
-
-// setVersion figures out the version information
-// based on variables set by -ldflags.
-func setVersion() {
-	// A development build is one that's not at a tag or has uncommitted changes
-	devBuild = gitTag == "" || gitShortStat != ""
-
-	// Only set the appVersion if -ldflags was used
-	if gitNearestTag != "" || gitTag != "" {
-		if devBuild && gitNearestTag != "" {
-			appVersion = fmt.Sprintf("%s (+%s %s)", strings.TrimPrefix(gitNearestTag, "v"), GitCommit, buildDate)
-		} else if gitTag != "" {
-			appVersion = strings.TrimPrefix(gitTag, "v")
-		}
-	}
-}
-
-// Flags that control program flow or startup
-var (
-	conf    string
-	version bool
-)
-
-// Build information obtained with the help of -ldflags
-var (
-	appVersion = "(untracked dev build)" // inferred at startup
-	devBuild   = true                    // inferred at startup
-
-	buildDate        string // date -u
-	gitTag           string // git describe --exact-match HEAD 2> /dev/null
-	gitNearestTag    string // git describe --abbrev=0 --tags HEAD
-	gitShortStat     string // git diff-index --shortstat
-	gitFilesModified string // git diff-index --name-only HEAD
-
-	// Gitcommit contains the commit where we built TXTDirect from.
-	GitCommit string
-)
-
-func getFlags() error {
-	versionFlag := flag.Lookup("version")
-	if versionFlag != nil {
-		versionVal, err := strconv.ParseBool(versionFlag.Value.String())
-		if err != nil {
-			return fmt.Errorf("Coudln't parse the -version flag: %s", err.Error())
-		}
-		version = versionVal
-	}
-
-	return nil
-}


Test patch:
diff --git a/dockerv2_test.go b/dockerv2_test.go
deleted file mode 100644
index ec178e9..0000000
--- a/dockerv2_test.go
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
-Copyright 2019 - The TXTDirect Authors
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-    http://www.apache.org/licenses/LICENSE-2.0
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package txtdirect
-
-import (
-	"net/http"
-	"net/http/httptest"
-	"testing"
-)
-
-func TestDockerv2_ParseRecordReference(t *testing.T) {
-	tests := []struct {
-		rec      record
-		expected Image
-	}{
-		{
-			rec: record{
-				To: "https://example.com",
-			},
-			expected: Image{
-				Registry: "https://example.com",
-			},
-		},
-		{
-			rec: record{
-				To: "https://example.com/txtdirect/txtdirect",
-			},
-			expected: Image{
-				Registry: "https://example.com",
-				Image:    "txtdirect/txtdirect",
-			},
-		},
-		{
-			rec: record{
-				To: "https://example.com/txtdirect",
-			},
-			expected: Image{
-				Registry: "https://example.com",
-				Image:    "txtdirect",
-			},
-		},
-		{
-			rec: record{
-				To: "https://example.com/txtdirect/txtdirect:v0.0.1",
-			},
-			expected: Image{
-				Registry: "https://example.com",
-				Image:    "txtdirect/txtdirect",
-				Tag:      "v0.0.1",
-			},
-		},
-		{
-			rec: record{
-				To: "https://example.com/txtdirect:v0.0.1",
-			},
-			expected: Image{
-				Registry: "https://example.com",
-				Image:    "txtdirect",
-				Tag:      "v0.0.1",
-			},
-		},
-	}
-	for _, test := range tests {
-		resp := httptest.NewRecorder()
-		docker := NewDockerv2(resp, &http.Request{}, test.rec, Config{})
-
-		if err := docker.ParseRecordReference(); err != nil {
-			t.Errorf("Unexpected error happened: %s", err)
-		}
-		if docker.image != test.expected {
-			t.Errorf("Expected %+v, got %+v", test.expected, docker.image)
-		}
-	}
-}
-
-func TestDockerv2_ParseReference(t *testing.T) {
-	tests := []struct {
-		rec      record
-		uri      string
-		expected string
-	}{
-		{
-			rec: record{
-				To: "https://example.com",
-			},
-			uri:      "https://example.test/v2/txtdirect/manifests/latest",
-			expected: "https://example.com/v2/txtdirect/manifests/latest",
-		},
-		{
-			rec: record{
-				To: "https://example.com",
-			},
-			uri:      "https://example.test/v2/txtdirect/manifests/v0.0.1",
-			expected: "https://example.com/v2/txtdirect/manifests/v0.0.1",
-		},
-		{
-			rec: record{
-				To: "https://example.com",
-			},
-			uri:      "https://example.test/v2/txtdirect/blobs/sha256:000000",
-			expected: "https://example.com/v2/txtdirect/blobs/sha256:000000",
-		},
-		{
-			rec: record{
-				To: "https://example.com/txtdirect/txtdirect",
-			},
-			uri:      "https://example.test/v2/txtdirect/txtdirect/manifests/latest",
-			expected: "https://example.com/v2/txtdirect/txtdirect/manifests/latest",
-		},
-		{
-			rec: record{
-				To: "https://example.com/txtdirect/txtdirect",
-			},
-			uri:      "https://example.test/v2/txtdirect/txtdirect/blobs/sha256:000000",
-			expected: "https://example.com/v2/txtdirect/txtdirect/blobs/sha256:000000",
-		},
-		{
-			rec: record{
-				To: "https://example.com/txtdirect",
-			},
-			uri:      "https://example.test/v2/txtdirect/txtdirect/manifests/latest",
-			expected: "https://example.com/v2/txtdirect/manifests/latest",
-		},
-		{
-			rec: record{
-				To: "https://example.com/txtdirect",
-			},
-			uri:      "https://example.test/v2/txtdirect/txtdirect/blobs/sha256:000000",
-			expected: "https://example.com/v2/txtdirect/blobs/sha256:000000",
-		},
-		{
-			rec: record{
-				To: "https://example.com/txtdirect/txtdirect:v0.0.1",
-			},
-			uri:      "https://example.test/v2/txtdirect/manifests/latest",
-			expected: "https://example.com/v2/txtdirect/txtdirect/manifests/v0.0.1",
-		},
-		{
-			rec: record{
-				To: "https://example.com/txtdirect:v0.0.1",
-			},
-			uri:      "https://example.test/v2/txtdirect/txtdirect/blobs/sha256:000000",
-			expected: "https://example.com/v2/txtdirect/blobs/sha256:000000",
-		},
-	}
-	for _, test := range tests {
-		req := httptest.NewRequest("GET", test.uri, nil)
-		resp := httptest.NewRecorder()
-		docker := NewDockerv2(resp, req, test.rec, Config{})
-
-		uri, err := docker.ParseReference()
-
-		if err != nil {
-			t.Errorf("Unexpected error happened: %s", err)
-		}
-
-		if uri != test.expected {
-			t.Errorf("Expected %s for dockerv2 redirect URI, got %s", test.expected, uri)
-		}
-	}
-}
diff --git a/e2e/Dockerfile b/e2e/Dockerfile
index d539064..c20b068 100644
--- a/e2e/Dockerfile
+++ b/e2e/Dockerfile
@@ -1,4 +1,4 @@
-FROM golang:1.13-alpine
+FROM golang:1.14-alpine
 
 RUN apk --no-cache add git
 
diff --git a/e2e/dockerv2/Corefile b/e2e/dockerv2/Corefile
deleted file mode 100644
index fc70b9d..0000000
--- a/e2e/dockerv2/Corefile
+++ /dev/null
@@ -1,6 +0,0 @@
-.:53 {
-  file /e2e/zonefile example.com
-  forward . 8.8.8.8
-  errors stdout
-  log
-}
diff --git a/e2e/dockerv2/main.go b/e2e/dockerv2/main.go
deleted file mode 100644
index 853ed72..0000000
--- a/e2e/dockerv2/main.go
+++ /dev/null
@@ -1,213 +0,0 @@
-package main
-
-import (
-	"errors"
-	"fmt"
-	"log"
-	"net/http"
-	"os/exec"
-)
-
-type data struct {
-	host  string
-	path  string
-	image string
-}
-
-type test struct {
-	name     string
-	args     data
-	expected string
-	referer  bool
-	status   int
-	headers  http.Header
-	kind     string
-	fallback bool
-}
-
-var tests = []test{
-	{
-		name: "Fallback to \"root=\"",
-		args: data{
-			host: "fallback.dockerv2.dockerv2.example.com",
-			path: "/",
-		},
-		headers: http.Header{
-			"User-Agent": []string{"Docker-Client"},
-		},
-		expected: "https://fallback-root.dockerv2.dockerv2.example.com",
-		fallback: true,
-	},
-	{
-		name: "Fallback to 404 when \"to=\" is not linked to a Docker image or registry",
-		args: data{
-			host: "fallback-wrong-to.dockerv2.dockerv2.example.com",
-			path: "/v2/test/path",
-		},
-		headers: http.Header{
-			"User-Agent": []string{"Docker-Client"},
-		},
-		status:   404,
-		fallback: true,
-	},
-	{
-		name: "Pull an image from the registry",
-		args: data{
-			image: "pull.dockerv2.dockerv2.example.com/txtdirect",
-		},
-		kind: "pull",
-	},
-	{
-		name: "Pull an image from registry only to= field",
-		args: data{
-			image: "registry.dockerv2.dockerv2.example.com/txtdirect",
-		},
-		kind: "pull",
-	},
-	{
-		name: "Pull an image using namespace/image from registry only to= field",
-		args: data{
-			image: "registry.dockerv2.dockerv2.example.com/txtdirect/txtdirect",
-		},
-		kind: "pull",
-	},
-	{
-		name: "Pull an image with tag from registry only to= field",
-		args: data{
-			image: "registry.dockerv2.dockerv2.example.com/txtdirect/txtdirect:test",
-		},
-		kind: "pull",
-	},
-	{
-		name: "Pull an image from a to= field without tag",
-		args: data{
-			image: "specific.dockerv2.dockerv2.example.com/txtdirect",
-		},
-		kind: "pull",
-	},
-	{
-		name: "Pull an image using namespace/image from a to= field without tag",
-		args: data{
-			image: "specific.dockerv2.dockerv2.example.com/txtdirect/txtdirect",
-		},
-		kind: "pull",
-	},
-	{
-		name: "Pull an image with tag from a to= field without tag",
-		args: data{
-			image: "specific.dockerv2.dockerv2.example.com/txtdirect/txtdirect:test",
-		},
-		kind: "pull",
-	},
-	{
-		name: "Pull an image from a specific to= field with tag",
-		args: data{
-			image: "specific-tag.dockerv2.dockerv2.example.com/txtdirect",
-		},
-		kind: "pull",
-	},
-	{
-		name: "Pull an image using namespace/image from a specific to= field with tag",
-		args: data{
-			image: "specific-tag.dockerv2.dockerv2.example.com/txtdirect/txtdirect",
-		},
-		kind: "pull",
-	},
-	{
-		name: "Pull an image with tag a specific to= field with tag",
-		args: data{
-			image: "specific-tag.dockerv2.dockerv2.example.com/txtdirect/txtdirect:test",
-		},
-		kind: "pull",
-	},
-}
-
-func main() {
-	result := make(map[bool][]test)
-	for _, test := range tests {
-		if test.fallback {
-			if err := fallbackTest(test, result); err != nil {
-				continue
-			}
-		}
-
-		switch test.kind {
-		case "pull":
-			_, err := exec.Command("crane", "pull", "-i", test.args.image, "txtdirect_e2e").CombinedOutput()
-			if err != nil {
-				result[false] = append(result[false], test)
-				log.Printf("[%s]: Couldn't pull the image from the custom Docker registry: %s", test.name, err.Error())
-				continue
-			}
-			_, err = exec.Command("rm", "./txtdirect_e2e").CombinedOutput()
-			if err != nil {
-				result[false] = append(result[false], test)
-				log.Printf("[%s]: Couldn't remove the pulled image: %s", test.name, err.Error())
-				continue
-			}
-		}
-
-		result[true] = append(result[true], test)
-	}
-	log.Printf("TestCase: \"dockerv2\", Total: %d, Passed: %d, Failed: %d", len(tests), len(result[true]), len(result[false]))
-}
-
-// fallbackTest handles the fallback tests and returns an empty non-nil error
-// in case of failure.
-func fallbackTest(test test, result map[bool][]test) error {
-	client := &http.Client{
-		CheckRedirect: func(req *http.Request, via []*http.Request) error {
-			return http.ErrUseLastResponse
-		},
-	}
-
-	req, err := http.NewRequest("GET", fmt.Sprintf("http://%s%s", test.args.host, test.args.path), nil)
-	if err != nil {
-		result[false] = append(result[false], test)
-		log.Printf("[%s]: Couldn't create the request: %s", test.name, err.Error())
-		return errors.New("")
-	}
-
-	req.Header = test.headers
-
-	resp, err := client.Do(req)
-	if err != nil {
-		result[false] = append(result[false], test)
-		log.Printf("[%s]: Couldn't send the request: %s", test.name, err.Error())
-		return errors.New("")
-	}
-
-	// Check response's status code
-	if test.status != 0 {
-		if resp.StatusCode != test.status {
-			result[false] = append(result[false], test)
-			log.Printf("[%s]: Expected %d status code, got %d", test.name, test.status, resp.StatusCode)
-			return errors.New("")
-		}
-		result[true] = append(result[true], test)
-		return errors.New("")
-	}
-
-	// Check "Location" header for redirects
-	location, err := resp.Location()
-
-	if err == http.ErrNoLocation {
-		result[false] = append(result[false], test)
-		log.Printf("[%s]: Location header is empty", test.name)
-		return errors.New("")
-	}
-
-	if location.String() != test.expected {
-		result[false] = append(result[false], test)
-		log.Printf("[%s]: Expected %s, got %s", test.name, test.expected, location)
-		return errors.New("")
-	}
-
-	// Check "Referer" header if enabled
-	if test.referer && resp.Header.Get("Referer") != req.Host {
-		result[false] = append(result[false], test)
-		log.Printf("Expected %s referer but got \"%s\"", req.Host, resp.Header.Get("Referer"))
-		return errors.New("")
-	}
-	return nil
-}
diff --git a/e2e/dockerv2/txtdirect.config b/e2e/dockerv2/txtdirect.config
deleted file mode 100644
index 28d47a6..0000000
--- a/e2e/dockerv2/txtdirect.config
+++ /dev/null
@@ -1,9 +0,0 @@
-:80 {
-    txtdirect {
-        enable dockerv2
-        resolver 172.20.10.1:53
-        logfile stdout
-    }
-    log / stdout "{remote} - [{when_iso}] \"{method} {uri} {proto}\" {status} {size} {latency}"
-    errors stdout
-}
diff --git a/e2e/dockerv2/zonefile b/e2e/dockerv2/zonefile
deleted file mode 100644
index fc13408..0000000
--- a/e2e/dockerv2/zonefile
+++ /dev/null
@@ -1,32 +0,0 @@
-@                   3600 IN SOA     ns.example.com. domains.example.com. (
-                                      2017101003   ; serial
-                                      5m           ; refresh
-                                      5m           ; retry
-                                      1w           ; expire
-                                      12h    )     ; minimum
-
-@                  86400 IN NS      ns.example.net.
-@                  86400 IN NS      ns.example.nl.
-
-$TTL 1h
-
-example.com.                IN A 172.20.10.2
-
-pull.dockerv2.dockerv2.example.com.                           IN A 172.20.10.2
-_redirect.pull.dockerv2.dockerv2.example.com.                 IN TXT "v=txtv0;to=http://172.20.10.3:5000/txtdirect;type=dockerv2" 
-
-fallback.dockerv2.dockerv2.example.com.                       IN A 172.20.10.2
-_redirect.fallback.dockerv2.dockerv2.example.com.             IN TXT "v=txtv0;to=https://fallback-to.dockerv2.dockerv2.example.com;root=https://fallback-root.dockerv2.dockerv2.example.com;type=dockerv2" 
-
-fallback-wrong-to.dockerv2.dockerv2.example.com.              IN A 172.20.10.2
-_redirect.fallback-wrong-to.dockerv2.dockerv2.example.com.    IN TXT "v=txtv0;to=:/wrong.uri/;type=dockerv2;website=https://fallback-website.dockerv2.dockerv2.example.com" 
-
-
-registry.dockerv2.dockerv2.example.com.                       IN A 172.20.10.2
-_redirect.registry.dockerv2.dockerv2.example.com.             IN TXT "v=txtv0;to=http://172.20.10.3:5000;type=dockerv2" 
-
-specific.dockerv2.dockerv2.example.com.                       IN A 172.20.10.2
-_redirect.specific.dockerv2.dockerv2.example.com.             IN TXT "v=txtv0;to=http://172.20.10.3:5000/txtdirect/txtdirect;type=dockerv2" 
-
-specific-tag.dockerv2.dockerv2.example.com.                   IN A 172.20.10.2
-_redirect.specific-tag.dockerv2.dockerv2.example.com.         IN TXT "v=txtv0;to=http://172.20.10.3:5000/txtdirect/txtdirect:e2e;type=dockerv2" 
\ No newline at end of file
diff --git a/e2e/git/Corefile b/e2e/git/Corefile
deleted file mode 100644
index fc70b9d..0000000
--- a/e2e/git/Corefile
+++ /dev/null
@@ -1,6 +0,0 @@
-.:53 {
-  file /e2e/zonefile example.com
-  forward . 8.8.8.8
-  errors stdout
-  log
-}
diff --git a/e2e/git/main.go b/e2e/git/main.go
deleted file mode 100644
index 941394d..0000000
--- a/e2e/git/main.go
+++ /dev/null
@@ -1,106 +0,0 @@
-package main
-
-import (
-	"fmt"
-	"log"
-	"net/http"
-	"os/exec"
-)
-
-type data struct {
-	host string
-	path string
-	dir  string
-}
-
-type test struct {
-	name     string
-	args     data
-	fallback bool
-	expected string
-}
-
-var tests = []test{
-	{
-		name: "Clone a repository using a \"git\" record",
-		args: data{
-			host: "http://package.git.git.example.com",
-			path: "",
-			dir:  "git",
-		},
-	},
-	{
-		name: "Clone a repository using a \"path\" record chained to a \"git\" record",
-		args: data{
-			host: "http://git.path.example.com",
-			path: "/package",
-			dir:  "gitpath",
-		},
-	},
-	{
-		name: "Fallback to \"website=\" when User-Agent header is not set",
-		args: data{
-			host: "fallback.git.git.example.com",
-			path: "/",
-		},
-		expected: "https://fallback-website.git.git.example.com",
-		fallback: true,
-	},
-	{
-		name: "Fallback to git record's \"website=\" when User-Agent header is not set",
-		args: data{
-			host: "fallback.git.path.example.com",
-			path: "/",
-		},
-		expected: "https://fallback-website.git.path.example.com",
-		fallback: true,
-	},
-}
-
-func main() {
-	result := make(map[bool][]test)
-	for _, test := range tests {
-		if test.fallback {
-			client := &http.Client{
-				CheckRedirect: func(req *http.Request, via []*http.Request) error {
-					return http.ErrUseLastResponse
-				},
-			}
-
-			req, err := http.NewRequest("GET", fmt.Sprintf("http://%s%s", test.args.host, test.args.path), nil)
-			resp, err := client.Do(req)
-			if err != nil {
-				result[false] = append(result[false], test)
-				log.Printf("[%s]: Couldn't send the request: %s", test.name, err.Error())
-				continue
-			}
-
-			location, err := resp.Location()
-
-			if err == http.ErrNoLocation {
-				result[false] = append(result[false], test)
-				log.Printf("[%s]: Location header is empty", test.name)
-				continue
-			}
-
-			if location.String() != test.expected {
-				result[false] = append(result[false], test)
-				log.Printf("[%s]: Expected %s, got %s", test.name, test.expected, location)
-				continue
-			}
-
-			result[true] = append(result[true], test)
-			continue
-		}
-
-		_, err := exec.Command("git", "clone", test.args.host+test.args.path, fmt.Sprintf("/tmp/%s", test.args.dir)).CombinedOutput()
-		if err != nil {
-			result[false] = append(result[false], test)
-			log.Printf("[%s]: Couldn't clone the repository: %s", test.name, err.Error())
-			continue
-		}
-
-		result[true] = append(result[true], test)
-	}
-	log.Printf("TestCase: \"git\", Total: %d, Passed: %d, Failed: %d", len(tests), len(result[true]), len(result[false]))
-}
diff --git a/e2e/git/txtdirect.config b/e2e/git/txtdirect.config
deleted file mode 100644
index 7bb7e0a..0000000
--- a/e2e/git/txtdirect.config
+++ /dev/null
@@ -1,9 +0,0 @@
-:80 {
-    txtdirect {
-        enable git path
-        resolver 172.20.10.1:53
-        logfile stdout
-    }
-    log / stdout "{remote} - [{when_iso}] \"{method} {uri} {proto}\" {status} {size} {latency}"
-    errors stdout
-}
diff --git a/e2e/git/zonefile b/e2e/git/zonefile
deleted file mode 100644
index 274974e..0000000
--- a/e2e/git/zonefile
+++ /dev/null
@@ -1,27 +0,0 @@
-@                   3600 IN SOA     ns.example.com. domains.example.com. (
-                                      2017101003   ; serial
-                                      5m           ; refresh
-                                      5m           ; retry
-                                      1w           ; expire
-                                      12h    )     ; minimum
-
-@                  86400 IN NS      ns.example.net.
-@                  86400 IN NS      ns.example.nl.
-
-$TTL 1h
-
-example.com.                IN A 172.20.10.2
-
-
-package.git.git.example.com.              IN A 172.20.10.2
-_redirect.package.git.git.example.com.    IN TXT "v=txtv0;to=https://github.com/okkur/torproxy.git;type=git" 
-
-git.path.example.com.                     IN A 172.20.10.2
-_redirect.git.path.example.com.           IN TXT "v=txtv0;to=https://fallback-to.git.path.example.com;type=path" 
-_redirect.package.git.path.example.com.   IN TXT "v=txtv0;to=https://github.com/okkur/torproxy.git;type=git" 
-
-fallback.git.git.example.com.             IN A 172.20.10.2
-_redirect.fallback.git.git.example.com.   IN TXT "v=txtv0;to=https://example.com/example/example.git;website=https://fallback-website.git.git.example.com;type=git"
-
-fallback.git.path.example.com.            IN A 172.20.10.2
-_redirect.fallback.git.path.example.com.  IN TXT "v=txtv0;to=https://example.com/example/example.git;website=https://fallback-website.git.path.example.com;type=git"
diff --git a/e2e/gometa/txtdirect.config b/e2e/gometa/txtdirect.config
index b20d193..ccfbe51 100644
--- a/e2e/gometa/txtdirect.config
+++ b/e2e/gometa/txtdirect.config
@@ -1,9 +1,9 @@
 :80 {
-    txtdirect {
-        enable path gometa
-        resolver 172.20.10.1:53
-        logfile stdout
+    route {
+        txtdirect {
+            enable path gometa
+            resolver 172.20.10.1:53
+            logfile stdout
+        }
     }
-    log / stdout "{remote} - [{when_iso}] \"{method} {uri} {proto}\" {status} {size} {latency}"
-    errors stdout
 }
diff --git a/e2e/host/main.go b/e2e/host/main.go
index 879fd02..56690c6 100644
--- a/e2e/host/main.go
+++ b/e2e/host/main.go
@@ -87,14 +87,6 @@ var tests = []test{
 		},
 		expected: "https://upstream.host.host.example.com",
 	},
-	{
-		name: "Redirect using chained path records to a host record",
-		args: data{
-			host: "chaining.path.path.example.com",
-			path: "/releases",
-		},
-		expected: "https://chained-redirect.host.path.example.com",
-	},
 	{
 		name: "Redirect to the apex zone's wildcard record to= field",
 		args: data{
diff --git a/e2e/host/txtdirect.config b/e2e/host/txtdirect.config
index 248c8b9..12ae5fa 100644
--- a/e2e/host/txtdirect.config
+++ b/e2e/host/txtdirect.config
@@ -1,9 +1,9 @@
 :80 {
-    txtdirect {
-        enable host path
-        resolver 172.20.10.1:53
-        logfile stdout
+    route {
+        txtdirect {
+            enable host path
+            resolver 172.20.10.1:53
+            logfile stdout
+        }
     }
-    log / stdout "{remote} - [{when_iso}] \"{method} {uri} {proto}\" {status} {size} {latency}"
-    errors stdout
 }
diff --git a/e2e/main.go b/e2e/main.go
index f069f4f..a4d6090 100644
--- a/e2e/main.go
+++ b/e2e/main.go
@@ -168,8 +168,11 @@ func (d *dockerManager) StartContainers() error {
 		"--name", "e2e_txtdirect_container",
 		txtdirectImage,
 		// CMD
-		"-conf",
+		"run",
+		"--config",
 		"/e2e/txtdirect.config",
+		"--adapter",
+		"caddyfile",
 	).CombinedOutput()
 	if err != nil {
 		return fmt.Errorf("Couldn't create the TXTDirect container: %s", err.Error())
diff --git a/e2e/path/main.go b/e2e/path/main.go
index b696963..67054eb 100644
--- a/e2e/path/main.go
+++ b/e2e/path/main.go
@@ -121,14 +121,6 @@ var tests = []test{
 		},
 		expected: "https://fallback-unknown-path.path.path.example.com",
 	},
-	{
-		name: "Use regex placeholders in a host record chained to a path record",
-		args: data{
-			host: "chaining.path.path.example.com",
-			path: "/host/",
-		},
-		expected: "https://redirect-host.host.path.example.com",
-	},
 	{
 		name: "Use regex placeholders in fallback triggered by chained record",
 		args: data{
diff --git a/e2e/path/txtdirect.config b/e2e/path/txtdirect.config
index 248c8b9..12ae5fa 100644
--- a/e2e/path/txtdirect.config
+++ b/e2e/path/txtdirect.config
@@ -1,9 +1,9 @@
 :80 {
-    txtdirect {
-        enable host path
-        resolver 172.20.10.1:53
-        logfile stdout
+    route {
+        txtdirect {
+            enable host path
+            resolver 172.20.10.1:53
+            logfile stdout
+        }
     }
-    log / stdout "{remote} - [{when_iso}] \"{method} {uri} {proto}\" {status} {size} {latency}"
-    errors stdout
 }
diff --git a/fallback_test.go b/fallback_test.go
index 07d791f..f16e4b4 100644
--- a/fallback_test.go
+++ b/fallback_test.go
@@ -11,7 +11,7 @@ import (
 
 func Test_fallback(t *testing.T) {
 	tests := []struct {
-		record       record
+		record       Record
 		redirect     string
 		fallbackType string
 		enable       []string
@@ -19,7 +19,7 @@ func Test_fallback(t *testing.T) {
 		expected     string
 	}{
 		{
-			record: record{
+			record: Record{
 				To:   "https://goto.fallback.test",
 				Code: 301,
 			},
@@ -27,7 +27,7 @@ func Test_fallback(t *testing.T) {
 			expected:     "https://goto.fallback.test",
 		},
 		{
-			record: record{
+			record: Record{
 				To:   "",
 				Code: 301,
 			},
@@ -36,7 +36,7 @@ func Test_fallback(t *testing.T) {
 			expected:     "https://redirect.test",
 		},
 		{
-			record: record{
+			record: Record{
 				To:   "https://goto.fallback.test",
 				Code: 404,
 			},
@@ -44,7 +44,7 @@ func Test_fallback(t *testing.T) {
 			expected:     "not found",
 		},
 		{
-			record: record{
+			record: Record{
 				Website: "https://goto.website.test",
 				Code:    302,
 			},
@@ -52,7 +52,7 @@ func Test_fallback(t *testing.T) {
 			expected:     "https://goto.website.test",
 		},
 		{
-			record: record{
+			record: Record{
 				Root: "https://dockerv2.root.test",
 				Code: 302,
 			},
@@ -60,7 +60,7 @@ func Test_fallback(t *testing.T) {
 			expected:     "https://dockerv2.root.test",
 		},
 		{
-			record: record{
+			record: Record{
 				Code: 302,
 			},
 			enable:       []string{"www"},
diff --git a/git_test.go b/git_test.go
deleted file mode 100644
index 3113a65..0000000
--- a/git_test.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package txtdirect
-
-import (
-	"net/http/httptest"
-	"testing"
-)
-
-func TestGit_Proxy(t *testing.T) {
-	tests := []struct {
-		url     string
-		rec     record
-		wantErr bool
-	}{
-		{
-			url: "http://git.example.test/info/refs?service=git-upload-pack",
-			rec: record{
-				To: "https://example.com/example/example.git",
-			},
-		},
-		{
-			url: "http://git.example.test/info/refs?service=git-upload-pack",
-			rec: record{
-				To: "https://example.com/example/example.git",
-			},
-		},
-	}
-	for _, test := range tests {
-		req := httptest.NewRequest("GET", test.url, nil)
-		resp := httptest.NewRecorder()
-		g := NewGit(resp, req, Config{}, test.rec)
-		if err := g.Proxy(); err != nil && !test.wantErr {
-			t.Errorf("Unexpected error while fetching the Git repository: %s", err.Error())
-		}
-	}
-}
diff --git a/gometa_test.go b/gometa_test.go
index 4c9efbc..ea292ec 100644
--- a/gometa_test.go
+++ b/gometa_test.go
@@ -24,13 +24,13 @@ func TestGometa(t *testing.T) {
 	tests := []struct {
 		host     string
 		path     string
-		record   record
+		record   Record
 		expected string
 	}{
 		{
 			host: "example.com",
 			path: "/testing",
-			record: record{
+			record: Record{
 				Vcs: "git",
 				To:  "redirect.com/my-go-pkg",
 			},
@@ -45,7 +45,7 @@ func TestGometa(t *testing.T) {
 		{
 			host:   "empty.com",
 			path:   "/testing",
-			record: record{},
+			record: Record{},
 			expected: `<!DOCTYPE html>
 <html>
 <head>
@@ -57,7 +57,7 @@ func TestGometa(t *testing.T) {
 		{
 			host: "root.com",
 			path: "/testing",
-			record: record{
+			record: Record{
 				Vcs: "git",
 				To:  "redirect.com/my-root-package",
 			},
@@ -72,7 +72,7 @@ func TestGometa(t *testing.T) {
 		{
 			host: "root.com",
 			path: "/testing",
-			record: record{
+			record: Record{
 				Vcs: "git",
 				To:  "github.com/txtdirect/txtdirect",
 			},
diff --git a/path_test.go b/path_test.go
index 5c7d6a1..90df1ce 100644
--- a/path_test.go
+++ b/path_test.go
@@ -155,7 +155,7 @@ func Test_zoneFromPath(t *testing.T) {
 		},
 	}
 	for _, test := range tests {
-		rec := record{}
+		rec := Record{}
 		rec.Re = test.regex
 		rec.From = test.from
 		req := httptest.NewRequest("GET", test.url, nil)
@@ -228,7 +228,7 @@ func Test_zoneFromPathRegexPlaceholders(t *testing.T) {
 		},
 	}
 	for _, test := range tests {
-		rec := record{
+		rec := Record{
 			Re:   test.regex,
 			From: test.from,
 			To:   test.to,
diff --git a/record_test.go b/record_test.go
index f80c6c2..fe45ed7 100644
--- a/record_test.go
+++ b/record_test.go
@@ -24,13 +24,13 @@ import (
 func TestParseRecord(t *testing.T) {
 	tests := []struct {
 		txtRecord string
-		expected  record
+		expected  Record
 		err       error
 		status    int
 	}{
 		{
 			txtRecord: "v=txtv0;to=https://example.com/;code=302",
-			expected: record{
+			expected: Record{
 				Version: "txtv0",
 				To:      "https://example.com/",
 				Code:    302,
@@ -40,7 +40,7 @@ func TestParseRecord(t *testing.T) {
 		},
 		{
 			txtRecord: "v=txtv0;to=https://example.com/",
-			expected: record{
+			expected: Record{
 				Version: "txtv0",
 				To:      "https://example.com/",
 				Code:    302,
@@ -50,7 +50,7 @@ func TestParseRecord(t *testing.T) {
 		},
 		{
 			txtRecord: "v=txtv0;to=https://example.com/;code=302",
-			expected: record{
+			expected: Record{
 				Version: "txtv0",
 				To:      "https://example.com/",
 				Code:    302,
@@ -60,7 +60,7 @@ func TestParseRecord(t *testing.T) {
 		},
 		{
 			txtRecord: "v=txtv0;to=https://example.com/;code=302;vcs=hg;type=gometa",
-			expected: record{
+			expected: Record{
 				Version: "txtv0",
 				To:      "https://example.com/",
 				Code:    302,
@@ -71,7 +71,7 @@ func TestParseRecord(t *testing.T) {
 		},
 		{
 			txtRecord: "v=txtv0;to=https://example.com/;code=302;type=gometa;vcs=git",
-			expected: record{
+			expected: Record{
 				Version: "txtv0",
 				To:      "https://example.com/",
 				Code:    302,
@@ -82,22 +82,22 @@ func TestParseRecord(t *testing.T) {
 		},
 		{
 			txtRecord: "v=txtv0;to=https://example.com/;code=test",
-			expected:  record{},
+			expected:  Record{},
 			err:       fmt.Errorf("could not parse status code"),
 		},
 		{
 			txtRecord: "v=txtv1;to=https://example.com/;code=test",
-			expected:  record{},
+			expected:  Record{},
 			err:       fmt.Errorf("unhandled version 'txtv1'"),
 		},
 		{
 			txtRecord: "v=txtv0;https://example.com/",
-			expected:  record{},
+			expected:  Record{},
 			err:       fmt.Errorf("arbitrary data not allowed"),
 		},
 		{
 			txtRecord: "v=txtv0;to=https://example.com/caddy;type=path;code=302",
-			expected: record{
+			expected: Record{
 				Version: "txtv0",
 				To:      "https://example.com/caddy",
 				Type:    "path",
@@ -107,7 +107,7 @@ func TestParseRecord(t *testing.T) {
 		},
 		{
 			txtRecord: "v=txtv0;to=https://example.com/;key=value",
-			expected: record{
+			expected: Record{
 				Version: "txtv0",
 				To:      "https://example.com/",
 				Code:    302,
@@ -117,7 +117,7 @@ func TestParseRecord(t *testing.T) {
 		},
 		{
 			txtRecord: "v=txtv0;to={?url}",
-			expected: record{
+			expected: Record{
 				Version: "txtv0",
 				To:      "https://example.com/testing",
 				Code:    302,
@@ -127,7 +127,7 @@ func TestParseRecord(t *testing.T) {
 		},
 		{
 			txtRecord: "v=txtv0;to={?url};from={method}",
-			expected: record{
+			expected: Record{
 				Version: "txtv0",
 				To:      "https://example.com/testing",
 				Code:    302,
@@ -138,7 +138,7 @@ func TestParseRecord(t *testing.T) {
 		},
 		{
 			txtRecord: "v=txtv0;ref=true;code=302",
-			expected: record{
+			expected: Record{
 				Version: "txtv0",
 				Type:    "host",
 				Code:    302,
@@ -148,7 +148,7 @@ func TestParseRecord(t *testing.T) {
 		},
 		{
 			txtRecord: "v=txtv0;ref=false;code=302",
-			expected: record{
+			expected: Record{
 				Version: "txtv0",
 				Type:    "host",
 				Code:    302,
@@ -158,7 +158,7 @@ func TestParseRecord(t *testing.T) {
 		},
 		{
 			txtRecord: "v=txtv0;type=path;code=302;>Header-1=HeaderValue",
-			expected: record{
+			expected: Record{
 				Version: "txtv0",
 				Type:    "path",
 				Code:    302,
@@ -168,7 +168,7 @@ func TestParseRecord(t *testing.T) {
 		},
 		{
 			txtRecord: "v=txtv0;type=path;code=302;>Header-1=HeaderValue;>Header-2=HeaderValue",
-			expected: record{
+			expected: Record{
 				Version: "txtv0",
 				Type:    "path",
 				Code:    302,
@@ -181,7 +181,7 @@ func TestParseRecord(t *testing.T) {
 		},
 		{
 			txtRecord: "v=txtv0;type=host;to=https://example.com;code=302;use=_redirect.example.com",
-			expected: record{
+			expected: Record{
 				Version: "txtv0",
 				Type:    "host",
 				Code:    302,
@@ -192,7 +192,7 @@ func TestParseRecord(t *testing.T) {
 		},
 		{
 			txtRecord: "v=txtv0;type=host;to=https://example.com;use=_redirect.example.com;use=_redirect.example2.com",
-			expected: record{
+			expected: Record{
 				Version: "txtv0",
 				Type:    "host",
 				Code:    302,
@@ -265,7 +265,7 @@ func TestParseRecord(t *testing.T) {
 						>X-Robots-Tag=noindex%2Cnofollow;
 						>X-UA-Compatible=Chome%3D1;
 						>X-XSS-Protection=1%3B%20mode%3Dblock`,
-			expected: record{
+			expected: Record{
 				Version: "txtv0",
 				Type:    "path",
 				Code:    302,
diff --git a/setup_test.go b/setup_test.go
deleted file mode 100644
index 65ae640..0000000
--- a/setup_test.go
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
-Copyright 2017 - The TXTDirect Authors
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-    http://www.apache.org/licenses/LICENSE-2.0
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package txtdirect
-
-import (
-	"fmt"
-	"log"
-	"strings"
-	"testing"
-
-	"github.com/caddyserver/caddy"
-)
-
-func TestCaddyParse(t *testing.T) {
-	tests := []struct {
-		input     string
-		shouldErr bool
-		expected  Config
-	}{
-		{
-			`
-			txtdirect {
-				wrong keyword
-			}
-			`,
-			true,
-			Config{},
-		},
-		{
-			`
-			txtdirect {
-				enable
-			}
-			`,
-			true,
-			Config{},
-		},
-		{
-			`
-			txtdirect {
-				disable
-			}
-			`,
-			true,
-			Config{},
-		},
-		{
-			`
-			txtdirect {
-				enable this
-				disable that
-			}
-			`,
-			true,
-			Config{},
-		},
-		{
-			`
-			txtdirect {
-				disable this
-				enable that
-			}
-			`,
-			true,
-			Config{},
-		},
-		{
-			`
-			txtdirect {
-				redirect
-			}
-			`,
-			true,
-			Config{},
-		},
-		{
-			`txtdirect`,
-			false,
-			Config{
-				Enable: allOptions,
-			},
-		},
-		{
-			`
-			txtdirect {
-				enable host
-			}
-			`,
-			false,
-			Config{
-				Enable: []string{"host"},
-			},
-		},
-		{
-			`
-			txtdirect {
-				disable host
-			}
-			`,
-			false,
-			Config{
-				Enable: []string{"path", "gometa", "www"},
-			},
-		},
-		{
-			`
-			txtdirect {
-				redirect https://example.com
-			}
-			`,
-			false,
-			Config{
-				Redirect: "https://example.com",
-				Enable:   allOptions,
-			},
-		},
-		{
-			`
-			txtdirect {
-				enable host
-				redirect https://example.com
-			}
-			`,
-			false,
-			Config{
-				Redirect: "https://example.com",
-				Enable:   []string{"host"},
-			},
-		},
-		{
-			`
-			txtdirect {
-				enable path
-				redirect https://example.com
-			}
-			`,
-			false,
-			Config{
-				Redirect: "https://example.com",
-				Enable:   []string{"path"},
-			},
-		},
-		{
-			`
-			txtdirect {
-				enable host
-				redirect https://example.com
-				prometheus
-			}
-			`,
-			false,
-			Config{
-				Redirect: "https://example.com",
-				Enable:   []string{"host"},
-				Prometheus: Prometheus{
-					Enable:  true,
-					Address: "localhost:9183",
-					Path:    "/metrics",
-				},
-			},
-		},
-		{
-			`
-			txtdirect {
-				enable host
-				redirect https://example.com
-				prometheus {
-					address localhost:6666
-					path /metrics
-				}
-			}
-			`,
-			false,
-			Config{
-				Redirect: "https://example.com",
-				Enable:   []string{"host"},
-				Prometheus: Prometheus{
-					Enable:  true,
-					Address: "localhost:6666",
-					Path:    "/metrics",
-				},
-			},
-		},
-		{
-			`
-			txtdirect {
-				enable host
-				redirect https://example.com
-				prometheus {
-					path /metrics
-					path_metrics_whitelist example.com,example.org
-				}
-			}
-			`,
-			false,
-			Config{
-				Redirect: "https://example.com",
-				Enable:   []string{"host"},
-				Prometheus: Prometheus{
-					Enable:        true,
-					Address:       "localhost:9183",
-					Path:          "/metrics",
-					PathWhitelist: []string{"example.com", "example.org"},
-				},
-			},
-		},
-		{
-			`
-			txtdirect {
-				enable host gometa
-				logfile stderr
-				resolver 127.0.0.1
-			}
-			`,
-			false,
-			Config{
-				Enable:    []string{"host", "gometa"},
-				Resolver:  "127.0.0.1",
-				LogOutput: "stderr",
-			},
-		},
-		{
-			`
-			txtdirect {
-				enable host gometa
-				logfile
-				resolver 127.0.0.1
-			}
-			`,
-			false,
-			Config{
-				Enable:    []string{"host", "gometa"},
-				Resolver:  "127.0.0.1",
-				LogOutput: "stdout",
-			},
-		},
-		{
-			`
-			txtdirect {
-				enable host
-				redirect https://example.com
-				qr {
-					size 256
-					background "#ffffff"
-					foreground "#000000"
-				}
-				resolver 127.0.0.1
-			}
-			`,
-			false,
-			Config{
-				Redirect: "https://example.com",
-				Enable:   []string{"host"},
-				Resolver: "127.0.0.1",
-				Qr: Qr{
-					Size:            256,
-					BackgroundColor: "ffffffff",
-					ForegroundColor: "000000ff",
-				},
-			},
-		},
-		{
-			`
-			txtdirect {
-				enable host
-				redirect https://example.com
-				qr {
-					size 256
-					background "#ffffff"
-					foreground "#000000"
-					recovery_level 1
-				}
-				resolver 127.0.0.1
-			}
-			`,
-			false,
-			Config{
-				Redirect: "https://example.com",
-				Enable:   []string{"host"},
-				Resolver: "127.0.0.1",
-				Qr: Qr{
-					Size:            256,
-					BackgroundColor: "ffffffff",
-					ForegroundColor: "000000ff",
-					RecoveryLevel:   1,
-				},
-			},
-		},
-		{
-			`
-			txtdirect {
-				enable host
-				redirect https://example.com
-				resolver 127.0.0.1
-				qr
-			}
-			`,
-			false,
-			Config{
-				Redirect: "https://example.com",
-				Enable:   []string{"host"},
-				Resolver: "127.0.0.1",
-				Qr: Qr{
-					Size:            256,
-					BackgroundColor: "ffffffff",
-					ForegroundColor: "00000000",
-				},
-			},
-		},
-	}
-
-	for i, test := range tests {
-		log.Println(log.Flags())
-		c := caddy.NewTestController("http", test.input)
-		conf, err := ParseConfig(c)
-		if !test.shouldErr && err != nil {
-			t.Errorf("Test %d: Unexpected error %s", i, err)
-			continue
-		}
-		if test.shouldErr {
-			if err == nil {
-				t.Errorf("Test %d: Expected error", i)
-			}
-			continue
-		}
-
-		// Check configs for each enabled type
-		for _, e := range conf.Enable {
-			switch e {
-			case "qr":
-				if conf.Qr != test.expected.Qr {
-					t.Errorf("Expected %+v for qr config got %+v", test.expected.Qr, conf.Qr)
-				}
-			}
-		}
-
-		if test.expected.Prometheus.Enable == true {
-			if conf.Prometheus.Address != test.expected.Prometheus.Address {
-				t.Errorf("Expected %s for Prometheus address, got %+s", test.expected.Prometheus.Address, conf.Prometheus.Address)
-			}
-			if conf.Prometheus.Path != test.expected.Prometheus.Path {
-				t.Errorf("Expected %s for Prometheus path, got %+s", test.expected.Prometheus.Path, conf.Prometheus.Path)
-			}
-			for _, uri := range test.expected.Prometheus.PathWhitelist {
-				if !contains(conf.Prometheus.PathWhitelist, uri) {
-					t.Errorf("Expected %s for Prometheus path metrics whitelist", uri)
-				}
-			}
-		}
-
-		if test.expected.Resolver != conf.Resolver {
-			t.Errorf("Expected resolver to be %s, but got %s", test.expected.Resolver, conf.Resolver)
-		}
-
-		if test.expected.LogOutput != conf.LogOutput {
-			t.Errorf("Expected log output to be %s, but got %s", test.expected.LogOutput, conf.LogOutput)
-		}
-
-		if !identical(conf.Enable, test.expected.Enable) {
-			options := fmt.Sprintf("[ %s ]", strings.Join(conf.Enable, ", "))
-			expected := fmt.Sprintf("[ %s ]", strings.Join(test.expected.Enable, ", "))
-			t.Errorf("Test %d: Expected options %s, got %s", i, expected, options)
-		}
-	}
-}
-
-func identical(s1, s2 []string) bool {
-	if s1 == nil {
-		if s2 == nil {
-			return true
-		}
-		return false
-	}
-	if s2 == nil {
-		return false
-	}
-
-	if len(s1) != len(s2) {
-		return false
-	}
-
-	for i := range s1 {
-		found := false
-		for j := range s2 {
-			if s1[i] == s2[j] {
-				found = true
-			}
-		}
-
-		if !found {
-			return false
-		}
-	}
-	return true
-}
diff --git a/txtdirect_test.go b/txtdirect_test.go
index ef9439f..b6a19b5 100644
--- a/txtdirect_test.go
+++ b/txtdirect_test.go
@@ -16,18 +16,12 @@ package txtdirect
 import (
 	"context"
 	"log"
-	"net/http"
 	"net/http/httptest"
-	"net/url"
 	"os"
 	"strconv"
 	"strings"
 	"testing"
-	"time"
 
-	"github.com/caddyserver/caddy/caddyhttp/header"
-	"github.com/caddyserver/caddy/caddyhttp/httpserver"
-	"github.com/caddyserver/caddy/caddyhttp/proxy"
 	"github.com/miekg/dns"
 )
 
@@ -311,13 +305,13 @@ func Test_contains(t *testing.T) {
 
 func Test_getBaseTarget(t *testing.T) {
 	tests := []struct {
-		record record
+		record Record
 		reqURL string
 		url    string
 		status int
 	}{
 		{
-			record{
+			Record{
 				To:   "https://example.test",
 				Code: 200,
 			},
@@ -326,7 +320,7 @@ func Test_getBaseTarget(t *testing.T) {
 			200,
 		},
 		{
-			record{
+			Record{
 				To:   "https://{host}/{method}",
 				Code: 200,
 			},
@@ -335,7 +329,7 @@ func Test_getBaseTarget(t *testing.T) {
 			200,
 		},
 		{
-			record{
+			Record{
 				To:   "https://testing.test{path}",
 				Code: 301,
 			},
@@ -358,176 +352,3 @@ func Test_getBaseTarget(t *testing.T) {
 		}
 	}
 }
-
-// Note: ServerHeader isn't a function, this test is for checking
-// response's Server header.
-func TestServerHeaderE2E(t *testing.T) {
-	tests := []struct {
-		url          string
-		enable       []string
-		headerPlugin bool
-		proxyPlugin  bool
-		expected     string
-	}{
-		{
-			"https://host.host.example.com",
-			[]string{"host"},
-			false,
-			false,
-			"TXTDirect",
-		},
-		{
-			"https://host.host.example.com",
-			[]string{"host"},
-			true,
-			false,
-			"Testing-TXTDirect",
-		},
-		{
-			"https://host.host.example.com",
-			[]string{"host"},
-			false,
-			true,
-			"Testing-TXTDirect",
-		},
-	}
-	for _, test := range tests {
-		req := httptest.NewRequest("GET", test.url, nil)
-		resp := httptest.NewRecorder()
-		c := Config{
-			Resolver: "127.0.0.1:" + strconv.Itoa(port),
-			Enable:   test.enable,
-		}
-		err := Redirect(resp, req, c)
-		if err != nil {
-			t.Errorf("Unexpected Error: %s", err.Error())
-		}
-
-		// Use Caddy's header plugin to replace the header
-		if test.headerPlugin {
-			s := header.Headers{
-				Next: httpserver.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
-					w.WriteHeader(http.StatusOK)
-					return 0, nil
-				}),
-				Rules: []header.Rule{
-					{Path: "/", Headers: http.Header{
-						"Server": []string{test.expected},
-					}},
-				},
-			}
-			_, err := s.ServeHTTP(resp, req)
-			if err != nil {
-				t.Errorf("Couldn't replace the header using caddy's header plugin: %s", err.Error())
-			}
-		}
-
-		if test.proxyPlugin {
-			backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-				w.Header().Set("Server", test.expected)
-				w.WriteHeader(http.StatusOK)
-				w.Write([]byte("Hello, client"))
-			}))
-			defer backend.Close()
-
-			// Setup the fake upsteam
-			uri, _ := url.Parse(backend.URL)
-			u := fakeUpstream{
-				name:          backend.URL,
-				from:          "/",
-				timeout:       proxyTimeout,
-				fallbackDelay: fallbackDelay,
-				host: &proxy.UpstreamHost{
-					Name:         backend.URL,
-					ReverseProxy: proxy.NewSingleHostReverseProxy(uri, "", http.DefaultMaxIdleConnsPerHost, proxyTimeout, fallbackDelay),
-				},
-			}
-
-			p := &proxy.Proxy{
-				Next:      httpserver.EmptyNext, // prevents panic in some cases when test fails
-				Upstreams: []proxy.Upstream{&u},
-			}
-			p.ServeHTTP(resp, req)
-		}
-
-		if !contains(resp.Header()["Server"], test.expected) {
-			t.Errorf("Expected \"Server\" header to be %s but it's %s", test.expected, resp.Header().Get("Server"))
-		}
-	}
-}
-
-// Note: RecordHeaders isn't a function, this test is for checking
-// response's headers with the custom headers in the record.
-func TestRecordHeadersE2E(t *testing.T) {
-	tests := []struct {
-		url     string
-		headers map[string]string
-	}{
-		{
-			"https://host.host.example.com",
-			map[string]string{"TestHeader": "TestValue"},
-		},
-		{
-			"https://path.path.example.com/host",
-			map[string]string{
-				"TestHeader":  "TestValue",
-				"TestHeader1": "TestValue1",
-			},
-		},
-		{
-			"https://host.host.example.com",
-			map[string]string{"testheader": "TestValue"},
-		},
-	}
-	for _, test := range tests {
-		req := httptest.NewRequest("GET", test.url, nil)
-		resp := httptest.NewRecorder()
-		c := Config{
-			Resolver: "127.0.0.1:" + strconv.Itoa(port),
-			Enable:   []string{"host", "path"},
-		}
-		err := Redirect(resp, req, c)
-		if err != nil {
-			t.Errorf("Unexpected Error: %s", err.Error())
-		}
-
-		for header, val := range test.headers {
-			if resp.Header().Get(header) != val {
-				t.Errorf("Expected \"%s\" header to be %s but it's %s", header, val, resp.Header().Get(header))
-			}
-		}
-
-	}
-}
-
-// Setup fakeUpstream type and methods
-type fakeUpstream struct {
-	name          string
-	host          *proxy.UpstreamHost
-	from          string
-	without       string
-	timeout       time.Duration
-	fallbackDelay time.Duration
-}
-
-func (u *fakeUpstream) AllowedPath(requestPath string) bool { return true }
-func (u *fakeUpstream) GetFallbackDelay() time.Duration     { return 300 * time.Millisecond }
-func (u *fakeUpstream) GetTryDuration() time.Duration       { return 1 * time.Second }
-func (u *fakeUpstream) GetTryInterval() time.Duration       { return 250 * time.Millisecond }
-func (u *fakeUpstream) GetTimeout() time.Duration           { return u.timeout }
-func (u *fakeUpstream) GetHostCount() int                   { return 1 }
-func (u *fakeUpstream) Stop() error                         { return nil }
-func (u *fakeUpstream) From() string                        { return u.from }
-func (u *fakeUpstream) Select(r *http.Request) *proxy.UpstreamHost {
-	if u.host == nil {
-		uri, err := url.Parse(u.name)
-		if err != nil {
-			log.Fatalf("Unable to url.Parse %s: %v", u.name, err)
-		}
-		u.host = &proxy.UpstreamHost{
-			Name:         u.name,
-			ReverseProxy: proxy.NewSingleHostReverseProxy(uri, u.without, http.DefaultMaxIdleConnsPerHost, u.GetTimeout(), u.GetFallbackDelay()),
-		}
-	}
-	return u.host
-}