├── app
├── src
│ ├── index.css
│ ├── actions
│ │ ├── index.ts
│ │ └── stories.ts
│ ├── store.ts
│ ├── StoryView.tsx
│ ├── proto
│ │ ├── hackernews_pb_service.ts
│ │ ├── hackernews_pb_service.js
│ │ ├── hackernews_pb.d.ts
│ │ └── hackernews_pb.js
│ ├── StoryList.tsx
│ ├── reducers
│ │ ├── stories.ts
│ │ └── stories.js
│ ├── Stories.tsx
│ └── middleware
│ │ └── grpc.ts
├── index.tsx
└── index.html
├── screenshots
└── grpc-web-hacker-news.png
├── server
├── README.md
├── proxy
│ └── article.go
├── middleware
│ └── grpcWeb.go
├── hackernews
│ ├── hackernews_service.go
│ └── api.go
├── main.go
└── proto
│ └── hackernews.pb.go
├── start.sh
├── protoc.sh
├── .gitignore
├── .gitpod.yml
├── proto
└── hackernews.proto
├── .github
└── workflows
│ ├── go.yml
│ ├── node.js.yml
│ └── codeql-analysis.yml
├── .editorconfig
├── go.mod
├── LICENSE
├── package.json
├── README.md
└── go.sum
/app/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/app/src/actions/index.ts:
--------------------------------------------------------------------------------
1 | import { StoryActionTypes } from './stories';
2 |
3 | export type RootAction =
4 | | StoryActionTypes;
5 |
--------------------------------------------------------------------------------
/screenshots/grpc-web-hacker-news.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easyCZ/grpc-web-hacker-news/HEAD/screenshots/grpc-web-hacker-news.png
--------------------------------------------------------------------------------
/server/README.md:
--------------------------------------------------------------------------------
1 | ## Example Hacker News Server
2 | The server is responsible for communication with the [Hacker News API](https://github.com/HackerNews/API)
3 |
4 | ### Running
5 | ```bash
6 | go run main.go
7 | ```
--------------------------------------------------------------------------------
/start.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | echo "Installing NPM dependencies with yarn"
3 | (cd app && yarn install)
4 |
5 | echo "Running go server"
6 | (cd server && go run main.go) &
7 | echo "Running frontend application"
8 | (cd app && yarn start) &
9 |
--------------------------------------------------------------------------------
/protoc.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | protoc \
3 | --go_out=plugins=grpc:./server \
4 | --plugin=protoc-gen-ts=./app/node_modules/.bin/protoc-gen-ts \
5 | --ts_out=service=true:./app/src \
6 | --js_out=import_style=commonjs,binary:./app/src \
7 | ./proto/hackernews.proto
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.dll
4 | *.so
5 | *.dylib
6 |
7 | # Test binary, build with `go test -c`
8 | *.test
9 |
10 | # Output of the go coverage tool, specifically when used with LiteIDE
11 | *.out
12 |
13 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
14 | .glide/
15 |
16 | .idea
17 | node_modules
18 | dist/
19 | .parcel-cache
20 |
--------------------------------------------------------------------------------
/app/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { Provider } from 'react-redux';
4 | import './src/index.css';
5 | import store from './src/store';
6 | import Stories from './src/Stories';
7 |
8 | ReactDOM.render(
9 |
10 |
11 |
12 |
13 | ,
14 | document.getElementById('root') as HTMLElement
15 | );
16 |
--------------------------------------------------------------------------------
/.gitpod.yml:
--------------------------------------------------------------------------------
1 | # This configuration file was automatically generated by Gitpod.
2 | # Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file)
3 | # and commit this file to your remote git repository to share the goodness with others.
4 |
5 | tasks:
6 | - name: Go deps
7 | init: go get && go build ./... && go test ./...
8 | command: go run
9 |
10 | - name: NPM deps
11 | init: npm install
12 | command: npm run
13 |
--------------------------------------------------------------------------------
/proto/hackernews.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package grpc_web_hacker_news;
4 |
5 | message Story {
6 | int32 id = 1;
7 | int32 score = 2;
8 | string title = 3;
9 | string by = 4;
10 | int32 time = 5;
11 | string url = 6;
12 | }
13 |
14 | service HackerNewsService {
15 | rpc ListStories (ListStoriesRequest) returns (stream ListStoriesResponse);
16 | }
17 |
18 | message ListStoriesResponse {
19 | Story story = 1;
20 | }
21 | message ListStoriesRequest {}
--------------------------------------------------------------------------------
/.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@v2
15 |
16 | - name: Set up Go
17 | uses: actions/setup-go@v2
18 | with:
19 | go-version: 1.17
20 |
21 | - name: Build
22 | run: go build -v ./...
23 |
24 | - name: Test
25 | run: go test -v ./...
26 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*.sh]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 |
12 | [*.{js,ts,tsx}]
13 | indent_style = space
14 | indent_size = 2
15 | charset = utf-8
16 | trim_trailing_whitespace = true
17 | insert_final_newline = true
18 | end_of_line = lf
19 |
20 | # Override for Makefile
21 | [{Makefile, makefile, GNUmakefile}]
22 | indent_style = tab
23 | indent_size = 4
--------------------------------------------------------------------------------
/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | HackerNews with grpc-web
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/store.ts:
--------------------------------------------------------------------------------
1 | import { applyMiddleware, combineReducers, createStore } from 'redux';
2 | import stories, { StoryState } from './reducers/stories';
3 | import { newGrpcMiddleware } from './middleware/grpc';
4 |
5 | interface StoreEnhancerState {
6 | }
7 |
8 | export interface RootState extends StoreEnhancerState {
9 | stories: StoryState;
10 | }
11 |
12 | const reducers = combineReducers({
13 | stories,
14 | });
15 |
16 | export default createStore(
17 | reducers,
18 | applyMiddleware(
19 | newGrpcMiddleware(),
20 | )
21 | );
22 |
--------------------------------------------------------------------------------
/app/src/StoryView.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Story } from './proto/hackernews_pb';
3 |
4 | type StoryViewProps = {
5 | story: Story.AsObject,
6 | };
7 |
8 | const StoryView: React.SFC = (props) => {
9 | const url = `http://localhost:8900/article-proxy?q=${encodeURIComponent(props.story.url)}`;
10 | return (
11 |
19 | );
20 | };
21 |
22 | export default StoryView;
23 |
--------------------------------------------------------------------------------
/server/proxy/article.go:
--------------------------------------------------------------------------------
1 | package proxy
2 |
3 | import (
4 | "net/http"
5 | "bufio"
6 | )
7 |
8 | func Article(w http.ResponseWriter, r *http.Request) {
9 | queryValues := r.URL.Query()
10 | url := queryValues.Get("q")
11 | if url == "" {
12 | http.Error(w, "Must specify the url to request", 400)
13 | }
14 | response, err := http.Get(url)
15 | if err != nil {
16 | http.Error(w, "Failed to retrieve article", 500)
17 | }
18 | if response.StatusCode >= 400 {
19 | if err != nil {
20 | http.Error(w, response.Status, response.StatusCode)
21 | }
22 | }
23 | reader := bufio.NewReader(response.Body)
24 | reader.WriteTo(w)
25 | }
26 |
--------------------------------------------------------------------------------
/server/middleware/grpcWeb.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/improbable-eng/grpc-web/go/grpcweb"
5 | "net/http"
6 | )
7 |
8 | type GrpcWebMiddleware struct {
9 | *grpcweb.WrappedGrpcServer
10 | }
11 |
12 | func (m *GrpcWebMiddleware) Handler(next http.Handler) http.Handler {
13 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
14 | if m.IsAcceptableGrpcCorsRequest(r) || m.IsGrpcWebRequest(r) {
15 | m.ServeHTTP(w, r)
16 | return
17 | }
18 | next.ServeHTTP(w, r)
19 | })
20 | }
21 |
22 | func NewGrpcWebMiddleware(grpcWeb *grpcweb.WrappedGrpcServer) *GrpcWebMiddleware {
23 | return &GrpcWebMiddleware{grpcWeb}
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/proto/hackernews_pb_service.ts:
--------------------------------------------------------------------------------
1 | // package: grpc_web_hacker_news
2 | // file: proto/hackernews.proto
3 |
4 | import * as proto_hackernews_pb from "../proto/hackernews_pb";
5 | export class HackerNewsService {
6 | static serviceName = "grpc_web_hacker_news.HackerNewsService";
7 | }
8 | export namespace HackerNewsService {
9 | export class ListStories {
10 | static readonly methodName = "ListStories";
11 | static readonly service = HackerNewsService;
12 | static readonly requestStream = false;
13 | static readonly responseStream = true;
14 | static readonly requestType = proto_hackernews_pb.ListStoriesRequest;
15 | static readonly responseType = proto_hackernews_pb.ListStoriesResponse;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/server/hackernews/hackernews_service.go:
--------------------------------------------------------------------------------
1 | package hackernews
2 |
3 | import (
4 | hackernews_pb "github.com/easyCZ/grpc-web-hacker-news/server/proto"
5 | )
6 |
7 | type hackerNewsService struct {
8 | api *hackerNewsApi
9 | }
10 |
11 | func NewHackerNewsService(api *hackerNewsApi) *hackerNewsService {
12 | if api == nil {
13 | api = NewHackerNewsApi(nil)
14 | }
15 | return &hackerNewsService{api}
16 | }
17 |
18 | func (s *hackerNewsService) ListStories(req *hackernews_pb.ListStoriesRequest, resp hackernews_pb.HackerNewsService_ListStoriesServer) error {
19 | stories, err := s.api.TopStories()
20 | defer close(stories)
21 | if err != nil {
22 | return err
23 | }
24 | for story := range stories {
25 | resp.Send(&hackernews_pb.ListStoriesResponse{
26 | Story: story,
27 | })
28 | }
29 |
30 | return nil
31 | }
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/easyCZ/grpc-web-hacker-news
2 |
3 | go 1.17
4 |
5 | require (
6 | github.com/go-chi/chi/v5 v5.0.7
7 | github.com/golang/protobuf v1.5.2
8 | github.com/improbable-eng/grpc-web v0.15.0
9 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
10 | google.golang.org/grpc v1.44.0
11 | gopkg.in/zabawaba99/firego.v1 v1.0.0-20190331000051-3bcc4b6a4599
12 | )
13 |
14 | require (
15 | github.com/cenkalti/backoff/v4 v4.1.2 // indirect
16 | github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
17 | github.com/klauspost/compress v1.14.2 // indirect
18 | github.com/rs/cors v1.8.2 // indirect
19 | github.com/zabawaba99/firego v0.0.0-20190331000051-3bcc4b6a4599 // indirect
20 | golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect
21 | golang.org/x/text v0.3.7 // indirect
22 | google.golang.org/genproto v0.0.0-20220211171837-173942840c17 // indirect
23 | google.golang.org/protobuf v1.27.1 // indirect
24 | nhooyr.io/websocket v1.8.7 // indirect
25 | )
26 |
--------------------------------------------------------------------------------
/.github/workflows/node.js.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: Node.js CI
5 |
6 | on:
7 | push:
8 | branches: [ master ]
9 | pull_request:
10 | branches: [ master ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | strategy:
18 | matrix:
19 | node-version: [12.x, 14.x, 16.x]
20 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
21 |
22 | steps:
23 | - uses: actions/checkout@v2
24 | - name: Use Node.js ${{ matrix.node-version }}
25 | uses: actions/setup-node@v2
26 | with:
27 | node-version: ${{ matrix.node-version }}
28 | cache: 'npm'
29 | - run: npm ci
30 | - run: npm run build --if-present
31 | - run: npm test
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Milan Pavlik
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "grpc-web-hacker-news",
3 | "source": "app/index.html",
4 | "browserslist": "> 0.5%, last 2 versions, not dead",
5 | "version": "1.0.0",
6 | "description": "Using grpc-web to build a hacker news reader",
7 | "scripts": {
8 | "start": "parcel",
9 | "build": "parcel build",
10 | "test": "echo 'TODO'"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/easyCZ/grpc-web-hacker-news.git"
15 | },
16 | "author": "easyCZ",
17 | "license": "ISC",
18 | "bugs": {
19 | "url": "https://github.com/easyCZ/grpc-web-hacker-news/issues"
20 | },
21 | "homepage": "https://github.com/easyCZ/grpc-web-hacker-news#readme",
22 | "devDependencies": {
23 | "@types/react": "^17.0.39",
24 | "@types/react-dom": "^17.0.11",
25 | "add": "^2.0.6",
26 | "google-protobuf": "3.0.0",
27 | "grpc-web-client": "^0.7.0",
28 | "parcel": "^2.3.1",
29 | "react": "^17.0.2",
30 | "react-dom": "^17.0.2",
31 | "react-redux": "^7.2.6",
32 | "semantic-ui-react": "^2.1.1",
33 | "typescript": "^4.5.5",
34 | "yarn": "^1.22.17"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/StoryList.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Item, Icon } from 'semantic-ui-react';
3 | import { Story } from './proto/hackernews_pb';
4 |
5 | type StoryListProps = {
6 | stories: Story.AsObject[],
7 | selected: Story.AsObject | null,
8 | onStorySelect: (id: number) => void
9 | };
10 |
11 | const StoryList: React.SFC = (props) => {
12 | return (
13 |
14 | {props.stories.map((story, i) =>
15 | - {
22 | if (story.id) {
23 | props.onStorySelect(story.id);
24 | }
25 | }}
26 | >
27 |
30 | {story.title}
31 | {story.score} | {story.by}
32 |
33 |
34 | )}
35 |
36 | );
37 | };
38 |
39 | export default StoryList;
40 |
--------------------------------------------------------------------------------
/app/src/reducers/stories.ts:
--------------------------------------------------------------------------------
1 | import { RootAction } from '../actions';
2 | import { ADD_STORY, SELECT_STORY, STORIES_INIT } from '../actions/stories';
3 | import { Story } from '../proto/hackernews_pb';
4 |
5 | export type StoryState = {
6 | readonly stories: { [storyId: number]: Story.AsObject },
7 | readonly error: Error | null,
8 | readonly loading: boolean,
9 | readonly selected: Story.AsObject | null,
10 | };
11 |
12 | const initialState = {
13 | stories: {},
14 | error: null,
15 | loading: false,
16 | selected: null,
17 | };
18 |
19 | export default function (state: StoryState = initialState, action: RootAction): StoryState {
20 |
21 | switch (action.type) {
22 |
23 | case STORIES_INIT:
24 | return {...state, loading: true};
25 |
26 | case ADD_STORY:
27 | const story: Story.AsObject = action.payload.toObject();
28 | const selected = state.selected !== null ? state.selected : story;
29 | if (story.id) {
30 | return {
31 | ...state,
32 | loading: false,
33 | stories: {...state.stories, [story.id]: story},
34 | selected,
35 | };
36 | }
37 | return state;
38 |
39 | case SELECT_STORY:
40 | return {...state, selected: state.stories[action.payload]};
41 |
42 | default:
43 | return state;
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/server/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "net/http"
6 |
7 | "github.com/easyCZ/grpc-web-hacker-news/server/hackernews"
8 | "github.com/easyCZ/grpc-web-hacker-news/server/middleware"
9 | hackernews_pb "github.com/easyCZ/grpc-web-hacker-news/server/proto"
10 | "github.com/easyCZ/grpc-web-hacker-news/server/proxy"
11 |
12 | "github.com/go-chi/chi/v5"
13 | chiMiddleware "github.com/go-chi/chi/v5/middleware"
14 |
15 | "github.com/improbable-eng/grpc-web/go/grpcweb"
16 | "google.golang.org/grpc"
17 | )
18 |
19 | func main() {
20 | grpcServer := grpc.NewServer()
21 | hackernewsService := hackernews.NewHackerNewsService(nil)
22 | hackernews_pb.RegisterHackerNewsServiceServer(grpcServer, hackernewsService)
23 |
24 | wrappedGrpc := grpcweb.WrapServer(grpcServer, grpcweb.WithOriginFunc(func(origin string) bool {
25 | // Allow all origins, DO NOT do this in production
26 | return true
27 | }))
28 |
29 | router := chi.NewRouter()
30 | router.Use(
31 | chiMiddleware.Logger,
32 | chiMiddleware.Recoverer,
33 | middleware.NewGrpcWebMiddleware(wrappedGrpc).Handler,
34 | )
35 |
36 | router.Get("/article-proxy", proxy.Article)
37 |
38 | log.Println("Serving API on http://127.0.0.1:8900")
39 | if err := http.ListenAndServe(":8900", router); err != nil {
40 | log.Fatalf("failed starting http2 server: %v", err)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/reducers/stories.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __assign = (this && this.__assign) || function () {
3 | __assign = Object.assign || function(t) {
4 | for (var s, i = 1, n = arguments.length; i < n; i++) {
5 | s = arguments[i];
6 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7 | t[p] = s[p];
8 | }
9 | return t;
10 | };
11 | return __assign.apply(this, arguments);
12 | };
13 | Object.defineProperty(exports, "__esModule", { value: true });
14 | var stories_1 = require("../actions/stories");
15 | var initialState = {
16 | stories: {},
17 | error: null,
18 | loading: false,
19 | selected: null,
20 | };
21 | function default_1(state, action) {
22 | var _a;
23 | if (state === void 0) { state = initialState; }
24 | switch (action.type) {
25 | case stories_1.STORIES_INIT:
26 | return __assign(__assign({}, state), { loading: true });
27 | case stories_1.ADD_STORY:
28 | var story = action.payload.toObject();
29 | var selected = state.selected !== null ? state.selected : story;
30 | if (story.id) {
31 | return __assign(__assign({}, state), { loading: false, stories: __assign(__assign({}, state.stories), (_a = {}, _a[story.id] = story, _a)), selected: selected });
32 | }
33 | return state;
34 | case stories_1.SELECT_STORY:
35 | return __assign(__assign({}, state), { selected: state.stories[action.payload] });
36 | default:
37 | return state;
38 | }
39 | }
40 | exports.default = default_1;
41 |
--------------------------------------------------------------------------------
/app/src/actions/stories.ts:
--------------------------------------------------------------------------------
1 | import { Action } from 'redux';
2 | import { ListStoriesRequest, ListStoriesResponse, Story } from '../proto/hackernews_pb';
3 | import { GrpcAction, grpcRequest } from '../middleware/grpc';
4 | import { Code, Metadata } from 'grpc-web-client';
5 | import { HackerNewsService } from '../proto/hackernews_pb_service';
6 |
7 | export const STORIES_INIT = 'STORIES_INIT';
8 | export const ADD_STORY = 'ADD_STORY';
9 | export const SELECT_STORY = 'SELECT_STORY';
10 |
11 | type AddStory = {
12 | type: typeof ADD_STORY,
13 | payload: Story,
14 | };
15 | export const addStory = (story: Story) => ({ type: ADD_STORY, payload: story });
16 |
17 | type ListStoriesInit = {
18 | type: typeof STORIES_INIT,
19 | };
20 | export const listStoriesInit = (): ListStoriesInit => ({type: STORIES_INIT});
21 |
22 | export const listStories = () => {
23 | return grpcRequest({
24 | request: new ListStoriesRequest(),
25 | onStart: () => listStoriesInit(),
26 | onEnd: (code: Code, message: string | undefined, trailers: Metadata): Action | void => {
27 | console.log(code, message, trailers);
28 | return;
29 | },
30 | host: 'http://localhost:8900',
31 | methodDescriptor: HackerNewsService.ListStories,
32 | onMessage: message => {
33 | const story = message.getStory();
34 | if (story) {
35 | return addStory(story);
36 | }
37 | return;
38 | },
39 | });
40 | };
41 |
42 | type SelectStory = {
43 | type: typeof SELECT_STORY,
44 | payload: number,
45 | };
46 | export const selectStory = (storyId: number): SelectStory => ({ type: SELECT_STORY, payload: storyId });
47 |
48 | export type StoryActionTypes =
49 | | ListStoriesInit
50 | | AddStory
51 | | SelectStory
52 | | GrpcAction;
53 |
--------------------------------------------------------------------------------
/server/hackernews/api.go:
--------------------------------------------------------------------------------
1 | package hackernews
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "log"
7 | "net/http"
8 |
9 | hackernews_pb "github.com/easyCZ/grpc-web-hacker-news/server/proto"
10 | "gopkg.in/zabawaba99/firego.v1"
11 | )
12 |
13 | type Item struct {
14 | Id int32 `json:id`
15 | Score int32 `json:score`
16 | Title string `json:title`
17 | By string `json:by`
18 | Time int32 `json:time`
19 | Url string `json:url`
20 | Type string `json:type`
21 | }
22 |
23 | type hackerNewsApi struct {
24 | *firego.Firebase
25 | }
26 |
27 | type ItemResult struct {
28 | Item *hackernews_pb.Story
29 | Error error
30 | }
31 |
32 | func NewHackerNewsApi(client *http.Client) *hackerNewsApi {
33 | firebase := firego.New("https://hacker-news.firebaseio.com", client)
34 | return &hackerNewsApi{
35 | Firebase: firebase,
36 | }
37 | }
38 |
39 | func (api *hackerNewsApi) GetStory(id int) (*hackernews_pb.Story, error) {
40 | ref, err := api.storyRef(id)
41 | if err != nil {
42 | log.Fatalf("Failed to get story reference")
43 | }
44 | var value Item
45 | if err := ref.Value(&value); err != nil {
46 | log.Fatal("failed to get Story", id, err)
47 | }
48 |
49 | return &hackernews_pb.Story{
50 | Id: value.Id,
51 | By: value.By,
52 | Score: value.Score,
53 | Time: value.Time,
54 | Title: value.Title,
55 | Url: value.Url,
56 | }, nil
57 | }
58 |
59 | func (api *hackerNewsApi) TopStories() (chan *hackernews_pb.Story, error) {
60 | stories := make(chan *hackernews_pb.Story)
61 | ref, err := api.topStoriesRef()
62 | if err != nil {
63 | return nil, err
64 | }
65 |
66 | var ids []float64
67 | if err := ref.Value(&ids); err != nil {
68 | return nil, errors.New("failed to get top stories")
69 | }
70 |
71 | ids = ids[:10]
72 | for _, id := range ids {
73 | go func(id int) {
74 | story, _ := api.GetStory(id)
75 | stories <- story
76 | }(int(id))
77 | }
78 |
79 | return stories, nil
80 | }
81 |
82 | func (api *hackerNewsApi) topStoriesRef() (*firego.Firebase, error) {
83 | return api.Firebase.Ref("/v0/topstories")
84 | }
85 |
86 | func (api *hackerNewsApi) storyRef(id int) (*firego.Firebase, error) {
87 | return api.Firebase.Ref(fmt.Sprintf("/v0/item/%d", id))
88 | }
89 |
--------------------------------------------------------------------------------
/app/src/proto/hackernews_pb_service.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | // package: grpc_web_hacker_news
3 | // file: proto/hackernews.proto
4 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5 | if (k2 === undefined) k2 = k;
6 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
7 | }) : (function(o, m, k, k2) {
8 | if (k2 === undefined) k2 = k;
9 | o[k2] = m[k];
10 | }));
11 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
12 | Object.defineProperty(o, "default", { enumerable: true, value: v });
13 | }) : function(o, v) {
14 | o["default"] = v;
15 | });
16 | var __importStar = (this && this.__importStar) || function (mod) {
17 | if (mod && mod.__esModule) return mod;
18 | var result = {};
19 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
20 | __setModuleDefault(result, mod);
21 | return result;
22 | };
23 | Object.defineProperty(exports, "__esModule", { value: true });
24 | exports.HackerNewsService = void 0;
25 | var proto_hackernews_pb = __importStar(require("../proto/hackernews_pb"));
26 | var HackerNewsService = /** @class */ (function () {
27 | function HackerNewsService() {
28 | }
29 | HackerNewsService.serviceName = "grpc_web_hacker_news.HackerNewsService";
30 | return HackerNewsService;
31 | }());
32 | exports.HackerNewsService = HackerNewsService;
33 | (function (HackerNewsService) {
34 | var ListStories = /** @class */ (function () {
35 | function ListStories() {
36 | }
37 | ListStories.methodName = "ListStories";
38 | ListStories.service = HackerNewsService;
39 | ListStories.requestStream = false;
40 | ListStories.responseStream = true;
41 | ListStories.requestType = proto_hackernews_pb.ListStoriesRequest;
42 | ListStories.responseType = proto_hackernews_pb.ListStoriesResponse;
43 | return ListStories;
44 | }());
45 | HackerNewsService.ListStories = ListStories;
46 | })(HackerNewsService = exports.HackerNewsService || (exports.HackerNewsService = {}));
47 | exports.HackerNewsService = HackerNewsService;
48 |
--------------------------------------------------------------------------------
/app/src/Stories.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { connect, Dispatch } from 'react-redux';
3 | import { RootState } from './store';
4 | import { Container, Grid, Header } from 'semantic-ui-react';
5 | import StoryList from './StoryList';
6 | import StoryView from './StoryView';
7 | import { RootAction } from './actions';
8 | import { listStories, selectStory } from './actions/stories';
9 | import { Story } from './proto/hackernews_pb';
10 |
11 | type StoriesProps = {
12 | stories: Story.AsObject[],
13 | loading: boolean,
14 | error: Error | null,
15 | selected: Story.AsObject | null,
16 |
17 | fetchStories: () => void,
18 | selectStory: (id: number) => void,
19 | };
20 |
21 | class Stories extends React.Component {
22 |
23 | componentDidMount() {
24 | this.props.fetchStories();
25 | }
26 |
27 | render() {
28 | return (
29 |
30 | Hacker News with gRPC-Web
31 |
32 |
33 |
34 |
39 |
40 |
41 |
42 | { this.props.selected
43 | ?
44 | : null
45 | }
46 |
47 |
48 |
49 |
50 | );
51 | }
52 |
53 | }
54 |
55 | function mapStateToProps(state: RootState) {
56 | return {
57 | stories: Object.keys(state.stories.stories).map(key => state.stories.stories[key]),
58 | loading: state.stories.loading,
59 | error: state.stories.error,
60 | selected: state.stories.selected,
61 | };
62 | }
63 |
64 | function mapDispatchToProps(dispatch: Dispatch) {
65 | return {
66 | fetchStories: () => {
67 | dispatch(listStories());
68 | },
69 | selectStory: (storyId: number) => {
70 | dispatch(selectStory(storyId));
71 | },
72 | };
73 | }
74 |
75 | export default connect(mapStateToProps, mapDispatchToProps)(Stories);
76 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [ master ]
17 | pull_request:
18 | # The branches below must be a subset of the branches above
19 | branches: [ master ]
20 | schedule:
21 | - cron: '25 15 * * 6'
22 |
23 | jobs:
24 | analyze:
25 | name: Analyze
26 | runs-on: ubuntu-latest
27 | permissions:
28 | actions: read
29 | contents: read
30 | security-events: write
31 |
32 | strategy:
33 | fail-fast: false
34 | matrix:
35 | language: [ 'go', 'javascript' ]
36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
37 | # Learn more about CodeQL language support at https://git.io/codeql-language-support
38 |
39 | steps:
40 | - name: Checkout repository
41 | uses: actions/checkout@v2
42 |
43 | # Initializes the CodeQL tools for scanning.
44 | - name: Initialize CodeQL
45 | uses: github/codeql-action/init@v1
46 | with:
47 | languages: ${{ matrix.language }}
48 | # If you wish to specify custom queries, you can do so here or in a config file.
49 | # By default, queries listed here will override any specified in a config file.
50 | # Prefix the list here with "+" to use these queries and those in the config file.
51 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
52 |
53 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
54 | # If this step fails, then you should remove it and run the build manually (see below)
55 | - name: Autobuild
56 | uses: github/codeql-action/autobuild@v1
57 |
58 | # ℹ️ Command-line programs to run using the OS shell.
59 | # 📚 https://git.io/JvXDl
60 |
61 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
62 | # and modify them (or add more) to build your code if your project
63 | # uses a compiled language
64 |
65 | #- run: |
66 | # make bootstrap
67 | # make release
68 |
69 | - name: Perform CodeQL Analysis
70 | uses: github/codeql-action/analyze@v1
71 |
--------------------------------------------------------------------------------
/app/src/proto/hackernews_pb.d.ts:
--------------------------------------------------------------------------------
1 | // package: grpc_web_hacker_news
2 | // file: proto/hackernews.proto
3 |
4 | import * as jspb from "google-protobuf";
5 |
6 | export class Story extends jspb.Message {
7 | getId(): number;
8 | setId(value: number): void;
9 |
10 | getScore(): number;
11 | setScore(value: number): void;
12 |
13 | getTitle(): string;
14 | setTitle(value: string): void;
15 |
16 | getBy(): string;
17 | setBy(value: string): void;
18 |
19 | getTime(): number;
20 | setTime(value: number): void;
21 |
22 | getUrl(): string;
23 | setUrl(value: string): void;
24 |
25 | serializeBinary(): Uint8Array;
26 | toObject(includeInstance?: boolean): Story.AsObject;
27 | static toObject(includeInstance: boolean, msg: Story): Story.AsObject;
28 | static extensions: {[key: number]: jspb.ExtensionFieldInfo};
29 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo};
30 | static serializeBinaryToWriter(message: Story, writer: jspb.BinaryWriter): void;
31 | static deserializeBinary(bytes: Uint8Array): Story;
32 | static deserializeBinaryFromReader(message: Story, reader: jspb.BinaryReader): Story;
33 | }
34 |
35 | export namespace Story {
36 | export type AsObject = {
37 | id: number,
38 | score: number,
39 | title: string,
40 | by: string,
41 | time: number,
42 | url: string,
43 | }
44 | }
45 |
46 | export class ListStoriesResponse extends jspb.Message {
47 | hasStory(): boolean;
48 | clearStory(): void;
49 | getStory(): Story | undefined;
50 | setStory(value?: Story): void;
51 |
52 | serializeBinary(): Uint8Array;
53 | toObject(includeInstance?: boolean): ListStoriesResponse.AsObject;
54 | static toObject(includeInstance: boolean, msg: ListStoriesResponse): ListStoriesResponse.AsObject;
55 | static extensions: {[key: number]: jspb.ExtensionFieldInfo};
56 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo};
57 | static serializeBinaryToWriter(message: ListStoriesResponse, writer: jspb.BinaryWriter): void;
58 | static deserializeBinary(bytes: Uint8Array): ListStoriesResponse;
59 | static deserializeBinaryFromReader(message: ListStoriesResponse, reader: jspb.BinaryReader): ListStoriesResponse;
60 | }
61 |
62 | export namespace ListStoriesResponse {
63 | export type AsObject = {
64 | story?: Story.AsObject,
65 | }
66 | }
67 |
68 | export class ListStoriesRequest extends jspb.Message {
69 | serializeBinary(): Uint8Array;
70 | toObject(includeInstance?: boolean): ListStoriesRequest.AsObject;
71 | static toObject(includeInstance: boolean, msg: ListStoriesRequest): ListStoriesRequest.AsObject;
72 | static extensions: {[key: number]: jspb.ExtensionFieldInfo};
73 | static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo};
74 | static serializeBinaryToWriter(message: ListStoriesRequest, writer: jspb.BinaryWriter): void;
75 | static deserializeBinary(bytes: Uint8Array): ListStoriesRequest;
76 | static deserializeBinaryFromReader(message: ListStoriesRequest, reader: jspb.BinaryReader): ListStoriesRequest;
77 | }
78 |
79 | export namespace ListStoriesRequest {
80 | export type AsObject = {
81 | }
82 | }
83 |
84 |
--------------------------------------------------------------------------------
/app/src/middleware/grpc.ts:
--------------------------------------------------------------------------------
1 | import { Action, Dispatch, Middleware, MiddlewareAPI } from 'redux';
2 | import { Code, grpc, Metadata, Transport } from 'grpc-web-client';
3 | import * as jspb from 'google-protobuf';
4 |
5 | const GRPC_WEB_REQUEST = 'GRPC_WEB_REQUEST';
6 |
7 | // Descriptor of a grpc-web payload
8 | // life-cycle methods mirror grpc-web but allow for an action to be dispatched when triggered
9 | export type GrpcActionPayload = {
10 | // The method descriptor to use for a gRPC request, equivalent to grpc.invoke(methodDescriptor, ...)
11 | methodDescriptor: grpc.MethodDefinition,
12 | // The transport to use for grpc-web, automatically selected if empty
13 | transport?: Transport,
14 | // toggle debug messages
15 | debug?: boolean,
16 | // the URL of a host this request should go to
17 | host: string,
18 | // An instance of of the request message
19 | request: RequestType,
20 | // Additional metadata to attach to the request, the same as grpc-web
21 | metadata?: Metadata.ConstructorArg,
22 | // Called immediately before the request is started, useful for toggling a loading status
23 | onStart?: () => Action | void,
24 | // Called when response headers are received
25 | onHeaders?: (headers: Metadata) => Action | void,
26 | // Called on each incoming message
27 | onMessage?: (res: ResponseType) => Action | void,
28 | // Called at the end of a request, make sure to check the exit code
29 | onEnd: (code: Code, message: string, trailers: Metadata) => Action | void,
30 | };
31 |
32 | // Basic type for a gRPC Action
33 | export type GrpcAction = {
34 | type: typeof GRPC_WEB_REQUEST,
35 | payload: GrpcActionPayload,
36 | };
37 |
38 | // Action creator, Use it to create a new grpc action
39 | export function grpcRequest(
40 | payload: GrpcActionPayload
41 | ): GrpcAction {
42 | return {
43 | type: GRPC_WEB_REQUEST,
44 | payload,
45 | };
46 | }
47 |
48 | /* tslint:disable:no-any*/
49 | export function newGrpcMiddleware(): Middleware {
50 | return ({getState, dispatch}: MiddlewareAPI<{}>) => (next: Dispatch<{}>) => (action: any) => {
51 | // skip non-grpc actions
52 | if (!isGrpcWebUnaryAction(action)) {
53 | return next(action);
54 | }
55 |
56 | const payload = action.payload;
57 |
58 | if (payload.onStart) {
59 | payload.onStart();
60 | }
61 |
62 | grpc.invoke(payload.methodDescriptor, {
63 | debug: payload.debug,
64 | host: payload.host,
65 | request: payload.request,
66 | metadata: payload.metadata,
67 | transport: payload.transport,
68 | onHeaders: headers => {
69 | if (!payload.onHeaders) { return; }
70 | const actionToDispatch = payload.onHeaders(headers);
71 | return actionToDispatch && dispatch(actionToDispatch);
72 | },
73 | onMessage: res => {
74 | if (!payload.onMessage) { return; }
75 | const actionToDispatch = payload.onMessage(res);
76 | return actionToDispatch && dispatch(actionToDispatch);
77 | },
78 | onEnd: (code, msg, trailers) => {
79 | const actionToDispatch = payload.onEnd(code, msg, trailers);
80 | return actionToDispatch && dispatch(actionToDispatch);
81 | },
82 | });
83 |
84 | return next(action);
85 | };
86 | }
87 |
88 | function isGrpcWebUnaryAction(action: any): action is GrpcAction {
89 | return action && action.type && action.type === GRPC_WEB_REQUEST && isGrpcWebPayload(action);
90 | }
91 |
92 | function isGrpcWebPayload(action: any): boolean {
93 | return action &&
94 | action.payload &&
95 | action.payload.methodDescriptor &&
96 | action.payload.request &&
97 | action.payload.onEnd &&
98 | action.payload.host;
99 | }
100 |
101 | /* tslint:enable:no-any*/
102 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## grpc-web-hacker-news
2 | An example app implementing a Hacker News reader. This example aims to demonstrate usage of [grpc-web](https://github.com/improbable-eng/grpc-web)(v0.5.0) with React. It additionally shows how to integrate with Redux.
3 |
4 | ### Running
5 | To start both the Go backend server and the frontend React application, run the following:
6 | ```bash
7 | ./start.sh
8 | ```
9 |
10 | 
11 |
12 |
13 | The backend server is running on `http://localhost:8900` while the frontend will by default start on `http://localhost:3000`
14 |
15 | ## Contributing
16 | Contributions are welcome, please open an Issue or raise a PR.
17 |
18 | ## Notable setup points
19 |
20 | ### Disable TSLint for protobuf generated classes
21 | Gernerated proto classes do not confirm to TS lint requirements, [disable linting](https://github.com/easyCZ/grpc-web-hacker-news/blob/master/app/tslint.json#L4)
22 | ```json
23 | {
24 | "linterOptions": {
25 | "exclude": [
26 | "src/proto/*"
27 | ]
28 | },
29 | }
30 | ```
31 |
32 | ### Configure protobuf compiler script
33 | In this example, we're using a `protoc.sh` script to aid compilation
34 | ```bash
35 | protoc \
36 | --go_out=plugins=grpc:./server \
37 | --plugin=protoc-gen-ts=./app/node_modules/.bin/protoc-gen-ts \
38 | --ts_out=service=true:./app/src \
39 | --js_out=import_style=commonjs,binary:./app/src \
40 | ./proto/hackernews.proto
41 | ```
42 |
43 | ### Generated proto classes with Redux
44 | Redux favors plain objects over object instances. This complicates usage of the generated proto classes, in this example class [`Story`](https://github.com/easyCZ/grpc-web-hacker-news/blob/master/app/src/proto/hackernews_pb.d.ts#L6). In order to use the generated classes with redux, we must use the `Story.AsObject` type which is the plain object representation. For example our reducer should look like this:
45 |
46 | ```js
47 | export type StoryState = {
48 | readonly stories: { [storyId: number]: Story.AsObject },
49 | readonly error: Error | null,
50 | readonly loading: boolean,
51 | readonly selected: Story.AsObject | null,
52 | };
53 |
54 | export default function (state: StoryState = initialState, action: RootAction): StoryState {
55 |
56 | switch (action.type) {
57 |
58 | case ADD_STORY:
59 | const story: Story.AsObject = action.payload.toObject();
60 | const selected = state.selected !== null ? state.selected : story;
61 | if (story.id && story.id) {
62 | return {
63 | ...state,
64 | loading: false,
65 | stories: {...state.stories, [story.id]: story},
66 | selected,
67 | };
68 | }
69 | return state;
70 |
71 | default:
72 | return state;
73 | }
74 |
75 | }
76 | ```
77 | Note the usage of `Story.AsObject` rather than just `Story`
78 |
79 | ### gRPC-Web Redux Middleware
80 | An [example redux middleware is included](https://github.com/easyCZ/grpc-web-hacker-news/blob/master/app/src/middleware/grpc.ts).
81 | ```js
82 | import { Action, Dispatch, Middleware, MiddlewareAPI } from 'redux';
83 | import { Code, grpc, Metadata, Transport } from 'grpc-web-client';
84 | import * as jspb from 'google-protobuf';
85 |
86 | const GRPC_WEB_REQUEST = 'GRPC_WEB_REQUEST';
87 | // const GRPC_WEB_INVOKE = 'GRPC_WEB_INVOKE';
88 |
89 | // Descriptor of a grpc-web payload
90 | // life-cycle methods mirror grpc-web but allow for an action to be dispatched when triggered
91 | export type GrpcActionPayload = {
92 | // The method descriptor to use for a gRPC request, equivalent to grpc.invoke(methodDescriptor, ...)
93 | methodDescriptor: grpc.MethodDefinition,
94 | // The transport to use for grpc-web, automatically selected if empty
95 | transport?: Transport,
96 | // toggle debug messages
97 | debug?: boolean,
98 | // the URL of a host this request should go to
99 | host: string,
100 | // An instance of of the request message
101 | request: RequestType,
102 | // Additional metadata to attach to the request, the same as grpc-web
103 | metadata?: Metadata.ConstructorArg,
104 | // Called immediately before the request is started, useful for toggling a loading status
105 | onStart?: () => Action | void,
106 | // Called when response headers are received
107 | onHeaders?: (headers: Metadata) => Action | void,
108 | // Called on each incoming message
109 | onMessage?: (res: ResponseType) => Action | void,
110 | // Called at the end of a request, make sure to check the exit code
111 | onEnd: (code: Code, message: string, trailers: Metadata) => Action | void,
112 | };
113 |
114 | // Basic type for a gRPC Action
115 | export type GrpcAction = {
116 | type: typeof GRPC_WEB_REQUEST,
117 | payload: GrpcActionPayload,
118 | };
119 |
120 | // Action creator, Use it to create a new grpc action
121 | export function grpcRequest(
122 | payload: GrpcActionPayload
123 | ): GrpcAction {
124 | return {
125 | type: GRPC_WEB_REQUEST,
126 | payload,
127 | };
128 | }
129 |
130 | export function newGrpcMiddleware(): Middleware {
131 | return ({getState, dispatch}: MiddlewareAPI<{}>) => (next: Dispatch<{}>) => (action: any) => {
132 | // skip non-grpc actions
133 | if (!isGrpcWebUnaryAction(action)) {
134 | return next(action);
135 | }
136 |
137 | const payload = action.payload;
138 |
139 | if (payload.onStart) {
140 | payload.onStart();
141 | }
142 |
143 | grpc.invoke(payload.methodDescriptor, {
144 | debug: payload.debug,
145 | host: payload.host,
146 | request: payload.request,
147 | metadata: payload.metadata,
148 | transport: payload.transport,
149 | onHeaders: headers => {
150 | if (!payload.onHeaders) { return; }
151 | const actionToDispatch = payload.onHeaders(headers);
152 | return actionToDispatch && dispatch(actionToDispatch);
153 | },
154 | onMessage: res => {
155 | if (!payload.onMessage) { return; }
156 | const actionToDispatch = payload.onMessage(res);
157 | return actionToDispatch && dispatch(actionToDispatch);
158 | },
159 | onEnd: (code, msg, trailers) => {
160 | const actionToDispatch = payload.onEnd(code, msg, trailers);
161 | return actionToDispatch && dispatch(actionToDispatch);
162 | },
163 | });
164 |
165 | return next(action);
166 | };
167 | }
168 |
169 | function isGrpcWebUnaryAction(action: any): action is GrpcAction {
170 | return action && action.type && action.type === GRPC_WEB_REQUEST && isGrpcWebPayload(action);
171 | }
172 |
173 | function isGrpcWebPayload(action: any): boolean {
174 | return action &&
175 | action.payload &&
176 | action.payload.methodDescriptor &&
177 | action.payload.request &&
178 | action.payload.onEnd &&
179 | action.payload.host;
180 | }
181 |
182 |
183 | ```
184 |
--------------------------------------------------------------------------------
/server/proto/hackernews.pb.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go. DO NOT EDIT.
2 | // source: proto/hackernews.proto
3 |
4 | /*
5 | Package grpc_web_hacker_news is a generated protocol buffer package.
6 |
7 | It is generated from these files:
8 | proto/hackernews.proto
9 |
10 | It has these top-level messages:
11 | Story
12 | ListStoriesResponse
13 | ListStoriesRequest
14 | */
15 | package grpc_web_hacker_news
16 |
17 | import proto "github.com/golang/protobuf/proto"
18 | import fmt "fmt"
19 | import math "math"
20 |
21 | import (
22 | context "golang.org/x/net/context"
23 | grpc "google.golang.org/grpc"
24 | )
25 |
26 | // Reference imports to suppress errors if they are not otherwise used.
27 | var _ = proto.Marshal
28 | var _ = fmt.Errorf
29 | var _ = math.Inf
30 |
31 | // This is a compile-time assertion to ensure that this generated file
32 | // is compatible with the proto package it is being compiled against.
33 | // A compilation error at this line likely means your copy of the
34 | // proto package needs to be updated.
35 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
36 |
37 | type Story struct {
38 | Id int32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"`
39 | Score int32 `protobuf:"varint,2,opt,name=score" json:"score,omitempty"`
40 | Title string `protobuf:"bytes,3,opt,name=title" json:"title,omitempty"`
41 | By string `protobuf:"bytes,4,opt,name=by" json:"by,omitempty"`
42 | Time int32 `protobuf:"varint,5,opt,name=time" json:"time,omitempty"`
43 | Url string `protobuf:"bytes,6,opt,name=url" json:"url,omitempty"`
44 | }
45 |
46 | func (m *Story) Reset() { *m = Story{} }
47 | func (m *Story) String() string { return proto.CompactTextString(m) }
48 | func (*Story) ProtoMessage() {}
49 | func (*Story) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
50 |
51 | func (m *Story) GetId() int32 {
52 | if m != nil {
53 | return m.Id
54 | }
55 | return 0
56 | }
57 |
58 | func (m *Story) GetScore() int32 {
59 | if m != nil {
60 | return m.Score
61 | }
62 | return 0
63 | }
64 |
65 | func (m *Story) GetTitle() string {
66 | if m != nil {
67 | return m.Title
68 | }
69 | return ""
70 | }
71 |
72 | func (m *Story) GetBy() string {
73 | if m != nil {
74 | return m.By
75 | }
76 | return ""
77 | }
78 |
79 | func (m *Story) GetTime() int32 {
80 | if m != nil {
81 | return m.Time
82 | }
83 | return 0
84 | }
85 |
86 | func (m *Story) GetUrl() string {
87 | if m != nil {
88 | return m.Url
89 | }
90 | return ""
91 | }
92 |
93 | type ListStoriesResponse struct {
94 | Story *Story `protobuf:"bytes,1,opt,name=story" json:"story,omitempty"`
95 | }
96 |
97 | func (m *ListStoriesResponse) Reset() { *m = ListStoriesResponse{} }
98 | func (m *ListStoriesResponse) String() string { return proto.CompactTextString(m) }
99 | func (*ListStoriesResponse) ProtoMessage() {}
100 | func (*ListStoriesResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
101 |
102 | func (m *ListStoriesResponse) GetStory() *Story {
103 | if m != nil {
104 | return m.Story
105 | }
106 | return nil
107 | }
108 |
109 | type ListStoriesRequest struct {
110 | }
111 |
112 | func (m *ListStoriesRequest) Reset() { *m = ListStoriesRequest{} }
113 | func (m *ListStoriesRequest) String() string { return proto.CompactTextString(m) }
114 | func (*ListStoriesRequest) ProtoMessage() {}
115 | func (*ListStoriesRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
116 |
117 | func init() {
118 | proto.RegisterType((*Story)(nil), "grpc_web_hacker_news.Story")
119 | proto.RegisterType((*ListStoriesResponse)(nil), "grpc_web_hacker_news.ListStoriesResponse")
120 | proto.RegisterType((*ListStoriesRequest)(nil), "grpc_web_hacker_news.ListStoriesRequest")
121 | }
122 |
123 | // Reference imports to suppress errors if they are not otherwise used.
124 | var _ context.Context
125 | var _ grpc.ClientConn
126 |
127 | // This is a compile-time assertion to ensure that this generated file
128 | // is compatible with the grpc package it is being compiled against.
129 | const _ = grpc.SupportPackageIsVersion4
130 |
131 | // Client API for HackerNewsService service
132 |
133 | type HackerNewsServiceClient interface {
134 | ListStories(ctx context.Context, in *ListStoriesRequest, opts ...grpc.CallOption) (HackerNewsService_ListStoriesClient, error)
135 | }
136 |
137 | type hackerNewsServiceClient struct {
138 | cc *grpc.ClientConn
139 | }
140 |
141 | func NewHackerNewsServiceClient(cc *grpc.ClientConn) HackerNewsServiceClient {
142 | return &hackerNewsServiceClient{cc}
143 | }
144 |
145 | func (c *hackerNewsServiceClient) ListStories(ctx context.Context, in *ListStoriesRequest, opts ...grpc.CallOption) (HackerNewsService_ListStoriesClient, error) {
146 | stream, err := grpc.NewClientStream(ctx, &_HackerNewsService_serviceDesc.Streams[0], c.cc, "/grpc_web_hacker_news.HackerNewsService/ListStories", opts...)
147 | if err != nil {
148 | return nil, err
149 | }
150 | x := &hackerNewsServiceListStoriesClient{stream}
151 | if err := x.ClientStream.SendMsg(in); err != nil {
152 | return nil, err
153 | }
154 | if err := x.ClientStream.CloseSend(); err != nil {
155 | return nil, err
156 | }
157 | return x, nil
158 | }
159 |
160 | type HackerNewsService_ListStoriesClient interface {
161 | Recv() (*ListStoriesResponse, error)
162 | grpc.ClientStream
163 | }
164 |
165 | type hackerNewsServiceListStoriesClient struct {
166 | grpc.ClientStream
167 | }
168 |
169 | func (x *hackerNewsServiceListStoriesClient) Recv() (*ListStoriesResponse, error) {
170 | m := new(ListStoriesResponse)
171 | if err := x.ClientStream.RecvMsg(m); err != nil {
172 | return nil, err
173 | }
174 | return m, nil
175 | }
176 |
177 | // Server API for HackerNewsService service
178 |
179 | type HackerNewsServiceServer interface {
180 | ListStories(*ListStoriesRequest, HackerNewsService_ListStoriesServer) error
181 | }
182 |
183 | func RegisterHackerNewsServiceServer(s *grpc.Server, srv HackerNewsServiceServer) {
184 | s.RegisterService(&_HackerNewsService_serviceDesc, srv)
185 | }
186 |
187 | func _HackerNewsService_ListStories_Handler(srv interface{}, stream grpc.ServerStream) error {
188 | m := new(ListStoriesRequest)
189 | if err := stream.RecvMsg(m); err != nil {
190 | return err
191 | }
192 | return srv.(HackerNewsServiceServer).ListStories(m, &hackerNewsServiceListStoriesServer{stream})
193 | }
194 |
195 | type HackerNewsService_ListStoriesServer interface {
196 | Send(*ListStoriesResponse) error
197 | grpc.ServerStream
198 | }
199 |
200 | type hackerNewsServiceListStoriesServer struct {
201 | grpc.ServerStream
202 | }
203 |
204 | func (x *hackerNewsServiceListStoriesServer) Send(m *ListStoriesResponse) error {
205 | return x.ServerStream.SendMsg(m)
206 | }
207 |
208 | var _HackerNewsService_serviceDesc = grpc.ServiceDesc{
209 | ServiceName: "grpc_web_hacker_news.HackerNewsService",
210 | HandlerType: (*HackerNewsServiceServer)(nil),
211 | Methods: []grpc.MethodDesc{},
212 | Streams: []grpc.StreamDesc{
213 | {
214 | StreamName: "ListStories",
215 | Handler: _HackerNewsService_ListStories_Handler,
216 | ServerStreams: true,
217 | },
218 | },
219 | Metadata: "proto/hackernews.proto",
220 | }
221 |
222 | func init() { proto.RegisterFile("proto/hackernews.proto", fileDescriptor0) }
223 |
224 | var fileDescriptor0 = []byte{
225 | // 241 bytes of a gzipped FileDescriptorProto
226 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x50, 0xbd, 0x4e, 0xc3, 0x30,
227 | 0x10, 0x56, 0xd2, 0xba, 0x12, 0x57, 0x09, 0xc1, 0x11, 0x21, 0x0b, 0x96, 0x2a, 0x53, 0x58, 0x02,
228 | 0x94, 0x97, 0xe8, 0x80, 0x18, 0xd2, 0x07, 0x88, 0x48, 0x72, 0x02, 0x8b, 0x52, 0x07, 0x9f, 0x4b,
229 | 0xe4, 0xb7, 0x47, 0x3e, 0x2f, 0x20, 0x3a, 0x74, 0xbb, 0xfb, 0xfe, 0xfc, 0xf9, 0xe0, 0x7a, 0x74,
230 | 0xd6, 0xdb, 0xfb, 0xf7, 0xd7, 0xfe, 0x83, 0xdc, 0x9e, 0x26, 0xae, 0x05, 0xc0, 0xe2, 0xcd, 0x8d,
231 | 0x7d, 0x3b, 0x51, 0xd7, 0x26, 0xaa, 0x8d, 0x5c, 0x19, 0x40, 0x6d, 0xbd, 0x75, 0x01, 0xcf, 0x21,
232 | 0x37, 0x83, 0xce, 0x56, 0x59, 0xa5, 0x9a, 0xdc, 0x0c, 0x58, 0x80, 0xe2, 0xde, 0x3a, 0xd2, 0xb9,
233 | 0x40, 0x69, 0x89, 0xa8, 0x37, 0x7e, 0x47, 0x7a, 0xb6, 0xca, 0xaa, 0xb3, 0x26, 0x2d, 0xd1, 0xdb,
234 | 0x05, 0x3d, 0x17, 0x28, 0xef, 0x02, 0x22, 0xcc, 0xbd, 0xf9, 0x24, 0xad, 0xc4, 0x2a, 0x33, 0x5e,
235 | 0xc0, 0xec, 0xe0, 0x76, 0x7a, 0x21, 0xa2, 0x38, 0x96, 0x1b, 0xb8, 0x7a, 0x36, 0xec, 0xe3, 0xf3,
236 | 0x86, 0xb8, 0x21, 0x1e, 0xed, 0x9e, 0x09, 0x1f, 0x41, 0x71, 0x6c, 0x24, 0x5d, 0x96, 0xeb, 0xdb,
237 | 0xfa, 0x58, 0xef, 0x5a, 0x4a, 0x37, 0x49, 0x59, 0x16, 0x80, 0x7f, 0x92, 0xbe, 0x0e, 0xc4, 0x7e,
238 | 0x1d, 0xe0, 0x72, 0x23, 0x8e, 0x17, 0x9a, 0x78, 0x4b, 0xee, 0xdb, 0xf4, 0x84, 0x03, 0x2c, 0x7f,
239 | 0x49, 0xb1, 0x3a, 0x9e, 0xfe, 0x3f, 0xed, 0xe6, 0xee, 0x04, 0x65, 0xfa, 0xc1, 0x43, 0xd6, 0x2d,
240 | 0xe4, 0xe4, 0x4f, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x45, 0x1a, 0xba, 0x9a, 0x8c, 0x01, 0x00,
241 | 0x00,
242 | }
243 |
--------------------------------------------------------------------------------
/app/src/proto/hackernews_pb.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview
3 | * @enhanceable
4 | * @public
5 | */
6 | // GENERATED CODE -- DO NOT EDIT!
7 |
8 | var jspb = require('google-protobuf');
9 | var goog = jspb;
10 | var global = Function('return this')();
11 |
12 | goog.exportSymbol('proto.grpc_web_hacker_news.ListStoriesRequest', null, global);
13 | goog.exportSymbol('proto.grpc_web_hacker_news.ListStoriesResponse', null, global);
14 | goog.exportSymbol('proto.grpc_web_hacker_news.Story', null, global);
15 |
16 | /**
17 | * Generated by JsPbCodeGenerator.
18 | * @param {Array=} opt_data Optional initial data array, typically from a
19 | * server response, or constructed directly in Javascript. The array is used
20 | * in place and becomes part of the constructed object. It is not cloned.
21 | * If no data is provided, the constructed object will be empty, but still
22 | * valid.
23 | * @extends {jspb.Message}
24 | * @constructor
25 | */
26 | proto.grpc_web_hacker_news.Story = function(opt_data) {
27 | jspb.Message.initialize(this, opt_data, 0, -1, null, null);
28 | };
29 | goog.inherits(proto.grpc_web_hacker_news.Story, jspb.Message);
30 | if (goog.DEBUG && !COMPILED) {
31 | proto.grpc_web_hacker_news.Story.displayName = 'proto.grpc_web_hacker_news.Story';
32 | }
33 |
34 |
35 | if (jspb.Message.GENERATE_TO_OBJECT) {
36 | /**
37 | * Creates an object representation of this proto suitable for use in Soy templates.
38 | * Field names that are reserved in JavaScript and will be renamed to pb_name.
39 | * To access a reserved field use, foo.pb_, eg, foo.pb_default.
40 | * For the list of reserved names please see:
41 | * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.
42 | * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
43 | * for transitional soy proto support: http://goto/soy-param-migration
44 | * @return {!Object}
45 | */
46 | proto.grpc_web_hacker_news.Story.prototype.toObject = function(opt_includeInstance) {
47 | return proto.grpc_web_hacker_news.Story.toObject(opt_includeInstance, this);
48 | };
49 |
50 |
51 | /**
52 | * Static version of the {@see toObject} method.
53 | * @param {boolean|undefined} includeInstance Whether to include the JSPB
54 | * instance for transitional soy proto support:
55 | * http://goto/soy-param-migration
56 | * @param {!proto.grpc_web_hacker_news.Story} msg The msg instance to transform.
57 | * @return {!Object}
58 | */
59 | proto.grpc_web_hacker_news.Story.toObject = function(includeInstance, msg) {
60 | var f, obj = {
61 | id: jspb.Message.getFieldWithDefault(msg, 1, 0),
62 | score: jspb.Message.getFieldWithDefault(msg, 2, 0),
63 | title: jspb.Message.getFieldWithDefault(msg, 3, ""),
64 | by: jspb.Message.getFieldWithDefault(msg, 4, ""),
65 | time: jspb.Message.getFieldWithDefault(msg, 5, 0),
66 | url: jspb.Message.getFieldWithDefault(msg, 6, "")
67 | };
68 |
69 | if (includeInstance) {
70 | obj.$jspbMessageInstance = msg;
71 | }
72 | return obj;
73 | };
74 | }
75 |
76 |
77 | /**
78 | * Deserializes binary data (in protobuf wire format).
79 | * @param {jspb.ByteSource} bytes The bytes to deserialize.
80 | * @return {!proto.grpc_web_hacker_news.Story}
81 | */
82 | proto.grpc_web_hacker_news.Story.deserializeBinary = function(bytes) {
83 | var reader = new jspb.BinaryReader(bytes);
84 | var msg = new proto.grpc_web_hacker_news.Story;
85 | return proto.grpc_web_hacker_news.Story.deserializeBinaryFromReader(msg, reader);
86 | };
87 |
88 |
89 | /**
90 | * Deserializes binary data (in protobuf wire format) from the
91 | * given reader into the given message object.
92 | * @param {!proto.grpc_web_hacker_news.Story} msg The message object to deserialize into.
93 | * @param {!jspb.BinaryReader} reader The BinaryReader to use.
94 | * @return {!proto.grpc_web_hacker_news.Story}
95 | */
96 | proto.grpc_web_hacker_news.Story.deserializeBinaryFromReader = function(msg, reader) {
97 | while (reader.nextField()) {
98 | if (reader.isEndGroup()) {
99 | break;
100 | }
101 | var field = reader.getFieldNumber();
102 | switch (field) {
103 | case 1:
104 | var value = /** @type {number} */ (reader.readInt32());
105 | msg.setId(value);
106 | break;
107 | case 2:
108 | var value = /** @type {number} */ (reader.readInt32());
109 | msg.setScore(value);
110 | break;
111 | case 3:
112 | var value = /** @type {string} */ (reader.readString());
113 | msg.setTitle(value);
114 | break;
115 | case 4:
116 | var value = /** @type {string} */ (reader.readString());
117 | msg.setBy(value);
118 | break;
119 | case 5:
120 | var value = /** @type {number} */ (reader.readInt32());
121 | msg.setTime(value);
122 | break;
123 | case 6:
124 | var value = /** @type {string} */ (reader.readString());
125 | msg.setUrl(value);
126 | break;
127 | default:
128 | reader.skipField();
129 | break;
130 | }
131 | }
132 | return msg;
133 | };
134 |
135 |
136 | /**
137 | * Serializes the message to binary data (in protobuf wire format).
138 | * @return {!Uint8Array}
139 | */
140 | proto.grpc_web_hacker_news.Story.prototype.serializeBinary = function() {
141 | var writer = new jspb.BinaryWriter();
142 | proto.grpc_web_hacker_news.Story.serializeBinaryToWriter(this, writer);
143 | return writer.getResultBuffer();
144 | };
145 |
146 |
147 | /**
148 | * Serializes the given message to binary data (in protobuf wire
149 | * format), writing to the given BinaryWriter.
150 | * @param {!proto.grpc_web_hacker_news.Story} message
151 | * @param {!jspb.BinaryWriter} writer
152 | */
153 | proto.grpc_web_hacker_news.Story.serializeBinaryToWriter = function(message, writer) {
154 | var f = undefined;
155 | f = message.getId();
156 | if (f !== 0) {
157 | writer.writeInt32(
158 | 1,
159 | f
160 | );
161 | }
162 | f = message.getScore();
163 | if (f !== 0) {
164 | writer.writeInt32(
165 | 2,
166 | f
167 | );
168 | }
169 | f = message.getTitle();
170 | if (f.length > 0) {
171 | writer.writeString(
172 | 3,
173 | f
174 | );
175 | }
176 | f = message.getBy();
177 | if (f.length > 0) {
178 | writer.writeString(
179 | 4,
180 | f
181 | );
182 | }
183 | f = message.getTime();
184 | if (f !== 0) {
185 | writer.writeInt32(
186 | 5,
187 | f
188 | );
189 | }
190 | f = message.getUrl();
191 | if (f.length > 0) {
192 | writer.writeString(
193 | 6,
194 | f
195 | );
196 | }
197 | };
198 |
199 |
200 | /**
201 | * optional int32 id = 1;
202 | * @return {number}
203 | */
204 | proto.grpc_web_hacker_news.Story.prototype.getId = function() {
205 | return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0));
206 | };
207 |
208 |
209 | /** @param {number} value */
210 | proto.grpc_web_hacker_news.Story.prototype.setId = function(value) {
211 | jspb.Message.setField(this, 1, value);
212 | };
213 |
214 |
215 | /**
216 | * optional int32 score = 2;
217 | * @return {number}
218 | */
219 | proto.grpc_web_hacker_news.Story.prototype.getScore = function() {
220 | return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 2, 0));
221 | };
222 |
223 |
224 | /** @param {number} value */
225 | proto.grpc_web_hacker_news.Story.prototype.setScore = function(value) {
226 | jspb.Message.setField(this, 2, value);
227 | };
228 |
229 |
230 | /**
231 | * optional string title = 3;
232 | * @return {string}
233 | */
234 | proto.grpc_web_hacker_news.Story.prototype.getTitle = function() {
235 | return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, ""));
236 | };
237 |
238 |
239 | /** @param {string} value */
240 | proto.grpc_web_hacker_news.Story.prototype.setTitle = function(value) {
241 | jspb.Message.setField(this, 3, value);
242 | };
243 |
244 |
245 | /**
246 | * optional string by = 4;
247 | * @return {string}
248 | */
249 | proto.grpc_web_hacker_news.Story.prototype.getBy = function() {
250 | return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, ""));
251 | };
252 |
253 |
254 | /** @param {string} value */
255 | proto.grpc_web_hacker_news.Story.prototype.setBy = function(value) {
256 | jspb.Message.setField(this, 4, value);
257 | };
258 |
259 |
260 | /**
261 | * optional int32 time = 5;
262 | * @return {number}
263 | */
264 | proto.grpc_web_hacker_news.Story.prototype.getTime = function() {
265 | return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 5, 0));
266 | };
267 |
268 |
269 | /** @param {number} value */
270 | proto.grpc_web_hacker_news.Story.prototype.setTime = function(value) {
271 | jspb.Message.setField(this, 5, value);
272 | };
273 |
274 |
275 | /**
276 | * optional string url = 6;
277 | * @return {string}
278 | */
279 | proto.grpc_web_hacker_news.Story.prototype.getUrl = function() {
280 | return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 6, ""));
281 | };
282 |
283 |
284 | /** @param {string} value */
285 | proto.grpc_web_hacker_news.Story.prototype.setUrl = function(value) {
286 | jspb.Message.setField(this, 6, value);
287 | };
288 |
289 |
290 |
291 | /**
292 | * Generated by JsPbCodeGenerator.
293 | * @param {Array=} opt_data Optional initial data array, typically from a
294 | * server response, or constructed directly in Javascript. The array is used
295 | * in place and becomes part of the constructed object. It is not cloned.
296 | * If no data is provided, the constructed object will be empty, but still
297 | * valid.
298 | * @extends {jspb.Message}
299 | * @constructor
300 | */
301 | proto.grpc_web_hacker_news.ListStoriesResponse = function(opt_data) {
302 | jspb.Message.initialize(this, opt_data, 0, -1, null, null);
303 | };
304 | goog.inherits(proto.grpc_web_hacker_news.ListStoriesResponse, jspb.Message);
305 | if (goog.DEBUG && !COMPILED) {
306 | proto.grpc_web_hacker_news.ListStoriesResponse.displayName = 'proto.grpc_web_hacker_news.ListStoriesResponse';
307 | }
308 |
309 |
310 | if (jspb.Message.GENERATE_TO_OBJECT) {
311 | /**
312 | * Creates an object representation of this proto suitable for use in Soy templates.
313 | * Field names that are reserved in JavaScript and will be renamed to pb_name.
314 | * To access a reserved field use, foo.pb_, eg, foo.pb_default.
315 | * For the list of reserved names please see:
316 | * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.
317 | * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
318 | * for transitional soy proto support: http://goto/soy-param-migration
319 | * @return {!Object}
320 | */
321 | proto.grpc_web_hacker_news.ListStoriesResponse.prototype.toObject = function(opt_includeInstance) {
322 | return proto.grpc_web_hacker_news.ListStoriesResponse.toObject(opt_includeInstance, this);
323 | };
324 |
325 |
326 | /**
327 | * Static version of the {@see toObject} method.
328 | * @param {boolean|undefined} includeInstance Whether to include the JSPB
329 | * instance for transitional soy proto support:
330 | * http://goto/soy-param-migration
331 | * @param {!proto.grpc_web_hacker_news.ListStoriesResponse} msg The msg instance to transform.
332 | * @return {!Object}
333 | */
334 | proto.grpc_web_hacker_news.ListStoriesResponse.toObject = function(includeInstance, msg) {
335 | var f, obj = {
336 | story: (f = msg.getStory()) && proto.grpc_web_hacker_news.Story.toObject(includeInstance, f)
337 | };
338 |
339 | if (includeInstance) {
340 | obj.$jspbMessageInstance = msg;
341 | }
342 | return obj;
343 | };
344 | }
345 |
346 |
347 | /**
348 | * Deserializes binary data (in protobuf wire format).
349 | * @param {jspb.ByteSource} bytes The bytes to deserialize.
350 | * @return {!proto.grpc_web_hacker_news.ListStoriesResponse}
351 | */
352 | proto.grpc_web_hacker_news.ListStoriesResponse.deserializeBinary = function(bytes) {
353 | var reader = new jspb.BinaryReader(bytes);
354 | var msg = new proto.grpc_web_hacker_news.ListStoriesResponse;
355 | return proto.grpc_web_hacker_news.ListStoriesResponse.deserializeBinaryFromReader(msg, reader);
356 | };
357 |
358 |
359 | /**
360 | * Deserializes binary data (in protobuf wire format) from the
361 | * given reader into the given message object.
362 | * @param {!proto.grpc_web_hacker_news.ListStoriesResponse} msg The message object to deserialize into.
363 | * @param {!jspb.BinaryReader} reader The BinaryReader to use.
364 | * @return {!proto.grpc_web_hacker_news.ListStoriesResponse}
365 | */
366 | proto.grpc_web_hacker_news.ListStoriesResponse.deserializeBinaryFromReader = function(msg, reader) {
367 | while (reader.nextField()) {
368 | if (reader.isEndGroup()) {
369 | break;
370 | }
371 | var field = reader.getFieldNumber();
372 | switch (field) {
373 | case 1:
374 | var value = new proto.grpc_web_hacker_news.Story;
375 | reader.readMessage(value,proto.grpc_web_hacker_news.Story.deserializeBinaryFromReader);
376 | msg.setStory(value);
377 | break;
378 | default:
379 | reader.skipField();
380 | break;
381 | }
382 | }
383 | return msg;
384 | };
385 |
386 |
387 | /**
388 | * Serializes the message to binary data (in protobuf wire format).
389 | * @return {!Uint8Array}
390 | */
391 | proto.grpc_web_hacker_news.ListStoriesResponse.prototype.serializeBinary = function() {
392 | var writer = new jspb.BinaryWriter();
393 | proto.grpc_web_hacker_news.ListStoriesResponse.serializeBinaryToWriter(this, writer);
394 | return writer.getResultBuffer();
395 | };
396 |
397 |
398 | /**
399 | * Serializes the given message to binary data (in protobuf wire
400 | * format), writing to the given BinaryWriter.
401 | * @param {!proto.grpc_web_hacker_news.ListStoriesResponse} message
402 | * @param {!jspb.BinaryWriter} writer
403 | */
404 | proto.grpc_web_hacker_news.ListStoriesResponse.serializeBinaryToWriter = function(message, writer) {
405 | var f = undefined;
406 | f = message.getStory();
407 | if (f != null) {
408 | writer.writeMessage(
409 | 1,
410 | f,
411 | proto.grpc_web_hacker_news.Story.serializeBinaryToWriter
412 | );
413 | }
414 | };
415 |
416 |
417 | /**
418 | * optional Story story = 1;
419 | * @return {?proto.grpc_web_hacker_news.Story}
420 | */
421 | proto.grpc_web_hacker_news.ListStoriesResponse.prototype.getStory = function() {
422 | return /** @type{?proto.grpc_web_hacker_news.Story} */ (
423 | jspb.Message.getWrapperField(this, proto.grpc_web_hacker_news.Story, 1));
424 | };
425 |
426 |
427 | /** @param {?proto.grpc_web_hacker_news.Story|undefined} value */
428 | proto.grpc_web_hacker_news.ListStoriesResponse.prototype.setStory = function(value) {
429 | jspb.Message.setWrapperField(this, 1, value);
430 | };
431 |
432 |
433 | proto.grpc_web_hacker_news.ListStoriesResponse.prototype.clearStory = function() {
434 | this.setStory(undefined);
435 | };
436 |
437 |
438 | /**
439 | * Returns whether this field is set.
440 | * @return {!boolean}
441 | */
442 | proto.grpc_web_hacker_news.ListStoriesResponse.prototype.hasStory = function() {
443 | return jspb.Message.getField(this, 1) != null;
444 | };
445 |
446 |
447 |
448 | /**
449 | * Generated by JsPbCodeGenerator.
450 | * @param {Array=} opt_data Optional initial data array, typically from a
451 | * server response, or constructed directly in Javascript. The array is used
452 | * in place and becomes part of the constructed object. It is not cloned.
453 | * If no data is provided, the constructed object will be empty, but still
454 | * valid.
455 | * @extends {jspb.Message}
456 | * @constructor
457 | */
458 | proto.grpc_web_hacker_news.ListStoriesRequest = function(opt_data) {
459 | jspb.Message.initialize(this, opt_data, 0, -1, null, null);
460 | };
461 | goog.inherits(proto.grpc_web_hacker_news.ListStoriesRequest, jspb.Message);
462 | if (goog.DEBUG && !COMPILED) {
463 | proto.grpc_web_hacker_news.ListStoriesRequest.displayName = 'proto.grpc_web_hacker_news.ListStoriesRequest';
464 | }
465 |
466 |
467 | if (jspb.Message.GENERATE_TO_OBJECT) {
468 | /**
469 | * Creates an object representation of this proto suitable for use in Soy templates.
470 | * Field names that are reserved in JavaScript and will be renamed to pb_name.
471 | * To access a reserved field use, foo.pb_, eg, foo.pb_default.
472 | * For the list of reserved names please see:
473 | * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.
474 | * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
475 | * for transitional soy proto support: http://goto/soy-param-migration
476 | * @return {!Object}
477 | */
478 | proto.grpc_web_hacker_news.ListStoriesRequest.prototype.toObject = function(opt_includeInstance) {
479 | return proto.grpc_web_hacker_news.ListStoriesRequest.toObject(opt_includeInstance, this);
480 | };
481 |
482 |
483 | /**
484 | * Static version of the {@see toObject} method.
485 | * @param {boolean|undefined} includeInstance Whether to include the JSPB
486 | * instance for transitional soy proto support:
487 | * http://goto/soy-param-migration
488 | * @param {!proto.grpc_web_hacker_news.ListStoriesRequest} msg The msg instance to transform.
489 | * @return {!Object}
490 | */
491 | proto.grpc_web_hacker_news.ListStoriesRequest.toObject = function(includeInstance, msg) {
492 | var f, obj = {
493 |
494 | };
495 |
496 | if (includeInstance) {
497 | obj.$jspbMessageInstance = msg;
498 | }
499 | return obj;
500 | };
501 | }
502 |
503 |
504 | /**
505 | * Deserializes binary data (in protobuf wire format).
506 | * @param {jspb.ByteSource} bytes The bytes to deserialize.
507 | * @return {!proto.grpc_web_hacker_news.ListStoriesRequest}
508 | */
509 | proto.grpc_web_hacker_news.ListStoriesRequest.deserializeBinary = function(bytes) {
510 | var reader = new jspb.BinaryReader(bytes);
511 | var msg = new proto.grpc_web_hacker_news.ListStoriesRequest;
512 | return proto.grpc_web_hacker_news.ListStoriesRequest.deserializeBinaryFromReader(msg, reader);
513 | };
514 |
515 |
516 | /**
517 | * Deserializes binary data (in protobuf wire format) from the
518 | * given reader into the given message object.
519 | * @param {!proto.grpc_web_hacker_news.ListStoriesRequest} msg The message object to deserialize into.
520 | * @param {!jspb.BinaryReader} reader The BinaryReader to use.
521 | * @return {!proto.grpc_web_hacker_news.ListStoriesRequest}
522 | */
523 | proto.grpc_web_hacker_news.ListStoriesRequest.deserializeBinaryFromReader = function(msg, reader) {
524 | while (reader.nextField()) {
525 | if (reader.isEndGroup()) {
526 | break;
527 | }
528 | var field = reader.getFieldNumber();
529 | switch (field) {
530 | default:
531 | reader.skipField();
532 | break;
533 | }
534 | }
535 | return msg;
536 | };
537 |
538 |
539 | /**
540 | * Serializes the message to binary data (in protobuf wire format).
541 | * @return {!Uint8Array}
542 | */
543 | proto.grpc_web_hacker_news.ListStoriesRequest.prototype.serializeBinary = function() {
544 | var writer = new jspb.BinaryWriter();
545 | proto.grpc_web_hacker_news.ListStoriesRequest.serializeBinaryToWriter(this, writer);
546 | return writer.getResultBuffer();
547 | };
548 |
549 |
550 | /**
551 | * Serializes the given message to binary data (in protobuf wire
552 | * format), writing to the given BinaryWriter.
553 | * @param {!proto.grpc_web_hacker_news.ListStoriesRequest} message
554 | * @param {!jspb.BinaryWriter} writer
555 | */
556 | proto.grpc_web_hacker_news.ListStoriesRequest.serializeBinaryToWriter = function(message, writer) {
557 | var f = undefined;
558 | };
559 |
560 |
561 | goog.object.extend(exports, proto.grpc_web_hacker_news);
562 |
--------------------------------------------------------------------------------
/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 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
4 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
5 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
6 | github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
7 | github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
8 | github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
9 | github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
10 | github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
11 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
12 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
13 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
14 | github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
15 | github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
16 | github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
17 | github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
18 | github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
19 | github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
20 | github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
21 | github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
22 | github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
23 | github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
24 | github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
25 | github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
26 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
27 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
28 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
29 | github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
30 | github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
31 | github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
32 | github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
33 | github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ=
34 | github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
35 | github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo=
36 | github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
37 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
38 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
39 | github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
40 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
41 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
42 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
43 | github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
44 | github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
45 | github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
46 | github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
47 | github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
48 | github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
49 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
50 | github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
51 | github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
52 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
53 | github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
54 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
55 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
56 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
57 | github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I=
58 | github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE=
59 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
60 | github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
61 | github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
62 | github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
63 | github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
64 | github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
65 | github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
66 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
67 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
68 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
69 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
70 | github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
71 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
72 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
73 | github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
74 | github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
75 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
76 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
77 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
78 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
79 | github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
80 | github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
81 | github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
82 | github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
83 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
84 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
85 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
86 | github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
87 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
88 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
89 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
90 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
91 | github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
92 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
93 | github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
94 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
95 | github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
96 | github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
97 | github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
98 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
99 | github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
100 | github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
101 | github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
102 | github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
103 | github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
104 | github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
105 | github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
106 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
107 | github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
108 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
109 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
110 | github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
111 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
112 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
113 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
114 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
115 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
116 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
117 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
118 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
119 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
120 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
121 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
122 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
123 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
124 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
125 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
126 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
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/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
130 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
131 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
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.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
137 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
138 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
139 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
140 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
141 | github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
142 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
143 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
144 | github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
145 | github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
146 | github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
147 | github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
148 | github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
149 | github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
150 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
151 | github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
152 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
153 | github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
154 | github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
155 | github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
156 | github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
157 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
158 | github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
159 | github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
160 | github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
161 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
162 | github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
163 | github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
164 | github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
165 | github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
166 | github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
167 | github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
168 | github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
169 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
170 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
171 | github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
172 | github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
173 | github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
174 | github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
175 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
176 | github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
177 | github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ=
178 | github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8=
179 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
180 | github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
181 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
182 | github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
183 | github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
184 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
185 | github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
186 | github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
187 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
188 | github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
189 | github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
190 | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
191 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
192 | github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
193 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
194 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
195 | github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
196 | github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg=
197 | github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
198 | github.com/klauspost/compress v1.14.2 h1:S0OHlFk/Gbon/yauFJ4FfJJF5V0fc5HbBTJazi28pRw=
199 | github.com/klauspost/compress v1.14.2/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
200 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
201 | github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
202 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
203 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
204 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
205 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
206 | github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
207 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
208 | github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
209 | github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
210 | github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
211 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
212 | github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
213 | github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
214 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
215 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
216 | github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
217 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
218 | github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
219 | github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
220 | github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
221 | github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
222 | github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
223 | github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
224 | github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
225 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
226 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
227 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
228 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
229 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
230 | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
231 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
232 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
233 | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
234 | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
235 | github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76/go.mod h1:x5OoJHDHqxHS801UIuhqGl6QdSAEJvtausosHSdazIo=
236 | github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
237 | github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
238 | github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
239 | github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
240 | github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
241 | github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
242 | github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
243 | github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
244 | github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
245 | github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
246 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
247 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
248 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
249 | github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
250 | github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
251 | github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
252 | github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
253 | github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
254 | github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
255 | github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
256 | github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
257 | github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
258 | github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
259 | github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
260 | github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
261 | github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
262 | github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
263 | github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
264 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
265 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
266 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
267 | github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
268 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
269 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
270 | github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
271 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
272 | github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
273 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
274 | github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
275 | github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
276 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
277 | github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
278 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
279 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
280 | github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
281 | github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
282 | github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
283 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
284 | github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
285 | github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
286 | github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
287 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
288 | github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
289 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
290 | github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
291 | github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
292 | github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
293 | github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
294 | github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
295 | github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
296 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
297 | github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
298 | github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
299 | github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U=
300 | github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
301 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
302 | github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
303 | github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
304 | github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
305 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
306 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
307 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
308 | github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
309 | github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
310 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
311 | github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
312 | github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
313 | github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
314 | github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
315 | github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
316 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
317 | github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
318 | github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
319 | github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
320 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
321 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
322 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
323 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
324 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
325 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
326 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
327 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
328 | github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
329 | github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
330 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
331 | github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
332 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
333 | github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
334 | github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
335 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
336 | github.com/zabawaba99/firego v0.0.0-20190331000051-3bcc4b6a4599 h1:Dp7CeY6ZqQryz7aK3h/7eCsBD9aB7bsS2LfZPcC06Co=
337 | github.com/zabawaba99/firego v0.0.0-20190331000051-3bcc4b6a4599/go.mod h1:j54MZVdpCPLSkR7SgnKOKtrMnjbfDWEbfSb+HodFaHY=
338 | go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
339 | go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
340 | go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
341 | go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
342 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
343 | go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
344 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
345 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
346 | go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
347 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
348 | go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
349 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
350 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
351 | go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
352 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
353 | golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
354 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
355 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
356 | golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
357 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
358 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
359 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
360 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
361 | golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
362 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
363 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
364 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
365 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
366 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
367 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
368 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
369 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
370 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
371 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
372 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
373 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
374 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
375 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
376 | golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
377 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
378 | golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
379 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
380 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
381 | golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
382 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
383 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
384 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
385 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
386 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
387 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
388 | golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
389 | golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
390 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
391 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
392 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
393 | golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
394 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
395 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
396 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
397 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
398 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
399 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
400 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
401 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
402 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
403 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
404 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
405 | golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
406 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
407 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
408 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
409 | golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
410 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
411 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
412 | golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
413 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
414 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
415 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
416 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
417 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
418 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
419 | golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
420 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
421 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
422 | golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
423 | golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
424 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
425 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
426 | golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
427 | golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
428 | golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
429 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
430 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
431 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
432 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
433 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
434 | golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
435 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
436 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
437 | golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c=
438 | golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
439 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
440 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
441 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
442 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
443 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
444 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
445 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
446 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
447 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
448 | golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
449 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
450 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
451 | golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
452 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
453 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
454 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
455 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
456 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
457 | golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
458 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
459 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
460 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
461 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
462 | golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
463 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
464 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
465 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
466 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
467 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
468 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
469 | google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
470 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
471 | google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
472 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
473 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
474 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
475 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
476 | google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
477 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
478 | google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
479 | google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
480 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
481 | google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506 h1:uLBY0yHDCj2PMQ98KWDSIDFwn9zK2zh+tgWtbvPPBjI=
482 | google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
483 | google.golang.org/genproto v0.0.0-20220211171837-173942840c17 h1:2X+CNIheCutWRyKRte8szGxrE5ggtV4U+NKAbh/oLhg=
484 | google.golang.org/genproto v0.0.0-20220211171837-173942840c17/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
485 | google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
486 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
487 | google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
488 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
489 | google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
490 | google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
491 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
492 | google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
493 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
494 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
495 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
496 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
497 | google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
498 | google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
499 | google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
500 | google.golang.org/grpc v1.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg=
501 | google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
502 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
503 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
504 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
505 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
506 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
507 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
508 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
509 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
510 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
511 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
512 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
513 | google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
514 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
515 | google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
516 | google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
517 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
518 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
519 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
520 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
521 | gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
522 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
523 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
524 | gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
525 | gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
526 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
527 | gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
528 | gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
529 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
530 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
531 | gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
532 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
533 | gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
534 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
535 | gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
536 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
537 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
538 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
539 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
540 | gopkg.in/zabawaba99/firego.v1 v1.0.0-20190331000051-3bcc4b6a4599 h1:6tee3tOL08HN/dELJ2oqGniOP4rguQapttHTRL+EXds=
541 | gopkg.in/zabawaba99/firego.v1 v1.0.0-20190331000051-3bcc4b6a4599/go.mod h1:rigVqetXSZPScx4X6R9+URJkQcxn9EDiqJxFuY2XQW0=
542 | honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
543 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
544 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
545 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
546 | nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k=
547 | nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
548 | nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
549 | nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
550 | sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
551 | sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
552 |
--------------------------------------------------------------------------------