├── fragments_test.go
├── example
├── fragments
│ ├── fallback.html
│ ├── fragment5.html
│ ├── fragment6.html
│ ├── fragment1.html
│ ├── fragment4.html
│ ├── fragment2.html
│ └── main.go
├── views
│ ├── layouts
│ │ └── main.html
│ └── index.html
└── main.go
├── SECURITY.md
├── .devcontainer
└── devcontainer.json
├── go.mod
├── .editorconfig
├── .envsh
├── .envrc
├── .github
└── workflows
│ └── main.yaml
├── LICENSE
├── CONTRIBUTING.md
├── resolver.go
├── document.go
├── links.go
├── CODE_OF_CONDUCT.md
├── .gitignore
├── README.md
├── fragments.go
├── fragment.go
└── go.sum
/fragments_test.go:
--------------------------------------------------------------------------------
1 | package fragments
2 |
--------------------------------------------------------------------------------
/example/fragments/fallback.html:
--------------------------------------------------------------------------------
1 |
{{ .Title }}
2 | This is a fallback fragment
--------------------------------------------------------------------------------
/example/fragments/fragment5.html:
--------------------------------------------------------------------------------
1 | {{ .Title }}
2 |
3 | Forward referenced content 1
4 |
--------------------------------------------------------------------------------
/example/fragments/fragment6.html:
--------------------------------------------------------------------------------
1 | {{ .Title }}
2 |
3 | Forward referenced content 2
4 |
--------------------------------------------------------------------------------
/example/fragments/fragment1.html:
--------------------------------------------------------------------------------
1 | {{ .Title }}
2 |
3 | - Number one
4 | - Number two
5 | - Number three
6 |
--------------------------------------------------------------------------------
/example/fragments/fragment4.html:
--------------------------------------------------------------------------------
1 | {{ .Title }}
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/example/views/layouts/main.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Main
6 |
7 |
8 |
9 | {{embed}}
10 |
11 |
12 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | If you discover a security issue in this repo, please submit it through the [GitHub Security Bug Bounty](https://hackerone.com/github)
2 |
3 | Thanks for helping make GitHub Actions safe for everyone.
4 |
--------------------------------------------------------------------------------
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "github/fiber-fragments",
3 | "image": "mcr.microsoft.com/vscode/devcontainers/go:latest",
4 | "forwardPorts": [8080],
5 | "appPort": [8080],
6 | "portsAttributes": {
7 | "8080": {
8 | "label": "web"
9 | }
10 | },
11 | "extensions": [
12 | "golang.Go"
13 | ],
14 | }
15 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/github/fiber-fragments
2 |
3 | go 1.16
4 |
5 | require (
6 | github.com/PuerkitoBio/goquery v1.7.0
7 | github.com/gofiber/fiber/v2 v2.13.0
8 | github.com/gofiber/template v1.6.12
9 | github.com/google/uuid v1.0.0
10 | github.com/valyala/fasthttp v1.26.0
11 | golang.org/x/net v0.0.0-20210510120150-4163338589ed
12 | )
13 |
--------------------------------------------------------------------------------
/example/views/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | charset = utf-8
7 | indent_style = space
8 | indent_size = 2
9 | end_of_line = lf
10 | insert_final_newline = true
11 | trim_trailing_whitespace = true
12 |
13 | [*.md]
14 | insert_final_newline = false
15 | trim_trailing_whitespace = false
16 |
17 | [{Makefile,**.mk}]
18 | # Use tabs for indentation (Makefiles require tabs)
19 | indent_style = tab
--------------------------------------------------------------------------------
/example/fragments/fragment2.html:
--------------------------------------------------------------------------------
1 | {{ .Title }}
2 |
3 | - Number one
4 | - Number two
5 | - Number three
6 |
7 |
8 |
9 | - Number one
10 | - Number two
11 | - Number three
12 |
13 |
14 |
15 | - Number one
16 | - Number two
17 | - Number three
18 |
19 |
20 |
21 | - Number one
22 | - Number two
23 | - Number three
24 |
--------------------------------------------------------------------------------
/example/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/gofiber/fiber/v2"
5 | "github.com/gofiber/template/html"
6 |
7 | fragments "github.com/github/fiber-fragments"
8 | )
9 |
10 | func main() {
11 | // Create a new engine
12 | engine := html.New("./views", ".html")
13 |
14 | // Pass the engine to the Views
15 | app := fiber.New(fiber.Config{
16 | Views: engine,
17 | })
18 |
19 | app.Get("/index", fragments.Template(fragments.Config{}, "index", fiber.Map{}, "layouts/main"))
20 |
21 | if err := app.Listen(":8080"); err != nil {
22 | panic(err)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/.envsh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | SCRIPT=`python -c "import os,sys; print(os.path.realpath(os.path.expanduser(sys.argv[1])))" "${BASH_SOURCE:-$0}"`
3 | export PROJECT_DIR=$(dirname $SCRIPT)
4 | export GO111MODULE=on
5 | export DOCKER_HOST_IP=127.0.0.1
6 | export GOPROXY=direct
7 | export PATH=$PATH:$PWD/bin
8 |
9 | WANT_VERSION=$(cat .goversion)
10 | GOT_VERSION=$(go version | awk '{print $3}')
11 | if [ "$WANT_VERSION" != "$GOT_VERSION" ]; then
12 | echo "!! The example is using $WANT_VERSION, but you're running $GOT_VERSION."
13 | echo "!! Some operations may not work as expected."
14 | fi
15 |
--------------------------------------------------------------------------------
/.envrc:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | SCRIPT=`python -c "import os,sys; print(os.path.realpath(os.path.expanduser(sys.argv[1])))" "${BASH_SOURCE:-$0}"`
3 | export PROJECT_DIR=$(dirname $SCRIPT)
4 |
5 | export GO111MODULE=on
6 | export DOCKER_HOST_IP=127.0.0.1
7 | export GOPROXY=direct
8 | export PATH=$PATH:$PWD/bin
9 |
10 | WANT_VERSION=$(cat .goversion)
11 | GOT_VERSION=$(go version | awk '{print $3}')
12 | if [ "$WANT_VERSION" != "$GOT_VERSION" ]; then
13 | echo "!! The example is using $WANT_VERSION, but you're running $GOT_VERSION."
14 | echo "!! Some operations may not work as expected."
15 | fi
16 |
--------------------------------------------------------------------------------
/.github/workflows/main.yaml:
--------------------------------------------------------------------------------
1 | # .github/workflows/main.yaml
2 | name: main
3 |
4 | on:
5 | push:
6 | branches:
7 | - main
8 | - release/*
9 | pull_request:
10 | branches:
11 | - main
12 |
13 | jobs:
14 | golangci:
15 | name: lint
16 | runs-on: ubuntu-latest
17 | steps:
18 | - uses: actions/checkout@v2
19 |
20 | - name: golangci-lint
21 | uses: golangci/golangci-lint-action@v2
22 | with:
23 | version: v1.29
24 |
25 | test:
26 | runs-on: ubuntu-latest
27 | steps:
28 | - name: Check out code into the Go module directory
29 | uses: actions/checkout@v2
30 |
31 | - name: Setup go
32 | uses: actions/setup-go@v2
33 |
34 | - name: Static Check
35 | run: GOBIN=$PWD/bin go install honnef.co/go/tools/cmd/staticcheck && ./bin/staticcheck ./...
36 |
37 | - name: Run Tests
38 | run: go test -cover -p 1 -race -v ./...
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 GitHub
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/example/fragments/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/gofiber/fiber/v2"
7 | "github.com/gofiber/template/html"
8 | )
9 |
10 | func main() {
11 | // Create a new engine
12 | engine := html.New(".", ".html")
13 |
14 | // Pass the engine to the Views
15 | app := fiber.New(fiber.Config{
16 | Views: engine,
17 | })
18 |
19 | app.Get("/fragment1", func(c *fiber.Ctx) error {
20 | c.Links("https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css", "stylesheet")
21 |
22 | return c.Render("fragment1", fiber.Map{
23 | "Title": "Example 1",
24 | })
25 | })
26 |
27 | app.Get("/fragment2", func(c *fiber.Ctx) error {
28 | c.Links("https://unpkg.com/react-dom@17/umd/react-dom.development.js", "script", "")
29 |
30 | c.Response().SetStatusCode(403)
31 |
32 | return c.Render("fragment2", fiber.Map{
33 | "Title": "Example 2",
34 | })
35 | })
36 |
37 | app.Get("/fragment3", func(c *fiber.Ctx) error {
38 | timer1 := time.NewTimer(90 * time.Second)
39 |
40 | <-timer1.C // wait here for fallback
41 |
42 | return c.Render("fragment3", fiber.Map{
43 | "Title": "Example 3",
44 | })
45 | })
46 |
47 | app.Get("/fragment4", func(c *fiber.Ctx) error {
48 | return c.Render("fragment4", fiber.Map{
49 | "Title": "Example 4",
50 | })
51 | })
52 |
53 | app.Get("/fragment5", func(c *fiber.Ctx) error {
54 | return c.Render("fragment5", fiber.Map{
55 | "Title": "Example 5",
56 | })
57 | })
58 |
59 | app.Get("/fragment6", func(c *fiber.Ctx) error {
60 | return c.Render("fragment6", fiber.Map{
61 | "Title": "Example 6",
62 | })
63 | })
64 |
65 | app.Get("/fallback", func(c *fiber.Ctx) error {
66 | return c.Render("fallback", fiber.Map{
67 | "Title": "Fallback",
68 | })
69 | })
70 |
71 | if err := app.Listen(":3000"); err != nil {
72 | panic(err)
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Contributing
2 |
3 | [fork]: https://github.com/github/fiber-fragments/fork
4 | [pr]: https://github.com/github/fiber-fragments/compare
5 | [style]: https://golang.org/doc/effective_go
6 | [code-of-conduct]: CODE_OF_CONDUCT.md
7 |
8 | Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great.
9 |
10 | Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE).
11 |
12 | Please note that this project is released with a [Contributor Code of Conduct][CODE_OF_CONDUCT.md]. By participating in this project you agree to abide by its terms.
13 |
14 | ## Submitting a pull request
15 |
16 | 0. [Fork][fork] and clone the repository
17 | 0. Verify that all tests are passing `go test ./...`
18 | 0. Create a new branch: `git checkout -b my-branch-name`
19 | 0. Make your change, add tests, and make sure the tests still pass
20 | 0. Push to your fork and [submit a pull request][pr]
21 | 0. Pat your self on the back and wait for your pull request to be reviewed and merged.
22 |
23 | Here are a few things you can do that will increase the likelihood of your pull request being accepted:
24 |
25 | - Follow the [style guide][style].
26 | - Write tests.
27 | - Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests.
28 | - Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
29 |
30 | ## Resources
31 |
32 | - [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
33 | - [Using Pull Requests](https://help.github.com/articles/about-pull-requests/)
34 | - [GitHub Help](https://help.github.com)
--------------------------------------------------------------------------------
/resolver.go:
--------------------------------------------------------------------------------
1 | package fragments
2 |
3 | import (
4 | "sync"
5 |
6 | "github.com/gofiber/fiber/v2"
7 | "golang.org/x/net/html"
8 | )
9 |
10 | // Resolver ...
11 | type Resolver struct {
12 | wg sync.WaitGroup
13 | }
14 |
15 | // NewResolver ...
16 | func NewResolver() *Resolver {
17 | return &Resolver{}
18 | }
19 |
20 | // ResolverFunc ...
21 | type ResolverFunc func(c *fiber.Ctx, cfg Config) error
22 |
23 | // Resolve blocks until all fragments have been called.
24 | func (r *Resolver) Resolve(c *fiber.Ctx, cfg Config, doc *HtmlFragment) (int, []*html.Node, error) {
25 | statusCode := fiber.StatusOK
26 | head := make([]*html.Node, 0)
27 |
28 | ff, err := doc.Fragments()
29 | if err != nil {
30 | return statusCode, head, err
31 | }
32 |
33 | for _, f := range ff {
34 | r.run(c, cfg, f.Resolve())
35 | }
36 |
37 | r.wg.Wait()
38 |
39 | for _, f := range ff {
40 | if f.Primary() && f.statusCode != 0 {
41 | statusCode = f.statusCode
42 | }
43 |
44 | fw, err := f.HtmlFragment().Fragments()
45 | if err != nil {
46 | return statusCode, head, err
47 | }
48 |
49 | for _, fwr := range fw {
50 | if fwr.Ref() == "" {
51 | continue
52 | }
53 |
54 | ref, ok := ff[fwr.Ref()]
55 | if !ok {
56 | continue
57 | }
58 |
59 | html, err := ref.HtmlFragment().Html()
60 | if err != nil {
61 | return statusCode, head, err
62 | }
63 |
64 | fwr.Element().ReplaceWithHtml(html)
65 | }
66 |
67 | html, err := f.HtmlFragment().Html()
68 | if err != nil {
69 | return statusCode, head, err
70 | }
71 |
72 | f.Element().ReplaceWithHtml(html)
73 |
74 | head = append(head, f.Links()...)
75 | }
76 |
77 | return statusCode, head, nil
78 | }
79 |
80 | func (r *Resolver) run(c *fiber.Ctx, cfg Config, fn ResolverFunc) {
81 | r.wg.Add(1)
82 |
83 | go func() {
84 | defer r.wg.Done()
85 |
86 | err := fn(c, cfg)
87 | if err != nil {
88 | return // ignoring errors for now
89 | }
90 | }()
91 | }
92 |
--------------------------------------------------------------------------------
/document.go:
--------------------------------------------------------------------------------
1 | package fragments
2 |
3 | import (
4 | "sync"
5 |
6 | "github.com/PuerkitoBio/goquery"
7 | "github.com/gofiber/fiber/v2"
8 | "golang.org/x/net/html"
9 | )
10 |
11 | // Document ...
12 | type Document struct {
13 | doc *goquery.Document
14 | html *HtmlFragment
15 | statusCode int
16 |
17 | sync.RWMutex
18 | }
19 |
20 | // NewDocument ...
21 | func NewDocument(root *html.Node) (*Document, error) {
22 | d := new(Document)
23 | // set the default status code
24 | d.statusCode = fiber.StatusOK
25 |
26 | html, err := NewHtmlFragment(root)
27 | if err != nil {
28 | return nil, err
29 | }
30 | d.html = html
31 |
32 | return d, nil
33 | }
34 |
35 | // Html is returning the final HTML output.
36 | func (d *Document) Html() (string, error) {
37 | d.RLock()
38 | defer d.RUnlock()
39 |
40 | html, err := d.html.Html()
41 | if err != nil {
42 | return "", err
43 | }
44 |
45 | return html, nil
46 | }
47 |
48 | // Fragments is returning the selection of fragments
49 | // from an HTML page.
50 | func (d *Document) Fragments() ([]*Fragment, error) {
51 | d.RLock()
52 | defer d.RUnlock()
53 |
54 | scripts := d.doc.Find("head script[type=fragment]")
55 | fragments := d.doc.Find("fragment").AddSelection(scripts)
56 |
57 | ff := make([]*Fragment, 0, fragments.Length())
58 |
59 | fragments.Each(func(i int, s *goquery.Selection) {
60 | f := FromSelection(s)
61 |
62 | if !f.deferred {
63 | ff = append(ff, f)
64 | }
65 | })
66 |
67 | return ff, nil
68 | }
69 |
70 | // Fragments is returning the selection of fragments
71 | // from an HTML page.
72 | func (d *Document) HtmlFragment() *HtmlFragment {
73 | d.RLock()
74 | defer d.RUnlock()
75 |
76 | return d.html
77 | }
78 |
79 | // SetStatusCode is setting the HTTP status code for the document.
80 | func (d *Document) SetStatusCode(status int) {
81 | d.Lock()
82 | defer d.Unlock() // could do this atomic
83 |
84 | d.statusCode = status
85 | }
86 |
87 | // StatusCode is getting the HTTP status code for the document.
88 | func (d *Document) StatusCode() int {
89 | d.RLock()
90 | defer d.RUnlock()
91 |
92 | return d.statusCode
93 | }
94 |
--------------------------------------------------------------------------------
/links.go:
--------------------------------------------------------------------------------
1 | package fragments
2 |
3 | import (
4 | "strings"
5 |
6 | "golang.org/x/net/html"
7 | "golang.org/x/net/html/atom"
8 | )
9 |
10 | const (
11 | StyleSheet = "stylesheet"
12 | Script = "script"
13 | )
14 |
15 | // Link ...
16 | type Link struct {
17 | URL string
18 | Rel string
19 | Params map[string]string
20 | }
21 |
22 | // Header ...
23 | type Header string
24 |
25 | // Link ...
26 | func (s Header) Links() []Link {
27 | links := make([]Link, 0)
28 |
29 | for _, chunk := range strings.Split(string(s), ",") {
30 |
31 | l := Link{URL: "", Rel: "", Params: make(map[string]string)}
32 |
33 | for _, part := range strings.Split(chunk, ";") {
34 | part = strings.Trim(part, " ")
35 | if part == "" {
36 | continue
37 | }
38 | if part[0] == '<' && part[len(part)-1] == '>' {
39 | l.URL = strings.Trim(part, "<>")
40 | continue
41 | }
42 |
43 | key, val := parseParam(part)
44 | if key == "" {
45 | continue
46 | }
47 |
48 | if strings.ToLower(key) == "rel" {
49 | l.Rel = val
50 |
51 | continue
52 | }
53 | l.Params[key] = val
54 | }
55 |
56 | if l.URL != "" {
57 | links = append(links, l)
58 | }
59 | }
60 |
61 | return links
62 | }
63 |
64 | // FilterByStylesheet ...
65 | func FilterByStylesheet(links ...Link) []Link {
66 | return FilterByRel(links, "stylesheet")
67 | }
68 |
69 | // FilterByStylesheet ...
70 | func FilterByScript(links ...Link) []Link {
71 | return FilterByRel(links, "script")
72 | }
73 |
74 | // FilterByRel ...
75 | func FilterByRel(links []Link, rel string) []Link {
76 | ll := make([]Link, 0)
77 |
78 | for _, l := range links {
79 | if l.Rel != rel {
80 | continue
81 | }
82 |
83 | ll = append(ll, l)
84 | }
85 |
86 | return ll
87 | }
88 |
89 | // CreateNodes ...
90 | func CreateNodes(links []Link) []*html.Node {
91 | nodes := make([]*html.Node, 0)
92 |
93 | for _, s := range links {
94 | attr := make([]html.Attribute, 0)
95 |
96 | if s.Rel == Script {
97 | attr = append(attr, html.Attribute{Key: "src", Val: s.URL})
98 | }
99 |
100 | if s.Rel == StyleSheet {
101 | attr = append(attr, html.Attribute{Key: "href", Val: s.URL})
102 | attr = append(attr, html.Attribute{Key: "rel", Val: s.Rel})
103 | }
104 |
105 | for k, p := range s.Params {
106 | attr = append(attr, html.Attribute{Key: k, Val: p})
107 | }
108 |
109 | node := &html.Node{
110 | Type: html.ElementNode,
111 | Attr: attr,
112 | }
113 |
114 | if s.Rel == "script" {
115 | node.Data = "script"
116 | node.DataAtom = atom.Script
117 | }
118 |
119 | if s.Rel == "stylesheet" {
120 | node.Data = "link"
121 | node.DataAtom = atom.Link
122 | }
123 |
124 | nodes = append(nodes, node)
125 | }
126 |
127 | return nodes
128 | }
129 |
130 | func parseParam(raw string) (key, val string) {
131 | parts := strings.SplitN(raw, "=", 2)
132 | if len(parts) == 1 {
133 | return parts[0], ""
134 | }
135 | if len(parts) != 2 {
136 | return "", ""
137 | }
138 |
139 | key = parts[0]
140 | val = strings.Trim(parts[1], "\"")
141 |
142 | return key, val
143 | }
144 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | +++
2 | version = "1.4"
3 | aliases = ["/version/1/4"]
4 | +++
5 |
6 | # Contributor Covenant Code of Conduct
7 |
8 | ## Our Pledge
9 |
10 | In the interest of fostering an open and welcoming environment, we as
11 | contributors and maintainers pledge to make participation in our project and
12 | our community a harassment-free experience for everyone, regardless of age, body
13 | size, disability, ethnicity, sex characteristics, gender identity and expression,
14 | level of experience, education, socio-economic status, nationality, personal
15 | appearance, race, religion, or sexual identity and orientation.
16 |
17 | ## Our Standards
18 |
19 | Examples of behavior that contributes to creating a positive environment
20 | include:
21 |
22 | * Using welcoming and inclusive language
23 | * Being respectful of differing viewpoints and experiences
24 | * Gracefully accepting constructive criticism
25 | * Focusing on what is best for the community
26 | * Showing empathy towards other community members
27 |
28 | Examples of unacceptable behavior by participants include:
29 |
30 | * The use of sexualized language or imagery and unwelcome sexual attention or
31 | advances
32 | * Trolling, insulting/derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or electronic
35 | address, without explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Our Responsibilities
40 |
41 | Project maintainers are responsible for clarifying the standards of acceptable
42 | behavior and are expected to take appropriate and fair corrective action in
43 | response to any instances of unacceptable behavior.
44 |
45 | Project maintainers have the right and responsibility to remove, edit, or
46 | reject comments, commits, code, wiki edits, issues, and other contributions
47 | that are not aligned to this Code of Conduct, or to ban temporarily or
48 | permanently any contributor for other behaviors that they deem inappropriate,
49 | threatening, offensive, or harmful.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all project spaces, and it also applies when
54 | an individual is representing the project or its community in public spaces.
55 | Examples of representing a project or community include using an official
56 | project e-mail address, posting via an official social media account, or acting
57 | as an appointed representative at an online or offline event. Representation of
58 | a project may be further defined and clarified by project maintainers.
59 |
60 | ## Enforcement
61 |
62 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
63 | reported by contacting the project team at opensource@github.com. All
64 | complaints will be reviewed and investigated and will result in a response that
65 | is deemed necessary and appropriate to the circumstances. The project team is
66 | obligated to maintain confidentiality with regard to the reporter of an incident.
67 | Further details of specific enforcement policies may be posted separately.
68 |
69 | Project maintainers who do not follow or enforce the Code of Conduct in good
70 | faith may face temporary or permanent repercussions as determined by other
71 | members of the project's leadership.
72 |
73 | ## Attribution
74 |
75 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
76 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
77 |
78 | [homepage]: https://www.contributor-covenant.org
79 |
80 | For answers to common questions about this code of conduct, see
81 | https://www.contributor-covenant.org/faq
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.toptal.com/developers/gitignore/api/go,webstorm,intellij
2 | # Edit at https://www.toptal.com/developers/gitignore?templates=go,webstorm,intellij
3 |
4 | ### Go ###
5 | # Binaries for programs and plugins
6 | *.exe
7 | *.exe~
8 | *.dll
9 | *.so
10 | *.dylib
11 |
12 | # Test binary, built with `go test -c`
13 | *.test
14 |
15 | # Output of the go coverage tool, specifically when used with LiteIDE
16 | *.out
17 |
18 | # Dependency directories (remove the comment below to include it)
19 | # vendor/
20 |
21 | ### Go Patch ###
22 | /vendor/
23 | /Godeps/
24 |
25 | ### Intellij ###
26 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
27 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
28 |
29 | # User-specific stuff
30 | .idea/**/workspace.xml
31 | .idea/**/tasks.xml
32 | .idea/**/usage.statistics.xml
33 | .idea/**/dictionaries
34 | .idea/**/shelf
35 |
36 | # Generated files
37 | .idea/**/contentModel.xml
38 |
39 | # Sensitive or high-churn files
40 | .idea/**/dataSources/
41 | .idea/**/dataSources.ids
42 | .idea/**/dataSources.local.xml
43 | .idea/**/sqlDataSources.xml
44 | .idea/**/dynamic.xml
45 | .idea/**/uiDesigner.xml
46 | .idea/**/dbnavigator.xml
47 |
48 | # Gradle
49 | .idea/**/gradle.xml
50 | .idea/**/libraries
51 |
52 | # Gradle and Maven with auto-import
53 | # When using Gradle or Maven with auto-import, you should exclude module files,
54 | # since they will be recreated, and may cause churn. Uncomment if using
55 | # auto-import.
56 | # .idea/artifacts
57 | # .idea/compiler.xml
58 | # .idea/jarRepositories.xml
59 | # .idea/modules.xml
60 | # .idea/*.iml
61 | # .idea/modules
62 | # *.iml
63 | # *.ipr
64 |
65 | # CMake
66 | cmake-build-*/
67 |
68 | # Mongo Explorer plugin
69 | .idea/**/mongoSettings.xml
70 |
71 | # File-based project format
72 | *.iws
73 |
74 | # IntelliJ
75 | out/
76 |
77 | # mpeltonen/sbt-idea plugin
78 | .idea_modules/
79 |
80 | # JIRA plugin
81 | atlassian-ide-plugin.xml
82 |
83 | # Cursive Clojure plugin
84 | .idea/replstate.xml
85 |
86 | # Crashlytics plugin (for Android Studio and IntelliJ)
87 | com_crashlytics_export_strings.xml
88 | crashlytics.properties
89 | crashlytics-build.properties
90 | fabric.properties
91 |
92 | # Editor-based Rest Client
93 | .idea/httpRequests
94 |
95 | # Android studio 3.1+ serialized cache file
96 | .idea/caches/build_file_checksums.ser
97 |
98 | ### Intellij Patch ###
99 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
100 |
101 | # *.iml
102 | # modules.xml
103 | # .idea/misc.xml
104 | # *.ipr
105 |
106 | # Sonarlint plugin
107 | # https://plugins.jetbrains.com/plugin/7973-sonarlint
108 | .idea/**/sonarlint/
109 |
110 | # SonarQube Plugin
111 | # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
112 | .idea/**/sonarIssues.xml
113 |
114 | # Markdown Navigator plugin
115 | # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
116 | .idea/**/markdown-navigator.xml
117 | .idea/**/markdown-navigator-enh.xml
118 | .idea/**/markdown-navigator/
119 |
120 | # Cache file creation bug
121 | # See https://youtrack.jetbrains.com/issue/JBR-2257
122 | .idea/$CACHE_FILE$
123 |
124 | # CodeStream plugin
125 | # https://plugins.jetbrains.com/plugin/12206-codestream
126 | .idea/codestream.xml
127 |
128 | ### WebStorm ###
129 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
130 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
131 |
132 | # User-specific stuff
133 |
134 | # Generated files
135 |
136 | # Sensitive or high-churn files
137 |
138 | # Gradle
139 |
140 | # Gradle and Maven with auto-import
141 | # When using Gradle or Maven with auto-import, you should exclude module files,
142 | # since they will be recreated, and may cause churn. Uncomment if using
143 | # auto-import.
144 | # .idea/artifacts
145 | # .idea/compiler.xml
146 | # .idea/jarRepositories.xml
147 | # .idea/modules.xml
148 | # .idea/*.iml
149 | # .idea/modules
150 | # *.iml
151 | # *.ipr
152 |
153 | # CMake
154 |
155 | # Mongo Explorer plugin
156 |
157 | # File-based project format
158 |
159 | # IntelliJ
160 |
161 | # mpeltonen/sbt-idea plugin
162 |
163 | # JIRA plugin
164 |
165 | # Cursive Clojure plugin
166 |
167 | # Crashlytics plugin (for Android Studio and IntelliJ)
168 |
169 | # Editor-based Rest Client
170 |
171 | # Android studio 3.1+ serialized cache file
172 |
173 | ### WebStorm Patch ###
174 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
175 |
176 | # *.iml
177 | # modules.xml
178 | # .idea/misc.xml
179 | # *.ipr
180 |
181 | # Sonarlint plugin
182 | # https://plugins.jetbrains.com/plugin/7973-sonarlint
183 |
184 | # SonarQube Plugin
185 | # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
186 |
187 | # Markdown Navigator plugin
188 | # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
189 |
190 | # Cache file creation bug
191 | # See https://youtrack.jetbrains.com/issue/JBR-2257
192 |
193 | # CodeStream plugin
194 | # https://plugins.jetbrains.com/plugin/12206-codestream
195 |
196 | # End of https://www.toptal.com/developers/gitignore/api/go,webstorm,intellij
197 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Fragments
2 |
3 | [](https://github.com/github/fiber-fragments/actions/workflows/main.yaml)
4 | [](https://goreportcard.com/report/github.com/github/fiber-fragments)
5 | [](https://opensource.org/licenses/MIT)
6 | [](https://twitter.com/SwiftOnSecurity)
7 |
8 | Fragments middleware for [Fiber](https://github.com/gofiber/fiber) enables building microservices for the frontend.
9 |
10 | A `` symbolizes a part of a template that can be served by a singular microservice. Thus, making a fragment the contract between different services and teams within a large engineering organization. The middleware concurrently fetches those parts from the service and replaces it in the template. It supports `GET` and `POST` [HTTP methods](https://developer.mozilla.org/de/docs/Web/HTTP/Methods) to fetcht the content. Related resources like CSS or JavaScript are injected via the [HTTP `LINK` entity header field](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link). A `` can occure in the [`body` element](https://developer.mozilla.org/de/docs/Web/HTML/Element/body) or the [`header` element](https://developer.mozilla.org/de/docs/Web/HTML/Element/header). See [Example](#example) to learn more about using fragments.
11 |
12 | [Tailor](https://github.com/zalando/tailor) by Zalando is prior art for this middleware.
13 |
14 | ## Fragement(s)
15 |
16 | A `fragment` will be hybrid-polymorphic (if this is a thing). On the server it is parsed and evaluate by the middleware. 🦄 In the browser it will be a web component that received data from the middleware (**this is still work in progress ⚠️**).
17 |
18 | ### Server
19 |
20 | * `src` The source to fetch for replacement in the DOM
21 | * `method` can be of `GET` (default) or `POST`.
22 | * `primary` denotes a fragment that sets the response code of the page
23 | * `id` is an optional unique identifier (optional)
24 | * `ref`is an optional forward reference to an `id` (optional)
25 | * `timeout` timeout of a fragement to receive in milliseconds (default is `300`)
26 | * `deferred` is deferring the fetch to the browser
27 | * `fallback` is the fallback source in case of timeout/error on the current fragment
28 |
29 |
30 | ## Example
31 |
32 | Import the middleware package this is part of the Fiber web framework.
33 |
34 | ```go
35 | package main
36 |
37 | import (
38 | "github.com/gofiber/fiber/v2"
39 | "github.com/gofiber/template/html"
40 |
41 | "github.com/github/fiber-fragments"
42 | )
43 | ```
44 |
45 | After you initiate your Fiber app, you can plugin in the fragments middleware. The middleware draws the templates for the fragments to load from the template engine. Thus it supports using all [template](https://github.com/gofiber/template) engines supported by the Fiber team.
46 |
47 | ```go
48 | // Create a new engine
49 | engine := html.New("./views", ".html")
50 |
51 | // Pass the engine to the Views
52 | app := fiber.New(fiber.Config{
53 | Views: engine,
54 | })
55 |
56 | // Associates the route with a specific template with fragments to render
57 | app.Get("/index", fragments.Template(fragments.Config{}, "index", fiber.Map{}, "layouts/main"))
58 |
59 | // this would listen to port 8080
60 | app.Listen(":8080")
61 | ```
62 |
63 | ```html
64 |
65 |
66 |
67 |
68 |
69 | Example
70 |
71 |
72 |
73 | ```
74 |
75 | The `example` folder contains many examples. You can learn how to use a forward reference of content for fetching outer and inner content and replace either one.
76 |
77 | ## Benchmark(s)
78 |
79 | This is run on a MacBook Pro 16 inch locally. It is the `example` run.
80 |
81 | * Parsing a local template with extrapolation with the fragments
82 | * Parsing the fragments
83 | * Doing fragments
84 | * Inlining results and adding `Link` header resources to the output
85 |
86 | ```bash
87 | echo "GET http://127.0.0.1:8080/index" | vegeta attack -duration=5s -rate 2000 | tee results.bin | vegeta report
88 | vegeta report -type=json results.bin > metrics.json
89 | cat results.bin | vegeta plot > plot.html
90 | cat results.bin | vegeta report -type="hist[0,100ms,200ms,300ms]"
91 |
92 | Requests [total, rate, throughput] 10000, 2000.26, 2000.15
93 | Duration [total, attack, wait] 5s, 4.999s, 285.172µs
94 | Latencies [min, mean, 50, 90, 95, 99, max] 183.725µs, 251.517µs, 226.993µs, 310.698µs, 394.601µs, 563.022µs, 1.347ms
95 | Bytes In [total, mean] 6240000, 624.00
96 | Bytes Out [total, mean] 0, 0.00
97 | Success [ratio] 100.00%
98 | Status Codes [code:count] 200:10000
99 | Error Set:
100 | Bucket # % Histogram
101 | [0s, 100ms] 10000 100.00% ###########################################################################
102 | [100ms, 200ms] 0 0.00%
103 | [200ms, 300ms] 0 0.00%
104 | [300ms, +Inf] 0 0.00%
105 | ```
106 |
107 | ## License
108 |
109 | [MIT](/LICENSE)
110 |
--------------------------------------------------------------------------------
/fragments.go:
--------------------------------------------------------------------------------
1 | // 🚀 Fiber is an Express inspired web framework written in Go with 💖
2 | // 📌 API Documentation: https://fiber.wiki
3 | // 📝 Github Repository: https://github.com/gofiber/fiber
4 |
5 | package fragments
6 |
7 | import (
8 | "bytes"
9 | "html/template"
10 | "io"
11 | "os"
12 | "path/filepath"
13 |
14 | "github.com/gofiber/fiber/v2"
15 | "github.com/valyala/fasthttp"
16 | "golang.org/x/net/html"
17 | )
18 |
19 | var client = fasthttp.Client{
20 | NoDefaultUserAgentHeader: true,
21 | DisablePathNormalizing: true,
22 | ReadBufferSize: 2 * 4096,
23 | }
24 |
25 | // Config ...
26 | type Config struct {
27 | // Filter defines a function to skip the middleware.
28 | // Optional. Default: nil
29 | Filter func(*fiber.Ctx) bool
30 |
31 | // FilterResponse defines a function to filter the responses
32 | // from the fragment sources.
33 | FilterResponse func(*fasthttp.Response) *fasthttp.Response
34 |
35 | // FilterRequest defines a function to filter the request
36 | // to the fragment sources.
37 | FilterRequest func(*fasthttp.Request) *fasthttp.Request
38 |
39 | // ErrorHandler defines a function which is executed
40 | // It may be used to define a custom error.
41 | // Optional. Default: 401 Invalid or expired key
42 | ErrorHandler fiber.ErrorHandler
43 |
44 | // FilterHead defines a function to filter the new
45 | // nodes in the of the document passed by the LINK header entity.
46 | FilterHead func([]*html.Node) []*html.Node
47 |
48 | // DefaultHost defines the host to use,
49 | // if no host is set on a fragment.
50 | // Optional. Default: localhost:3000
51 | DefaultHost string
52 | }
53 |
54 | // Template ...
55 | func Template(config Config, name string, bind interface{}, layouts ...string) fiber.Handler {
56 | // Set default config
57 | cfg := configDefault(config)
58 |
59 | return func(c *fiber.Ctx) error {
60 | // Filter request to skip middleware
61 | if cfg.Filter != nil && cfg.Filter(c) {
62 | return c.Next()
63 | }
64 |
65 | var err error
66 | var buf *bytes.Buffer = new(bytes.Buffer)
67 |
68 | if c.App().Config().Views != nil {
69 | // Render template based on global layout if exists
70 | if len(layouts) == 0 && c.App().Config().ViewsLayout != "" {
71 | layouts = []string{
72 | c.App().Config().ViewsLayout,
73 | }
74 | }
75 | // Render template from Views
76 | if err := c.App().Config().Views.Render(buf, name, bind, layouts...); err != nil {
77 | return cfg.ErrorHandler(c, err)
78 | }
79 | } else {
80 | // Render raw template using 'name' as filepath if no engine is set
81 | var tmpl *template.Template
82 | if _, err = readContent(buf, name); err != nil {
83 | return cfg.ErrorHandler(c, err)
84 | }
85 | // Parse template
86 | if tmpl, err = template.New("").Parse(buf.String()); err != nil {
87 | return cfg.ErrorHandler(c, err)
88 | }
89 | buf.Reset()
90 | // Render template
91 | if err = tmpl.Execute(buf, bind); err != nil {
92 | return cfg.ErrorHandler(c, err)
93 | }
94 | }
95 |
96 | r := bytes.NewReader(buf.Bytes())
97 |
98 | root, e := html.Parse(r)
99 | if e != nil {
100 | return cfg.ErrorHandler(c, err)
101 | }
102 |
103 | doc, err := NewDocument(root)
104 | if err != nil {
105 | return cfg.ErrorHandler(c, err)
106 | }
107 |
108 | return Do(c, cfg, doc)
109 | }
110 | }
111 |
112 | // Do represents the core functionality of the middleware.
113 | // It resolves the fragments from a parsed template.
114 | func Do(c *fiber.Ctx, cfg Config, doc *Document) error {
115 | r := NewResolver()
116 | statusCode, head, err := r.Resolve(c, cfg, doc.HtmlFragment())
117 | if err != nil {
118 | return err
119 | }
120 |
121 | // get final output
122 | f := doc.HtmlFragment()
123 | f.AppendHead(cfg.FilterHead(head)...)
124 |
125 | html, err := f.Html()
126 | if err != nil {
127 | return cfg.ErrorHandler(c, err)
128 | }
129 |
130 | c.Response().SetStatusCode(statusCode)
131 | c.Response().Header.SetContentType(fiber.MIMETextHTMLCharsetUTF8)
132 | c.Response().SetBody([]byte(html))
133 |
134 | return nil
135 | }
136 |
137 | // readContent opens a named file and read content from it
138 | func readContent(rf io.ReaderFrom, name string) (n int64, err error) {
139 | // Read file
140 | f, err := os.Open(filepath.Clean(name))
141 | if err != nil {
142 | return 0, err
143 | }
144 | defer func() {
145 | err = f.Close()
146 | }()
147 | return rf.ReadFrom(f)
148 | }
149 |
150 | // Helper function to set default values
151 | func configDefault(config ...Config) Config {
152 | // Init config
153 | var cfg Config
154 | if len(config) > 0 {
155 | cfg = config[0]
156 | }
157 |
158 | if cfg.ErrorHandler == nil {
159 | cfg.ErrorHandler = func(c *fiber.Ctx, err error) error {
160 | return c.Status(fiber.StatusInternalServerError).SendString("cannot create response")
161 | }
162 | }
163 |
164 | if cfg.FilterResponse == nil {
165 | cfg.FilterResponse = func(res *fasthttp.Response) *fasthttp.Response {
166 | return res
167 | }
168 | }
169 |
170 | if cfg.FilterRequest == nil {
171 | cfg.FilterRequest = func(req *fasthttp.Request) *fasthttp.Request {
172 | return req
173 | }
174 | }
175 |
176 | if cfg.DefaultHost == "" {
177 | cfg.DefaultHost = "localhost:3000"
178 | }
179 |
180 | if cfg.FilterHead == nil {
181 | cfg.FilterHead = func(nodes []*html.Node) []*html.Node {
182 | return nodes
183 | }
184 | }
185 |
186 | return cfg
187 | }
188 |
--------------------------------------------------------------------------------
/fragment.go:
--------------------------------------------------------------------------------
1 | package fragments
2 |
3 | import (
4 | "bytes"
5 | "strconv"
6 | "strings"
7 | "sync"
8 | "time"
9 |
10 | "github.com/PuerkitoBio/goquery"
11 | "github.com/gofiber/fiber/v2"
12 | "github.com/google/uuid"
13 | "github.com/valyala/fasthttp"
14 | "golang.org/x/net/html"
15 | "golang.org/x/net/html/atom"
16 | )
17 |
18 | // HtmlFragment is representation of HTML fragments.
19 | type HtmlFragment struct {
20 | doc *goquery.Document
21 | sync.RWMutex
22 | }
23 |
24 | // NewHtmlFragment creates a new fragment of HTML.
25 | func NewHtmlFragment(root *html.Node) (*HtmlFragment, error) {
26 | h := new(HtmlFragment)
27 | h.doc = goquery.NewDocumentFromNode(root)
28 |
29 | return h, nil
30 | }
31 |
32 | // Document get the full document representation
33 | // of the HTML fragment.
34 | func (h *HtmlFragment) Fragment() *goquery.Document {
35 | return h.doc
36 | }
37 |
38 | // Fragments is returning the selection of fragments
39 | // from an HTML page.
40 | func (h *HtmlFragment) Fragments() (map[string]*Fragment, error) {
41 | h.RLock()
42 | defer h.RUnlock()
43 |
44 | scripts := h.doc.Find("head script[type=fragment]")
45 | fragments := h.doc.Find("fragment").AddSelection(scripts)
46 |
47 | ff := make(map[string]*Fragment)
48 |
49 | fragments.Each(func(i int, s *goquery.Selection) {
50 | f := FromSelection(s)
51 |
52 | if !f.deferred {
53 | ff[f.ID()] = f
54 | }
55 | })
56 |
57 | return ff, nil
58 | }
59 |
60 | // Html creates the HTML output of the created document.
61 | func (h *HtmlFragment) Html() (string, error) {
62 | h.RLock()
63 | defer h.RUnlock()
64 |
65 | html, err := h.doc.Html()
66 | if err != nil {
67 | return "", err
68 | }
69 |
70 | return html, nil
71 | }
72 |
73 | // AppendHead ...
74 | func (d *HtmlFragment) AppendHead(ns ...*html.Node) {
75 | head := d.doc.Find("head")
76 | head.AppendNodes(ns...)
77 | }
78 |
79 | // Fragment is a in the or
80 | // of a HTML page.
81 | type Fragment struct {
82 | deferred bool
83 | fallback string
84 | method string
85 | primary bool
86 | src string
87 | timeout int64
88 |
89 | id string
90 | ref string
91 |
92 | statusCode int
93 | head []*html.Node
94 |
95 | f *HtmlFragment
96 | s *goquery.Selection
97 | }
98 |
99 | // FromSelection creates a new fragment from a
100 | // fragment selection in the DOM.
101 | func FromSelection(s *goquery.Selection) *Fragment {
102 | f := new(Fragment)
103 | f.s = s
104 |
105 | src, _ := s.Attr("src")
106 | f.src = src
107 |
108 | fallback, _ := s.Attr("fallback")
109 | f.fallback = fallback
110 |
111 | method, _ := s.Attr("method")
112 | f.method = method
113 |
114 | timeout, ok := s.Attr("timeout")
115 | if !ok {
116 | timeout = "60"
117 | }
118 | t, _ := strconv.ParseInt(timeout, 10, 64)
119 | f.timeout = t
120 |
121 | id, ok := s.Attr("id")
122 | if !ok {
123 | id = uuid.New().String()
124 | }
125 | f.id = id
126 |
127 | ref, _ := s.Attr("ref")
128 | f.ref = ref
129 |
130 | deferred, ok := s.Attr("deferred")
131 | f.deferred = ok && strings.ToUpper(deferred) != "FALSE"
132 |
133 | primary, ok := s.Attr("primary")
134 | f.primary = ok && strings.ToUpper(primary) != "FALSE"
135 |
136 | f.head = make([]*html.Node, 0)
137 |
138 | return f
139 | }
140 |
141 | // Src is the URL for the fragment.
142 | func (f *Fragment) Src() string {
143 | return f.src
144 | }
145 |
146 | // Fallback is the fallback URL for the fragment.
147 | func (f *Fragment) Fallback() string {
148 | return f.fallback
149 | }
150 |
151 | // Timeout is the timeout for fetching the fragment.
152 | func (f *Fragment) Timeout() time.Duration {
153 | return time.Duration(f.timeout) * time.Second
154 | }
155 |
156 | // Method is the HTTP method to use for fetching the fragment.
157 | func (f *Fragment) Method() string {
158 | return f.method
159 | }
160 |
161 | // Element is a pointer to the selected element in the DOM.
162 | func (f *Fragment) Element() *goquery.Selection {
163 | return f.s
164 | }
165 |
166 | // Deferred is deferring the fetching to the browser.
167 | func (f *Fragment) Deferred() bool {
168 | return f.deferred
169 | }
170 |
171 | // Primary denotes a fragment as responsible for setting
172 | // the response code of the entire HTML page.
173 | func (f *Fragment) Primary() bool {
174 | return f.primary
175 | }
176 |
177 | // Links returns the new nodes that go in the head via
178 | // the LINK HTTP header entity.
179 | func (f *Fragment) Links() []*html.Node {
180 | return f.head
181 | }
182 |
183 | // Ref represents the reference to another fragment
184 | func (f *Fragment) Ref() string {
185 | return f.ref
186 | }
187 |
188 | // ID represents a unique id for the fragment
189 | func (f *Fragment) ID() string {
190 | return f.id
191 | }
192 |
193 | // HtmlFragment returns embedded fragments of HTML.
194 | func (f *Fragment) HtmlFragment() *HtmlFragment {
195 | return f.f
196 | }
197 |
198 | // Resolve is resolving all needed data, setting headers
199 | // and the status code.
200 | func (f *Fragment) Resolve() ResolverFunc {
201 | return func(c *fiber.Ctx, cfg Config) error {
202 | err := f.do(c, cfg, f.src)
203 | if err == nil {
204 | return err
205 | }
206 |
207 | if err != fasthttp.ErrTimeout {
208 | return err
209 | }
210 |
211 | err = f.do(c, cfg, f.fallback)
212 | if err != nil {
213 | return err
214 | }
215 |
216 | return nil
217 | }
218 | }
219 |
220 | func (f *Fragment) do(c *fiber.Ctx, cfg Config, src string) error {
221 | req := fasthttp.AcquireRequest()
222 | res := fasthttp.AcquireResponse()
223 |
224 | defer fasthttp.ReleaseRequest(req)
225 | defer fasthttp.ReleaseResponse(res)
226 |
227 | c.Request().CopyTo(req)
228 |
229 | uri := fasthttp.AcquireURI()
230 | defer fasthttp.ReleaseURI(uri)
231 |
232 | if err := uri.Parse(nil, []byte(src)); err != nil {
233 | return err
234 | }
235 |
236 | if len(uri.Host()) == 0 {
237 | uri.SetHost(cfg.DefaultHost)
238 | }
239 | req.SetRequestURI(uri.String())
240 | req.Header.Del(fiber.HeaderConnection)
241 |
242 | t := f.Timeout()
243 | if err := client.DoTimeout(req, res, t); err != nil {
244 | return err
245 | }
246 |
247 | res = cfg.FilterResponse(res)
248 | f.statusCode = res.StatusCode()
249 |
250 | // if res.StatusCode() != http.StatusOK {
251 | // // TODO: wrap in custom error, to not replace
252 | // return fmt.Errorf("resolve: could not resolve fragment at %s", f.Src())
253 | // }
254 |
255 | res.Header.Del(fiber.HeaderConnection)
256 |
257 | contentEncoding := res.Header.Peek("Content-Encoding")
258 | body := res.Body()
259 |
260 | var err error
261 | if bytes.EqualFold(contentEncoding, []byte("gzip")) {
262 | body, err = res.BodyGunzip()
263 | if err != nil {
264 | return cfg.ErrorHandler(c, err)
265 | }
266 | }
267 |
268 | h := Header(string(res.Header.Peek("link")))
269 | nodes := CreateNodes(h.Links())
270 | f.head = append(f.head, nodes...)
271 |
272 | root := &html.Node{
273 | Type: html.ElementNode,
274 | DataAtom: atom.Body,
275 | Data: "body",
276 | }
277 |
278 | ns, err := html.ParseFragment(bytes.NewReader(body), root)
279 | if err != nil {
280 | return err
281 | }
282 |
283 | for _, n := range ns {
284 | root.AppendChild(n)
285 | }
286 |
287 | doc, err := NewHtmlFragment(root)
288 | if err != nil {
289 | return nil
290 | }
291 | f.f = doc
292 |
293 | return nil
294 | }
295 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
6 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
7 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
8 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
9 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
10 | cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
11 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
12 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
13 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
14 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
15 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
16 | github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
17 | github.com/CloudyKit/jet/v6 v6.1.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4=
18 | github.com/Djarvur/go-err113 v0.0.0-20200511133814-5174e21577d5/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs=
19 | github.com/Joker/hpp v0.0.0-20180418125244-6893e659854a/go.mod h1:MzD2WMdSxvbHw5fM/OXOFily/lipJWRc9C1px0Mt0ZE=
20 | github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
21 | github.com/Joker/jade v1.0.0/go.mod h1:efZIdO0py/LtcJRSa/j2WEklMSAw84WV0zZVMxNToB8=
22 | github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
23 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
24 | github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM=
25 | github.com/PuerkitoBio/goquery v1.7.0 h1:O5SP3b9JWqMSVMG69zMfj577zwkSNpxrFf7ybS74eiw=
26 | github.com/PuerkitoBio/goquery v1.7.0/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
27 | github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
28 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
29 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
30 | github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E=
31 | github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
32 | github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
33 | github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
34 | github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
35 | github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
36 | github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
37 | github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
38 | github.com/aymerick/raymond v2.0.2+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
39 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
40 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
41 | github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
42 | github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
43 | github.com/bombsimon/wsl/v3 v3.1.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc=
44 | github.com/cbroglie/mustache v1.2.2/go.mod h1:gomHsVlF4zTcsY2H8d7U9SipCYbbrAks5breARbqAM0=
45 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
46 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
47 | github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
48 | github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
49 | github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
50 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
51 | github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
52 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
53 | github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
54 | github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
55 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
56 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
57 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
58 | github.com/denis-tingajkin/go-header v0.3.1/go.mod h1:sq/2IxMhaZX+RRcgHfCRx/m0M5na0fBt4/CRe7Lrji0=
59 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
60 | github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
61 | github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
62 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
63 | github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
64 | github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8=
65 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
66 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
67 | github.com/go-critic/go-critic v0.5.0/go.mod h1:4jeRh3ZAVnRYhuWdOEvwzVqLUpxMSoAT0xZ74JsTPlo=
68 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
69 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
70 | github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM=
71 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
72 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
73 | github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
74 | github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
75 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
76 | github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4=
77 | github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ=
78 | github.com/go-toolsmith/astequal v0.0.0-20180903214952-dcb477bfacd6/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
79 | github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
80 | github.com/go-toolsmith/astfmt v0.0.0-20180903215011-8f8ee99c3086/go.mod h1:mP93XdblcopXwlyN4X4uodxXQhldPGZbcEJIimQHrkg=
81 | github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw=
82 | github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU=
83 | github.com/go-toolsmith/astp v0.0.0-20180903215135-0af7e3c24f30/go.mod h1:SV2ur98SGypH1UjcPpCatrV5hPazG6+IfNHbkDXBRrk=
84 | github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI=
85 | github.com/go-toolsmith/pkgload v0.0.0-20181119091011-e9e65178eee8/go.mod h1:WoMrjiy4zvdS+Bg6z9jZH82QXwkcgCBX6nOfnmdaHks=
86 | github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc=
87 | github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
88 | github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
89 | github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
90 | github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
91 | github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
92 | github.com/gofiber/fiber/v2 v2.13.0 h1:jJBCPwq+hlsfHRDVsmfu6pbgW85Y8jL9dE+VmTzfE6I=
93 | github.com/gofiber/fiber/v2 v2.13.0/go.mod h1:oZTLWqYnqpMMuF922SjGbsYZsdpE1MCfh416HNdweIM=
94 | github.com/gofiber/template v1.6.12 h1:xFFp3cXNR8fiiNk7fLvQ17JAzt+M0E4ume4TACcpGy4=
95 | github.com/gofiber/template v1.6.12/go.mod h1:Ewlj7ZHAno12VPabFZa1dWKkD5ilaBEnN2pXb0QoqBs=
96 | github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
97 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
98 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
99 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
100 | github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
101 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
102 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
103 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
104 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
105 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
106 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
107 | github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
108 | github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4=
109 | github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk=
110 | github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0=
111 | github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8=
112 | github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o=
113 | github.com/golangci/gocyclo v0.0.0-20180528144436-0a533e8fa43d/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU=
114 | github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU=
115 | github.com/golangci/golangci-lint v1.28.3/go.mod h1:JlLqleIwwgLVJtjKtrB37OKp3LGLrUhEx9tWY4VKWSY=
116 | github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU=
117 | github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg=
118 | github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o=
119 | github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA=
120 | github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bzsHdTM0bsB7+8mt0GUMvjCgwLpTapNZHU8AajI=
121 | github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4=
122 | github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ=
123 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
124 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
125 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
126 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
127 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
128 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
129 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
130 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
131 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
132 | github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA=
133 | github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
134 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
135 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
136 | github.com/gookit/color v1.2.4/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg=
137 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
138 | github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
139 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
140 | github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
141 | github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
142 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
143 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
144 | github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
145 | github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
146 | github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
147 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
148 | github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
149 | github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
150 | github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
151 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
152 | github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
153 | github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
154 | github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
155 | github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
156 | github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
157 | github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
158 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
159 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
160 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
161 | github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
162 | github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
163 | github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
164 | github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
165 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
166 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
167 | github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a/go.mod h1:xRskid8CManxVta/ALEhJha/pweKBaVG6fWgc0yH25s=
168 | github.com/jirfag/go-printf-func-name v0.0.0-20191110105641-45db9963cdd3/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0=
169 | github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
170 | github.com/jmoiron/sqlx v1.2.1-0.20190826204134-d7d95172beb5/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
171 | github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
172 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
173 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
174 | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
175 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
176 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
177 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
178 | github.com/klauspost/compress v1.10.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
179 | github.com/klauspost/compress v1.10.5/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
180 | github.com/klauspost/compress v1.12.2 h1:2KCfW3I9M7nSc5wOqXAlW2v2U6v+w6cbjvbfp+OykW8=
181 | github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
182 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
183 | github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
184 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
185 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
186 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
187 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
188 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
189 | github.com/kyoh86/exportloopref v0.1.4/go.mod h1:h1rDl2Kdj97+Kwh4gdz3ujE7XHmH51Q0lUiZ1z4NLj8=
190 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
191 | github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
192 | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
193 | github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
194 | github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpApTE5fXSKAqwDU=
195 | github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
196 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
197 | github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
198 | github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
199 | github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
200 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
201 | github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
202 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
203 | github.com/mattn/go-slim v0.0.0-20200618151855-bde33eecb5ee/go.mod h1:ma9TUJeni8LGZMJvOwbAv/FOwiwqIMQN570LnpqCBSM=
204 | github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
205 | github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
206 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
207 | github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
208 | github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
209 | github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
210 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
211 | github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
212 | github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
213 | github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
214 | github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
215 | github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
216 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
217 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
218 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
219 | github.com/mozilla/tls-observatory v0.0.0-20200317151703-4fa42e1c2dee/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
220 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
221 | github.com/nakabonne/nestif v0.3.0/go.mod h1:dI314BppzXjJ4HsCnbo7XzrJHPszZsjnk5wEBSYHI2c=
222 | github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
223 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
224 | github.com/nishanths/exhaustive v0.0.0-20200525081945-8e46705b6132/go.mod h1:wBEpHwM2OdmeNpdCvRPUlkEbBuaFmcK4Wv8Q7FuGW3c=
225 | github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
226 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
227 | github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
228 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
229 | github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
230 | github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
231 | github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
232 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
233 | github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw=
234 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
235 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
236 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
237 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
238 | github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
239 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
240 | github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
241 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
242 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
243 | github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
244 | github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
245 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
246 | github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
247 | github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
248 | github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
249 | github.com/quasilyte/go-ruleguard v0.1.2-0.20200318202121-b00d7a75d3d8/go.mod h1:CGFX09Ci3pq9QZdj86B+VGIdNj4VyCo2iPOGS9esB/k=
250 | github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0=
251 | github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
252 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
253 | github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
254 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
255 | github.com/ryancurrah/gomodguard v1.1.0/go.mod h1:4O8tr7hBODaGE6VIhfJDHcwzh5GUccKSJBU0UMXJFVM=
256 | github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0KCtEdgEkHwDbigdA=
257 | github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
258 | github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
259 | github.com/securego/gosec/v2 v2.3.0/go.mod h1:UzeVyUXbxukhLeHKV3VVqo7HdoQR9MrRfFmZYotn8ME=
260 | github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc=
261 | github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
262 | github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
263 | github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
264 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
265 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
266 | github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
267 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
268 | github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
269 | github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
270 | github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4lqBjiZI=
271 | github.com/sourcegraph/go-diff v0.5.3/go.mod h1:v9JDtjCE4HHHCZGId75rg8gkKKa98RVjBcBGsVmMmak=
272 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
273 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
274 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
275 | github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
276 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
277 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
278 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
279 | github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
280 | github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
281 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
282 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
283 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
284 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
285 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
286 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
287 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
288 | github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
289 | github.com/tdakkota/asciicheck v0.0.0-20200416190851-d7f85be797a2/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM=
290 | github.com/tetafro/godot v0.4.2/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0=
291 | github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk=
292 | github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
293 | github.com/tommy-muehle/go-mnd v1.3.1-0.20200224220436-e6f9a994e8fa/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig=
294 | github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
295 | github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
296 | github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA=
297 | github.com/uudashr/gocognit v1.0.1/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM=
298 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
299 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
300 | github.com/valyala/fasthttp v1.12.0/go.mod h1:229t1eWu9UXTPmoUkbpN/fctKPBY4IJoFXQnxHGXy6E=
301 | github.com/valyala/fasthttp v1.26.0 h1:k5Tooi31zPG/g8yS6o2RffRO2C9B9Kah9SY8j/S7058=
302 | github.com/valyala/fasthttp v1.26.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA=
303 | github.com/valyala/quicktemplate v1.5.0/go.mod h1:v7yYWpBEiutDyNfVaph6oC/yKwejzVyTX/2cwwHxyok=
304 | github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
305 | github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
306 | github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
307 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
308 | github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
309 | github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0=
310 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
311 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
312 | go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
313 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
314 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
315 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
316 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
317 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
318 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
319 | golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
320 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
321 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
322 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
323 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
324 | golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
325 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
326 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
327 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
328 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
329 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
330 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
331 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
332 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
333 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
334 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
335 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
336 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
337 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
338 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
339 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
340 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
341 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
342 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
343 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
344 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
345 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
346 | golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
347 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
348 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
349 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
350 | golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
351 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
352 | golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
353 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
354 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
355 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
356 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
357 | golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
358 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
359 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
360 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
361 | golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
362 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
363 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
364 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
365 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
366 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
367 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
368 | golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I=
369 | golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
370 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
371 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
372 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
373 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
374 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
375 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
376 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
377 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
378 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
379 | golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
380 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
381 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
382 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
383 | golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
384 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
385 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
386 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
387 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
388 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
389 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
390 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
391 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
392 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
393 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
394 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
395 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
396 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
397 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
398 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
399 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
400 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
401 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
402 | golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E=
403 | golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
404 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
405 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
406 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
407 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
408 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
409 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
410 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
411 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
412 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
413 | golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
414 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
415 | golang.org/x/tools v0.0.0-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
416 | golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
417 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
418 | golang.org/x/tools v0.0.0-20190221204921-83362c3779f5/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
419 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
420 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
421 | golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
422 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
423 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
424 | golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
425 | golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
426 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
427 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
428 | golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
429 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
430 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
431 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
432 | golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
433 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
434 | golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
435 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
436 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
437 | golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
438 | golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
439 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
440 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
441 | golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
442 | golang.org/x/tools v0.0.0-20200321224714-0d839f3cf2ed/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
443 | golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
444 | golang.org/x/tools v0.0.0-20200331202046-9d5940d49312/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
445 | golang.org/x/tools v0.0.0-20200414032229-332987a829c3/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
446 | golang.org/x/tools v0.0.0-20200422022333-3d57cf2e726e/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
447 | golang.org/x/tools v0.0.0-20200428185508-e9a00ec82136/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
448 | golang.org/x/tools v0.0.0-20200519015757-0d0afa43d58a/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
449 | golang.org/x/tools v0.0.0-20200625211823-6506e20df31f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
450 | golang.org/x/tools v0.0.0-20200702044944-0cc1aa72b347/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
451 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
452 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
453 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
454 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
455 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
456 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
457 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
458 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
459 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
460 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
461 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
462 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
463 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
464 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
465 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
466 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
467 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
468 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
469 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
470 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
471 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
472 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
473 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
474 | google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
475 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
476 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
477 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
478 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
479 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
480 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
481 | gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
482 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
483 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
484 | gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
485 | gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
486 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
487 | gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
488 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
489 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
490 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
491 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
492 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
493 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
494 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
495 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
496 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
497 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
498 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
499 | mvdan.cc/gofumpt v0.0.0-20200513141252-abc0db2c416a/go.mod h1:4q/PlrZKQLU5MowSvCKM3U4xJUPtJ8vKWx7vsWFJ3MI=
500 | mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
501 | mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
502 | mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=
503 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
504 | sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
505 |
--------------------------------------------------------------------------------