├── defaults
├── ari.d
│ ├── keep.conf
│ └── k8s-asterisk-config.conf.tmpl
├── cli.d
│ └── keep.conf
├── cli_custom.conf
├── manager.d
│ └── keep.conf
├── pjsip.d
│ ├── keep.conf
│ └── k8s-asterisk-config.conf.tmpl
├── pjsip_custom.conf
├── extensions.d
│ └── keep.conf
├── extensions_custom.conf
├── voicemail.d
│ └── keep.conf
├── pjsip.conf
├── manager.conf
├── extensions.conf
├── ari_custom.conf
├── musiconhold.conf
├── voicemail.conf
├── voicemail_custom.conf
├── logger.conf
├── ari.conf
├── manager_custom.conf
├── confbridge.conf
├── cli.conf
├── http.conf
├── cdr.conf
├── asterisk.conf
├── cdr_custom.conf
├── indications.conf
└── modules.conf
├── .gitignore
├── Dockerfile.goreleaser
├── check.sh
├── random.go
├── Dockerfile
├── release.sh
├── .github
└── workflows
│ ├── go.yml
│ ├── release.yaml
│ └── master.yaml
├── LICENSE
├── go.mod
├── CODE_OF_CONDUCT.md
├── .goreleaser.yml
├── Documentation
├── pjsip-ext-ext.svg
├── pjsip-int-ext.svg
└── pjsip-int-int.svg
├── main.go
├── README.md
└── go.sum
/defaults/ari.d/keep.conf:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/defaults/cli.d/keep.conf:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/defaults/cli_custom.conf:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/defaults/manager.d/keep.conf:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/defaults/pjsip.d/keep.conf:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/defaults/pjsip_custom.conf:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/defaults/extensions.d/keep.conf:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/defaults/extensions_custom.conf:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/defaults/voicemail.d/keep.conf:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /asterisk-config
2 | /vendor/
3 | /test/
4 | /local_test.sh
5 |
--------------------------------------------------------------------------------
/defaults/pjsip.conf:
--------------------------------------------------------------------------------
1 | #include pjsip_custom.conf
2 | #include pjsip.d/*.conf
3 |
--------------------------------------------------------------------------------
/defaults/manager.conf:
--------------------------------------------------------------------------------
1 | #include manager_custom.conf
2 | #include manager.d/*.conf
3 |
--------------------------------------------------------------------------------
/defaults/extensions.conf:
--------------------------------------------------------------------------------
1 | #include extensions_custom.conf
2 | #include extensions.d/*.conf
3 |
--------------------------------------------------------------------------------
/defaults/ari_custom.conf:
--------------------------------------------------------------------------------
1 | [general]
2 | enabled = yes
3 | pretty = yes
4 | allowed_origins = *
5 |
--------------------------------------------------------------------------------
/defaults/musiconhold.conf:
--------------------------------------------------------------------------------
1 | [general]
2 |
3 | [default]
4 | mode = files
5 | directory = moh
6 |
--------------------------------------------------------------------------------
/defaults/voicemail.conf:
--------------------------------------------------------------------------------
1 | #include voicemail_custom.conf
2 | #include voicemail.d/*.conf
3 |
4 |
--------------------------------------------------------------------------------
/defaults/voicemail_custom.conf:
--------------------------------------------------------------------------------
1 | [general]
2 | format = wav49|gsm|wav
3 |
4 | [default]
5 |
6 |
--------------------------------------------------------------------------------
/defaults/logger.conf:
--------------------------------------------------------------------------------
1 | [general]
2 |
3 | [logfiles]
4 |
5 | console = verbose,notice,warning,error
6 |
7 |
--------------------------------------------------------------------------------
/defaults/ari.conf:
--------------------------------------------------------------------------------
1 | [general]
2 | enabled = yes
3 |
4 | #include ari_custom.conf
5 | #include ari.d/*.conf
6 |
--------------------------------------------------------------------------------
/defaults/manager_custom.conf:
--------------------------------------------------------------------------------
1 | [general]
2 | enabled = yes
3 | port = 5038
4 | bindaddr = 127.0.0.1
5 | webenabled = no
6 |
7 |
--------------------------------------------------------------------------------
/defaults/confbridge.conf:
--------------------------------------------------------------------------------
1 | ; All conferences use default settings. This config must be present to load the confbridge application
2 |
--------------------------------------------------------------------------------
/defaults/ari.d/k8s-asterisk-config.conf.tmpl:
--------------------------------------------------------------------------------
1 | [k8s-asterisk-config]
2 | type = user
3 | password = {{.Env "ARI_AUTOSECRET"}}
4 | password_format = plain
5 |
--------------------------------------------------------------------------------
/defaults/cli.conf:
--------------------------------------------------------------------------------
1 | [startup_commands]
2 | dialplan set global ASTERISK_CONFIG_SYSTEM_READY 1 = yes
3 |
4 | #include cli_custom.conf
5 | #include cli.d/*.conf
6 |
--------------------------------------------------------------------------------
/defaults/http.conf:
--------------------------------------------------------------------------------
1 | [general]
2 | enabled=yes
3 | bindaddr=127.0.0.1
4 | bindport=8088
5 | sessionlimit=500
6 | session_inactivity=30000
7 | session_keep_alive=15000
8 |
--------------------------------------------------------------------------------
/Dockerfile.goreleaser:
--------------------------------------------------------------------------------
1 | FROM gcr.io/distroless/static
2 | COPY asterisk-config /go/bin/asterisk-config
3 | COPY defaults /defaults
4 | ENTRYPOINT ["/go/bin/asterisk-config"]
5 |
--------------------------------------------------------------------------------
/defaults/cdr.conf:
--------------------------------------------------------------------------------
1 | [general]
2 | enable=yes
3 |
4 | [custom]
5 | ; We log the unique ID as it can be useful for troubleshooting any issues
6 | ; that arise.
7 | loguniqueid=yes
8 |
--------------------------------------------------------------------------------
/check.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | #dep ensure
3 | #gometalinter --skip test --skip defaults --cyclo-over=15 --deadline=90s --vendor ./...
4 | golangci-lint run
5 | go test ./...
6 | go build ./...
7 | go build
8 |
--------------------------------------------------------------------------------
/random.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "github.com/nats-io/nuid"
4 |
5 | var secretGenerator *nuid.NUID
6 |
7 | func init() {
8 | secretGenerator = nuid.New()
9 | }
10 |
11 | func genSecret() string {
12 | return secretGenerator.Next()
13 | }
14 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:1.17 AS builder
2 | WORKDIR /go/src
3 | COPY . .
4 | RUN go get -d -v
5 | RUN CGO_ENABLED=0 go build -o /go/bin/app
6 |
7 | FROM gcr.io/distroless/static
8 | COPY defaults /defaults
9 | COPY --from=builder /go/bin/app /go/bin/app
10 | ENTRYPOINT ["/go/bin/app"]
11 |
--------------------------------------------------------------------------------
/release.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | # Only run if we are inside Travis-CI
4 | if [ ! -e $CI ]; then
5 | echo "Logging in to Docker..."
6 | echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
7 |
8 | # Create the release
9 | echo "Creating release..."
10 | goreleaser release
11 | fi
12 |
13 |
--------------------------------------------------------------------------------
/defaults/asterisk.conf:
--------------------------------------------------------------------------------
1 | [options]
2 | ; If we want to start Asterisk with a default verbosity for the verbose
3 | ; or debug logger channel types, then we use these settings (by default
4 | ; they are disabled).
5 | ;verbose = 5
6 | ;debug = 2
7 |
8 | ; User and group to run asterisk as. NOTE: This will require changes to
9 | ; directory and device permissions.
10 | ;runuser = asterisk ; The user to run as. The default is root.
11 | ;rungroup = asterisk ; The group to run as. The default is root
12 |
13 | ;defaultlanguage = es
14 |
--------------------------------------------------------------------------------
/.github/workflows/go.yml:
--------------------------------------------------------------------------------
1 | name: Go
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 |
11 | build:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v3
15 |
16 | - name: Set up Go
17 | uses: actions/setup-go@v3
18 | with:
19 | go-version: 1.18
20 |
21 | - name: lint
22 | uses: golangci/golangci-lint-action@v3
23 |
24 | - name: Build
25 | run: go build -v ./...
26 |
27 | - name: Test
28 | run: go test -v ./...
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2018 CyCore Systems, Inc.
2 |
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
--------------------------------------------------------------------------------
/defaults/cdr_custom.conf:
--------------------------------------------------------------------------------
1 | [mappings]
2 | ; Our CDR log will be written to /var/log/asterisk/cdr-custom/Master.csv
3 | ; with the following schema.
4 | ;Master.csv => ${CSV_QUOTE(${CDR(clid)})},${CSV_QUOTE(${CDR(src)})},${CSV_QUOTE(${CDR(dst)})},${CSV_QUOTE(${CDR(dcontext)})},${CSV_QUOTE(${CDR(channel)})},${CSV_QUOTE(${CDR(dstchannel)})},${CSV_QUOTE(${CDR(lastapp)})},${CSV_QUOTE(${CDR(lastdata)})},${CSV_QUOTE(${CDR(start)})},${CSV_QUOTE(${CDR(answer)})},${CSV_QUOTE(${CDR(end)})},${CSV_QUOTE(${CDR(duration)})},${CSV_QUOTE(${CDR(billsec)})},${CSV_QUOTE(${CDR(disposition)})},${CSV_QUOTE(${CDR(amaflags)})},${CSV_QUOTE(${CDR(accountcode)})},${CSV_QUOTE(${CDR(uniqueid)})},${CSV_QUOTE(${CDR(userfield)})},${CDR(sequence)}
5 |
--------------------------------------------------------------------------------
/defaults/indications.conf:
--------------------------------------------------------------------------------
1 | [general]
2 | country = us ; We are in Waldo, Al, USA so the US is our default.
3 |
4 | [us]
5 | description = United States / North America
6 | ringcadence = 2000,4000
7 | dial = 350+440
8 | busy = 480+620/500,0/500
9 | ring = 440+480/2000,0/4000
10 | congestion = 480+620/250,0/250
11 | callwaiting = 440/300,0/10000
12 | dialrecall = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440
13 | record = 1400/500,0/15000
14 | info = !950/330,!1400/330,!1800/330,0
15 | stutter = !350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440
16 |
17 | ; Additional country configurations can be found in the Asterisk source
18 | ; at /configs/samples/indications.conf.sample
19 |
--------------------------------------------------------------------------------
/defaults/pjsip.d/k8s-asterisk-config.conf.tmpl:
--------------------------------------------------------------------------------
1 | [k8s-internal-ipv4-internal-media]
2 | type=transport
3 | protocol=udp
4 | bind=0.0.0.0:5080
5 | local_net={{.Network "privateIPv4"}}
6 | external_media_address={{.Network "privateIPv4"}}
7 | external_signaling_address={{.Network "privateIPv4"}}
8 |
9 | [k8s-internal-ipv4-external-media]
10 | type=transport
11 | protocol=udp
12 | bind=0.0.0.0:5070
13 | local_net={{.Network "privateIPv4"}}
14 | external_media_address={{.Network "publicIPv4"}}
15 | external_signaling_address={{.Network "privateIPv4"}}
16 |
17 | [k8s-external-ipv4-external-media]
18 | type=transport
19 | protocol=udp
20 | bind=0.0.0.0:5060
21 | local_net={{.Network "privateIPv4"}}
22 | external_media_address={{.Network "publicIPv4"}}
23 | external_signaling_address={{.Network "publicIPv4"}}
24 |
25 |
--------------------------------------------------------------------------------
/.github/workflows/release.yaml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | push:
5 | tags:
6 | - "*"
7 |
8 | jobs:
9 | release:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v3
13 |
14 | - name: Set up Buildx
15 | id: buildx
16 | uses: docker/setup-buildx-action@v1
17 |
18 | - name: Set up Go
19 | uses: actions/setup-go@v3
20 | with:
21 | go-version: 1.18
22 |
23 | - name: Docker Hub Login
24 | uses: docker/login-action@v1
25 | with:
26 | username: ${{ secrets.DOCKER_USERNAME }}
27 | password: ${{ secrets.DOCKER_PASSWORD }}
28 |
29 | - name: GHCR Login
30 | uses: docker/login-action@v1
31 | with:
32 | registry: ghcr.io
33 | username: ${{ github.repository_owner }}
34 | password: ${{ secrets.GITHUB_TOKEN }}
35 |
36 | - name: GoReleaser
37 | uses: goreleaser/goreleaser-action@v2.8.0
38 | with:
39 | args: release --rm-dist
40 | env:
41 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
42 |
--------------------------------------------------------------------------------
/.github/workflows/master.yaml:
--------------------------------------------------------------------------------
1 | name: Master branch push
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 |
7 | jobs:
8 |
9 | image:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v3
13 | - name: PrepareReg Names
14 | run: |
15 | echo IMAGE_REPOSITORY=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]') >> $GITHUB_ENV
16 | echo IMAGE_TAG=$(echo ${{ github.ref }} | tr '[:upper:]' '[:lower:]' | awk '{split($0,a,"/"); print a[3]}') >> $GITHUB_ENV
17 |
18 | - name: Set up Buildx
19 | id: buildx
20 | uses: docker/setup-buildx-action@v1
21 |
22 | - name: Set up Go
23 | uses: actions/setup-go@v3
24 | with:
25 | go-version: 1.18
26 |
27 | - name: GHCR Login
28 | uses: docker/login-action@v1
29 | with:
30 | registry: ghcr.io
31 | username: ${{ github.repository_owner }}
32 | password: ${{ secrets.GITHUB_TOKEN }}
33 |
34 | - name: GHCR Push
35 | uses: docker/build-push-action@v2
36 | with:
37 | push: true
38 | tags: |
39 | ghcr.io/${{ env.IMAGE_REPOSITORY }}:${{ github.sha }}
40 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/CyCoreSystems/asterisk-config
2 |
3 | require (
4 | github.com/CyCoreSystems/kubetemplate v0.6.0-rc1
5 | github.com/CyCoreSystems/netdiscover v1.2.4
6 | github.com/nats-io/nuid v1.0.1
7 | github.com/rotisserie/eris v0.4.1
8 | k8s.io/client-go v0.23.1
9 | )
10 |
11 | require (
12 | github.com/davecgh/go-spew v1.1.1 // indirect
13 | github.com/go-logr/logr v1.2.0 // indirect
14 | github.com/gogo/protobuf v1.3.2 // indirect
15 | github.com/golang/protobuf v1.5.2 // indirect
16 | github.com/google/go-cmp v0.5.5 // indirect
17 | github.com/google/gofuzz v1.1.0 // indirect
18 | github.com/googleapis/gnostic v0.5.5 // indirect
19 | github.com/json-iterator/go v1.1.12 // indirect
20 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
21 | github.com/modern-go/reflect2 v1.0.2 // indirect
22 | golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
23 | golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect
24 | golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e // indirect
25 | golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
26 | golang.org/x/text v0.3.7 // indirect
27 | golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
28 | google.golang.org/appengine v1.6.7 // indirect
29 | google.golang.org/protobuf v1.27.1 // indirect
30 | gopkg.in/inf.v0 v0.9.1 // indirect
31 | gopkg.in/yaml.v2 v2.4.0 // indirect
32 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
33 | k8s.io/api v0.23.1 // indirect
34 | k8s.io/apimachinery v0.23.1 // indirect
35 | k8s.io/klog/v2 v2.30.0 // indirect
36 | k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
37 | k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b // indirect
38 | sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
39 | sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect
40 | sigs.k8s.io/yaml v1.2.0 // indirect
41 | )
42 |
43 | go 1.17
44 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at sys@cycoresys.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/defaults/modules.conf:
--------------------------------------------------------------------------------
1 | [modules]
2 | autoload = no
3 |
4 | ; This is a minimal module load. We are loading only the modules required for
5 | ; the Asterisk features used in the Super Awesome Company configuration.
6 |
7 | ; Applications
8 |
9 | load = app_bridgewait.so
10 | load = app_dial.so
11 | load = app_playback.so
12 | load = app_stack.so
13 | load = app_verbose.so
14 | load = app_voicemail.so
15 | load = app_directory.so
16 | load = app_confbridge.so
17 | load = app_stasis.so
18 |
19 | ; Bridging
20 |
21 | load = bridge_builtin_features.so
22 | load = bridge_builtin_interval_features.so
23 | load = bridge_holding.so
24 | load = bridge_native_rtp.so
25 | load = bridge_simple.so
26 | load = bridge_softmix.so
27 |
28 | ; Call Detail Records
29 |
30 | load = cdr_custom.so
31 |
32 | ; Channel Drivers
33 |
34 | load = chan_bridge_media.so
35 | load = chan_pjsip.so
36 |
37 | ; Codecs
38 |
39 | load = codec_gsm.so
40 | load = codec_resample.so
41 | load = codec_ulaw.so
42 | load = codec_g722.so
43 |
44 | ; Formats
45 |
46 | load = format_gsm.so
47 | load = format_pcm.so
48 | load = format_wav_gsm.so
49 | load = format_wav.so
50 |
51 | ; Functions
52 |
53 | load = func_callerid.so
54 | load = func_cdr.so
55 | load = func_pjsip_endpoint.so
56 | load = func_sorcery.so
57 | load = func_devstate.so
58 | load = func_strings.so
59 |
60 | ; Core/PBX
61 |
62 | load = pbx_config.so
63 |
64 | ; Resources
65 |
66 | load = res_musiconhold.so
67 | load = res_pjproject.so
68 | load = res_pjsip_acl.so
69 | load = res_pjsip_authenticator_digest.so
70 | load = res_pjsip_caller_id.so
71 | load = res_pjsip_dialog_info_body_generator.so
72 | load = res_pjsip_diversion.so
73 | load = res_pjsip_dtmf_info.so
74 | load = res_pjsip_endpoint_identifier_anonymous.so
75 | load = res_pjsip_endpoint_identifier_ip.so
76 | load = res_pjsip_endpoint_identifier_user.so
77 | load = res_pjsip_exten_state.so
78 | load = res_pjsip_header_funcs.so
79 | load = res_pjsip_logger.so
80 | load = res_pjsip_messaging.so
81 | load = res_pjsip_mwi_body_generator.so
82 | load = res_pjsip_mwi.so
83 | load = res_pjsip_nat.so
84 | load = res_pjsip_notify.so
85 | load = res_pjsip_one_touch_record_info.so
86 | load = res_pjsip_outbound_authenticator_digest.so
87 | load = res_pjsip_outbound_publish.so
88 | load = res_pjsip_outbound_registration.so
89 | load = res_pjsip_path.so
90 | load = res_pjsip_pidf_body_generator.so
91 | load = res_pjsip_pidf_digium_body_supplement.so
92 | load = res_pjsip_pidf_eyebeam_body_supplement.so
93 | load = res_pjsip_publish_asterisk.so
94 | load = res_pjsip_pubsub.so
95 | load = res_pjsip_refer.so
96 | load = res_pjsip_registrar_expire.so
97 | load = res_pjsip_registrar.so
98 | load = res_pjsip_rfc3326.so
99 | load = res_pjsip_sdp_rtp.so
100 | load = res_pjsip_send_to_voicemail.so
101 | load = res_pjsip_session.so
102 | load = res_pjsip.so
103 | load = res_pjsip_t38.so
104 | load = res_pjsip_transport_websocket.so
105 | load = res_pjsip_xpidf_body_generator.so
106 | load = res_rtp_asterisk.so
107 | load = res_sorcery_astdb.so
108 | load = res_sorcery_config.so
109 | load = res_sorcery_memory.so
110 | load = res_sorcery_realtime.so
111 | load = res_stasis_answer.so
112 | load = res_stasis_device_state.so
113 | load = res_stasis_playback.so
114 | load = res_stasis_recording.so
115 | load = res_stasis_snoop.so
116 | load = res_stasis.so
117 | load = res_ari_applications.so
118 | load = res_ari_asterisk.so
119 | load = res_ari_bridges.so
120 | load = res_ari_channels.so
121 | load = res_ari_device_states.so
122 | load = res_ari_endpoints.so
123 | load = res_ari_events.so
124 | load = res_ari_model.so
125 | load = res_ari_playbacks.so
126 | load = res_ari_recordings.so
127 | load = res_ari_sounds.so
128 | load = res_ari.so
129 | load = res_timing_timerfd.so
130 |
--------------------------------------------------------------------------------
/.goreleaser.yml:
--------------------------------------------------------------------------------
1 | project_name: Asterisk Config
2 | builds:
3 | - binary: asterisk-config
4 | env:
5 | - CGO_ENABLED=0
6 | goos:
7 | - linux
8 | - darwin
9 | - windows
10 | goarch:
11 | - amd64
12 | - arm64
13 |
14 | archives:
15 | - id: asterisk-config
16 | format: tar.gz
17 | name_template: "{{ .Binary }}.{{ .Os }}.{{ .Arch }}"
18 | files:
19 | - 'defaults/*'
20 | checksum:
21 | name_template: 'checksums.txt'
22 | snapshot:
23 | name_template: "{{ .Tag }}-next"
24 | changelog:
25 | sort: asc
26 | filters:
27 | exclude:
28 | - '^docs:'
29 | - '^doc:'
30 | - '^test:'
31 |
32 | dockers:
33 | - image_templates:
34 | - 'cycoresystems/asterisk-config:{{ .Tag }}-amd64'
35 | - 'cycoresystems/asterisk-config:v{{ .Major }}-amd64'
36 | - 'cycoresystems/asterisk-config:v{{ .Major }}.{{ .Minor }}-amd64'
37 | - 'cycoresystems/asterisk-config:latest-amd64'
38 | - 'ghcr.io/cycoresystems/asterisk-config:{{ .Tag }}-amd64'
39 | - 'ghcr.io/cycoresystems/asterisk-config:v{{ .Major }}-amd64'
40 | - 'ghcr.io/cycoresystems/asterisk-config:v{{ .Major }}.{{ .Minor }}-amd64'
41 | - 'ghcr.io/cycoresystems/asterisk-config:latest-amd64'
42 | use: buildx
43 | goos: linux
44 | goarch: amd64
45 | dockerfile: Dockerfile.goreleaser
46 | extra_files:
47 | - 'defaults/'
48 | build_flag_templates:
49 | - "--platform=linux/amd64"
50 | - image_templates:
51 | - 'cycoresystems/asterisk-config:{{ .Tag }}-arm64v8'
52 | - 'cycoresystems/asterisk-config:v{{ .Major }}-arm64v8'
53 | - 'cycoresystems/asterisk-config:v{{ .Major }}.{{ .Minor }}-arm64v8'
54 | - 'cycoresystems/asterisk-config:latest-arm64v8'
55 | - 'ghcr.io/cycoresystems/asterisk-config:{{ .Tag }}-arm64v8'
56 | - 'ghcr.io/cycoresystems/asterisk-config:v{{ .Major }}-arm64v8'
57 | - 'ghcr.io/cycoresystems/asterisk-config:v{{ .Major }}.{{ .Minor }}-arm64v8'
58 | - 'ghcr.io/cycoresystems/asterisk-config:latest-arm64v8'
59 | use: buildx
60 | goos: linux
61 | goarch: arm64
62 | dockerfile: Dockerfile.goreleaser
63 | extra_files:
64 | - 'defaults/'
65 | build_flag_templates:
66 | - "--platform=linux/arm64/v8"
67 | docker_manifests:
68 | - name_template: 'cycoresystems/asterisk-config:{{ .Tag }}'
69 | image_templates:
70 | - cycoresystems/asterisk-config:{{ .Tag }}-amd64
71 | - cycoresystems/asterisk-config:{{ .Tag }}-arm64v8
72 | - name_template: 'ghcr.io/cycoresystems/asterisk-config:{{ .Tag }}'
73 | image_templates:
74 | - ghcr.io/cycoresystems/asterisk-config:{{ .Tag }}-amd64
75 | - ghcr.io/cycoresystems/asterisk-config:{{ .Tag }}-arm64v8
76 | - name_template: 'cycoresystems/asterisk-config:v{{ .Major }}'
77 | image_templates:
78 | - cycoresystems/asterisk-config:v{{ .Major }}-amd64
79 | - cycoresystems/asterisk-config:v{{ .Major }}-arm64v8
80 | - name_template: 'ghcr.io/cycoresystems/asterisk-config:v{{ .Major }}'
81 | image_templates:
82 | - ghcr.io/cycoresystems/asterisk-config:v{{ .Major }}-amd64
83 | - ghcr.io/cycoresystems/asterisk-config:v{{ .Major }}-arm64v8
84 | - name_template: 'cycoresystems/asterisk-config:v{{ .Major }}.{{ .Minor }}'
85 | image_templates:
86 | - cycoresystems/asterisk-config:v{{ .Major }}.{{ .Minor }}-amd64
87 | - cycoresystems/asterisk-config:v{{ .Major }}.{{ .Minor }}-arm64v8
88 | - name_template: 'ghcr.io/cycoresystems/asterisk-config:v{{ .Major }}.{{ .Minor }}'
89 | image_templates:
90 | - ghcr.io/cycoresystems/asterisk-config:v{{ .Major }}.{{ .Minor }}-amd64
91 | - ghcr.io/cycoresystems/asterisk-config:v{{ .Major }}.{{ .Minor }}-arm64v8
92 | - name_template: 'cycoresystems/asterisk-config:latest'
93 | image_templates:
94 | - cycoresystems/asterisk-config:latest-amd64
95 | - cycoresystems/asterisk-config:latest-arm64v8
96 | - name_template: 'ghcr.io/cycoresystems/asterisk-config:latest'
97 | image_templates:
98 | - ghcr.io/cycoresystems/asterisk-config:latest-amd64
99 | - ghcr.io/cycoresystems/asterisk-config:latest-arm64v8
100 |
--------------------------------------------------------------------------------
/Documentation/pjsip-ext-ext.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Documentation/pjsip-int-ext.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Documentation/pjsip-int-int.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "archive/zip"
5 | "context"
6 | "encoding/json"
7 | "errors"
8 | "fmt"
9 | "io"
10 | "io/ioutil"
11 | "log"
12 | "net/http"
13 | "os"
14 | "path"
15 | "path/filepath"
16 | "strings"
17 | "sync"
18 | "time"
19 |
20 | "github.com/CyCoreSystems/kubetemplate"
21 | "github.com/CyCoreSystems/netdiscover/discover"
22 | "github.com/rotisserie/eris"
23 | "k8s.io/client-go/kubernetes"
24 | "k8s.io/client-go/rest"
25 | )
26 |
27 | const ariUsername = "k8s-asterisk-config"
28 | const secretFilename = ".k8s-generated-secret"
29 | const renderFlagFilename = ".asterisk-config"
30 |
31 | var maxShortDeaths = 10
32 | var minRuntime = time.Minute
33 | var defaultMinReloadInterval = 5 * time.Second
34 |
35 | // Service maintains an Asterisk configuration set
36 | type Service struct {
37 |
38 | // Discoverer is the engine which should be used for network discovery
39 | Discoverer discover.Discoverer
40 |
41 | // Secret is the password which should be used for internal administrative authentication
42 | Secret string
43 |
44 | // CustomRoot is the directory which contains the tree of custom configuration templates
45 | CustomRoot string
46 |
47 | // DefaultsRoot is the directory which contains the default configuration templates
48 | DefaultsRoot string
49 |
50 | // ExportRoot is the destination directory to which the rendered configuration set will be exported.
51 | ExportRoot string
52 |
53 | // Modules is the list of Asterisk modules which should be reloaded after each render is complete.
54 | Modules string
55 |
56 | // engine is the template rendering and monitoring engine
57 | engine kubetemplate.Engine
58 | }
59 |
60 | // nolint: gocyclo
61 | func main() {
62 | var err error
63 |
64 | cloud := ""
65 | if os.Getenv("CLOUD") != "" {
66 | cloud = os.Getenv("CLOUD")
67 | }
68 | disc := getDiscoverer(cloud)
69 |
70 | source := "/source/asterisk-config.zip"
71 | if os.Getenv("SOURCE") != "" {
72 | source = os.Getenv("SOURCE")
73 | }
74 |
75 | defaultsRoot := "/defaults"
76 | if os.Getenv("DEFAULTS_DIR") != "" {
77 | defaultsRoot = os.Getenv("DEFAULTS_DIR")
78 | }
79 |
80 | customRoot := "/custom"
81 | if os.Getenv("CUSTOM_DIR") != "" {
82 | customRoot = os.Getenv("CUSTOM_DIR")
83 | }
84 | if err := os.MkdirAll(customRoot, os.ModePerm); err != nil {
85 | log.Println("failed to ensure custom directory", customRoot, ":", err.Error())
86 | os.Exit(1)
87 | }
88 |
89 | exportRoot := "/etc/asterisk"
90 | if os.Getenv("EXPORT_DIR") != "" {
91 | exportRoot = os.Getenv("EXPORT_DIR")
92 | }
93 | if err = os.MkdirAll(exportRoot, os.ModePerm); err != nil {
94 | log.Println("failed to ensure destination directory", exportRoot, ":", err.Error())
95 | os.Exit(1)
96 | }
97 |
98 | modules := "res_pjsip.so"
99 | if os.Getenv("RELOAD_MODULES") != "" {
100 | modules = os.Getenv("RELOAD_MODULES")
101 | }
102 |
103 | secret := os.Getenv("ARI_AUTOSECRET")
104 | if secret == "" {
105 | secret, err = getOrCreateSecret(exportRoot)
106 | if err != nil {
107 | log.Println("failed to get secret:", err)
108 | os.Exit(1)
109 | }
110 | os.Setenv("ARI_AUTOSECRET", secret)
111 | }
112 |
113 | // Try to extract the source
114 | if err := extractSource(source, customRoot); err != nil {
115 | log.Printf("failed to load source from %s: %s\n", source, err.Error())
116 | }
117 |
118 | var shortDeaths int
119 | var t time.Time
120 | for shortDeaths < maxShortDeaths {
121 |
122 | svc := &Service{
123 | Discoverer: disc,
124 | Secret: secret,
125 | CustomRoot: customRoot,
126 | DefaultsRoot: defaultsRoot,
127 | ExportRoot: exportRoot,
128 | Modules: modules,
129 | }
130 |
131 | t = time.Now()
132 | log.Println("running service")
133 | err := svc.Run()
134 | log.Println("service exited:", err)
135 | if time.Since(t) < minRuntime {
136 | shortDeaths++
137 | } else {
138 | shortDeaths = 0
139 | }
140 | }
141 |
142 | log.Println("asterisk-config exiting")
143 | os.Exit(1)
144 | }
145 |
146 | // Run executes the Service
147 | func (s *Service) Run() error {
148 | ctx, cancel := context.WithCancel(context.Background())
149 | defer cancel()
150 |
151 | r := newReloader(ctx, ariUsername, s.Secret, s.Modules)
152 |
153 | kconfig, err := rest.InClusterConfig()
154 | if err != nil {
155 | return fmt.Errorf("failed to create in-cluster Kubernetes config: %w", err)
156 | }
157 |
158 | kc, err := kubernetes.NewForConfig(kconfig)
159 | if err != nil {
160 | return eris.Wrap(err, "failed to create Kubernetes client")
161 | }
162 |
163 | s.engine, err = kubetemplate.NewEngine(kc, s.Discoverer, 10*time.Minute)
164 | if err != nil {
165 | return eris.Wrap(err, "failed to create templating engine")
166 | }
167 |
168 | defer s.engine.Close()
169 |
170 | // Learn the templates first
171 | if err := s.learnTemplates(); err != nil {
172 | return eris.Wrap(err, "failed to learn defaults")
173 | }
174 |
175 | // Execute first template render
176 | if err := s.renderTemplates(); err != nil {
177 | return eris.Wrap(err, "failed to render configuration")
178 | }
179 |
180 | // Write out render flag file to signal completion
181 | if err := ioutil.WriteFile(path.Join(s.ExportRoot, renderFlagFilename), []byte("complete"), 0666); err != nil {
182 | return eris.Wrap(err, "failed to write render flag file")
183 | }
184 |
185 | r.Reload()
186 |
187 | for ctx.Err() == nil {
188 | s.engine.Wait(ctx)
189 |
190 | log.Println("change detected")
191 |
192 | if err := s.renderTemplates(); err != nil {
193 | return eris.Wrap(err, "failed to render configuration")
194 | }
195 |
196 | r.Reload()
197 | }
198 |
199 | return ctx.Err()
200 | }
201 |
202 | func (s *Service) learnTemplates() error {
203 | if err := render(s.engine, true, s.DefaultsRoot, s.ExportRoot); err != nil {
204 | return eris.Wrap(err, "failed to learn defaults")
205 | }
206 | if err := render(s.engine, true, s.CustomRoot, s.ExportRoot); err != nil {
207 | return eris.Wrap(err, "failed to learn templates")
208 | }
209 |
210 | return nil
211 | }
212 |
213 | func (s *Service) renderTemplates() error {
214 | if err := render(s.engine, false, s.DefaultsRoot, s.ExportRoot); err != nil {
215 | return eris.Wrap(err, "failed to render defaults")
216 | }
217 | if err := render(s.engine, false, s.CustomRoot, s.ExportRoot); err != nil {
218 | return eris.Wrap(err, "failed to render templates")
219 | }
220 |
221 | return nil
222 | }
223 |
224 | func getDiscoverer(cloud string) discover.Discoverer {
225 | switch cloud {
226 | case "aws":
227 | return discover.NewAWSDiscoverer()
228 | case "azure":
229 | return discover.NewAzureDiscoverer()
230 | case "digitalocean":
231 | return discover.NewDigitalOceanDiscoverer()
232 | case "do":
233 | return discover.NewDigitalOceanDiscoverer()
234 | case "gcp":
235 | return discover.NewGCPDiscoverer()
236 | case "":
237 | return discover.NewDiscoverer()
238 | default:
239 | log.Printf("WARNING: unhandled cloud %s\n", cloud)
240 | return discover.NewDiscoverer()
241 | }
242 | }
243 |
244 | func getOrCreateSecret(exportRoot string) (string, error) {
245 | secret := genSecret()
246 | secretPath := path.Join(exportRoot, secretFilename)
247 |
248 | // Determine if a secret has already been generated
249 | if data, err := ioutil.ReadFile(secretPath); err == nil {
250 | if len(data) > 0 {
251 | return string(data), nil
252 | }
253 | }
254 |
255 | if err := ioutil.WriteFile(secretPath, []byte(secret), 0600); err != nil {
256 | return "", eris.Wrap(err, "failed to write secret to file")
257 | }
258 | return secret, nil
259 | }
260 |
261 | func render(e kubetemplate.Engine, learn bool, customRoot string, exportRoot string) error {
262 | var fileCount int
263 |
264 | err := filepath.Walk(customRoot, func(fn string, info os.FileInfo, err error) error {
265 | if err != nil {
266 | return eris.Wrapf(err, "failed to access file %s", fn)
267 | }
268 |
269 | isTemplate := path.Ext(fn) == ".tmpl"
270 |
271 | outFile := path.Join(exportRoot, strings.TrimPrefix(fn, customRoot))
272 | if isTemplate {
273 | outFile = strings.TrimSuffix(outFile, ".tmpl")
274 | }
275 |
276 | if info.IsDir() {
277 | return os.MkdirAll(outFile, os.ModePerm)
278 | }
279 | if err = os.MkdirAll(path.Dir(outFile), os.ModePerm); err != nil {
280 | return eris.Wrapf(err, "failed to create destination directory %s", path.Dir(outFile))
281 | }
282 | fileCount++
283 |
284 | out, err := os.Create(outFile)
285 | if err != nil {
286 | return eris.Wrapf(err, "failed to open file for writing: %s", outFile)
287 | }
288 | defer out.Close() // nolint: errcheck
289 |
290 | in, err := os.Open(fn) // nolint: gosec
291 | if err != nil {
292 | return eris.Wrapf(err, "failed to open template for reading: %s", fn)
293 | }
294 | defer in.Close() // nolint: errcheck
295 |
296 | if isTemplate {
297 | if learn {
298 | return e.Learn(in, os.Getenv("POD_NAMESPACE"))
299 | }
300 | return e.Render(out, in, os.Getenv("POD_NAMESPACE"))
301 | }
302 |
303 | _, err = io.Copy(out, in)
304 | return err
305 | })
306 | if err != nil {
307 | return err
308 | }
309 |
310 | if fileCount < 1 {
311 | return errors.New("no files processed")
312 | }
313 |
314 | return nil
315 | }
316 |
317 | func waitAsterisk(username, secret string) error {
318 | r, err := http.NewRequest("GET", "http://127.0.0.1:8088/ari/asterisk/variable?variable=ASTERISK_CONFIG_SYSTEM_READY", nil)
319 | if err != nil {
320 | return eris.Wrap(err, "failed to construct ping request")
321 | }
322 | r.Header.Set("Content-Type", "application/json")
323 | r.SetBasicAuth(username, secret)
324 |
325 | type response struct {
326 | Value string `json:"value"`
327 | }
328 | resp := new(response)
329 |
330 | for {
331 | time.Sleep(time.Second / 2)
332 |
333 | ret, err := http.DefaultClient.Do(r)
334 | if err != nil {
335 | continue
336 | }
337 |
338 | if err = json.NewDecoder(ret.Body).Decode(resp); err != nil {
339 | // failed to decode into resp format
340 | log.Println("failed to decode Asterisk response:", err)
341 | continue
342 | }
343 | if resp.Value != "1" {
344 | // not yet ready
345 | continue
346 | }
347 |
348 | // System ready
349 | log.Println("Asterisk ready")
350 | return nil
351 | }
352 | }
353 |
354 | func extractSource(source, customRoot string) (err error) {
355 | if strings.HasPrefix(source, "http") {
356 | source, err = downloadSource(source)
357 | if err != nil {
358 | return eris.Wrap(err, "failed to download source")
359 | }
360 | }
361 |
362 | r, err := zip.OpenReader(source)
363 | if err != nil {
364 | return eris.Wrap(err, "failed to open source archive")
365 | }
366 | defer r.Close() // nolint: errcheck
367 |
368 | for _, f := range r.File {
369 |
370 | in, err := f.Open()
371 | if err != nil {
372 | return eris.Wrapf(err, "failed to read file %s", f.Name)
373 | }
374 | defer in.Close() // nolint: errcheck
375 |
376 | dest := path.Join(customRoot, f.Name)
377 | if f.FileInfo().IsDir() {
378 | if err = os.MkdirAll(dest, os.ModePerm); err != nil {
379 | return eris.Wrapf(err, "failed to create destination directory %s", f.Name)
380 | }
381 | continue
382 | }
383 |
384 | if err = os.MkdirAll(path.Dir(dest), os.ModePerm); err != nil {
385 | return eris.Wrapf(err, "failed to create destination directory %s", path.Dir(dest))
386 | }
387 |
388 | out, err := os.Create(dest)
389 | if err != nil {
390 | return eris.Wrapf(err, "failed to create file %s", dest)
391 | }
392 |
393 | _, err = io.Copy(out, in)
394 | out.Close() // nolint
395 | if err != nil {
396 | return eris.Wrapf(err, "error writing file %s", dest)
397 | }
398 |
399 | }
400 |
401 | return nil
402 | }
403 |
404 | func downloadSource(uri string) (string, error) {
405 | req, err := http.NewRequest("GET", uri, nil)
406 | if err != nil {
407 | return "", eris.Wrapf(err, "failed to construct web request to %s", uri)
408 | }
409 |
410 | if os.Getenv("URL_USERNAME") != "" {
411 | req.SetBasicAuth(os.Getenv("URL_USERNAME"), os.Getenv("URL_PASSWORD"))
412 | }
413 | if os.Getenv("URL_AUTHORIZATION") != "" {
414 | req.Header.Add("Authorization", os.Getenv("URL_AUTHORIZATION"))
415 | }
416 |
417 | resp, err := http.DefaultClient.Do(req)
418 | if err != nil {
419 | return "", err
420 | }
421 | defer resp.Body.Close() // nolint: errcheck
422 |
423 | if resp.StatusCode < 200 || resp.StatusCode > 299 {
424 | return "", fmt.Errorf("request failed: %s", resp.Status)
425 | }
426 | if resp.ContentLength < 1 {
427 | return "", errors.New("empty response")
428 | }
429 |
430 | tf, err := ioutil.TempFile("", "config-download")
431 | if err != nil {
432 | return "", eris.Wrap(err, "failed to create temporary file for download")
433 | }
434 | defer tf.Close() // nolint: errcheck
435 |
436 | _, err = io.Copy(tf, resp.Body)
437 |
438 | return tf.Name(), err
439 | }
440 |
441 | type reloader struct {
442 | minReloadInterval time.Duration
443 |
444 | username string
445 | secret string
446 |
447 | modules []string
448 |
449 | needReload bool
450 |
451 | mu sync.Mutex
452 | }
453 |
454 | func newReloader(ctx context.Context, username, secret, modules string) *reloader {
455 | r := &reloader{
456 | minReloadInterval: defaultMinReloadInterval,
457 | username: username,
458 | secret: secret,
459 | }
460 |
461 | for _, m := range strings.Split(modules, ",") {
462 | r.modules = append(r.modules, strings.TrimSpace(m))
463 | }
464 |
465 | go r.run(ctx)
466 |
467 | return r
468 | }
469 |
470 | func (r *reloader) run(ctx context.Context) {
471 | // Wait for Asterisk to come up before proceeding, so as to not interrupt
472 | // normal Asterisk loading with a reload
473 | log.Println("Waiting for Asterisk to be ready...")
474 | if err := waitAsterisk(r.username, r.secret); err != nil {
475 | log.Fatalln("failed to wait for Asterisk to come up:", err)
476 | }
477 |
478 | for {
479 | select {
480 | case <-ctx.Done():
481 | return
482 | case <-time.After(r.minReloadInterval):
483 | }
484 |
485 | if err := r.maybeRunReload(); err != nil {
486 | log.Println("failed to reload modules", err)
487 | }
488 | }
489 | }
490 |
491 | func (r *reloader) maybeRunReload() error {
492 | r.mu.Lock()
493 | defer r.mu.Unlock()
494 |
495 | if r.needReload {
496 | if err := r.reload(); err != nil {
497 | return err
498 | }
499 |
500 | r.needReload = false
501 | }
502 |
503 | return nil
504 | }
505 |
506 | func (r *reloader) Reload() {
507 | r.mu.Lock()
508 | r.needReload = true
509 | r.mu.Unlock()
510 | }
511 |
512 | func (r *reloader) reload() error {
513 | log.Println("reloading Asterisk modules")
514 | for _, m := range r.modules {
515 | if err := r.reloadModule(m); err != nil {
516 | return err
517 | }
518 | }
519 | log.Println("Asterisk modules reloaded")
520 |
521 | return nil
522 | }
523 |
524 | func (r *reloader) reloadModule(name string) error {
525 | url := fmt.Sprintf("http://127.0.0.1:8088/ari/asterisk/modules/%s", name)
526 |
527 | req, err := http.NewRequest("PUT", url, nil)
528 | if err != nil {
529 | return eris.Wrapf(err, "failed to construct module reload request for module %s", name)
530 | }
531 | req.Header.Set("Content-Type", "application/json")
532 | req.SetBasicAuth(r.username, r.secret)
533 |
534 | ret, err := http.DefaultClient.Do(req)
535 | if err != nil {
536 | return eris.Wrapf(err, "failed to contact ARI to reload module %s", name)
537 | }
538 | ret.Body.Close() // nolint
539 |
540 | switch ret.StatusCode {
541 | case http.StatusNoContent:
542 | return nil
543 | case http.StatusNotFound:
544 | return fmt.Errorf("module %s not already loaded", name)
545 | case http.StatusUnauthorized:
546 | return fmt.Errorf("module %s failed to reload due bad authentication", name)
547 | case 409:
548 | return fmt.Errorf("module %s could not be reloaded", name)
549 | default:
550 | return fmt.Errorf("module %s reload failed: %s", name, ret.Status)
551 | }
552 | }
553 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Asterisk Config
2 |
3 | Asterisk Config is a kubernetes sidecar container which constructs the
4 | configuration for Asterisk. It is comprised of a custom configuration set and a
5 | standardized dynamic environment set to build the Asterisk configuration for the
6 | Pod in question.
7 |
8 | The primary dynamic component of Asterisk Config is the IP address (internal and
9 | external) for use by the SIP and PJSIP modules.
10 |
11 | ## Automatic reloading
12 |
13 | Any time dynamic data is updated, Asterisk is told to reload. By default, we
14 | only reload `res_pjsip.so`, since the dynamic data usually just involves PJSIP
15 | endpoint IPs. However, you can set the `RELOAD_MODULES` environment variable to
16 | a comma-separated list of modules which should be reloaded when the dynamic data
17 | is updated.
18 |
19 | The reloads are performed by executing the ARI "/asterisk/modules" "PUT"
20 | (reload) once for each of the specified modules. This ARI connection is
21 | automatically created with a randomly-generated password by Asterisk Config.
22 |
23 | ## Layering
24 |
25 | There are two layers of files which are used:
26 |
27 | - Default configuration
28 | - Custom configuration
29 |
30 | ### Default configuration
31 |
32 | Included within this package is the standard Asterisk basic configuration set
33 | with minimal alterations to:
34 |
35 | - include custom configurations
36 | - include configuration directories
37 | - disable all file-based logging
38 |
39 | Any file in the default configuration my be replaced by including it in your
40 | custom configuration bundle, but see the Custom configuration section below for
41 | better methods.
42 |
43 | The default configuration also creates configurations for ARI, so that it may
44 | call a reload when necessary, and PJSIP, to configure the IP information for
45 | transports.
46 |
47 | #### PJSIP default transports
48 |
49 | The following default PJSIP transports will be specified:
50 |
51 | - `k8s-internal-ipv4-internal-media` (internal SIP/signaling advertisement,
52 | internal RTP/media advertisement, port 5080/UDP)
53 | - `k8s-internal-ipv4-external-media` (internal SIP/signaling advertisement,
54 | external RTP/media advertisement, port 5070/UDP)
55 | - `k8s-external-ipv4-external-media` (external SIP/signaling advertisement,
56 | external RTP/media advertisement, port 5060/UDP)
57 |
58 | In most cloud-based kubernetes setups, the Pod will be assigned an internal IP
59 | address, and it will have a NATed external IP address. The choice of transports
60 | depends on two things:
61 |
62 | - Where is the _signaling_ endpoint?
63 | - Where is the _media_ endpoint?
64 |
65 | It is common, for instance, to use kamailio as a SIP proxy to handle a scalable
66 | set of Asterisk servers. In this case, you would want to use _internal_
67 | signaling IPs. The RTP, however, will depend on whether you want your media to
68 | flow _directly_ to your Asterisk Pods (`-external-media`) or by way of
69 | `rtpengine` or `rtpproxy` (`-internal-media`).
70 |
71 | For each of your PJSIP `Endpoints`, just specify the transport you wish to
72 | use.
73 |
74 | - 
75 | - 
76 | - 
77 |
78 | ### Custom configuration
79 |
80 | While your custom configurations are allowed to overwrite any Asterisk
81 | configuration file, there are generally two schemes by which customized configurations may be
82 | applied:
83 |
84 | - `.d/XXXX.conf`
85 | - `_custom.conf`
86 |
87 | The most flexible approach is to create any number of discrete files in the
88 | module configuration subdirectories. For instance, you might add a PJSIP
89 | endpoint configuration in:
90 |
91 | `pjsip.d/ext-101.conf`
92 |
93 | Any file with the `.conf` extension in one of these directories will
94 | automatically be loaded.
95 |
96 | Modules which are configured to load configurations using this scheme are:
97 |
98 | - AMI (`manager.d/`)
99 | - ARI (`ari.d/`)
100 | - Extensions (`extensions.d/`)
101 | - PJSIP (`pjsip.d/`)
102 | - Voicemail (`voicemail.d/`)
103 |
104 | If there is any default configuration for any of these modules, that
105 | configuration will exist in `_custom.conf`. The corresponding
106 | `.conf` only contains include statements.
107 |
108 | Take special note that ARI and PJSIP modules are used internally by Asterisk
109 | Config, so changing their root `ari.conf` and `pjsip.conf` is not recommended
110 | unless you really know what you are doing.
111 |
112 | ## Usage
113 |
114 | It is presumed that you have a kubernetes installation on a standard cloud
115 | platform (such as AWS, GCP, Azure, DigitalOcean, etc) or are running a baremetal
116 | kubernetes cluster which you can control to supply the public and private IP
117 | addresses for the Asterisk Pod.
118 |
119 | It is strongly recommended to set the `CLOUD` environment variable to match your
120 | environment. The valid options are:
121 |
122 | - `aws` Amazon Web Services
123 | - `azure` Microsoft Azure
124 | - `digitalocean` or `do` Digital Ocean
125 | - `gcp` Google Cloud Platform
126 | - `` default discovery
127 |
128 | Default discovery is useful for baremetal configurations or situations where you
129 | do not wish to use the cloud provider's self discovery API.
130 |
131 | ***NOTE***: Importantly, in cases where you need Asterisk to use the kubernetes
132 | Pod IP address instead of the Node IP address, set the `CLOUD` variable to be
133 | the empty string. Default discovery also works for public IP addresses by using
134 | the `jsonip.io` service.
135 |
136 | Asterisk Config offers varying levels of configuration complexity, allowing you
137 | to easily just get your Asterisk system off the ground or to build a
138 | fully-templated configuration set.
139 |
140 | It is a common problem that Asterisk may start before the config has been
141 | written. In order to eliminate that eventuality, you should check for the
142 | existence of the `.asterisk-config` file before allowing Asterisk to start.
143 |
144 | ### Basic Usage
145 |
146 | The simplest use is: to create the set of custom Asterisk configurations
147 |
148 | 1. create the set of custom Asterisk configurations for your scenario
149 | 2. generate a `.zip` file of that configuration tree
150 | 3. load that `.zip` file to a ConfigMap, Secret, or Web URL
151 |
152 | For example:
153 |
154 | We will define a simple dialplan with a single PJSIP endpoint to a carrier.
155 | When a call comes in from the carrier, it will be answered and any audio
156 | received will be played back to the caller.
157 |
158 | First, create a directory to contain the configuration files. Files stored in
159 | this directory will be copied into `/etc/asterisk/` on the live Asterisk Pod.
160 | In this example, we will use the local directory named
161 | `/home/user/asterisk/config`.
162 |
163 | Inside your directory, we create two files: `pjsip.d/my_carrier.conf` and
164 | `extensions.d/dialin.conf`.
165 |
166 | `pjsip.d/my_carrier.conf`:
167 |
168 | ```ini
169 | [pstn]
170 | type=endpoint
171 | transport=k8s-external-ipv4-external-media
172 | context=dialin
173 | disallow=all
174 | allow=ulaw
175 | aors=pstn
176 | rtp_symmetric=yes
177 |
178 | [pstn]
179 | type=aor
180 | contact=sip:my.carrier.com:5060
181 |
182 | [pstn]
183 | type=identify
184 | endpoint=pstn
185 | match=12.34.56.78
186 | match=87.65.43.21
187 |
188 | [acl]
189 | type=acl
190 | deny=0.0.0.0/0.0.0.0
191 | permit=12.34.56.78/255.255.255.255
192 | permit=87.65.43.21/255.255.255.255
193 | ```
194 |
195 | `extensions.d/dialin.conf`:
196 |
197 | ```ini
198 | [dialin]
199 | exten = echo,1,Verbose(1, "Running Echo")
200 | same = n,Answer()
201 | same = n,Echo()
202 | same = n,Hangup()
203 |
204 | exten = 15555555555,1,Verbose(1, "Received call to +1 555 555.5555")
205 | same = n,Goto(echo,1)
206 | ```
207 |
208 | Now zip up these configuration files to a new `asterisk-config.zip`:
209 |
210 | ```sh
211 | zip -r asterisk-config.zip *
212 | ```
213 |
214 | Then store the `asterisk-config.zip` file to kubernetes as a Secret named
215 | "asterisk-config":
216 |
217 | ```sh
218 | kubectl create secret generic asterisk-config --from-file=asterisk-config.zip
219 | ```
220 |
221 | **NOTE**: By default, Asterisk-Config looks for the Secret named
222 | "asterisk-config" to load the custom configuration. See the section below for
223 | sourcing the custom configuration from a different location.
224 |
225 | Now we create a normal Pod spec for kubernetes including the Asterisk
226 | Configuration sidecar container:
227 |
228 | ```yaml
229 | apiVersion: extensions/v1beta1
230 | kind: Deployment
231 | metadata:
232 | name: asterisk
233 | labels:
234 | component: asterisk
235 | spec:
236 | replicas: 1
237 | template:
238 | metadata:
239 | labels:
240 | component: asterisk
241 | spec:
242 | hostNetwork: true
243 | containers:
244 | - name: config
245 | image: ghcr.io/cycoresystems/asterisk-config
246 | env:
247 | - name: POD_NAMESPACE
248 | valueFrom:
249 | fieldRef:
250 | fieldPath: metadata.namespace
251 | volumeMounts:
252 | - name: config
253 | mountPath: /etc/asterisk
254 | - name: source
255 | mountPath: /source
256 | - name: asterisk
257 | image: cycoresystems/asterisk
258 | volumeMounts:
259 | - name: config
260 | mountPath: /etc/asterisk
261 | volumes:
262 | - name: config
263 | - name: source
264 | secret:
265 | secretName: "asterisk-config"
266 | ```
267 |
268 |
269 | ## Custom Configuration source
270 |
271 | By default, Asterisk Config looks for the file `/source/asterisk-config.zip` as
272 | the source of configuration. However, this can be customized by setting the
273 | `SOURCE` environment variable.
274 |
275 | You may also obtain the source from an HTTP URL by specifying that URL as the
276 | `SOURCE`. Additional environment variables may be provided for HTTP authentication:
277 |
278 | - `URL_USERNAME` (for basic authentication)
279 | - `URL_PASSWORD` (for basic authentication),
280 | - `URL_AUTHORIZATION` (explicit `"Authorization" header`)
281 |
282 | If no `SOURCE` file can be found or is specified, Asterisk Config will attempt to
283 | load the (expanded) configuration tree in the `/custom/` directory. In this
284 | way, you may plug in your own source-obtaining method and have it populate the
285 | custom configuration files in this directory.
286 |
287 | To make sure the Asterisk container is not successfully started before the
288 | configuration can be loaded, Asterisk Config will die if no valid custom
289 | configuration can be obtained. Asterisk will already die if it cannot find its
290 | configuration. Kubernetes will automatically restart each of these if they die.
291 |
292 | ## Templates
293 |
294 | Asterisk Config will process any file within the source bundle which ends in the
295 | `.tmpl` extension. These files will be processed as Go `text/template`
296 | files and the output stored as the same filename without the `.tmpl` extension.
297 |
298 | Values for the templates may come from a number of sources:
299 |
300 | - ConfigMap
301 | - Environment Variables
302 | - Service
303 | - Endpoints (of a Service)
304 | - EndpointIPs (of a Service)
305 | - Network
306 |
307 | ### ConfigMap
308 |
309 | To obtain ConfigMap entries, Asterisk Config will use the Kubernetes API to
310 | attempt to pull in the ConfigMap and key requested.
311 |
312 | **Format**: `{{.ConfigMap "" "" ""}}`
313 |
314 | The provided namespace _may_ be `""` if both the ConfigMap is in the same
315 | namespace as the Pod _and_ the `POD_NAMESPACE` environment variable is properly
316 | set.
317 |
318 | The ConfigMap will be monitored by Asterisk Config, and if it is updated, the
319 | configuration files will be regenerated, and a reload will be performed.
320 |
321 | Note that this will likely require an RBAC entry to allow the `ServiceAccount`
322 | under which Asterisk Config is running to access the referenced ConfigMap.
323 |
324 |
325 | ### Environment Variables
326 |
327 | **Format**: `{{.Env ""}}`
328 |
329 | It is useful to note that IP addresses of services within the same namespace
330 | will automatically be populated as environment variables by kubernetes. These
331 | will be of the form `_SERVICE_HOST`. For instance, the IP of a
332 | service named "kamailio" will be stored in the environment variable
333 | `KAMAILIO_SERVICE_HOST`. This is a normal, default feature of all kubernetes
334 | containers. See the [documentation](https://kubernetes.io/docs/concepts/services-networking/service/) for more information.
335 |
336 | ### Service
337 |
338 | Data from a kubernetes Service may be obtained using the Kubernetes API.
339 |
340 | **Format**: `{{.Service "" "]"}}`
341 |
342 | The provided namespace _may_ be `""` if both the Service is in the same
343 | namespace as the Pod _and_ the `POD_NAMESPACE` environment variable is properly
344 | set.
345 |
346 | The value returned here is the Kubernetes
347 | [Service](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/#service-v1-core).
348 | Keep in mind that Go uses PascalCase for the fields, so "clusterIP" becomes
349 | "ClusterIP".
350 |
351 | For example, to get the ClusterIP of a service named "kamailio" in the "voip"
352 | namespace:
353 |
354 | `{{ with .Service "kamailio" "voip"}}{{.Spec.ClusterIP}}{{end}}`
355 |
356 | Note that the IP address of a service within the same namespace can be obtained
357 | more simply by environment variable, as described above.
358 |
359 |
360 | ### Endpoints
361 |
362 | Data from the kubernetes Endpoints of a Service may be obtained using the
363 | Kubernetes API.
364 |
365 | **Format**: `{{.Service "" ""}}`
366 |
367 | The provided namespace _may_ be `""` if both the Service is in the same
368 | namespace as the Pod _and_ the `POD_NAMESPACE` environment variable is properly
369 | set.
370 |
371 | The value returned is the Kubernetes [Endpoints](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/#endpoints-v1-core).
372 |
373 | The Endpoints will be monitored by Asterisk Config, and if it is updated, the
374 | configuration files will be regenerated, and a reload will be performed.
375 |
376 | This is usually used to obtain the dynamic set of proxy servers, but since the
377 | most common reason to do this is to obtain the set of IPs for endpoints of a
378 | service, we provide a second helper function just for that.
379 |
380 | ### Endpoint IPs
381 |
382 | One of the most common pieces of dynamic data to retrieve is the set of IPs for
383 | the endpoints of a service. Therefore, to simplify the relatively tedious
384 | iteration of these directly from the Endpoints spec, we provide the EndpointIPs
385 | macro, which returns the list of IPs of all Endpoints of the given service
386 | name.
387 |
388 | **Format**: `{{.EndpointIPs "" ""}}`
389 |
390 | The provided namespace _may_ be `""` if both the Service is in the same
391 | namespace as the Pod _and_ the `POD_NAMESPACE` environment variable is properly
392 | set.
393 |
394 | Using this is then easy. For example, to create a PJSIP endpoint from the set
395 | of proxy servers running as the "kamailio" service:
396 |
397 | `pjsip.d/proxies.conf`:
398 |
399 | ```ini
400 | [proxies]
401 | type=endpoint
402 | transport=k8s-internal-ipv4-external-media
403 | context=from-proxies
404 | disallow=all
405 | allow=ulaw
406 | aors=proxies
407 | rtp_symmetric=yes
408 |
409 | [proxies]
410 | type=aor
411 | {{range .EndpointIPs "kamailio"}}
412 | contact=sip:{{.}}
413 | {{end}}
414 |
415 | [proxies]
416 | type=identify
417 | endpoint=proxies
418 | {{range .EndpointIPs "kamailio"}}
419 | match={{.}}
420 | {{end}}
421 |
422 | [proxies]
423 | type=acl
424 | deny=0.0.0.0/0.0.0.0
425 | {{range .EndpointIPs "kamailio"}}
426 | permit={{.}}
427 | {{end}}
428 | ```
429 |
430 | The Endpoints IPs will be monitored by Asterisk Config, and if they are updated, the
431 | configuration files will be regenerated, and a reload will be performed.
432 |
433 |
434 | ### Network data
435 |
436 | The IP addresses for the running Pod are made available, as well.
437 |
438 | **Format**: `{{.Network ""}}`
439 |
440 | The available data kinds correspond to the data available from
441 | [NetDiscover](https://github.com/CyCoreSystems/netdiscover):
442 |
443 | - "hostname"
444 | - "privatev4"
445 | - "publicv4"
446 | - "publicv6"
447 |
448 | Note that PJSIP transports are already automatically set up, as described above.
449 |
450 |
--------------------------------------------------------------------------------
/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 v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
9 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
10 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
11 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
12 | cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
13 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
14 | cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
15 | cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
16 | cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
17 | cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
18 | cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
19 | cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
20 | cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
21 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
22 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
23 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
24 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
25 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
26 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
27 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
28 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
29 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
30 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
31 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
32 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
33 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
34 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
35 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
36 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
37 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
38 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
39 | github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
40 | github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA=
41 | github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M=
42 | github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
43 | github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
44 | github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
45 | github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
46 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
47 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
48 | github.com/CyCoreSystems/kubetemplate v0.6.0-rc1 h1:AUkKHwYW4bIeLVxxyava0y9FTOtZ3/sbofHxATMwXBU=
49 | github.com/CyCoreSystems/kubetemplate v0.6.0-rc1/go.mod h1:6N6GpbDmvgwmS3j/fBeSD8pCC05y++JOG4sIEI2cLIU=
50 | github.com/CyCoreSystems/netdiscover v1.2.4 h1:/9e1KlFkn5LPUMXEwDbkVfXqMJrgCWbiiXkt7GEItFs=
51 | github.com/CyCoreSystems/netdiscover v1.2.4/go.mod h1:RN7msKC9tTuYeqyMPJSEOzVUruw6xYgisO4XJ25hjFw=
52 | github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
53 | github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
54 | github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
55 | github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
56 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
57 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
58 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
59 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
60 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
61 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
62 | github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
63 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
64 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
65 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
66 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
67 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
68 | github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
69 | github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
70 | github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
71 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
72 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
73 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
74 | github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
75 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
76 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
77 | github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
78 | github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
79 | github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
80 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
81 | github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
82 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
83 | github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
84 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
85 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
86 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
87 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
88 | github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
89 | github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
90 | github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE=
91 | github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
92 | github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
93 | github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
94 | github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
95 | github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
96 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
97 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
98 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
99 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
100 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
101 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
102 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
103 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
104 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
105 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
106 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
107 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
108 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
109 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
110 | github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
111 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
112 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
113 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
114 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
115 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
116 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
117 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
118 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
119 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
120 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
121 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
122 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
123 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
124 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
125 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
126 | github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
127 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
128 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
129 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
130 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
131 | github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
132 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
133 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
134 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
135 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
136 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
137 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
138 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
139 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
140 | github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
141 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
142 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
143 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
144 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
145 | github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
146 | github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
147 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
148 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
149 | github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
150 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
151 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
152 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
153 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
154 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
155 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
156 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
157 | github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
158 | github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
159 | github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
160 | github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
161 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
162 | github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
163 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
164 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
165 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
166 | github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
167 | github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
168 | github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
169 | github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
170 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
171 | github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
172 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
173 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
174 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
175 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
176 | github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
177 | github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
178 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
179 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
180 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
181 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
182 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
183 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
184 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
185 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
186 | github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
187 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
188 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
189 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
190 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
191 | github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
192 | github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
193 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
194 | github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
195 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
196 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
197 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
198 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
199 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
200 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
201 | github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
202 | github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
203 | github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
204 | github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
205 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
206 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
207 | github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
208 | github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
209 | github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
210 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
211 | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
212 | github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
213 | github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
214 | github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
215 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
216 | github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
217 | github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
218 | github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
219 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
220 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
221 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
222 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
223 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
224 | github.com/rotisserie/eris v0.4.1 h1:0IHaklBg2X5z10qpXS8F6eR3bUM2Xsbr1bH8W/eLUlo=
225 | github.com/rotisserie/eris v0.4.1/go.mod h1:lODN/gtqebxPHRbCcWeCYOE350FC2M3V/oAPT2wKxAU=
226 | github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
227 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
228 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
229 | github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
230 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
231 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
232 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
233 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
234 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
235 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
236 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
237 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
238 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
239 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
240 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
241 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
242 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
243 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
244 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
245 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
246 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
247 | go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
248 | go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
249 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
250 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
251 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
252 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
253 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
254 | golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
255 | golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
256 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
257 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
258 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
259 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
260 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
261 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
262 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
263 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
264 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
265 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
266 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
267 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
268 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
269 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
270 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
271 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
272 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
273 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
274 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
275 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
276 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
277 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
278 | golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
279 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
280 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
281 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
282 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
283 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
284 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
285 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
286 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
287 | golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
288 | golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
289 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
290 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
291 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
292 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
293 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
294 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
295 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
296 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
297 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
298 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
299 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
300 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
301 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
302 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
303 | golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
304 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
305 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
306 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
307 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
308 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
309 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
310 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
311 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
312 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
313 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
314 | golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
315 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
316 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
317 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
318 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
319 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
320 | golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
321 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
322 | golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
323 | golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
324 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
325 | golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
326 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
327 | golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY=
328 | golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
329 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
330 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
331 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
332 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
333 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
334 | golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
335 | golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
336 | golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
337 | golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
338 | golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
339 | golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
340 | golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw=
341 | golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
342 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
343 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
344 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
345 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
346 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
347 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
348 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
349 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
350 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
351 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
352 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
353 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
354 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
355 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
356 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
357 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
358 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
359 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
360 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
361 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
362 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
363 | golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
364 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
365 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
366 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
367 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
368 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
369 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
370 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
371 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
372 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
373 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
374 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
375 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
376 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
377 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
378 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
379 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
380 | golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
381 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
382 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
383 | golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
384 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
385 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
386 | golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
387 | golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
388 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
389 | golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
390 | golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
391 | golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
392 | golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
393 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
394 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
395 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
396 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
397 | golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e h1:XMgFehsDnnLGtjvjOfqWSUzt0alpTR1RSEuznObga2c=
398 | golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
399 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
400 | golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
401 | golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
402 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
403 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
404 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
405 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
406 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
407 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
408 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
409 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
410 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
411 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
412 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
413 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
414 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
415 | golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
416 | golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
417 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
418 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
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-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
422 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
423 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
424 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
425 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
426 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
427 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
428 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
429 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
430 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
431 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
432 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
433 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
434 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
435 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
436 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
437 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
438 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
439 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
440 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
441 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
442 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
443 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
444 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
445 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
446 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
447 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
448 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
449 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
450 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
451 | golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
452 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
453 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
454 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
455 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
456 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
457 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
458 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
459 | golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
460 | golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
461 | golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
462 | golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
463 | golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
464 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
465 | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
466 | golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
467 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
468 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
469 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
470 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
471 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
472 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
473 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
474 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
475 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
476 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
477 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
478 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
479 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
480 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
481 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
482 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
483 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
484 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
485 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
486 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
487 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
488 | google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
489 | google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
490 | google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
491 | google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
492 | google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
493 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
494 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
495 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
496 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
497 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
498 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
499 | google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
500 | google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
501 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
502 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
503 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
504 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
505 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
506 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
507 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
508 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
509 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
510 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
511 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
512 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
513 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
514 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
515 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
516 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
517 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
518 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
519 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
520 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
521 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
522 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
523 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
524 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
525 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
526 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
527 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
528 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
529 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
530 | google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
531 | google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
532 | google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
533 | google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
534 | google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
535 | google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
536 | google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
537 | google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
538 | google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
539 | google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
540 | google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
541 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
542 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
543 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
544 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
545 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
546 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
547 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
548 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
549 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
550 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
551 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
552 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
553 | google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
554 | google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
555 | google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
556 | google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
557 | google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
558 | google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
559 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
560 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
561 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
562 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
563 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
564 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
565 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
566 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
567 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
568 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
569 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
570 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
571 | google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
572 | google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
573 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
574 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
575 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
576 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
577 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
578 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
579 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
580 | gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
581 | gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
582 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
583 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
584 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
585 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
586 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
587 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
588 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
589 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
590 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
591 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
592 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
593 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
594 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
595 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
596 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
597 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
598 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
599 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
600 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
601 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
602 | k8s.io/api v0.23.1 h1:ncu/qfBfUoClqwkTGbeRqqOqBCRoUAflMuOaOD7J0c8=
603 | k8s.io/api v0.23.1/go.mod h1:WfXnOnwSqNtG62Y1CdjoMxh7r7u9QXGCkA1u0na2jgo=
604 | k8s.io/apimachinery v0.23.1 h1:sfBjlDFwj2onG0Ijx5C+SrAoeUscPrmghm7wHP+uXlo=
605 | k8s.io/apimachinery v0.23.1/go.mod h1:SADt2Kl8/sttJ62RRsi9MIV4o8f5S3coArm0Iu3fBno=
606 | k8s.io/client-go v0.23.1 h1:Ma4Fhf/p07Nmj9yAB1H7UwbFHEBrSPg8lviR24U2GiQ=
607 | k8s.io/client-go v0.23.1/go.mod h1:6QSI8fEuqD4zgFK0xbdwfB/PthBsIxCJMa3s17WlcO0=
608 | k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
609 | k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
610 | k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
611 | k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw=
612 | k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
613 | k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4=
614 | k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
615 | k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
616 | k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b h1:wxEMGetGMur3J1xuGLQY7GEQYg9bZxKn3tKo5k/eYcs=
617 | k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
618 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
619 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
620 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
621 | sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s=
622 | sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
623 | sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
624 | sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno=
625 | sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
626 | sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
627 | sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
628 |
--------------------------------------------------------------------------------