Browse Source

Store home latitude and longitude in database

Improve error handling in API and clients
Add Air configuration for running API locally
master
Devin Dooley 1 year ago
parent
commit
b96774521a
10 changed files with 180 additions and 44 deletions
  1. +47
    -0
      .air.conf
  2. +2
    -0
      .gitignore
  3. +2
    -2
      Makefile
  4. +4
    -3
      README.md
  5. +35
    -22
      api/api.go
  6. +12
    -2
      api/auth.go
  7. +18
    -0
      api/weather.go
  8. +12
    -14
      clients/shared/api.js
  9. +8
    -1
      go.mod
  10. +40
    -0
      go.sum

+ 47
- 0
.air.conf View File

@ -0,0 +1,47 @@
# Config file for [Air](https://github.com/cosmtrek/air) in TOML format
# Working directory
# . or absolute path, please note that the directories following must be under root.
root = "."
tmp_dir = "tmp"
[build]
# Just plain old shell command. You could use `make` as well.
cmd = "go build -o ./tmp/me"
# Binary file yields from `cmd`.
bin = "tmp/me"
# Customize binary.
full_bin = "./tmp/me --config .config.yml"
# Watch these filename extensions.
include_ext = ["go"]
# Ignore these filename extensions or directories.
exclude_dir = ["clients"]
# Watch these directories if you specified.
include_dir = []
# Exclude files.
exclude_file = []
# This log file places in your tmp_dir.
log = "air.log"
# It's not necessary to trigger build each time file changes if it's too frequent.
delay = 1000 # ms
# Stop running old binary when build errors occur.
stop_on_error = true
# Send Interrupt signal before killing process (windows does not support this feature)
send_interrupt = false
# Delay after sending Interrupt signal
kill_delay = 500 # ms
[log]
# Show log time
time = true
[color]
# Customize each part's color. If no color found, use the raw app log.
main = "magenta"
watcher = "cyan"
build = "yellow"
runner = "green"
[misc]
# Delete tmp directory on exit
clean_on_exit = true

+ 2
- 0
.gitignore View File

@ -2,6 +2,8 @@ me
.config.yml
/tmp/*
/clients/web/build
/clients/web/node_modules


+ 2
- 2
Makefile View File

@ -7,8 +7,8 @@ build_web:
start: build build_web
./me --config .config.yml
start_api: build
./me --config .config.yml
start_api:
air
start_web:
npm run start --prefix clients/web


+ 4
- 3
README.md View File

@ -29,6 +29,10 @@ and a web client that supports logging in and viewing account balances. We'll se
more I get before my focus gets drawn elsewhere.
## Development Dependencies
- [air](https://github.com/cosmtrek/air)
## Configuration
### Plaid
@ -62,8 +66,6 @@ cta:
dark_sky:
secret_key: DARK_SKY_SECRET_KEY
home_latitude: HOME_LAT
home_longitude: HOME_LONG
db:
address: ADDRESS_OF_POSTGRES_DB
@ -72,7 +74,6 @@ plaid:
client_id: PLAID_CLIENT_ID
public_key: PLAID_PUBLIC_KEY
secret_key: PLAID_SECRET_KEY
access_token: PLAID_ITEM_ACCESS_TOKEN
environment: development
version: 2019-05-29
```


+ 35
- 22
api/api.go View File

@ -137,15 +137,17 @@ func signUpHandler(c *gin.Context) {
var loginVals Login
err := c.ShouldBindJSON(&loginVals)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
c.JSON(http.StatusInternalServerError, err.Error())
return
}
err = signUp(&loginVals)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
c.JSON(http.StatusInternalServerError, err.Error())
return
}
c.String(http.StatusOK, "")
c.Writer.WriteHeader(http.StatusNoContent)
}
// Banking handlers
@ -157,15 +159,17 @@ func createPlaidItemHandler(c *gin.Context) {
var publicToken PlaidPublicToken
err := c.ShouldBindJSON(&publicToken)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
c.JSON(http.StatusInternalServerError, err.Error())
return
}
err = createPlaidItem(userId, &publicToken)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
c.JSON(http.StatusInternalServerError, err.Error())
return
}
c.String(http.StatusOK, "")
c.Writer.WriteHeader(http.StatusNoContent)
}
// Returns true if a user has Plaid items configured
@ -175,7 +179,8 @@ func userHasPlaidItemsHandler(c *gin.Context) {
hasItems, err := userHasPlaidItems(userId)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
c.JSON(http.StatusInternalServerError, err.Error())
return
}
c.JSON(http.StatusOK, hasItems)
@ -186,14 +191,15 @@ func balancesHandler(c *gin.Context) {
balances, err := userBalances(userId)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
c.JSON(http.StatusInternalServerError, err.Error())
return
}
c.JSON(http.StatusOK, balances)
}
func transactionsHandler(c *gin.Context) {
c.String(http.StatusOK, "This functionality is not implemented yet")
c.JSON(http.StatusOK, "This functionality is not implemented yet")
}
// Location handlers
@ -201,19 +207,21 @@ func logLocationHandler(c *gin.Context) {
var location Location
err := c.ShouldBindQuery(&location)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
c.JSON(http.StatusInternalServerError, err.Error())
return
}
err = location.log()
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
c.JSON(http.StatusInternalServerError, err.Error())
return
}
c.String(http.StatusOK, "")
c.Writer.WriteHeader(http.StatusNoContent)
}
func getLocationHandler(c *gin.Context) {
c.JSON(http.StatusOK, "This functionality is not implemented yet")
}
// Transit handlers
@ -221,7 +229,8 @@ func arrivalsHandler(c *gin.Context) {
station := c.Param("station")
arrivals, err := arrivals(station)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
c.JSON(http.StatusInternalServerError, err.Error())
return
}
c.JSON(http.StatusOK, arrivals)
@ -231,7 +240,8 @@ func homeArrivalsHandler(c *gin.Context) {
station := conf.CTA.HomeStation
arrivals, err := arrivals(station)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
c.JSON(http.StatusInternalServerError, err.Error())
return
}
c.JSON(http.StatusOK, arrivals)
@ -241,7 +251,8 @@ func workArrivalsHandler(c *gin.Context) {
station := conf.CTA.WorkStation
arrivals, err := arrivals(station)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
c.JSON(http.StatusInternalServerError, err.Error())
return
}
c.JSON(http.StatusOK, arrivals)
@ -254,7 +265,8 @@ func forecastHandler(c *gin.Context) {
weather, err := forecast(latitude, longitude)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
c.JSON(http.StatusInternalServerError, err.Error())
return
}
c.JSON(http.StatusOK, weather)
@ -267,7 +279,8 @@ func timeTravelHandler(c *gin.Context) {
weather, err := timeTravel(latitude, longitude, time)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
c.JSON(http.StatusInternalServerError, err.Error())
return
}
c.JSON(http.StatusOK, weather)
@ -275,12 +288,12 @@ func timeTravelHandler(c *gin.Context) {
}
func homeForecastHandler(c *gin.Context) {
latitude := conf.DarkSky.HomeLatitude
longitude := conf.DarkSky.HomeLongitude
userId := int64(jwt.ExtractClaims(c)["id"].(float64))
weather, err := forecast(latitude, longitude)
weather, err := homeForecast(userId)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
c.JSON(http.StatusInternalServerError, err.Error())
return
}
c.JSON(http.StatusOK, weather)


+ 12
- 2
api/auth.go View File

@ -123,9 +123,17 @@ func authorizator(data interface{}, c *gin.Context) bool {
}
func unauthorized(c *gin.Context, code int, message string) {
c.JSON(code, message)
}
func logoutResponse(c *gin.Context, code int) {
c.Writer.WriteHeader(code)
}
func refreshResponse(c *gin.Context, code int, token string, expire time.Time) {
c.JSON(code, gin.H{
"jwt": "",
"error": message,
"token": token,
"expire": expire.Format(time.RFC3339),
})
}
@ -141,6 +149,8 @@ func initAuth() (*jwt.GinJWTMiddleware, error) {
Authenticator: authenticator,
Authorizator: authorizator,
Unauthorized: unauthorized,
LogoutResponse: logoutResponse,
RefreshResponse: refreshResponse,
// TokenLookup is a string in the form of "<source>:<name>" that is used
// to extract token from the request.
// Optional. Default value "header:Authorization".


+ 18
- 0
api/weather.go View File

@ -1,6 +1,7 @@
package api
import (
"context"
"encoding/json"
"io/ioutil"
"net/http"
@ -78,6 +79,23 @@ type WeatherAlert struct {
Uri string `json:"uri,omitempty"`
}
func homeForecast(userId int64) (Weather, error) {
var latitude string
var longitude string
err := conn.QueryRow(
context.Background(),
"SELECT home_latitude::text, home_longitude::text FROM users WHERE id=$1",
userId,
).Scan(&latitude, &longitude)
if err != nil {
return Weather{}, err
}
return forecast(latitude, longitude)
}
func forecast(latitude string, longitude string) (Weather, error) {
weather := Weather{}
reqUrl := "https://api.darksky.net/forecast/" +


+ 12
- 14
clients/shared/api.js View File

@ -10,7 +10,7 @@ let jwt = null;
// It is expected that the consumer of these static methods will handle Promise rejection
//
// If the response returns an error field, we always throw that error
// This is how API authentication errors are caught, but in the future this may be used anywhere
// This is how all errors are planned to be caught, and we just display backend errors to the user
export default class api {
static get(route, authenticate=true) {
const url = getURL(route);
@ -18,13 +18,12 @@ export default class api {
method: 'GET',
headers: getHeaders(authenticate),
}).then((resp) => {
return resp.json();
}).then((resp) => {
if (resp.error) {
throw resp.error;
return Promise.all([resp, resp.json()])
}).then(([resp, body]) => {
if (!resp.ok) {
throw body
}
return resp;
return body
});
}
@ -35,13 +34,12 @@ export default class api {
headers: getHeaders(authenticate),
body: JSON.stringify(body),
}).then((resp) => {
return resp.json();
}).then((resp) => {
if (resp.error) {
throw resp.error;
return Promise.all([resp, resp.json()])
}).then(([resp, body]) => {
if (!resp.ok) {
throw body
}
return resp;
return body
});
}
}
@ -69,5 +67,5 @@ function getHeaders(authenticate) {
'Accept': 'application/json',
...(authenticate ? { 'Authorization': 'Bearer ' + jwt } : {}),
'Content-Type': 'application/json',
};
}
}

+ 8
- 1
go.mod View File

@ -4,12 +4,19 @@ go 1.13
require (
github.com/appleboy/gin-jwt/v2 v2.6.3
github.com/cosmtrek/air v1.12.1 // indirect
github.com/creack/pty v1.1.11 // indirect
github.com/fatih/color v1.9.0 // indirect
github.com/gin-contrib/cors v1.3.1
github.com/gin-gonic/contrib v0.0.0-20191209060500-d6e26eeaa607
github.com/gin-gonic/gin v1.5.0
github.com/imdario/mergo v0.3.9 // indirect
github.com/jackc/pgx/v4 v4.6.0
github.com/mattn/go-colorable v0.1.7 // indirect
github.com/pelletier/go-toml v1.8.0 // indirect
github.com/plaid/plaid-go v0.0.0-20200226182544-efa72c1a50fd
github.com/spf13/viper v1.6.2
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59
gopkg.in/yaml.v2 v2.2.7
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae // indirect
gopkg.in/yaml.v2 v2.3.0
)

+ 40
- 0
go.sum View File

@ -21,15 +21,27 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cosmtrek/air v1.12.1 h1:5YnQHF0a09Yt8vNWYtK3CtlR8aodV4w23Iz+fLSDLE4=
github.com/cosmtrek/air v1.12.1/go.mod h1:5EsgUqrBIHlW2ghNoevwPBEG1FQvF5XNulikjPte538=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/cors v1.3.1 h1:doAsuITavI4IOcd0Y19U4B+O0dNWihRyX//nn4sEmgA=
github.com/gin-contrib/cors v1.3.1/go.mod h1:jjEJ4268OPZUcU7k9Pm653S7lXUGcqMADzFA61xsmDk=
@ -69,6 +81,10 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
@ -134,11 +150,20 @@ github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzR
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
@ -150,6 +175,10 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4=
github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
github.com/pelletier/go-toml v1.8.0 h1:Keo9qb7iRJs2voHvunFtuuYFsbWeOBh8/P9v/kVMFtw=
github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/plaid/plaid-go v0.0.0-20200226182544-efa72c1a50fd h1:Zaoqxkm/32UmBmHchKJ8g9xutM+IQExlQNEC+RMevUI=
@ -255,6 +284,15 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4 h1:Hynbrlo6LbYI3H1IqXpkVDOcX/3HiPdhVEuyj5a59RM=
golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
@ -295,4 +333,6 @@ gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

Loading…
Cancel
Save